module Noir::JSObjectConfigExtractor

Overview

Extracts declarative object-literal configs out of JS/TS sources.

Several frameworks describe their HTTP surface as a plain object rather than as route calls — Payload CMS collections ({ slug, fields }) and Strapi route files ({ routes: [...] }) among them. Both are read the same way: find the object literals that carry a known set of keys and decode them into Crystal data.

The search is a depth-first sweep for any object node holding the required keys, deliberately not a match on the export const X = {…} declaration spine. That makes it indifferent to how the object is declared, which in the wild means all of:

export const Posts: CollectionConfig = { slug: 'posts', fields: [] }
export const Posts = { slug: 'posts', fields: [] } satisfies CollectionConfig
export default buildConfig({ collections: [{ slug: 'posts', fields: [] }] })
module.exports = { slug: 'posts', fields: [] }

TypeScript is parsed with the vendored JavaScript grammar (no TypeScript grammar is vendored — see tree_sitter.cr) after two narrow annotation strips, below.

Extended Modules

Defined in:

miniparsers/js_object_config_extractor.cr

Constant Summary

DECLARATION_ANNOTATION = /(\b(?:export\s+)?(?:const|let|var)\s+[A-Za-z_$][\w$]*)\s*:\s*[^=\n]+=/

export const Posts: CollectionConfig = { would otherwise parse with the type as the variable name. Line-preserving so the reported line still matches the original source.

MAX_VALUE_DEPTH = 12

Guards against pathological nesting in generated configs.

SATISFIES_ASSERTION = /\bsatisfies\s+[A-Za-z_$][\w$.]*(?:<[^>\n]*>)?/

} satisfies CollectionConfig is Payload's modern idiom and the JS grammar has no satisfies operator.

Instance Method Summary

Instance Method Detail

def extract(source : String, required_keys : Array(String)) : Array(ConfigObject) #

Returns every object literal in source carrying all of required_keys. Once an object matches, its own subtree is not searched again — otherwise a nested config would surface twice.


[View source]