@objectstack/sdui-parser 17.2.0 → 17.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/parse.ts","../src/validate.ts","../src/codegen.ts","../src/index.ts"],"sourcesContent":["/**\n * ObjectUI — SDUI JSX-source parser (ADR-0080)\n *\n * A small recursive-descent parser for a CONSTRAINED JSX subset. It is\n * deliberately not a full JS/JSX parser: a bounded grammar is the point\n * (Markdoc model) — it shrinks the attack surface and the expressible-but-wrong\n * space. Output is the existing SDUI `SchemaNode` tree. Nothing is executed.\n *\n * Grammar (informal):\n * document := element (exactly one root)\n * element := openTag child-star closeTag, or a self-closing tag\n * attr := name '=' (string | braced), or a bare name meaning true\n * child := element | text | jsx-block-comment\n * tag := [A-Za-z][A-Za-z0-9:_-]star (matches registry keys)\n */\n\nimport type { Diagnostic, ParseOptions, ParseResult, SchemaElement, SchemaNode } from './types.js';\n\n/** Event handlers and raw-HTML injection are never allowed (parse ≠ execute). */\nconst EVENT_ATTR = /^on[A-Z]/;\nconst FORBIDDEN_ATTRS = new Set(['dangerouslySetInnerHTML', 'ref', 'key']);\n\nexport function parseJsx(source: string, options: ParseOptions = {}): ParseResult {\n return new Parser(source, options).parseDocument();\n}\n\nconst isNameStart = (c: string) => /[A-Za-z]/.test(c);\nconst isNameChar = (c: string) => /[A-Za-z0-9:_-]/.test(c);\n\nclass Parser {\n private pos = 0;\n private readonly diagnostics: Diagnostic[] = [];\n\n constructor(private readonly src: string, private readonly opts: ParseOptions) {}\n\n parseDocument(): ParseResult {\n this.skipTrivia();\n if (this.peek() !== '<') {\n this.error('no-root', 'Expected a single root element');\n return { tree: null, diagnostics: this.diagnostics };\n }\n const tree = this.parseElement();\n this.skipTrivia();\n if (tree && this.pos < this.src.length) {\n this.error('multiple-roots', 'A page must have exactly one root element', this.pos);\n }\n return { tree, diagnostics: this.diagnostics };\n }\n\n private parseElement(): SchemaElement | null {\n const start = this.pos;\n if (!this.eat('<')) {\n this.error('expected-element', 'Expected \"<\"', start);\n return null;\n }\n const tag = this.readName();\n if (!tag) {\n this.error('bad-tag', 'Expected a tag name after \"<\"', start);\n return null;\n }\n if (this.opts.allowedTags && !this.opts.allowedTags.has(tag)) {\n this.error('forbidden-tag', `<${tag}> is not an allowed component`, start, tag);\n }\n\n const props: Record<string, unknown> = {};\n for (;;) {\n this.skipWs();\n const c = this.peek();\n if (c === '' || c === '>' || c === '/') break;\n const attr = this.parseAttr(start, tag);\n if (!attr) break;\n props[attr.name] = attr.value;\n }\n\n this.skipWs();\n let children: SchemaNode[] | undefined;\n if (this.eat('/')) {\n if (!this.eat('>')) this.error('bad-self-close', `Malformed self-closing <${tag}>`, this.pos, tag);\n } else if (this.eat('>')) {\n children = this.parseChildren(tag);\n } else {\n this.error('unterminated-open-tag', `Unterminated <${tag}> open tag`, start, tag);\n }\n\n const node: SchemaElement = { type: tag, ...props };\n if (children && children.length) node.children = children;\n return node;\n }\n\n private parseAttr(elStart: number, tag: string): { name: string; value: unknown } | null {\n const name = this.readName();\n if (!name) {\n this.error('bad-attr', `Malformed attribute on <${tag}>`, this.pos, tag);\n // skip one char to avoid an infinite loop on garbage\n this.pos++;\n return null;\n }\n this.skipWs();\n let value: unknown = true; // bare attribute => boolean true\n if (this.eat('=')) {\n this.skipWs();\n value = this.parseAttrValue(tag);\n }\n if (EVENT_ATTR.test(name) || FORBIDDEN_ATTRS.has(name)) {\n this.error('forbidden-attr', `Attribute \"${name}\" is not allowed on <${tag}>`, elStart, tag);\n return { name: `__forbidden_${name}`, value: undefined };\n }\n return { name, value };\n }\n\n private parseAttrValue(tag: string): unknown {\n const c = this.peek();\n if (c === '\"' || c === \"'\") return this.readString(c);\n if (c === '{') return interpretBrace(this.readBraced());\n this.error('bad-attr-value', `Expected an attribute value on <${tag}>`, this.pos, tag);\n return undefined;\n }\n\n private parseChildren(parentTag: string): SchemaNode[] {\n const children: SchemaNode[] = [];\n for (;;) {\n if (this.pos >= this.src.length) {\n this.error('unclosed-element', `Unclosed <${parentTag}>`, this.pos, parentTag);\n break;\n }\n // closing tag\n if (this.src.startsWith('</', this.pos)) {\n this.pos += 2;\n this.skipWs();\n const close = this.readName();\n this.skipWs();\n this.eat('>');\n if (close !== parentTag) {\n this.error('mismatched-tag', `Expected </${parentTag}> but found </${close}>`, this.pos, parentTag);\n }\n break;\n }\n // JSX comment {/* ... */}\n if (this.src.startsWith('{/*', this.pos)) {\n const end = this.src.indexOf('*/}', this.pos);\n if (end === -1) {\n this.error('unclosed-comment', 'Unclosed comment', this.pos);\n this.pos = this.src.length;\n } else {\n this.pos = end + 3;\n }\n continue;\n }\n // nested element\n if (this.peek() === '<') {\n const el = this.parseElement();\n if (el) children.push(el);\n continue;\n }\n // expression child {expr} — out of grammar for v1: skip with a warning\n if (this.peek() === '{') {\n const start = this.pos;\n this.readBraced();\n this.error(\n 'expression-child',\n 'Inline {expression} children are not supported yet — bind via a component prop',\n start,\n );\n continue;\n }\n // text\n const text = this.readTextRun();\n const trimmed = text.replace(/\\s+/g, ' ').trim();\n if (trimmed) children.push(trimmed);\n }\n return children;\n }\n\n /* ----------------------------- lexing ----------------------------- */\n\n private peek(): string {\n return this.pos < this.src.length ? this.src[this.pos] : '';\n }\n\n private eat(ch: string): boolean {\n if (this.src[this.pos] === ch) {\n this.pos++;\n return true;\n }\n return false;\n }\n\n private readName(): string {\n if (!isNameStart(this.peek())) return '';\n const start = this.pos;\n this.pos++;\n while (this.pos < this.src.length && isNameChar(this.src[this.pos])) this.pos++;\n return this.src.slice(start, this.pos);\n }\n\n private readString(quote: string): string {\n this.pos++; // opening quote\n const start = this.pos;\n while (this.pos < this.src.length && this.src[this.pos] !== quote) this.pos++;\n const value = this.src.slice(start, this.pos);\n if (!this.eat(quote)) this.error('unterminated-string', 'Unterminated string literal', start);\n return value;\n }\n\n /** Reads a balanced `{ ... }` run and returns the inner text (no outer braces). */\n private readBraced(): string {\n const start = this.pos;\n let depth = 0;\n let inStr: string | null = null;\n for (; this.pos < this.src.length; this.pos++) {\n const ch = this.src[this.pos];\n if (inStr) {\n if (ch === inStr && this.src[this.pos - 1] !== '\\\\') inStr = null;\n continue;\n }\n if (ch === '\"' || ch === \"'\") inStr = ch;\n else if (ch === '{') depth++;\n else if (ch === '}') {\n depth--;\n if (depth === 0) {\n const inner = this.src.slice(start + 1, this.pos);\n this.pos++; // consume closing brace\n return inner;\n }\n }\n }\n this.error('unterminated-brace', 'Unterminated \"{\"', start);\n return this.src.slice(start + 1);\n }\n\n private readTextRun(): string {\n const start = this.pos;\n while (this.pos < this.src.length && this.src[this.pos] !== '<' && this.src[this.pos] !== '{') this.pos++;\n return this.src.slice(start, this.pos);\n }\n\n private skipWs(): void {\n while (this.pos < this.src.length && /\\s/.test(this.src[this.pos])) this.pos++;\n }\n\n /** whitespace + top-level JSX comments */\n private skipTrivia(): void {\n for (;;) {\n this.skipWs();\n if (this.src.startsWith('{/*', this.pos)) {\n const end = this.src.indexOf('*/}', this.pos);\n this.pos = end === -1 ? this.src.length : end + 3;\n continue;\n }\n break;\n }\n }\n\n private error(code: string, message: string, start?: number, tag?: string): void {\n this.diagnostics.push({ severity: 'error', code, message, start: start ?? this.pos, tag });\n }\n}\n\n/**\n * Interpret a braced attribute value `{...}`.\n * JSON-literal values (numbers, booleans, null, strings, arrays, objects with\n * quoted keys) are materialized. Anything else is kept as a deferred expression\n * marker `{ $expr }` — typed and validated later, NEVER evaluated here.\n */\nexport function interpretBrace(raw: string): unknown {\n const trimmed = raw.trim();\n try {\n return JSON.parse(trimmed);\n } catch {\n return { $expr: trimmed };\n }\n}\n","/**\n * ObjectUI — SDUI tree validation against the registry manifest (ADR-0080 §3/§6)\n *\n * Shallow, author-time validation: unknown component, unknown/missing prop,\n * wrong coarse type, illegal enum value. Collects `requires` (plugin provenance)\n * and binding sites the SERVER must resolve against object schema (we cannot\n * resolve objects/fields here — that check is framework-side by design).\n */\n\nimport type {\n Diagnostic,\n Manifest,\n ManifestInput,\n SchemaElement,\n SchemaNode,\n ValidationResult,\n} from './types.js';\n\n/** Base props every node may carry (mirrors BaseSchema) — never \"unknown prop\". */\nconst BASE_PROPS = new Set([\n 'type',\n 'id',\n 'className',\n 'style',\n 'visible',\n 'visibleOn',\n 'disabled',\n 'disabledOn',\n 'children',\n]);\n\nconst isExpr = (v: unknown): boolean =>\n typeof v === 'object' && v !== null && '$expr' in (v as Record<string, unknown>);\n\nexport function validateTree(tree: SchemaElement | null, manifest: Manifest): ValidationResult {\n const diagnostics: Diagnostic[] = [];\n const requires = new Set<string>();\n const bindings: ValidationResult['bindings'] = [];\n\n const visit = (node: SchemaNode): void => {\n if (typeof node === 'string') return;\n const comp = manifest.components[node.type];\n if (!comp) {\n diagnostics.push({\n severity: 'error',\n code: 'unknown-component',\n message: `<${node.type}> is not a known component`,\n tag: node.type,\n });\n } else {\n if (comp.namespace) requires.add(comp.namespace);\n const byName = new Map(comp.inputs.map((i) => [i.name, i]));\n\n // required present?\n for (const input of comp.inputs) {\n if (input.required && !(input.name in node)) {\n diagnostics.push({\n severity: 'error',\n code: 'missing-required-prop',\n message: `<${node.type}> is missing required prop \"${input.name}\"`,\n tag: node.type,\n });\n }\n }\n\n // each provided prop\n for (const [key, value] of Object.entries(node)) {\n if (BASE_PROPS.has(key)) continue;\n const input = byName.get(key);\n if (!input) {\n diagnostics.push({\n severity: 'warning',\n code: 'unknown-prop',\n message: `<${node.type}> has no prop \"${key}\"`,\n tag: node.type,\n });\n continue;\n }\n if (input.binding) {\n bindings.push({ tag: node.type, input: key, kind: input.binding, value });\n }\n if (!isExpr(value)) {\n const typeDiag = checkType(node.type, input, value);\n if (typeDiag) diagnostics.push(typeDiag);\n }\n }\n\n // containment\n if (node.children?.length && !comp.isContainer) {\n diagnostics.push({\n severity: 'warning',\n code: 'not-a-container',\n message: `<${node.type}> does not accept children`,\n tag: node.type,\n });\n }\n }\n\n if (node.children) node.children.forEach(visit);\n };\n\n if (tree) visit(tree);\n return { diagnostics, requires: [...requires], bindings };\n}\n\nfunction checkType(tag: string, input: ManifestInput, value: unknown): Diagnostic | null {\n const mismatch = (expected: string): Diagnostic => ({\n severity: 'warning',\n code: 'type-mismatch',\n message: `<${tag}> prop \"${input.name}\" expected ${expected}`,\n tag,\n });\n switch (input.type) {\n case 'number':\n return typeof value === 'number' ? null : mismatch('a number');\n case 'boolean':\n return typeof value === 'boolean' ? null : mismatch('a boolean');\n case 'string':\n case 'color':\n case 'date':\n case 'code':\n case 'file':\n return typeof value === 'string' ? null : mismatch('a string');\n case 'array':\n return Array.isArray(value) ? null : mismatch('an array');\n case 'object':\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? null\n : mismatch('an object');\n case 'enum': {\n const allowed = (input.enum ?? []).map((e) => (typeof e === 'object' ? e.value : e));\n return allowed.includes(value as never)\n ? null\n : {\n severity: 'error',\n code: 'invalid-enum',\n message: `<${tag}> prop \"${input.name}\"=${JSON.stringify(value)} is not one of ${JSON.stringify(allowed)}`,\n tag,\n };\n }\n default:\n return null;\n }\n}\n","/**\n * ObjectUI — codegen the JSX type surface from the registry manifest (ADR-0080 §3)\n *\n * Emits a `.d.ts` that augments `JSX.IntrinsicElements` so a constrained\n * JSX-source page type-checks in `.tsx`: tag name === registry `type` key,\n * attributes === the component's manifest `inputs`. This is a TYPE-CHECKING\n * fiction — no real React intrinsic named `flex` exists; the interpreter\n * fulfills it via the registry at render time.\n */\n\nimport type { Manifest, ManifestComponent, ManifestInput } from './types.js';\n\nexport interface CodegenOptions {\n /** include a self-contained minimal JSX namespace so the d.ts type-checks\n * standalone (no React types needed). Default true. */\n standaloneJsx?: boolean;\n}\n\nexport function generateDts(manifest: Manifest, options: CodegenOptions = {}): string {\n const { standaloneJsx = true } = options;\n const comps = Object.values(manifest.components).sort((a, b) => a.type.localeCompare(b.type));\n\n const interfaces = comps.map(emitInterface).join('\\n\\n');\n const intrinsics = comps\n .map((c) => ` ${JSON.stringify(c.type)}: ${propsName(c.type)};`)\n .join('\\n');\n\n const baseElement = standaloneJsx\n ? `\n // minimal, so the surface type-checks without pulling React types\n type Element = unknown;\n interface ElementClass {}\n interface ElementAttributesProperty {}\n interface ElementChildrenAttribute { children: object; }`\n : '';\n\n return `// AUTO-GENERATED by @object-ui/sdui-parser — DO NOT EDIT.\n// Source of truth: ComponentRegistry inputs (ADR-0080 §3). Regenerate via codegen.\n/* eslint-disable */\n\nexport interface SduiBaseProps {\n id?: string;\n className?: string;\n style?: Record<string, unknown>;\n visible?: boolean;\n visibleOn?: string;\n disabled?: boolean;\n disabledOn?: string;\n children?: unknown;\n}\n\n${interfaces}\n\ndeclare global {\n namespace JSX {\n interface IntrinsicElements {\n${intrinsics}\n }${baseElement}\n }\n}\n\nexport {};\n`;\n}\n\nfunction emitInterface(comp: ManifestComponent): string {\n const lines = comp.inputs\n .filter((i) => i.type !== 'slot')\n .map((i) => ` ${propLine(i)}`)\n .join('\\n');\n return `export interface ${propsName(comp.type)} extends SduiBaseProps {\\n${lines}\\n}`;\n}\n\nfunction propLine(input: ManifestInput): string {\n const opt = input.required ? '' : '?';\n return `${quoteKeyIfNeeded(input.name)}${opt}: ${tsType(input)};`;\n}\n\nfunction tsType(input: ManifestInput): string {\n switch (input.type) {\n case 'number':\n return 'number';\n case 'boolean':\n return 'boolean';\n case 'array':\n return 'unknown[]';\n case 'object':\n return 'Record<string, unknown>';\n case 'enum': {\n const vals = (input.enum ?? []).map((e) => (typeof e === 'object' ? e.value : e));\n return vals.length ? vals.map((v) => JSON.stringify(v)).join(' | ') : 'string';\n }\n case 'string':\n case 'color':\n case 'date':\n case 'code':\n case 'file':\n default:\n return 'string';\n }\n}\n\nconst IDENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\nconst quoteKeyIfNeeded = (name: string): string => (IDENT.test(name) ? name : JSON.stringify(name));\n\n/** 'object-grid' -> 'ObjectGrid', 'record:details' -> 'RecordDetails' */\nexport function propsName(type: string): string {\n const pascal = type\n .split(/[^A-Za-z0-9]+/)\n .filter(Boolean)\n .map((s) => s[0].toUpperCase() + s.slice(1))\n .join('');\n return `${pascal}Props`;\n}\n\n/**\n * Generate the human-facing PUBLIC block list (the curated \"清单\") from a\n * manifest — a Markdown table. Derived, never hand-maintained (ADR-0046).\n */\nexport function generateBlockList(manifest: Manifest): string {\n const rows = Object.values(manifest.components)\n .sort((a, b) => a.type.localeCompare(b.type))\n .map((c) => {\n const req = c.inputs.filter((i) => i.required).map((i) => i.name);\n const binds = c.inputs.filter((i) => i.binding).map((i) => `${i.name}:${i.binding}`);\n return `| \\`${c.type}\\` | ${c.namespace ?? '—'} | ${c.isContainer ? '✓' : ''} | ${req.join(', ') || '—'} | ${binds.join(', ') || '—'} |`;\n });\n return [\n `# SDUI public blocks (${Object.keys(manifest.components).length})`,\n '',\n '> Auto-generated from the registry `tier:\\'public\\'` set (ADR-0080). Do not edit by hand.',\n '',\n '| block | plugin | container | required props | bindings |',\n '|---|---|---|---|---|',\n ...rows,\n '',\n ].join('\\n');\n}\n","/**\n * @objectstack/sdui-parser — constrained JSX-source → SDUI SchemaNode tree (ADR-0080)\n *\n * Isomorphic, zero React. Run server-side as the authoritative save-time gate;\n * may also run client-side for live edit preview (re-validated on the server —\n * never the trust boundary). It PARSES; it never executes.\n */\n\nexport * from './types.js';\nexport { parseJsx, interpretBrace } from './parse.js';\nexport { validateTree } from './validate.js';\nexport { generateDts, propsName, generateBlockList } from './codegen.js';\nexport type { CodegenOptions } from './codegen.js';\n\nimport { parseJsx } from './parse.js';\nimport { validateTree } from './validate.js';\nimport type { Diagnostic, Manifest, SchemaElement, ValidationResult } from './types.js';\n\nexport interface CompileResult {\n tree: SchemaElement | null;\n diagnostics: Diagnostic[];\n requires: string[];\n bindings: ValidationResult['bindings'];\n /** true when there are no error-severity diagnostics — the save gate's pass/fail */\n ok: boolean;\n}\n\n/**\n * The authoritative pipeline: parse (with the manifest's tags as the whitelist)\n * → validate against the manifest → derive `requires` + binding sites.\n */\nexport function compile(source: string, manifest: Manifest): CompileResult {\n const allowedTags = new Set(Object.keys(manifest.components));\n const parsed = parseJsx(source, { allowedTags });\n const validated = validateTree(parsed.tree, manifest);\n const diagnostics = [...parsed.diagnostics, ...validated.diagnostics];\n return {\n tree: parsed.tree,\n diagnostics,\n requires: validated.requires,\n bindings: validated.bindings,\n ok: !diagnostics.some((d) => d.severity === 'error'),\n };\n}\n\n/* ------------------------------------------------------------------ *\n * Registry → manifest adapter. Structural input (no @object-ui/core\n * dependency) so the package stays pure and hoistable to framework.\n * Feed it `ComponentRegistry.getAllConfigs()` (optionally filtered to\n * the `tier:'public'` set).\n * ------------------------------------------------------------------ */\n\nexport interface RegistryConfigLike {\n type: string;\n namespace?: string;\n isContainer?: boolean;\n /** ADR-0080 contract tier — only 'public' configs form the AI/contract surface. */\n tier?: 'public' | 'internal';\n label?: string;\n category?: string;\n inputs?: Array<{\n name: string;\n type: string;\n required?: boolean;\n enum?: Array<string | { value: unknown; label?: string }>;\n binding?: 'object' | 'field';\n description?: string;\n }>;\n}\n\nconst INPUT_TYPES = new Set([\n 'string',\n 'number',\n 'boolean',\n 'enum',\n 'array',\n 'object',\n 'color',\n 'date',\n 'code',\n 'file',\n 'slot',\n]);\n\nexport function manifestFromConfigs(\n configs: RegistryConfigLike[],\n opts: { only?: Set<string>; publicOnly?: boolean } = {},\n): Manifest {\n const components: Manifest['components'] = {};\n for (const c of configs) {\n if (opts.only && !opts.only.has(c.type)) continue;\n if (opts.publicOnly && c.tier !== 'public') continue;\n components[c.type] = {\n type: c.type,\n namespace: c.namespace,\n isContainer: c.isContainer,\n inputs: (c.inputs ?? []).map((i) => ({\n name: i.name,\n type: (INPUT_TYPES.has(i.type) ? i.type : 'string') as Manifest['components'][string]['inputs'][number]['type'],\n required: i.required,\n enum: i.enum,\n binding: i.binding,\n description: i.description,\n })),\n };\n }\n return { components };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/parse.ts","../src/input-type.ts","../src/dashboard-widget-options.ts","../src/validate.ts","../src/codegen.ts","../src/index.ts"],"sourcesContent":["/**\n * ObjectUI — SDUI JSX-source parser (ADR-0080)\n *\n * A small recursive-descent parser for a CONSTRAINED JSX subset. It is\n * deliberately not a full JS/JSX parser: a bounded grammar is the point\n * (Markdoc model) — it shrinks the attack surface and the expressible-but-wrong\n * space. Output is the existing SDUI `SchemaNode` tree. Nothing is executed.\n *\n * Grammar (informal):\n * document := element (exactly one root)\n * element := openTag child-star closeTag, or a self-closing tag\n * attr := name '=' (string | braced), or a bare name meaning true\n * child := element | text | jsx-block-comment\n * tag := [A-Za-z][A-Za-z0-9:_-]star (matches registry keys)\n */\n\nimport type { Diagnostic, ParseOptions, ParseResult, SchemaElement, SchemaNode } from './types.js';\n\n/** Event handlers and raw-HTML injection are never allowed (parse ≠ execute). */\nconst EVENT_ATTR = /^on[A-Z]/;\nconst FORBIDDEN_ATTRS = new Set(['dangerouslySetInnerHTML', 'ref', 'key']);\n\n/**\n * The envelope's own discriminator, which on THIS tier the tag name sets.\n *\n * An authored `type=` attribute is a NAME COLLISION with it, and the parser\n * refuses it at parse time (maintainer ruling 2026-09-01, recorded as an\n * amendment on ADR-0080 — 「响亮拒绝」, quoted verbatim there). One diagnostic\n * naming BOTH the tag and the attribute replaces two bad outcomes:\n *\n * - the value named another REGISTERED type (`<flex type=\"grid\">`) — the tree\n * carried `type:'grid'`, `validateTree` found `grid` in the manifest, every\n * check passed, and the page rendered a grid where the author wrote a flex.\n * ZERO diagnostics. On the one tier whose whole premise is that unreviewed\n * and AI-authored source is safe to accept.\n * - the value named NOTHING registered (`<object-chart type=\"bar\">`, the shape\n * a react-tier author carries across) — loud, but `unknown-component`\n * naming `\"bar\"` reads as a missing plugin, never as a bad prop.\n *\n * ⛔ NOT rescued as `specType` the way the react tier rescues it (objectui#2880):\n * that is consumer-side tolerance, and it would spread an alias concept to a\n * second tier. ⛔ NOT a warning grace period either — the same ruling declined\n * a staged rollout. ⛔ And NOT fixable at the warning layer: `type` is in\n * `validate.ts`'s `BASE_PROPS` deliberately (it is correct for every other\n * member), so removing it there would make every legitimate node warn. The\n * refusal belongs here, at parse.\n *\n * ⚠️ The code is the EXISTING `forbidden-attr`, not a new one, and that is\n * load-bearing rather than lazy: `scripts/check-sdui-lockstep.mjs` holds this\n * copy's diagnostic-code set equal to objectui's at the pinned revision, so a\n * code minted on one side only IS the dialect split that gate exists to catch\n * (#12719). `forbidden-attr` already carries this shape — an attribute this\n * tier refuses, named beside its element — and both copies stamp it.\n */\nconst DISCRIMINATOR_ATTR = 'type';\n\nexport function parseJsx(source: string, options: ParseOptions = {}): ParseResult {\n return new Parser(source, options).parseDocument();\n}\n\nconst isNameStart = (c: string) => /[A-Za-z]/.test(c);\nconst isNameChar = (c: string) => /[A-Za-z0-9:_-]/.test(c);\n\nclass Parser {\n private pos = 0;\n private readonly diagnostics: Diagnostic[] = [];\n\n constructor(private readonly src: string, private readonly opts: ParseOptions) {}\n\n parseDocument(): ParseResult {\n this.skipTrivia();\n if (this.peek() !== '<') {\n this.error('no-root', 'Expected a single root element');\n return { tree: null, diagnostics: this.diagnostics };\n }\n const tree = this.parseElement();\n this.skipTrivia();\n if (tree && this.pos < this.src.length) {\n this.error('multiple-roots', 'A page must have exactly one root element', this.pos);\n }\n return { tree, diagnostics: this.diagnostics };\n }\n\n private parseElement(): SchemaElement | null {\n const start = this.pos;\n if (!this.eat('<')) {\n this.error('expected-element', 'Expected \"<\"', start);\n return null;\n }\n const tag = this.readName();\n if (!tag) {\n this.error('bad-tag', 'Expected a tag name after \"<\"', start);\n return null;\n }\n if (this.opts.allowedTags && !this.opts.allowedTags.has(tag)) {\n this.error('forbidden-tag', `<${tag}> is not an allowed component`, start, tag);\n }\n\n const props: Record<string, unknown> = {};\n for (;;) {\n this.skipWs();\n const c = this.peek();\n if (c === '' || c === '>' || c === '/') break;\n const attr = this.parseAttr(start, tag);\n if (!attr) break;\n // `drop` is set only for the refused discriminator attribute, and only so\n // that ONE diagnostic is what the author gets. The `__forbidden_<name>`\n // sentinel the other refusals park in `props` reaches `validateTree`,\n // which knows no such prop and adds `unknown-prop` naming a key nobody\n // wrote — loud, and pointing at the wrong thing, which is the species of\n // diagnostic this whole change exists to remove. The existing sentinel\n // behaviour is left exactly as it was for the attributes that already had\n // it (`ref`, `key`, `dangerouslySetInnerHTML`, `on*`).\n if (!attr.drop) props[attr.name] = attr.value;\n }\n\n this.skipWs();\n let children: SchemaNode[] | undefined;\n if (this.eat('/')) {\n if (!this.eat('>')) this.error('bad-self-close', `Malformed self-closing <${tag}>`, this.pos, tag);\n } else if (this.eat('>')) {\n children = this.parseChildren(tag);\n } else {\n this.error('unterminated-open-tag', `Unterminated <${tag}> open tag`, start, tag);\n }\n\n // DEFENSE IN DEPTH (ruled together with the refusal above). `props` used to\n // be spread AFTER `type: tag`, so an authored `type` attribute overwrote the\n // discriminator the tag established and nothing downstream restored it —\n // `compile()` returns this tree as-is and `validateTree` then looks up\n // `manifest.components[node.type]`, i.e. the value the author wrote, not the\n // tag they wrote. The refusal makes that overwrite unreachable; the order\n // here makes it impossible. ⚠️ Reversing the order ALONE would have been a\n // regression of its own — the authored value would then be dropped in\n // silence, trading one silence for another. It is correct only BECAUSE the\n // attribute is refused loudly one function up.\n const node: SchemaElement = { ...props, type: tag };\n if (children && children.length) node.children = children;\n return node;\n }\n\n private parseAttr(elStart: number, tag: string): { name: string; value: unknown; drop?: boolean } | null {\n const name = this.readName();\n if (!name) {\n this.error('bad-attr', `Malformed attribute on <${tag}>`, this.pos, tag);\n // skip one char to avoid an infinite loop on garbage\n this.pos++;\n return null;\n }\n this.skipWs();\n let value: unknown = true; // bare attribute => boolean true\n if (this.eat('=')) {\n this.skipWs();\n value = this.parseAttrValue(tag);\n }\n if (name === DISCRIMINATOR_ATTR) {\n // ONE diagnostic naming both the tag and the attribute — see\n // DISCRIMINATOR_ATTR above for why it replaces both prior outcomes.\n this.error(\n 'forbidden-attr',\n `Attribute \"${DISCRIMINATOR_ATTR}\" is not allowed on <${tag}> — on this tier the tag name IS the `\n + `component, so <${tag}> already means type \"${tag}\". Delete the attribute, or write the tag of the `\n + 'component you meant.',\n elStart,\n tag,\n );\n return { name, value: undefined, drop: true };\n }\n if (EVENT_ATTR.test(name) || FORBIDDEN_ATTRS.has(name)) {\n this.error('forbidden-attr', `Attribute \"${name}\" is not allowed on <${tag}>`, elStart, tag);\n return { name: `__forbidden_${name}`, value: undefined };\n }\n return { name, value };\n }\n\n private parseAttrValue(tag: string): unknown {\n const c = this.peek();\n if (c === '\"' || c === \"'\") return this.readString(c);\n if (c === '{') return interpretBrace(this.readBraced());\n this.error('bad-attr-value', `Expected an attribute value on <${tag}>`, this.pos, tag);\n return undefined;\n }\n\n private parseChildren(parentTag: string): SchemaNode[] {\n const children: SchemaNode[] = [];\n for (;;) {\n if (this.pos >= this.src.length) {\n this.error('unclosed-element', `Unclosed <${parentTag}>`, this.pos, parentTag);\n break;\n }\n // closing tag\n if (this.src.startsWith('</', this.pos)) {\n this.pos += 2;\n this.skipWs();\n const close = this.readName();\n this.skipWs();\n this.eat('>');\n if (close !== parentTag) {\n this.error('mismatched-tag', `Expected </${parentTag}> but found </${close}>`, this.pos, parentTag);\n }\n break;\n }\n // JSX comment {/* ... */}\n if (this.src.startsWith('{/*', this.pos)) {\n const end = this.src.indexOf('*/}', this.pos);\n if (end === -1) {\n this.error('unclosed-comment', 'Unclosed comment', this.pos);\n this.pos = this.src.length;\n } else {\n this.pos = end + 3;\n }\n continue;\n }\n // nested element\n if (this.peek() === '<') {\n const el = this.parseElement();\n if (el) children.push(el);\n continue;\n }\n // expression child {expr} — out of grammar for v1: skip with a warning\n if (this.peek() === '{') {\n const start = this.pos;\n this.readBraced();\n this.error(\n 'expression-child',\n 'Inline {expression} children are not supported yet — bind via a component prop',\n start,\n );\n continue;\n }\n // text\n //\n // HTML collapses a whitespace run to ONE space; it does not delete it. A\n // bare `.trim()` here deleted the space that separates a text run from an\n // adjacent sibling element, so `A <strong>x</strong> page` compiled to\n // `A`/`page` and the words ran together wherever the tree is rendered.\n // The rule (triage option (b), shared verbatim with the downstream copy\n // of this parser so the two agree): collapse the run, then keep a single\n // leading space only when a sibling precedes the run, and a single\n // trailing space only when a sibling element follows it. At the parent's\n // own start/end the edge space is still dropped, so `<p> hi </p>` stays\n // `hi`. A whitespace-only run survives as one space only when it sits\n // BETWEEN siblings — that is the bounded over-generosity of this rule\n // inside block containers like `<ul>`, pinned in the tests.\n const text = this.readTextRun();\n const collapsed = text.replace(/\\s+/g, ' ');\n const core = collapsed.trim();\n const afterSibling = children.length > 0;\n const beforeElement = this.peek() === '<' && !this.src.startsWith('</', this.pos);\n if (core) {\n const lead = afterSibling && collapsed.startsWith(' ') ? ' ' : '';\n const trail = beforeElement && collapsed.endsWith(' ') ? ' ' : '';\n children.push(`${lead}${core}${trail}`);\n } else if (collapsed && afterSibling && beforeElement) {\n children.push(' ');\n }\n }\n return children;\n }\n\n /* ----------------------------- lexing ----------------------------- */\n\n private peek(): string {\n return this.pos < this.src.length ? this.src[this.pos] : '';\n }\n\n private eat(ch: string): boolean {\n if (this.src[this.pos] === ch) {\n this.pos++;\n return true;\n }\n return false;\n }\n\n private readName(): string {\n if (!isNameStart(this.peek())) return '';\n const start = this.pos;\n this.pos++;\n while (this.pos < this.src.length && isNameChar(this.src[this.pos])) this.pos++;\n return this.src.slice(start, this.pos);\n }\n\n private readString(quote: string): string {\n this.pos++; // opening quote\n const start = this.pos;\n while (this.pos < this.src.length && this.src[this.pos] !== quote) this.pos++;\n const value = this.src.slice(start, this.pos);\n if (!this.eat(quote)) this.error('unterminated-string', 'Unterminated string literal', start);\n return value;\n }\n\n /** Reads a balanced `{ ... }` run and returns the inner text (no outer braces). */\n private readBraced(): string {\n const start = this.pos;\n let depth = 0;\n let inStr: string | null = null;\n for (; this.pos < this.src.length; this.pos++) {\n const ch = this.src[this.pos];\n if (inStr) {\n if (ch === inStr && this.src[this.pos - 1] !== '\\\\') inStr = null;\n continue;\n }\n if (ch === '\"' || ch === \"'\") inStr = ch;\n else if (ch === '{') depth++;\n else if (ch === '}') {\n depth--;\n if (depth === 0) {\n const inner = this.src.slice(start + 1, this.pos);\n this.pos++; // consume closing brace\n return inner;\n }\n }\n }\n this.error('unterminated-brace', 'Unterminated \"{\"', start);\n return this.src.slice(start + 1);\n }\n\n private readTextRun(): string {\n const start = this.pos;\n while (this.pos < this.src.length && this.src[this.pos] !== '<' && this.src[this.pos] !== '{') this.pos++;\n return this.src.slice(start, this.pos);\n }\n\n private skipWs(): void {\n while (this.pos < this.src.length && /\\s/.test(this.src[this.pos])) this.pos++;\n }\n\n /** whitespace + top-level JSX comments */\n private skipTrivia(): void {\n for (;;) {\n this.skipWs();\n if (this.src.startsWith('{/*', this.pos)) {\n const end = this.src.indexOf('*/}', this.pos);\n this.pos = end === -1 ? this.src.length : end + 3;\n continue;\n }\n break;\n }\n }\n\n private error(code: string, message: string, start?: number, tag?: string): void {\n this.diagnostics.push({ severity: 'error', code, message, start: start ?? this.pos, tag });\n }\n}\n\n/**\n * Interpret a braced attribute value `{...}`.\n *\n * Strict-JSON values are materialized by `JSON.parse`, exactly as they always\n * were. Beyond that, the JS **literal subset** below is materialized too\n * (objectui#6614 Q1-A, maintainer ruling 2026-08-28). Anything left over — a\n * genuine expression — is kept as the deferred marker `{ $expr }`: typed and\n * validated later, drawing `inert-expression`, and NEVER evaluated here.\n *\n * ORDER IS LOAD-BEARING. `JSON.parse` runs FIRST and is untouched, so every\n * input JSON accepts takes byte-identically the path it took before the literal\n * subset existed. The reader below only ever sees strings `JSON.parse` has\n * already thrown on, which makes strict-JSON invariance a property of the\n * structure rather than of a test.\n *\n * LOCKSTEP: this grammar is the port of objectui's `packages/sdui-parser` copy\n * (objectui#6614). The two copies must agree on the accepted grammar AND on\n * diagnostic codes — if they drift, the save gate and the renderer speak\n * different dialects and a page can save clean and render inert\n * (objectstack#12719 states the invariant; #12977 carries this half of it).\n * Change this block only together with the objectui copy.\n */\nexport function interpretBrace(raw: string): unknown {\n const trimmed = raw.trim();\n try {\n return JSON.parse(trimmed);\n } catch {\n const literal = readLiteral(trimmed);\n return literal === NOT_LITERAL ? { $expr: trimmed } : literal;\n }\n}\n\n/* ---------------------- the JS literal subset (#6614) ---------------------- */\n\n/**\n * EXACTLY TWO widenings over JSON, and nothing else:\n *\n * 1. **single-quoted strings** — `{'name'}`, `{['name','amount']}`, and in\n * key position `{{'pageSize': 25}}`;\n * 2. **unquoted identifier object keys** — `{{pageSize: 25}}`.\n *\n * Everything else JSON refuses is still refused and still becomes `{ $expr }`:\n * trailing commas, comments, array holes, spreads, `undefined` / `NaN` /\n * `Infinity`, `+1` / `.5` / `1.` / `0x1f`, template literals, and every genuine\n * expression — identifiers, member access, calls, operators, ternaries.\n *\n * That list is deliberately short. This is a VALUE grammar, not an evaluator:\n * it contains no identifier lookup and no operator, so there is nothing here to\n * execute (ADR-0080 — this tier parses, never executes). The widening moves the\n * spellings an author writes by habit onto the materialized side; it does not\n * move the boundary between data and code.\n */\nconst NOT_LITERAL = Symbol('not-a-literal');\n\n/** JSON's whitespace set, not JS's — narrower, and one less thing to diverge. */\nconst LITERAL_WS = /[ \\t\\n\\r]/;\nconst IDENT_START = /[A-Za-z_$]/;\nconst IDENT_CHAR = /[A-Za-z0-9_$]/;\n/** JSON's number grammar verbatim: no leading `+`, no `.5`, no `1.`, no hex. */\nconst NUMBER = /^-?(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/;\n/** JSON's escape set. `\\'` is added for single-quoted strings only. */\nconst SIMPLE_ESCAPE: Record<string, string> = {\n '\"': '\"',\n '\\\\': '\\\\',\n '/': '/',\n b: '\\b',\n f: '\\f',\n n: '\\n',\n r: '\\r',\n t: '\\t',\n};\n\nfunction readLiteral(src: string): unknown {\n const reader = new LiteralReader(src);\n const value = reader.value();\n if (value === NOT_LITERAL) return NOT_LITERAL;\n reader.ws();\n // Trailing anything means the input was an expression that merely STARTS with\n // a literal (`['a'] + x`, `1 + 2`). Refuse the whole input.\n return reader.done() ? value : NOT_LITERAL;\n}\n\nclass LiteralReader {\n private pos = 0;\n\n constructor(private readonly src: string) {}\n\n done(): boolean {\n return this.pos >= this.src.length;\n }\n\n ws(): void {\n while (this.pos < this.src.length && LITERAL_WS.test(this.src[this.pos])) this.pos++;\n }\n\n value(): unknown {\n this.ws();\n const c = this.src[this.pos];\n if (c === undefined) return NOT_LITERAL;\n if (c === '\"' || c === \"'\") return this.string(c);\n if (c === '[') return this.array();\n if (c === '{') return this.object();\n if (this.keyword('true')) return true;\n if (this.keyword('false')) return false;\n if (this.keyword('null')) return null;\n return this.number();\n }\n\n /** A keyword only when it is not the prefix of a longer identifier. */\n private keyword(word: string): boolean {\n if (!this.src.startsWith(word, this.pos)) return false;\n const after = this.src[this.pos + word.length];\n if (after !== undefined && IDENT_CHAR.test(after)) return false;\n this.pos += word.length;\n return true;\n }\n\n private number(): unknown {\n const m = NUMBER.exec(this.src.slice(this.pos));\n if (!m) return NOT_LITERAL;\n this.pos += m[0].length;\n return Number(m[0]);\n }\n\n private string(quote: string): unknown {\n this.pos++; // opening quote\n let out = '';\n for (;;) {\n const c = this.src[this.pos];\n if (c === undefined) return NOT_LITERAL; // unterminated\n if (c === quote) {\n this.pos++;\n return out;\n }\n if (c === '\\\\') {\n const esc = this.src[this.pos + 1];\n if (esc === undefined) return NOT_LITERAL;\n if (esc === 'u') {\n const hex = this.src.slice(this.pos + 2, this.pos + 6);\n if (!/^[0-9a-fA-F]{4}$/.test(hex)) return NOT_LITERAL;\n out += String.fromCharCode(parseInt(hex, 16));\n this.pos += 6;\n continue;\n }\n // `\\'` is legal inside a single-quoted string only — JSON's set otherwise.\n if (esc === \"'\" && quote === \"'\") {\n out += \"'\";\n this.pos += 2;\n continue;\n }\n const simple = SIMPLE_ESCAPE[esc];\n if (simple === undefined) return NOT_LITERAL; // `\\x41`, `\\0`, line continuation\n out += simple;\n this.pos += 2;\n continue;\n }\n // JSON forbids raw control characters inside a string; so does this.\n if (c < ' ') return NOT_LITERAL;\n out += c;\n this.pos++;\n }\n }\n\n private array(): unknown {\n this.pos++; // '['\n const out: unknown[] = [];\n this.ws();\n if (this.src[this.pos] === ']') {\n this.pos++;\n return out;\n }\n for (;;) {\n const item = this.value();\n if (item === NOT_LITERAL) return NOT_LITERAL;\n out.push(item);\n this.ws();\n const c = this.src[this.pos];\n // A trailing comma leaves `value()` facing `]`, which it refuses — so\n // `['a',]` is NOT in the subset. Only two widenings were ruled.\n if (c === ',') {\n this.pos++;\n continue;\n }\n if (c === ']') {\n this.pos++;\n return out;\n }\n return NOT_LITERAL;\n }\n }\n\n private object(): unknown {\n this.pos++; // '{'\n const out: Record<string, unknown> = {};\n this.ws();\n if (this.src[this.pos] === '}') {\n this.pos++;\n return out;\n }\n for (;;) {\n this.ws();\n const key = this.key();\n if (key === NOT_LITERAL) return NOT_LITERAL;\n this.ws();\n if (this.src[this.pos] !== ':') return NOT_LITERAL;\n this.pos++;\n const item = this.value();\n if (item === NOT_LITERAL) return NOT_LITERAL;\n // ⚠️ Plain `out[key] = item` would hand an authored `__proto__` key the\n // prototype SETTER. `JSON.parse` creates an ordinary own data property,\n // and this path must too: the whole point of this tier is that untrusted\n // source is safe to parse, so a widening must not open a\n // prototype-pollution lever the strict-JSON path never had.\n Object.defineProperty(out, key as string, {\n value: item,\n writable: true,\n enumerable: true,\n configurable: true,\n });\n this.ws();\n const c = this.src[this.pos];\n if (c === ',') {\n this.pos++;\n continue;\n }\n if (c === '}') {\n this.pos++;\n return out;\n }\n return NOT_LITERAL;\n }\n }\n\n /** A quoted string, or a bare identifier — the second ruled widening. */\n private key(): unknown {\n const c = this.src[this.pos];\n if (c === '\"' || c === \"'\") return this.string(c);\n if (c !== undefined && IDENT_START.test(c)) {\n const start = this.pos;\n this.pos++;\n while (this.pos < this.src.length && IDENT_CHAR.test(this.src[this.pos])) this.pos++;\n return this.src.slice(start, this.pos);\n }\n return NOT_LITERAL;\n }\n}\n","/**\n * ObjectUI — the arms of a manifest input's coarse type (objectui#3832)\n *\n * `ManifestInput.type` carries ONE coarse kind, or an ARRAY of kinds when the\n * key's contract is a union. Every reader of that field needs the same two\n * decisions made the same way — how to see the arms, and which single form to\n * publish — so they live here once instead of at each call site. A reader that\n * forgets is not loud: `switch (input.type)` handed an array falls through to\n * the default branch and reports NOTHING, which looks exactly like a value that\n * validated cleanly.\n */\n\nimport type { ManifestInput, ManifestInputType } from './types.js';\n\n/** The eleven coarse kinds, as a runtime set for guarding untyped input. */\nexport const MANIFEST_INPUT_TYPES: ReadonlySet<string> = new Set<ManifestInputType>([\n 'string',\n 'number',\n 'boolean',\n 'enum',\n 'array',\n 'object',\n 'color',\n 'date',\n 'code',\n 'file',\n 'slot',\n]);\n\n/**\n * The declared arms of an input's coarse type, always as an array.\n *\n * Exported (not merely internal) so a third-party manifest consumer — a\n * designer panel, a codegen, a validator of its own — reads the arms through\n * the same accessor this package's own gate does, rather than re-deriving the\n * `Array.isArray` branch and getting it subtly wrong on the union form.\n */\nexport function inputTypeArms(\n type: ManifestInput['type'] | undefined,\n): ManifestInputType[] {\n if (type === undefined) return [];\n return Array.isArray(type) ? type : [type];\n}\n\n/**\n * Project a DECLARED type (which may come from an untyped registry config) into\n * the canonical published form: a bare string for one arm, an array for a real\n * union.\n *\n * Two deliberate asymmetries between the single and array forms:\n *\n * - A single unrecognized kind still becomes `'string'`. That coercion predates\n * the union work and is kept exactly: with one arm there is no other\n * information to fall back on, and a manifest whose `type` is off-vocabulary\n * would make every consumer's switch silently inert.\n * - An unrecognized arm INSIDE an array is DROPPED, not coerced. Promoting it\n * to `'string'` would publish an arm the author never declared — a widening\n * invented by the serializer — and the surviving arms already carry the\n * declaration. If dropping empties the array, the single-arm fallback applies\n * so the output is always a valid manifest.\n *\n * Collapsing one arm to the bare string is what keeps this a backward-compatible\n * extension of `sdui.manifest.json`: every input declared today serializes to\n * the byte-identical entry it does now, and arrays appear only where a union was\n * really declared.\n */\nexport function canonicalizeInputType(type: unknown): ManifestInputType | ManifestInputType[] {\n const arms = (Array.isArray(type) ? type : [type]).filter(\n (arm): arm is ManifestInputType => typeof arm === 'string' && MANIFEST_INPUT_TYPES.has(arm),\n );\n const distinct = [...new Set(arms)];\n if (distinct.length === 0) return 'string';\n if (distinct.length === 1) return distinct[0];\n return distinct;\n}\n","/**\n * Unconsumed dashboard-widget `options` keys (objectui#5709), ported into this\n * copy in lockstep (objectstack#12810).\n *\n * `@objectstack/spec`'s `DashboardWidgetOptionsSchema` ends in `.passthrough()`\n * (\"declared query keys + open renderer extras\"), so ANY key parses, validates\n * and lints cleanly — including one no renderer reads. That is how a showcase\n * dashboard shipped `options: { invert: true }` on a gauge with a comment\n * saying what it was believed to do, and rendered the un-inverted measure with\n * no diagnostic anywhere (objectui#5709). The 2026-08-23 maintainer ruling:\n * open extras stay open — they just stop being SILENT. A key that reaches no\n * renderer draws a WARNING naming the consumed set. Not an error: no gate\n * weakening and no new red gates were ruled.\n *\n * ## LOCKSTEP — what is byte-equal here and what deliberately is not\n *\n * Two copies of this parser exist: objectui's `packages/sdui-parser` and this\n * hoisted `@objectstack/sdui-parser`. The invariant they owe each other is that\n * both agree on the accepted grammar AND on diagnostic codes — if they drift,\n * the save gate and the renderer speak different dialects and a page can save\n * clean and render inert, or the reverse (objectstack#12719, objectstack#12810).\n *\n * Everything from the `import` line below to end of file is a byte-equal port of\n * objectui's `src/dashboard-widget-options.ts` SAVE FOR ONE TOKEN, called out\n * at the site itself: the emitted `code` is spelled as an inline literal here\n * and as the constant there, because this repo runs a vocabulary gate objectui\n * does not. The emitted `code`, `severity`, `message` and the whole census\n * scope are identical, and `__tests__/dashboard-widget-options.test.ts`\n * re-derives that rather than trusting it — including an explicit pin that the\n * literal equals `UNCONSUMED_WIDGET_OPTION`. Change these functions only\n * together with the objectui copy.\n *\n * THIS HEADER is the one deliberate divergence, and it has to be: objectui's\n * header cites the maintenance machinery that derives the census — its\n * `DatasetWidget.tsx` / `DashboardRenderer.tsx` read sites, its\n * `plugin-dashboard.mdx` claim and its two census tests. NONE of those files\n * exists in this repo (measured: no dashboard renderer package here at all), so\n * copying those sentences would ship claims this checkout cannot support and\n * nothing here would ever notice them going false. What follows instead states\n * where each half of the census is derivable, and from what.\n *\n * ## The accepted set, and where each half is authoritative\n *\n * The spec REQUIRES `dataset` on every widget (`DashboardWidgetSchema`, this\n * repo: `packages/spec/src/ui/dashboard.zod.ts`), and both of objectui's\n * dashboard surfaces route a dataset-bound widget to `DatasetWidget`. On that —\n * the only spec-legal — path the renderer-consumed `options` keys are exactly\n * the five the spec DECLARES:\n *\n * dateGranularity, sortBy, sortOrder, limit (query-affecting, framework#3588)\n * stageOrder (funnel/pyramid stage order)\n *\n * plus ONE undeclared key with a real read site:\n *\n * description — the metric-card sub-caption channel. `translateDashboard`\n * OVERLAYS the `widgets.{id}.subCaption` translation onto this key, and that\n * pipeline lives IN THIS REPO: `packages/spec/src/system/i18n-resolver.ts`\n * documents `WidgetLike.options` as \"the renderer-extras bag …\n * `translateDashboard` writes exactly one key into it — `description`\"\n * (objectstack#5428 item 4, objectstack#7862). Warning on a key the\n * platform's own translation pipeline writes would be a false positive on\n * legal metadata, so it is in the accepted set even though the dataset-bound\n * render path does not currently display it.\n *\n * Notably NOT consumed on the path a widget really renders through:\n * `thresholds` and `format`. Both were widely believed to work; both draw this\n * warning, which is the point. Their closure claims are objectui's to derive —\n * `thresholds` by a repo-wide read-site scan there, `format` by the bounded\n * claim that the dataset-bound path formats from the MEASURE's own metadata —\n * and they are NOT restated here as claims about this repo, which has no\n * renderer to make them about.\n *\n * ## The drift risk that lives on THIS side\n *\n * The spec whose `.passthrough()` this reasons about ships from this repo. So\n * the one way this list can go stale HERE is a new DECLARED key landing in\n * `DashboardWidgetOptionsSchema` without landing in the array below: the key\n * would be spec-legal, renderer-consumed on the objectui side, and warned about\n * here — a false positive on legal metadata. `@objectstack/sdui-parser` takes\n * no dependency on `@objectstack/spec` (it is dependency-free and hoistable by\n * design), so that cross-check is not mechanized in this copy; the census test\n * next door pins the array and names the spec file to re-read when it moves.\n *\n * ## Scope — where the warning deliberately does NOT fire\n *\n * - Widgets WITHOUT `dataset`: the legacy inline forms (`options.data`\n * arrays, `provider: 'object'` bags) consume a much larger, spread-shaped\n * key set, whose true reach is each child component's prop surface. That\n * form is spec-illegal today (`dataset` is required) and its census would be\n * the unmaintainable one; skipping it keeps every warning this module emits\n * a statement about the path the widget actually renders through.\n * - Widgets in the legacy COMPONENT format (`widget.component`): `options`\n * is not part of that contract.\n * - Widgets carrying the spec's own escape hatch\n * `suppressWarnings: ['unconsumed-widget-option']` — the spec models\n * per-widget diagnostic suppression (`DashboardWidgetSchema.suppressWarnings`,\n * \"Build diagnostic rule ids suppressed on this widget\"), so an author with\n * a genuine out-of-band consumer can say so in metadata.\n */\nimport type { Diagnostic, SchemaElement } from './types.js';\n\n/** The diagnostic `code` — also the id `suppressWarnings` suppresses. */\nexport const UNCONSUMED_WIDGET_OPTION = 'unconsumed-widget-option';\n\n/**\n * Component types that host a dashboard `widgets` array. Both resolve to the\n * surfaces measured by the census above (`DashboardRenderer`,\n * `DashboardGridLayout`), which share one dispatch (`widgetDispatch.ts`).\n */\nexport const DASHBOARD_WIDGET_HOST_TYPES: ReadonlySet<string> = new Set([\n 'dashboard',\n 'dashboard-grid',\n]);\n\n/**\n * The accepted set: every `options` key with a renderer read site on the\n * dataset-bound path, plus the sub-caption convention key. Alphabetical; the\n * warning message prints it verbatim. Derivation and evidence: file header.\n */\nexport const CONSUMED_WIDGET_OPTION_KEYS: readonly string[] = [\n 'dateGranularity',\n 'description',\n 'limit',\n 'sortBy',\n 'sortOrder',\n 'stageOrder',\n];\n\nconst CONSUMED = new Set<string>(CONSUMED_WIDGET_OPTION_KEYS);\n\nconst isPlainObject = (v: unknown): v is Record<string, unknown> =>\n typeof v === 'object' && v !== null && !Array.isArray(v);\n\n/** The parser's deferred-expression marker — opaque here, never evaluated. */\nconst isExpr = (v: unknown): boolean => isPlainObject(v) && '$expr' in v;\n\n/**\n * Diagnostics for `options` keys no renderer consumes, over one dashboard-host\n * node's `widgets` array. Pure and shallow by design: it never descends into\n * `children` (the caller's walk owns that) and answers `[]` for every shape\n * outside its census — see the scope notes in the file header.\n */\nexport function checkDashboardWidgetOptions(node: SchemaElement): Diagnostic[] {\n if (!DASHBOARD_WIDGET_HOST_TYPES.has(node.type)) return [];\n const widgets = (node as Record<string, unknown>).widgets;\n if (!Array.isArray(widgets)) return [];\n\n const diagnostics: Diagnostic[] = [];\n widgets.forEach((widget, index) => {\n if (!isPlainObject(widget) || isExpr(widget)) return;\n // Legacy component format: `options` is not part of that contract.\n if (widget.component !== undefined) return;\n // Only the dataset-bound (spec-legal) path is censused — see file header.\n if (widget.dataset === undefined || widget.dataset === null || widget.dataset === '') return;\n const options = widget.options;\n if (!isPlainObject(options) || isExpr(options)) return;\n if (\n Array.isArray(widget.suppressWarnings) &&\n widget.suppressWarnings.includes(UNCONSUMED_WIDGET_OPTION)\n ) {\n return;\n }\n const label = typeof widget.id === 'string' && widget.id !== '' ? widget.id : `#${index}`;\n const widgetType = typeof widget.type === 'string' && widget.type !== '' ? widget.type : 'widget';\n for (const key of Object.keys(options)) {\n if (CONSUMED.has(key)) continue;\n diagnostics.push({\n severity: 'warning',\n // DIVERGENCE FROM OBJECTUI, and the only one below this file's header:\n // objectui writes `code: UNCONSUMED_WIDGET_OPTION` here. This repo runs\n // `check:dispatcher-error-vocabulary`, whose `objlitconst` shape reads\n // the SCREAMING_SNAKE constant NAME at a `code:` position and then must\n // reduce it to a literal — and its literal grammar is\n // `[A-Za-z][A-Za-z0-9_]*`, which a KEBAB-case value cannot satisfy. So\n // the constant form is reported as an unresolvable code constant, and\n // that finding cannot be declared away. `unconsumed-widget-option` is a\n // parser DIAGNOSTIC code, not an ADR-0112 wire code, and an inline\n // quoted literal is the form both vocabulary gates already accept for\n // the six sibling diagnostic codes in `validate.ts`\n // (`unknown-component`, `unknown-prop`, `not-a-container`,\n // `inert-expression`, `type-mismatch`, `invalid-enum`). The emitted\n // VALUE is unchanged, and the test next door pins it equal to\n // `UNCONSUMED_WIDGET_OPTION` so the two spellings cannot drift apart.\n code: 'unconsumed-widget-option',\n message:\n `<${node.type}> widget \"${label}\" (${widgetType}): options.${key} reaches no renderer — ` +\n `dashboard widget renderers read only: ${CONSUMED_WIDGET_OPTION_KEYS.join(', ')}`,\n tag: node.type,\n });\n }\n });\n return diagnostics;\n}\n","/**\n * ObjectUI — SDUI tree validation against the registry manifest (ADR-0080 §3/§6)\n *\n * Shallow, author-time validation: unknown component, unknown/missing prop,\n * wrong coarse type, illegal enum value. Collects `requires` (plugin provenance)\n * and binding sites the SERVER must resolve against object schema (we cannot\n * resolve objects/fields here — that check is framework-side by design).\n */\n\nimport type {\n Diagnostic,\n Manifest,\n ManifestInput,\n ManifestInputType,\n SchemaElement,\n SchemaNode,\n ValidationResult,\n} from './types.js';\nimport { inputTypeArms } from './input-type.js';\nimport { checkDashboardWidgetOptions } from './dashboard-widget-options.js';\n\n/** Base props every node may carry (mirrors BaseSchema) — never \"unknown prop\". */\nconst BASE_PROPS = new Set([\n 'type',\n 'id',\n 'className',\n 'style',\n 'visible',\n 'visibleOn',\n 'disabled',\n 'disabledOn',\n 'children',\n]);\n\nconst isExpr = (v: unknown): boolean =>\n typeof v === 'object' && v !== null && '$expr' in (v as Record<string, unknown>);\n\nexport function validateTree(tree: SchemaElement | null, manifest: Manifest): ValidationResult {\n const diagnostics: Diagnostic[] = [];\n const requires = new Set<string>();\n const bindings: ValidationResult['bindings'] = [];\n\n const visit = (node: SchemaNode): void => {\n if (typeof node === 'string') return;\n const comp = manifest.components[node.type];\n if (!comp) {\n diagnostics.push({\n severity: 'error',\n code: 'unknown-component',\n message: `<${node.type}> is not a known component`,\n tag: node.type,\n });\n } else {\n if (comp.namespace) requires.add(comp.namespace);\n const byName = new Map(comp.inputs.map((i) => [i.name, i]));\n\n // required present?\n for (const input of comp.inputs) {\n if (input.required && !(input.name in node)) {\n diagnostics.push({\n severity: 'error',\n code: 'missing-required-prop',\n message: `<${node.type}> is missing required prop \"${input.name}\"`,\n tag: node.type,\n });\n }\n }\n\n // each provided prop\n for (const [key, value] of Object.entries(node)) {\n if (BASE_PROPS.has(key)) continue;\n const input = byName.get(key);\n if (!input) {\n diagnostics.push({\n severity: 'warning',\n code: 'unknown-prop',\n message: `<${node.type}> has no prop \"${key}\"`,\n tag: node.type,\n });\n continue;\n }\n if (input.binding) {\n bindings.push({ tag: node.type, input: key, kind: input.binding, value });\n }\n if (isExpr(value)) {\n // A braced value that failed JSON materialization compiled to the\n // parser's deferred `{ $expr }` marker — and NOTHING downstream\n // evaluates that marker: this tier parses, never executes\n // (ADR-0080), and no renderer consumes `$expr`. The value therefore\n // reaches the renderer as an opaque object, every defensive\n // non-array/non-object read degrades it to \"not declared\", and the\n // author's binding silently vanishes (objectui#6598: eight `columns`\n // spellings on a data block, all eaten without a single diagnostic —\n // rows rendered, zero data columns). ADR-0078 prohibits exactly this\n // parsed-but-silently-inert state, so name it at compile time, with\n // the fix in the message.\n //\n // The message must name the CURRENT accepted grammar, and objectui#6614\n // (Q1-A, ruled 2026-08-28) moved it: `interpretBrace` now materializes\n // the JS literal subset, so single-quoted strings and unquoted\n // identifier keys REACH the renderer and can no longer draw this\n // warning. The old wording (\"write it as JSON, double-quoted\") named a\n // now-legal spelling as the illegal one — advice that would have sent\n // an author to edit working source. What is left on this side of the\n // boundary is a genuine expression, so that is what the message names.\n //\n // Warning, not error, per the objectui#5709 precedent for inert\n // authored keys. ⛔ Escalation to error is objectui#6614 Q2 and is\n // deliberately NOT part of this change: it belongs at the SAVE GATE,\n // once the framework wires the registry manifest into\n // `validate-jsx-pages` (#12719 records that gap).\n //\n // LOCKSTEP: this diagnostic is the byte-equal port of objectui's\n // `packages/sdui-parser` copy (objectui#6613, message reworded by\n // objectui#6614). The two copies must agree on the accepted grammar\n // AND on diagnostic codes — if they drift, the save gate and the\n // renderer speak different dialects and a page can save clean and\n // render inert. Change this block only together with the objectui\n // copy.\n diagnostics.push({\n severity: 'warning',\n code: 'inert-expression',\n message:\n `<${node.type}> prop \"${key}\" is a braced expression this tier never evaluates — ` +\n `the value will be silently ignored at render. This tier materializes LITERALS only ` +\n `(strings, numbers, booleans, null, arrays, objects; quotes may be single or double, ` +\n `object keys may be unquoted), e.g. columns={['name','amount']} works — ` +\n `columns={rows.map((r) => r.name)} cannot`,\n tag: node.type,\n });\n } else {\n const typeDiag = checkType(node.type, input, value);\n if (typeDiag) diagnostics.push(typeDiag);\n }\n }\n\n // containment\n if (node.children?.length && !comp.isContainer) {\n diagnostics.push({\n severity: 'warning',\n code: 'not-a-container',\n message: `<${node.type}> does not accept children`,\n tag: node.type,\n });\n }\n\n // Dashboard widgets: an `options` key riding the spec's `.passthrough()`\n // that no renderer consumes is legal, silent and inert — warn, naming\n // the consumed set (objectui#5709 ruling; census + scope in\n // `./dashboard-widget-options.ts`). Like `not-a-container`, this runs\n // only for a component the manifest knows: an unresolved tag already\n // drew `unknown-component`, and deep diagnostics on it would be noise.\n //\n // LOCKSTEP: this call site and the module behind it are the byte-equal\n // port of objectui's copy (objectstack#12810). The two copies must agree\n // on the accepted grammar AND on diagnostic codes — if they drift, the\n // save gate and the renderer speak different dialects and a page can save\n // clean and render inert. Change this only together with objectui.\n diagnostics.push(...checkDashboardWidgetOptions(node));\n }\n\n if (node.children) node.children.forEach(visit);\n };\n\n if (tree) visit(tree);\n return { diagnostics, requires: [...requires], bindings };\n}\n\n/* LOCKSTEP: everything below this line is the byte-equal port of objectui's\n * `packages/sdui-parser` coarse type check (objectui#3832 — union-typed inputs\n * are checked over their arms). The two copies must agree on the accepted\n * grammar AND on diagnostic codes/severities — if they drift, the save gate\n * and the renderer speak different dialects. Change these functions only\n * together with the objectui copy. */\n\n/** The values an `enum` arm admits, flattened from either declaration form. */\nconst enumValues = (input: ManifestInput): unknown[] =>\n (input.enum ?? []).map((e) => (typeof e === 'object' ? e.value : e));\n\n/**\n * Does ONE coarse arm accept this value?\n *\n * An arm outside the vocabulary — and `'slot'`, which describes a child\n * position rather than a value — accepts everything, preserving the old\n * `default: return null` branch: those inputs never drew a diagnostic and must\n * not start now.\n */\nfunction armAccepts(arm: ManifestInputType, input: ManifestInput, value: unknown): boolean {\n switch (arm) {\n case 'number':\n return typeof value === 'number';\n case 'boolean':\n return typeof value === 'boolean';\n case 'string':\n case 'color':\n case 'date':\n case 'code':\n case 'file':\n return typeof value === 'string';\n case 'array':\n return Array.isArray(value);\n case 'object':\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n case 'enum':\n return enumValues(input).includes(value as never);\n default:\n return true;\n }\n}\n\n/** How one arm is named in a diagnostic message. */\nfunction armExpectation(arm: ManifestInputType, input: ManifestInput): string {\n switch (arm) {\n case 'number':\n return 'a number';\n case 'boolean':\n return 'a boolean';\n case 'array':\n return 'an array';\n case 'object':\n return 'an object';\n case 'enum':\n return `one of ${JSON.stringify(enumValues(input))}`;\n default:\n return 'a string';\n }\n}\n\n/**\n * Coarse type check, over the arms an input declares (objectui#3832).\n *\n * ANY arm accepting the value clears the prop — that is what lets a key whose\n * contract is a union (`string | number`, or a string plus an inline\n * translation map) be declared honestly instead of picking one arm and having\n * this function report the other arm's legal values.\n *\n * When NO arm accepts it the prop is still reported; a union widens what counts\n * as legal, it does not turn the check off. Two properties of the reporting are\n * deliberate:\n *\n * - A single-arm input produces the byte-identical diagnostic it always did,\n * `invalid-enum` included. This change adds a form; it does not restate the\n * old one.\n * - A multi-arm input produces ONE diagnostic naming every arm, at the\n * STRICTEST arm's severity — `error` when an `enum` arm is present, because\n * an enum's closed list is the one fact this layer can be certain about, and\n * a value outside it should not become dismissible merely because a second\n * arm was added next to it. Its code is `type-mismatch` (not `invalid-enum`)\n * since the reported fact is \"fits none of the declared arms\", and the\n * message carries the allowed values so the author still sees the list.\n */\nfunction checkType(tag: string, input: ManifestInput, value: unknown): Diagnostic | null {\n const arms = inputTypeArms(input.type);\n if (arms.length === 0) return null;\n if (arms.some((arm) => armAccepts(arm, input, value))) return null;\n\n if (arms.length === 1 && arms[0] === 'enum') {\n return {\n severity: 'error',\n code: 'invalid-enum',\n message: `<${tag}> prop \"${input.name}\"=${JSON.stringify(value)} is not one of ${JSON.stringify(enumValues(input))}`,\n tag,\n };\n }\n\n return {\n severity: arms.includes('enum') ? 'error' : 'warning',\n code: 'type-mismatch',\n message: `<${tag}> prop \"${input.name}\" expected ${arms\n .map((arm) => armExpectation(arm, input))\n .join(' or ')}`,\n tag,\n };\n}\n","/**\n * ObjectUI — codegen the JSX type surface from the registry manifest (ADR-0080 §3)\n *\n * Emits a `.d.ts` that augments `JSX.IntrinsicElements` so a constrained\n * JSX-source page type-checks in `.tsx`: tag name === registry `type` key,\n * attributes === the component's manifest `inputs`. This is a TYPE-CHECKING\n * fiction — no real React intrinsic named `flex` exists; the interpreter\n * fulfills it via the registry at render time.\n */\n\nimport type { Manifest, ManifestComponent, ManifestInput, ManifestInputType } from './types.js';\nimport { inputTypeArms } from './input-type.js';\n\nexport interface CodegenOptions {\n /** include a self-contained minimal JSX namespace so the d.ts type-checks\n * standalone (no React types needed). Default true. */\n standaloneJsx?: boolean;\n}\n\nexport function generateDts(manifest: Manifest, options: CodegenOptions = {}): string {\n const { standaloneJsx = true } = options;\n const comps = Object.values(manifest.components).sort((a, b) => a.type.localeCompare(b.type));\n\n const interfaces = comps.map(emitInterface).join('\\n\\n');\n const intrinsics = comps\n .map((c) => ` ${JSON.stringify(c.type)}: ${propsName(c.type)};`)\n .join('\\n');\n\n const baseElement = standaloneJsx\n ? `\n // minimal, so the surface type-checks without pulling React types\n type Element = unknown;\n interface ElementClass {}\n interface ElementAttributesProperty {}\n interface ElementChildrenAttribute { children: object; }`\n : '';\n\n return `// AUTO-GENERATED by @object-ui/sdui-parser — DO NOT EDIT.\n// Source of truth: ComponentRegistry inputs (ADR-0080 §3). Regenerate via codegen.\n\nexport interface SduiBaseProps {\n id?: string;\n className?: string;\n style?: Record<string, unknown>;\n visible?: boolean;\n visibleOn?: string;\n disabled?: boolean;\n disabledOn?: string;\n children?: unknown;\n}\n\n${interfaces}\n\ndeclare global {\n namespace JSX {\n interface IntrinsicElements {\n${intrinsics}\n }${baseElement}\n }\n}\n\nexport {};\n`;\n}\n\n/**\n * A `'slot'` arm names a child position, not a prop value — `SduiBaseProps`\n * already types `children`, so a slot input contributes no attribute. An input\n * is therefore emitted when it has at least one NON-slot arm, and typed from\n * those arms only (objectui#3832): the old test was `i.type !== 'slot'`, which a\n * union like `['slot', 'string']` would have passed while `tsType` fell through\n * to the default and typed it `string` anyway.\n */\nfunction emitInterface(comp: ManifestComponent): string {\n const lines = comp.inputs\n .filter((i) => valueArms(i).length > 0)\n .map((i) => ` ${propLine(i)}`)\n .join('\\n');\n return `export interface ${propsName(comp.type)} extends SduiBaseProps {\\n${lines}\\n}`;\n}\n\n/** The arms that describe a VALUE (every arm except `'slot'`). */\nconst valueArms = (input: ManifestInput): ManifestInputType[] =>\n inputTypeArms(input.type).filter((arm) => arm !== 'slot');\n\nfunction propLine(input: ManifestInput): string {\n const opt = input.required ? '' : '?';\n return `${quoteKeyIfNeeded(input.name)}${opt}: ${tsType(input)};`;\n}\n\n/**\n * The TypeScript type for one arm. Kinds that are a string with a narrower\n * authoring control (`color`, `date`, `code`, `file`) are `string` here, as\n * before — the JSX surface types the VALUE, and the control kind is the\n * designer's business.\n */\nfunction armTsType(arm: ManifestInputType, input: ManifestInput): string {\n switch (arm) {\n case 'number':\n return 'number';\n case 'boolean':\n return 'boolean';\n case 'array':\n return 'unknown[]';\n case 'object':\n return 'Record<string, unknown>';\n case 'enum': {\n const vals = (input.enum ?? []).map((e) => (typeof e === 'object' ? e.value : e));\n return vals.length ? vals.map((v) => JSON.stringify(v)).join(' | ') : 'string';\n }\n default:\n return 'string';\n }\n}\n\n/**\n * A union declaration emits a TypeScript union, so the `.d.ts` an author\n * type-checks their page against accepts exactly the arms the manifest gate\n * accepts. Arms that collapse to the same TS type (`string` and `color`, say)\n * are de-duplicated rather than emitted as `string | string`.\n */\nfunction tsType(input: ManifestInput): string {\n const arms = valueArms(input);\n if (arms.length === 0) return 'string';\n const emitted = [...new Set(arms.map((arm) => armTsType(arm, input)))];\n return emitted.join(' | ');\n}\n\nconst IDENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\nconst quoteKeyIfNeeded = (name: string): string => (IDENT.test(name) ? name : JSON.stringify(name));\n\n/** 'object-grid' -> 'ObjectGrid', 'record:details' -> 'RecordDetails' */\nexport function propsName(type: string): string {\n const pascal = type\n .split(/[^A-Za-z0-9]+/)\n .filter(Boolean)\n .map((s) => s[0].toUpperCase() + s.slice(1))\n .join('');\n return `${pascal}Props`;\n}\n\n/**\n * Generate the human-facing PUBLIC block list (the curated \"清单\") from a\n * manifest — a Markdown table. Derived, never hand-maintained (ADR-0046).\n */\nexport function generateBlockList(manifest: Manifest): string {\n const rows = Object.values(manifest.components)\n .sort((a, b) => a.type.localeCompare(b.type))\n .map((c) => {\n const req = c.inputs.filter((i) => i.required).map((i) => i.name);\n const binds = c.inputs.filter((i) => i.binding).map((i) => `${i.name}:${i.binding}`);\n return `| \\`${c.type}\\` | ${c.namespace ?? '—'} | ${c.isContainer ? '✓' : ''} | ${req.join(', ') || '—'} | ${binds.join(', ') || '—'} |`;\n });\n return [\n `# SDUI public blocks (${Object.keys(manifest.components).length})`,\n '',\n '> Auto-generated from the registry `tier:\\'public\\'` set (ADR-0080). Do not edit by hand.',\n '',\n '| block | plugin | container | required props | bindings |',\n '|---|---|---|---|---|',\n ...rows,\n '',\n ].join('\\n');\n}\n","/**\n * @objectstack/sdui-parser — constrained JSX-source → SDUI SchemaNode tree (ADR-0080)\n *\n * Isomorphic, zero React. Run server-side as the authoritative save-time gate;\n * may also run client-side for live edit preview (re-validated on the server —\n * never the trust boundary). It PARSES; it never executes.\n */\n\nexport * from './types.js';\nexport { parseJsx, interpretBrace } from './parse.js';\nexport { validateTree } from './validate.js';\nexport {\n checkDashboardWidgetOptions,\n CONSUMED_WIDGET_OPTION_KEYS,\n DASHBOARD_WIDGET_HOST_TYPES,\n UNCONSUMED_WIDGET_OPTION,\n} from './dashboard-widget-options.js';\nexport { generateDts, propsName, generateBlockList } from './codegen.js';\nexport type { CodegenOptions } from './codegen.js';\nexport { inputTypeArms, canonicalizeInputType, MANIFEST_INPUT_TYPES } from './input-type.js';\n\nimport { parseJsx } from './parse.js';\nimport { validateTree } from './validate.js';\nimport { canonicalizeInputType } from './input-type.js';\nimport type { Diagnostic, Manifest, SchemaElement, ValidationResult } from './types.js';\n\nexport interface CompileResult {\n tree: SchemaElement | null;\n diagnostics: Diagnostic[];\n requires: string[];\n bindings: ValidationResult['bindings'];\n /** true when there are no error-severity diagnostics — the save gate's pass/fail */\n ok: boolean;\n}\n\n/**\n * The authoritative pipeline: parse (with the manifest's tags as the whitelist)\n * → validate against the manifest → derive `requires` + binding sites.\n */\nexport function compile(source: string, manifest: Manifest): CompileResult {\n const allowedTags = new Set(Object.keys(manifest.components));\n const parsed = parseJsx(source, { allowedTags });\n const validated = validateTree(parsed.tree, manifest);\n const diagnostics = [...parsed.diagnostics, ...validated.diagnostics];\n return {\n tree: parsed.tree,\n diagnostics,\n requires: validated.requires,\n bindings: validated.bindings,\n ok: !diagnostics.some((d) => d.severity === 'error'),\n };\n}\n\n/* ------------------------------------------------------------------ *\n * Registry → manifest adapter. Structural input (no @object-ui/core\n * dependency) so the package stays pure and hoistable to framework.\n * Feed it `ComponentRegistry.getAllConfigs()` (optionally filtered to\n * the `tier:'public'` set).\n * ------------------------------------------------------------------ */\n\nexport interface RegistryConfigLike {\n type: string;\n namespace?: string;\n isContainer?: boolean;\n /** ADR-0080 contract tier — only 'public' configs form the AI/contract surface. */\n tier?: 'public' | 'internal';\n label?: string;\n category?: string;\n inputs?: Array<{\n name: string;\n /**\n * One coarse kind, or the arms of a union (objectui#3832). Typed loosely\n * (`string`) on purpose — this interface is the STRUCTURAL boundary that\n * keeps this package free of a dependency on the registry, so an\n * off-vocabulary value has to be representable here and is normalized by\n * `canonicalizeInputType` on the way in.\n */\n type: string | string[];\n required?: boolean;\n enum?: Array<string | { value: unknown; label?: string }>;\n binding?: 'object' | 'field';\n description?: string;\n }>;\n}\n\n/* The arm vocabulary and the two projections over it now live in\n * `input-type.ts` — `manifestFromConfigs` below, `validateTree` and the codegen\n * all read `ManifestInput.type` and must agree on how, since it holds one arm\n * or an array of them (objectui#3832). */\n\nexport function manifestFromConfigs(\n configs: RegistryConfigLike[],\n opts: { only?: Set<string>; publicOnly?: boolean } = {},\n): Manifest {\n const components: Manifest['components'] = {};\n for (const c of configs) {\n if (opts.only && !opts.only.has(c.type)) continue;\n if (opts.publicOnly && c.tier !== 'public') continue;\n components[c.type] = {\n type: c.type,\n namespace: c.namespace,\n isContainer: c.isContainer,\n inputs: (c.inputs ?? []).map((i) => ({\n name: i.name,\n type: canonicalizeInputType(i.type),\n required: i.required,\n enum: i.enum,\n binding: i.binding,\n description: i.description,\n })),\n };\n }\n return { components };\n}\n"],"mappings":"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","names":["isExpr"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@objectstack/sdui-parser",
3
- "version": "17.2.0",
3
+ "version": "17.3.0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "ObjectStack constrained JSX-source → SDUI SchemaNode tree compiler (parse, never execute). Isomorphic, zero React. ADR-0080.",
6
6
  "main": "dist/index.js",
@@ -40,7 +40,7 @@
40
40
  "CHANGELOG.md"
41
41
  ],
42
42
  "scripts": {
43
- "build": "tsup --config ../../tsup.config.ts",
43
+ "build": "tsup --config ../../tsup.config.ts && node ../../scripts/check-dts-emitted.mjs",
44
44
  "test": "vitest run",
45
45
  "typecheck": "tsc --noEmit"
46
46
  }