@formspec/build 0.1.0-alpha.28 → 0.1.0-alpha.29
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.
- package/dist/analyzer/class-analyzer.d.ts +11 -5
- package/dist/analyzer/class-analyzer.d.ts.map +1 -1
- package/dist/analyzer/program.d.ts +3 -2
- package/dist/analyzer/program.d.ts.map +1 -1
- package/dist/browser.cjs +485 -76
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.js +486 -77
- package/dist/browser.js.map +1 -1
- package/dist/build-alpha.d.ts +18 -2
- package/dist/build-beta.d.ts +18 -2
- package/dist/build-internal.d.ts +18 -2
- package/dist/build.d.ts +18 -2
- package/dist/canonicalize/chain-dsl-canonicalizer.d.ts +5 -2
- package/dist/canonicalize/chain-dsl-canonicalizer.d.ts.map +1 -1
- package/dist/canonicalize/tsdoc-canonicalizer.d.ts +5 -1
- package/dist/canonicalize/tsdoc-canonicalizer.d.ts.map +1 -1
- package/dist/cli.cjs +1031 -170
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1032 -171
- package/dist/cli.js.map +1 -1
- package/dist/generators/class-schema.d.ts +6 -1
- package/dist/generators/class-schema.d.ts.map +1 -1
- package/dist/generators/method-schema.d.ts.map +1 -1
- package/dist/generators/mixed-authoring.d.ts.map +1 -1
- package/dist/index.cjs +998 -170
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +999 -171
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +921 -155
- package/dist/internals.cjs.map +1 -1
- package/dist/internals.js +922 -156
- package/dist/internals.js.map +1 -1
- package/dist/json-schema/generator.d.ts +3 -1
- package/dist/json-schema/generator.d.ts.map +1 -1
- package/dist/json-schema/ir-generator.d.ts.map +1 -1
- package/dist/metadata/collision-guards.d.ts +3 -0
- package/dist/metadata/collision-guards.d.ts.map +1 -0
- package/dist/metadata/index.d.ts +7 -0
- package/dist/metadata/index.d.ts.map +1 -0
- package/dist/metadata/policy.d.ts +11 -0
- package/dist/metadata/policy.d.ts.map +1 -0
- package/dist/metadata/resolve.d.ts +20 -0
- package/dist/metadata/resolve.d.ts.map +1 -0
- package/dist/ui-schema/generator.d.ts +11 -2
- package/dist/ui-schema/generator.d.ts.map +1 -1
- package/dist/ui-schema/ir-generator.d.ts +2 -1
- package/dist/ui-schema/ir-generator.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/browser.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/browser.ts","../src/canonicalize/chain-dsl-canonicalizer.ts","../src/canonicalize/tsdoc-canonicalizer.ts","../src/json-schema/ir-generator.ts","../src/json-schema/generator.ts","../src/ui-schema/schema.ts","../src/ui-schema/ir-generator.ts","../src/ui-schema/generator.ts","../src/json-schema/types.ts","../src/extensions/registry.ts","../src/json-schema/schema.ts","../src/validate/constraint-validator.ts"],"sourcesContent":["/**\n * Browser-safe exports for `@formspec/build`.\n *\n * This entry point excludes Node.js-specific functions like `writeSchemas`\n * that use `node:fs` and `node:path`, making it suitable for browser environments.\n *\n * @example\n * ```typescript\n * // In browser code (e.g., playground)\n * import { buildFormSchemas, generateJsonSchema, generateUiSchema } from \"@formspec/build/browser\";\n *\n * const form = formspec(field.text(\"name\"));\n * const { jsonSchema, uiSchema } = buildFormSchemas(form);\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { FormElement, FormSpec } from \"@formspec/core\";\nimport { generateJsonSchema, type GenerateJsonSchemaOptions } from \"./json-schema/generator.js\";\nimport { generateUiSchema } from \"./ui-schema/generator.js\";\nimport { type JsonSchema2020 } from \"./json-schema/ir-generator.js\";\nimport type { UISchema } from \"./ui-schema/types.js\";\n\n// Re-export types\nexport type { JsonSchema2020 } from \"./json-schema/ir-generator.js\";\nexport type { GenerateJsonSchemaFromIROptions } from \"./json-schema/ir-generator.js\";\nexport type { GenerateJsonSchemaOptions } from \"./json-schema/generator.js\";\nexport type {\n BuiltinConstraintBroadeningRegistration,\n ConstraintTagRegistration,\n CustomAnnotationRegistration,\n CustomConstraintRegistration,\n CustomTypeRegistration,\n ExtensionDefinition,\n} from \"@formspec/core\";\n\nexport type {\n JSONSchema7,\n JSONSchemaType,\n ExtendedJSONSchema7,\n FormSpecSchemaExtensions,\n} from \"./json-schema/types.js\";\n\nexport { setSchemaExtension, getSchemaExtension } from \"./json-schema/types.js\";\nexport { createExtensionRegistry } from \"./extensions/index.js\";\nexport type { ExtensionRegistry } from \"./extensions/index.js\";\n\nexport type {\n UISchema,\n UISchemaElement,\n UISchemaElementBase,\n UISchemaElementType,\n ControlElement,\n VerticalLayout,\n HorizontalLayout,\n GroupLayout,\n Categorization,\n Category,\n LabelElement,\n Rule,\n RuleEffect,\n RuleConditionSchema,\n SchemaBasedCondition,\n} from \"./ui-schema/types.js\";\n\n// Zod validation schemas\nexport {\n ruleEffectSchema,\n uiSchemaElementTypeSchema,\n ruleConditionSchema,\n schemaBasedConditionSchema,\n ruleSchema,\n controlSchema,\n verticalLayoutSchema,\n horizontalLayoutSchema,\n groupLayoutSchema,\n categorizationSchema,\n categorySchema,\n labelElementSchema,\n uiSchemaElementSchema,\n uiSchema as uiSchemaSchema,\n} from \"./ui-schema/schema.js\";\n\nexport { jsonSchemaTypeSchema, jsonSchema7Schema } from \"./json-schema/schema.js\";\n\n// Re-export individual generators\nexport { generateJsonSchema } from \"./json-schema/generator.js\";\nexport { generateJsonSchemaFromIR } from \"./json-schema/ir-generator.js\";\nexport { generateUiSchema } from \"./ui-schema/generator.js\";\n\n// IR canonicalization (browser-safe: no Node.js dependencies)\nexport { canonicalizeChainDSL } from \"./canonicalize/chain-dsl-canonicalizer.js\";\n\n// IR validation (browser-safe: no Node.js dependencies)\nexport { validateIR } from \"./validate/constraint-validator.js\";\nexport type {\n ValidationDiagnostic,\n ValidationResult,\n ValidateIROptions,\n} from \"./validate/constraint-validator.js\";\n\n/**\n * Result of building form schemas.\n */\nexport interface BuildResult {\n /** JSON Schema 2020-12 for validation */\n readonly jsonSchema: JsonSchema2020;\n /** JSON Forms UI Schema for rendering */\n readonly uiSchema: UISchema;\n}\n\n/**\n * Options for building schemas from a FormSpec in browser-safe code.\n *\n * Currently identical to `GenerateJsonSchemaOptions`. Defined separately so the\n * browser-safe surface can grow independently in the future if needed.\n */\nexport type BuildFormSchemasOptions = GenerateJsonSchemaOptions;\n\n/**\n * Builds both JSON Schema and UI Schema from a FormSpec.\n *\n * This is a browser-safe version that does not include file system operations.\n *\n * @example\n * ```typescript\n * const form = formspec(\n * field.text(\"name\", { required: true }),\n * field.number(\"age\", { min: 0 }),\n * );\n *\n * const { jsonSchema, uiSchema } = buildFormSchemas(form);\n * ```\n *\n * @param form - The FormSpec to build schemas from\n * @returns Object containing both jsonSchema and uiSchema\n */\nexport function buildFormSchemas<E extends readonly FormElement[]>(\n form: FormSpec<E>,\n options?: BuildFormSchemasOptions\n): BuildResult {\n return {\n jsonSchema: generateJsonSchema(form, options),\n uiSchema: generateUiSchema(form),\n };\n}\n","/**\n * Canonicalizer that translates chain DSL `FormSpec` objects into the\n * canonical FormIR intermediate representation.\n *\n * This module maps the runtime objects produced by `@formspec/dsl` builder\n * functions (`field.*`, `group`, `when`, `formspec`) into the IR that all\n * downstream phases (validation, JSON Schema generation, UI Schema generation)\n * consume.\n */\n\nimport type {\n // Source types (chain DSL)\n AnyField,\n ArrayField,\n BooleanField,\n Conditional,\n DynamicEnumField,\n DynamicSchemaField,\n EnumOptionValue,\n FormElement,\n FormSpec,\n Group,\n NumberField,\n ObjectField,\n StaticEnumField,\n TextField,\n} from \"@formspec/core\";\nimport type {\n // IR types\n JsonValue,\n AnnotationNode,\n ArrayTypeNode,\n ConstraintNode,\n ConditionalLayoutNode,\n DisplayNameAnnotationNode,\n DynamicTypeNode,\n EnumMember,\n EnumTypeNode,\n FieldNode,\n FormIR,\n FormIRElement,\n GroupLayoutNode,\n LengthConstraintNode,\n NumericConstraintNode,\n ObjectProperty,\n PatternConstraintNode,\n ObjectTypeNode,\n PlaceholderAnnotationNode,\n PrimitiveTypeNode,\n Provenance,\n TypeNode,\n} from \"@formspec/core/internals\";\nimport { IR_VERSION } from \"@formspec/core/internals\";\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\n/** Default provenance for chain DSL nodes (no source location available). */\nconst CHAIN_DSL_PROVENANCE: Provenance = {\n surface: \"chain-dsl\",\n file: \"\",\n line: 0,\n column: 0,\n} as const;\n\n// =============================================================================\n// TYPE GUARDS\n// =============================================================================\n\nfunction isGroup(el: FormElement): el is Group<readonly FormElement[]> {\n return el._type === \"group\";\n}\n\nfunction isConditional(\n el: FormElement\n): el is Conditional<string, unknown, readonly FormElement[]> {\n return el._type === \"conditional\";\n}\n\nfunction isField(el: FormElement): el is AnyField {\n return el._type === \"field\";\n}\n\n// =============================================================================\n// PUBLIC API\n// =============================================================================\n\n/**\n * Translates a chain DSL `FormSpec` into the canonical `FormIR`.\n *\n * @param form - A form specification created via `formspec(...)` from `@formspec/dsl`\n * @returns The canonical intermediate representation\n */\nexport function canonicalizeChainDSL(form: FormSpec<readonly FormElement[]>): FormIR {\n return {\n kind: \"form-ir\",\n irVersion: IR_VERSION,\n elements: canonicalizeElements(form.elements),\n rootAnnotations: [],\n typeRegistry: {},\n provenance: CHAIN_DSL_PROVENANCE,\n };\n}\n\n// =============================================================================\n// ELEMENT CANONICALIZATION\n// =============================================================================\n\n/**\n * Canonicalizes an array of chain DSL form elements into IR elements.\n */\nfunction canonicalizeElements(elements: readonly FormElement[]): FormIRElement[] {\n return elements.map(canonicalizeElement);\n}\n\n/**\n * Dispatches a single form element to its specific canonicalization function.\n */\nfunction canonicalizeElement(element: FormElement): FormIRElement {\n if (isField(element)) {\n return canonicalizeField(element);\n }\n if (isGroup(element)) {\n return canonicalizeGroup(element);\n }\n if (isConditional(element)) {\n return canonicalizeConditional(element);\n }\n const _exhaustive: never = element;\n throw new Error(`Unknown element type: ${JSON.stringify(_exhaustive)}`);\n}\n\n// =============================================================================\n// FIELD CANONICALIZATION\n// =============================================================================\n\n/**\n * Dispatches a field element to its type-specific canonicalization function.\n */\nfunction canonicalizeField(field: AnyField): FieldNode {\n switch (field._field) {\n case \"text\":\n return canonicalizeTextField(field);\n case \"number\":\n return canonicalizeNumberField(field);\n case \"boolean\":\n return canonicalizeBooleanField(field);\n case \"enum\":\n return canonicalizeStaticEnumField(field);\n case \"dynamic_enum\":\n return canonicalizeDynamicEnumField(field);\n case \"dynamic_schema\":\n return canonicalizeDynamicSchemaField(field);\n case \"array\":\n return canonicalizeArrayField(field);\n case \"object\":\n return canonicalizeObjectField(field);\n default: {\n const _exhaustive: never = field;\n throw new Error(`Unknown field type: ${JSON.stringify(_exhaustive)}`);\n }\n }\n}\n\n// =============================================================================\n// SPECIFIC FIELD TYPE CANONICALIZERS\n// =============================================================================\n\nfunction canonicalizeTextField(field: TextField<string>): FieldNode {\n const type: PrimitiveTypeNode = { kind: \"primitive\", primitiveKind: \"string\" };\n const constraints: ConstraintNode[] = [];\n\n if (field.minLength !== undefined) {\n const c: LengthConstraintNode = {\n kind: \"constraint\",\n constraintKind: \"minLength\",\n value: field.minLength,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n constraints.push(c);\n }\n\n if (field.maxLength !== undefined) {\n const c: LengthConstraintNode = {\n kind: \"constraint\",\n constraintKind: \"maxLength\",\n value: field.maxLength,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n constraints.push(c);\n }\n\n if (field.pattern !== undefined) {\n const c: PatternConstraintNode = {\n kind: \"constraint\",\n constraintKind: \"pattern\",\n pattern: field.pattern,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n constraints.push(c);\n }\n\n return buildFieldNode(\n field.name,\n type,\n field.required,\n buildAnnotations(field.label, field.placeholder),\n constraints\n );\n}\n\nfunction canonicalizeNumberField(field: NumberField<string>): FieldNode {\n const type: PrimitiveTypeNode = { kind: \"primitive\", primitiveKind: \"number\" };\n const constraints: ConstraintNode[] = [];\n\n if (field.min !== undefined) {\n const c: NumericConstraintNode = {\n kind: \"constraint\",\n constraintKind: \"minimum\",\n value: field.min,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n constraints.push(c);\n }\n\n if (field.max !== undefined) {\n const c: NumericConstraintNode = {\n kind: \"constraint\",\n constraintKind: \"maximum\",\n value: field.max,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n constraints.push(c);\n }\n\n if (field.multipleOf !== undefined) {\n const c: NumericConstraintNode = {\n kind: \"constraint\",\n constraintKind: \"multipleOf\",\n value: field.multipleOf,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n constraints.push(c);\n }\n\n return buildFieldNode(\n field.name,\n type,\n field.required,\n buildAnnotations(field.label),\n constraints\n );\n}\n\nfunction canonicalizeBooleanField(field: BooleanField<string>): FieldNode {\n const type: PrimitiveTypeNode = { kind: \"primitive\", primitiveKind: \"boolean\" };\n return buildFieldNode(field.name, type, field.required, buildAnnotations(field.label));\n}\n\nfunction canonicalizeStaticEnumField(\n field: StaticEnumField<string, readonly EnumOptionValue[]>\n): FieldNode {\n const members: EnumMember[] = field.options.map((opt) => {\n if (typeof opt === \"string\") {\n return { value: opt } satisfies EnumMember;\n }\n // Object option with id/label\n return { value: opt.id, displayName: opt.label } satisfies EnumMember;\n });\n\n const type: EnumTypeNode = { kind: \"enum\", members };\n return buildFieldNode(field.name, type, field.required, buildAnnotations(field.label));\n}\n\nfunction canonicalizeDynamicEnumField(field: DynamicEnumField<string, string>): FieldNode {\n const type: DynamicTypeNode = {\n kind: \"dynamic\",\n dynamicKind: \"enum\",\n sourceKey: field.source,\n parameterFields: field.params ? [...field.params] : [],\n };\n return buildFieldNode(field.name, type, field.required, buildAnnotations(field.label));\n}\n\nfunction canonicalizeDynamicSchemaField(field: DynamicSchemaField<string>): FieldNode {\n const type: DynamicTypeNode = {\n kind: \"dynamic\",\n dynamicKind: \"schema\",\n sourceKey: field.schemaSource,\n parameterFields: [],\n };\n return buildFieldNode(field.name, type, field.required, buildAnnotations(field.label));\n}\n\nfunction canonicalizeArrayField(field: ArrayField<string, readonly FormElement[]>): FieldNode {\n // Array items form an object type from the sub-elements\n const itemProperties = buildObjectProperties(field.items);\n const itemsType: ObjectTypeNode = {\n kind: \"object\",\n properties: itemProperties,\n additionalProperties: true,\n };\n const type: ArrayTypeNode = { kind: \"array\", items: itemsType };\n\n const constraints: ConstraintNode[] = [];\n if (field.minItems !== undefined) {\n const c: LengthConstraintNode = {\n kind: \"constraint\",\n constraintKind: \"minItems\",\n value: field.minItems,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n constraints.push(c);\n }\n if (field.maxItems !== undefined) {\n const c: LengthConstraintNode = {\n kind: \"constraint\",\n constraintKind: \"maxItems\",\n value: field.maxItems,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n constraints.push(c);\n }\n\n return buildFieldNode(\n field.name,\n type,\n field.required,\n buildAnnotations(field.label),\n constraints\n );\n}\n\nfunction canonicalizeObjectField(field: ObjectField<string, readonly FormElement[]>): FieldNode {\n const properties = buildObjectProperties(field.properties);\n const type: ObjectTypeNode = {\n kind: \"object\",\n properties,\n additionalProperties: true,\n };\n return buildFieldNode(field.name, type, field.required, buildAnnotations(field.label));\n}\n\n// =============================================================================\n// LAYOUT CANONICALIZATION\n// =============================================================================\n\nfunction canonicalizeGroup(g: Group<readonly FormElement[]>): GroupLayoutNode {\n return {\n kind: \"group\",\n label: g.label,\n elements: canonicalizeElements(g.elements),\n provenance: CHAIN_DSL_PROVENANCE,\n };\n}\n\nfunction canonicalizeConditional(\n c: Conditional<string, unknown, readonly FormElement[]>\n): ConditionalLayoutNode {\n return {\n kind: \"conditional\",\n fieldName: c.field,\n // Conditional values from the chain DSL are JSON-serializable primitives\n // (strings, numbers, booleans) produced by the `is()` predicate helper.\n value: assertJsonValue(c.value),\n elements: canonicalizeElements(c.elements),\n provenance: CHAIN_DSL_PROVENANCE,\n };\n}\n\n// =============================================================================\n// HELPERS\n// =============================================================================\n\n/**\n * Validates that a value is JSON-serializable (`JsonValue`).\n * The chain DSL's `is()` helper constrains conditional values to\n * JSON-compatible primitives, but the TypeScript type is `unknown`.\n * This runtime guard replaces an `as` cast with a validated assertion.\n */\nfunction assertJsonValue(v: unknown): JsonValue {\n if (v === null || typeof v === \"string\" || typeof v === \"number\" || typeof v === \"boolean\") {\n return v;\n }\n if (Array.isArray(v)) {\n return v.map(assertJsonValue);\n }\n if (typeof v === \"object\") {\n const result: Record<string, JsonValue> = {};\n for (const [key, val] of Object.entries(v)) {\n result[key] = assertJsonValue(val);\n }\n return result;\n }\n // Remaining types (function, symbol, bigint, undefined) are not JSON-serializable\n throw new TypeError(`Conditional value is not a valid JsonValue: ${typeof v}`);\n}\n\n/**\n * Builds a FieldNode from common field properties.\n */\nfunction buildFieldNode(\n name: string,\n type: TypeNode,\n required: boolean | undefined,\n annotations: AnnotationNode[],\n constraints: ConstraintNode[] = []\n): FieldNode {\n return {\n kind: \"field\",\n name,\n type,\n required: required === true,\n constraints,\n annotations,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n}\n\n/**\n * Builds annotation nodes from optional label and placeholder values.\n */\nfunction buildAnnotations(label?: string, placeholder?: string): AnnotationNode[] {\n const annotations: AnnotationNode[] = [];\n\n if (label !== undefined) {\n const a: DisplayNameAnnotationNode = {\n kind: \"annotation\",\n annotationKind: \"displayName\",\n value: label,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n annotations.push(a);\n }\n\n if (placeholder !== undefined) {\n const a: PlaceholderAnnotationNode = {\n kind: \"annotation\",\n annotationKind: \"placeholder\",\n value: placeholder,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n annotations.push(a);\n }\n\n return annotations;\n}\n\n/**\n * Converts an array of form elements into ObjectProperty nodes.\n * Used for ObjectField properties and ArrayField items.\n *\n * Only field elements produce properties; groups and conditionals within\n * an object/array context are recursively flattened to extract their fields.\n *\n * Fields inside conditional branches are always marked `optional: true`\n * because their presence in the data depends on the condition being met.\n * This matches the DSL's type inference behavior where conditional fields\n * produce optional properties in `InferFormSchema`.\n *\n * @param elements - The form elements to convert\n * @param insideConditional - Whether these elements are inside a conditional branch\n */\nfunction buildObjectProperties(\n elements: readonly FormElement[],\n insideConditional = false\n): ObjectProperty[] {\n const properties: ObjectProperty[] = [];\n\n for (const el of elements) {\n if (isField(el)) {\n const fieldNode = canonicalizeField(el);\n properties.push({\n name: fieldNode.name,\n type: fieldNode.type,\n // Fields inside a conditional branch are always optional in the\n // data schema, regardless of their `required` flag — the condition\n // may not be met, so the field may be absent.\n optional: insideConditional || !fieldNode.required,\n constraints: fieldNode.constraints,\n annotations: fieldNode.annotations,\n provenance: CHAIN_DSL_PROVENANCE,\n });\n } else if (isGroup(el)) {\n // Groups inside object/array items contribute their fields by flattening.\n // Groups do not affect optionality — pass through the current state.\n properties.push(...buildObjectProperties(el.elements, insideConditional));\n } else if (isConditional(el)) {\n // Conditionals inside object/array items contribute their fields by\n // flattening, but all fields inside are forced optional.\n properties.push(...buildObjectProperties(el.elements, true));\n }\n }\n\n return properties;\n}\n","/**\n * TSDoc canonicalizer — assembles an {@link IRClassAnalysis} into a canonical\n * {@link FormIR}, applying layout metadata from `@Group` and `@ShowWhen`\n * TSDoc tags.\n *\n * The analysis functions in `class-analyzer.ts` produce `FieldNode[]`,\n * `fieldLayouts`, and `typeRegistry` directly. This canonicalizer uses\n * the layout metadata to wrap fields in `GroupLayoutNode` and\n * `ConditionalLayoutNode` elements.\n */\n\nimport type {\n FormIR,\n FormIRElement,\n FieldNode,\n GroupLayoutNode,\n ConditionalLayoutNode,\n Provenance,\n} from \"@formspec/core/internals\";\nimport { IR_VERSION } from \"@formspec/core/internals\";\nimport type { IRClassAnalysis, FieldLayoutMetadata } from \"../analyzer/class-analyzer.js\";\n\n/**\n * Source-level metadata for provenance tracking.\n */\nexport interface TSDocSource {\n /** Absolute path to the source file. */\n readonly file: string;\n}\n\n/**\n * Wraps an {@link IRClassAnalysis} (from `analyzeClassToIR`,\n * `analyzeInterfaceToIR`, or `analyzeTypeAliasToIR`) into a canonical\n * {@link FormIR}.\n *\n * Fields with `@Group` TSDoc tags are grouped into `GroupLayoutNode` elements.\n * Fields with `@ShowWhen` TSDoc tags are wrapped in `ConditionalLayoutNode` elements.\n * When both are present, the conditional wraps the field inside the group.\n *\n * @param analysis - IR analysis result (fields are already FieldNode[])\n * @param source - Optional source file metadata for provenance\n * @returns The canonical FormIR\n */\nexport function canonicalizeTSDoc(analysis: IRClassAnalysis, source?: TSDocSource): FormIR {\n const file = source?.file ?? \"\";\n\n const provenance: Provenance = {\n surface: \"tsdoc\",\n file,\n line: 1,\n column: 0,\n };\n\n const elements = assembleElements(analysis.fields, analysis.fieldLayouts, provenance);\n\n return {\n kind: \"form-ir\",\n irVersion: IR_VERSION,\n elements,\n typeRegistry: analysis.typeRegistry,\n ...(analysis.annotations !== undefined &&\n analysis.annotations.length > 0 && { rootAnnotations: analysis.annotations }),\n ...(analysis.annotations !== undefined &&\n analysis.annotations.length > 0 && { annotations: analysis.annotations }),\n provenance,\n };\n}\n\n/**\n * Assembles flat fields and their layout metadata into a tree of\n * `FormIRElement[]` with groups and conditionals.\n *\n * Fields are processed in order. Consecutive fields with the same\n * `@Group` label are collected into a single `GroupLayoutNode`.\n * Fields with `@ShowWhen` are wrapped in `ConditionalLayoutNode`.\n */\nfunction assembleElements(\n fields: readonly FieldNode[],\n layouts: readonly FieldLayoutMetadata[],\n provenance: Provenance\n): readonly FormIRElement[] {\n const elements: FormIRElement[] = [];\n\n // Group consecutive fields with the same group label together.\n // We use an ordered map to preserve insertion order of groups.\n const groupMap = new Map<string, FormIRElement[]>();\n const topLevelOrder: (\n | { type: \"group\"; label: string }\n | { type: \"element\"; element: FormIRElement }\n )[] = [];\n\n for (let i = 0; i < fields.length; i++) {\n const field = fields[i];\n const layout = layouts[i];\n if (!field || !layout) continue;\n\n // Wrap in conditional if @ShowWhen is present\n const element = wrapInConditional(field, layout, provenance);\n\n if (layout.groupLabel !== undefined) {\n const label = layout.groupLabel;\n let groupElements = groupMap.get(label);\n if (!groupElements) {\n groupElements = [];\n groupMap.set(label, groupElements);\n topLevelOrder.push({ type: \"group\", label });\n }\n groupElements.push(element);\n } else {\n topLevelOrder.push({ type: \"element\", element });\n }\n }\n\n // Assemble the final element array in order\n for (const entry of topLevelOrder) {\n if (entry.type === \"group\") {\n const groupElements = groupMap.get(entry.label);\n if (groupElements) {\n const groupNode: GroupLayoutNode = {\n kind: \"group\",\n label: entry.label,\n elements: groupElements,\n provenance,\n };\n elements.push(groupNode);\n // Clear so duplicate group labels in topLevelOrder don't re-emit\n groupMap.delete(entry.label);\n }\n } else {\n elements.push(entry.element);\n }\n }\n\n return elements;\n}\n\n/**\n * Wraps a field in a `ConditionalLayoutNode` if the layout has `showWhen` metadata.\n */\nfunction wrapInConditional(\n field: FieldNode,\n layout: FieldLayoutMetadata,\n provenance: Provenance\n): FormIRElement {\n if (layout.showWhen === undefined) {\n return field;\n }\n\n const conditional: ConditionalLayoutNode = {\n kind: \"conditional\",\n fieldName: layout.showWhen.field,\n value: layout.showWhen.value,\n elements: [field],\n provenance,\n };\n\n return conditional;\n}\n","/**\n * JSON Schema 2020-12 generator that consumes the canonical FormIR.\n *\n * This generator is a pure function of the IR. It never consults the TypeScript\n * AST or surface syntax directly — only the IR (per the JSON Schema vocabulary spec §1.2).\n *\n * @see https://json-schema.org/draft/2020-12/schema\n * @see https://json-schema.org/draft/2020-12/schema\n */\n\nimport type {\n FormIR,\n FormIRElement,\n FieldNode,\n TypeNode,\n PrimitiveTypeNode,\n EnumTypeNode,\n ArrayTypeNode,\n ObjectTypeNode,\n RecordTypeNode,\n UnionTypeNode,\n ReferenceTypeNode,\n DynamicTypeNode,\n CustomTypeNode,\n ConstraintNode,\n AnnotationNode,\n ObjectProperty,\n} from \"@formspec/core/internals\";\nimport type { ExtensionRegistry } from \"../extensions/index.js\";\n\n// =============================================================================\n// OUTPUT TYPE\n// =============================================================================\n\n/**\n * A JSON Schema 2020-12 document, sub-schema, or keyword collection.\n *\n * This interface covers the subset of JSON Schema 2020-12 that this generator\n * emits, plus an index signature for custom `x-formspec-*` extension keywords.\n *\n * @public\n */\nexport interface JsonSchema2020 {\n /** Declared JSON Schema dialect URI for the document root. */\n $schema?: string;\n /** Reference to another schema location. */\n $ref?: string;\n /** Named reusable schema definitions keyed by definition name. */\n $defs?: Record<string, JsonSchema2020>;\n /** JSON Schema type keyword for the current node. */\n type?: string;\n /** Object properties keyed by property name. */\n properties?: Record<string, JsonSchema2020>;\n /** Property names that must be present on object values. */\n required?: string[];\n /** Item schema applied to array elements. */\n items?: JsonSchema2020;\n /** Whether, or how, additional object properties are allowed. */\n additionalProperties?: boolean | JsonSchema2020;\n /** Closed set of allowed scalar values. */\n enum?: readonly (string | number)[];\n /** Literal value the instance must equal. */\n const?: unknown;\n /** Schemas that must all validate successfully. */\n allOf?: readonly JsonSchema2020[];\n /** Schemas of which exactly one should validate successfully. */\n oneOf?: readonly JsonSchema2020[];\n /** Schemas of which at least one may validate successfully. */\n anyOf?: readonly JsonSchema2020[];\n // Constraints\n /** Inclusive numeric lower bound. */\n minimum?: number;\n /** Inclusive numeric upper bound. */\n maximum?: number;\n /** Exclusive numeric lower bound. */\n exclusiveMinimum?: number;\n /** Exclusive numeric upper bound. */\n exclusiveMaximum?: number;\n /** Required numeric step interval. */\n multipleOf?: number;\n /** Inclusive minimum string length. */\n minLength?: number;\n /** Inclusive maximum string length. */\n maxLength?: number;\n /** Inclusive minimum array length. */\n minItems?: number;\n /** Inclusive maximum array length. */\n maxItems?: number;\n /** Regular expression pattern applied to string values. */\n pattern?: string;\n /** Whether array elements must be unique. */\n uniqueItems?: boolean;\n /** Format hint for downstream validators and tooling. */\n format?: string;\n // Annotations\n /** Human-readable title for the schema node. */\n title?: string;\n /** Human-readable description for the schema node. */\n description?: string;\n /** Default value suggested for the schema node. */\n default?: unknown;\n /** Whether the schema node is deprecated. */\n deprecated?: boolean;\n // Extensions (open for vendor-prefixed keywords, e.g., x-formspec-*, x-stripe-*)\n // The vendor prefix is configurable (white-labelable).\n /** Additional vendor-prefixed extension keywords. */\n [key: `x-${string}`]: unknown;\n}\n\n// =============================================================================\n// CONTEXT\n// =============================================================================\n\n/**\n * Mutable accumulator passed through the generation traversal.\n *\n * Using a context object rather than return-value threading keeps the\n * recursive generators simple and avoids repeated object spreading.\n */\ninterface GeneratorContext {\n /** Named type schemas collected during traversal, keyed by reference name. */\n readonly defs: Record<string, JsonSchema2020>;\n /** Optional extension registry for resolving custom IR nodes. */\n readonly extensionRegistry: ExtensionRegistry | undefined;\n /** Vendor prefix passed through to extension toJsonSchema handlers. */\n readonly vendorPrefix: string;\n}\n\n/**\n * Options for generating JSON Schema from a canonical FormIR.\n *\n * @internal\n */\nexport interface GenerateJsonSchemaFromIROptions {\n /**\n * Registry used to resolve custom types, constraints, and annotations.\n *\n * JSON Schema generation throws when custom IR nodes are present without a\n * matching registration in this registry.\n */\n readonly extensionRegistry?: ExtensionRegistry | undefined;\n /**\n * Vendor prefix passed to extension `toJsonSchema` hooks.\n * @defaultValue \"x-formspec\"\n */\n readonly vendorPrefix?: string | undefined;\n}\n\nfunction makeContext(options?: GenerateJsonSchemaFromIROptions): GeneratorContext {\n const vendorPrefix = options?.vendorPrefix ?? \"x-formspec\";\n if (!vendorPrefix.startsWith(\"x-\")) {\n throw new Error(\n `Invalid vendorPrefix \"${vendorPrefix}\". Extension JSON Schema keywords must start with \"x-\".`\n );\n }\n\n return {\n defs: {},\n extensionRegistry: options?.extensionRegistry,\n vendorPrefix,\n };\n}\n\n// =============================================================================\n// PUBLIC API\n// =============================================================================\n\n/**\n * Generates a JSON Schema 2020-12 object from a canonical FormIR.\n *\n * Groups and conditionals are flattened — they influence UI layout but do not\n * affect the data schema. All fields appear at the level they would occupy in\n * the output data.\n *\n * Named types in the `typeRegistry` are emitted as `$defs` entries and\n * referenced via `$ref` (per PP7 — high-fidelity output).\n *\n * @example\n * ```typescript\n * import { canonicalizeDSL } from \"./canonicalize/index.js\";\n * import { generateJsonSchemaFromIR } from \"./json-schema/ir-generator.js\";\n * import { formspec, field } from \"@formspec/dsl\";\n *\n * const form = formspec(\n * field.text(\"name\", { label: \"Name\", required: true }),\n * field.number(\"age\", { min: 0 }),\n * );\n * const ir = canonicalizeDSL(form);\n * const schema = generateJsonSchemaFromIR(ir);\n * // {\n * // $schema: \"https://json-schema.org/draft/2020-12/schema\",\n * // type: \"object\",\n * // properties: {\n * // name: { type: \"string\", title: \"Name\" },\n * // age: { type: \"number\", minimum: 0 }\n * // },\n * // required: [\"name\"]\n * // }\n * ```\n *\n * Advanced API — most consumers should use `generateJsonSchema()` or\n * `buildFormSchemas()`, which canonicalize form definitions automatically.\n * Callers of this function are responsible for providing pre-canonicalized IR.\n *\n * @param ir - The canonical FormIR produced by a canonicalizer\n * @returns A plain JSON-serializable JSON Schema 2020-12 object\n *\n * @internal\n */\nexport function generateJsonSchemaFromIR(\n ir: FormIR,\n options?: GenerateJsonSchemaFromIROptions\n): JsonSchema2020 {\n const ctx = makeContext(options);\n\n // Seed $defs from the type registry so referenced types are available even if\n // the field tree traversal never visits them (e.g., unreferenced types added\n // by a TSDoc canonicalizer pass).\n for (const [name, typeDef] of Object.entries(ir.typeRegistry)) {\n ctx.defs[name] = generateTypeNode(typeDef.type, ctx);\n if (typeDef.constraints && typeDef.constraints.length > 0) {\n applyConstraints(ctx.defs[name], typeDef.constraints, ctx);\n }\n if (typeDef.annotations && typeDef.annotations.length > 0) {\n applyAnnotations(ctx.defs[name], typeDef.annotations, ctx);\n }\n }\n\n const properties: Record<string, JsonSchema2020> = {};\n const required: string[] = [];\n\n collectFields(ir.elements, properties, required, ctx);\n\n // Deduplicate required (same field can appear across conditional branches).\n const uniqueRequired = [...new Set(required)];\n\n const result: JsonSchema2020 = {\n $schema: \"https://json-schema.org/draft/2020-12/schema\",\n type: \"object\",\n properties,\n ...(uniqueRequired.length > 0 && { required: uniqueRequired }),\n };\n\n if (ir.annotations && ir.annotations.length > 0) {\n applyAnnotations(result, ir.annotations, ctx);\n }\n\n if (Object.keys(ctx.defs).length > 0) {\n result.$defs = ctx.defs;\n }\n\n return result;\n}\n\n// =============================================================================\n// ELEMENT TRAVERSAL\n// =============================================================================\n\n/**\n * Recursively visits all IR elements, collecting field schemas and required names.\n *\n * Groups and conditionals are transparent to the schema — their children are\n * lifted to the enclosing level (per the JSON Schema vocabulary spec §1.2).\n */\nfunction collectFields(\n elements: readonly FormIRElement[],\n properties: Record<string, JsonSchema2020>,\n required: string[],\n ctx: GeneratorContext\n): void {\n for (const element of elements) {\n switch (element.kind) {\n case \"field\":\n properties[element.name] = generateFieldSchema(element, ctx);\n if (element.required) {\n required.push(element.name);\n }\n break;\n\n case \"group\":\n // Groups are UI-only; flatten children into the enclosing schema.\n collectFields(element.elements, properties, required, ctx);\n break;\n\n case \"conditional\":\n // Conditional visibility is UI-only; all fields remain in the schema.\n collectFields(element.elements, properties, required, ctx);\n break;\n\n default: {\n const _exhaustive: never = element;\n void _exhaustive;\n }\n }\n }\n}\n\n// =============================================================================\n// FIELD SCHEMA GENERATION\n// =============================================================================\n\n/**\n * Generates the JSON Schema sub-schema for a single FieldNode.\n */\nfunction generateFieldSchema(field: FieldNode, ctx: GeneratorContext): JsonSchema2020 {\n const schema = generateTypeNode(field.type, ctx);\n const itemStringSchema =\n schema.type === \"array\" && schema.items?.type === \"string\" ? schema.items : undefined;\n\n // Partition constraints into direct (no path) and path-targeted.\n const directConstraints: ConstraintNode[] = [];\n const itemConstraints: ConstraintNode[] = [];\n const pathConstraints: ConstraintNode[] = [];\n for (const c of field.constraints) {\n if (c.path) {\n pathConstraints.push(c);\n } else if (itemStringSchema !== undefined && isStringItemConstraint(c)) {\n itemConstraints.push(c);\n } else {\n directConstraints.push(c);\n }\n }\n\n // Apply direct constraints. multipleOf:1 on a number type is a special case:\n // it promotes the type to \"integer\" and removes the multipleOf keyword.\n applyConstraints(schema, directConstraints, ctx);\n\n if (itemStringSchema !== undefined) {\n applyConstraints(itemStringSchema, itemConstraints, ctx);\n }\n\n // Apply annotations (title, description, default, deprecated, etc.).\n const rootAnnotations: AnnotationNode[] = [];\n const itemAnnotations: AnnotationNode[] = [];\n for (const annotation of field.annotations) {\n if (itemStringSchema !== undefined && annotation.annotationKind === \"format\") {\n itemAnnotations.push(annotation);\n } else {\n rootAnnotations.push(annotation);\n }\n }\n\n applyAnnotations(schema, rootAnnotations, ctx);\n if (itemStringSchema !== undefined) {\n applyAnnotations(itemStringSchema, itemAnnotations, ctx);\n }\n\n // If no path-targeted constraints, return as-is.\n if (pathConstraints.length === 0) {\n return schema;\n }\n\n return applyPathTargetedConstraints(schema, pathConstraints, ctx);\n}\n\n/**\n * Returns true if a constraint should be applied to the `items` schema of a\n * primitive `string[]` rather than the array itself.\n *\n * `@const` is intentionally excluded: arrays cannot carry primitive const\n * constraints in FormSpec, so `@const` on `string[]` remains a validation\n * error instead of targeting the item schema.\n */\nfunction isStringItemConstraint(constraint: ConstraintNode): boolean {\n switch (constraint.constraintKind) {\n case \"minLength\":\n case \"maxLength\":\n case \"pattern\":\n return true;\n default:\n return false;\n }\n}\n\n/**\n * Applies path-targeted constraints to a schema via allOf composition.\n *\n * For $ref schemas: wraps in allOf with property overrides.\n * For inline object schemas: applies directly to nested properties.\n * For array schemas: applies path constraints to the items sub-schema.\n */\nfunction applyPathTargetedConstraints(\n schema: JsonSchema2020,\n pathConstraints: readonly ConstraintNode[],\n ctx: GeneratorContext\n): JsonSchema2020 {\n // Array transparency: path-targeted constraints target the item type.\n if (schema.type === \"array\" && schema.items) {\n schema.items = applyPathTargetedConstraints(schema.items, pathConstraints, ctx);\n return schema;\n }\n\n // Group path constraints by target field name (first path segment).\n // Callers guarantee all entries have a defined `path` (filtered upstream).\n const byTarget = new Map<string, ConstraintNode[]>();\n for (const c of pathConstraints) {\n const target = c.path?.segments[0];\n if (!target) continue;\n const group = byTarget.get(target) ?? [];\n group.push(c);\n byTarget.set(target, group);\n }\n\n // Build the property overrides object.\n const propertyOverrides: Record<string, JsonSchema2020> = {};\n for (const [target, constraints] of byTarget) {\n const subSchema: JsonSchema2020 = {};\n applyConstraints(subSchema, constraints, ctx);\n propertyOverrides[target] = subSchema;\n }\n\n // $ref schema: wrap in allOf to preserve $ref semantics while adding overrides.\n if (schema.$ref) {\n const { $ref, ...rest } = schema;\n const refPart: JsonSchema2020 = { $ref };\n const overridePart: JsonSchema2020 = {\n properties: propertyOverrides,\n ...rest,\n };\n return { allOf: [refPart, overridePart] };\n }\n\n // Inline object schema: merge property overrides directly where possible.\n if (schema.type === \"object\" && schema.properties) {\n const missingOverrides: Record<string, JsonSchema2020> = {};\n\n for (const [target, overrideSchema] of Object.entries(propertyOverrides)) {\n if (schema.properties[target]) {\n Object.assign(schema.properties[target], overrideSchema);\n } else {\n // Do not introduce new properties directly; compose via allOf instead\n // to preserve additionalProperties semantics on the base object.\n missingOverrides[target] = overrideSchema;\n }\n }\n\n if (Object.keys(missingOverrides).length === 0) {\n return schema;\n }\n\n return {\n allOf: [schema, { properties: missingOverrides }],\n };\n }\n\n // allOf schema (already composed): add property overrides as another member.\n if (schema.allOf) {\n schema.allOf = [...schema.allOf, { properties: propertyOverrides }];\n return schema;\n }\n\n // Fallback: for non-object/non-$ref schemas, path-targeted constraints do not\n // apply in a meaningful way. Return the original schema unchanged and rely\n // on validation diagnostics to surface misuse of path-based constraints.\n return schema;\n}\n\n// =============================================================================\n// TYPE NODE GENERATION\n// =============================================================================\n\n/**\n * Converts a TypeNode to a JSON Schema sub-schema.\n *\n * This function is intentionally exhaustive — all TypeNode variants are handled.\n * TypeScript's exhaustiveness check via the default branch ensures new variants\n * added to the IR are caught at compile time.\n */\nfunction generateTypeNode(type: TypeNode, ctx: GeneratorContext): JsonSchema2020 {\n switch (type.kind) {\n case \"primitive\":\n return generatePrimitiveType(type);\n\n case \"enum\":\n return generateEnumType(type);\n\n case \"array\":\n return generateArrayType(type, ctx);\n\n case \"object\":\n return generateObjectType(type, ctx);\n\n case \"record\":\n return generateRecordType(type, ctx);\n\n case \"union\":\n return generateUnionType(type, ctx);\n\n case \"reference\":\n return generateReferenceType(type);\n\n case \"dynamic\":\n return generateDynamicType(type);\n\n case \"custom\":\n return generateCustomType(type, ctx);\n\n default: {\n // TypeScript exhaustiveness guard.\n const _exhaustive: never = type;\n return _exhaustive;\n }\n }\n}\n\n/**\n * Maps primitive IR types to JSON Schema type keywords.\n *\n * Note: `integer` is NOT a primitive kind in the IR. Integer semantics are\n * expressed via a `multipleOf: 1` constraint on a number type; `applyConstraints`\n * handles the promotion (per the JSON Schema vocabulary spec §2.1).\n */\nfunction generatePrimitiveType(type: PrimitiveTypeNode): JsonSchema2020 {\n return {\n type:\n type.primitiveKind === \"integer\" || type.primitiveKind === \"bigint\"\n ? \"integer\"\n : type.primitiveKind,\n };\n}\n\n/**\n * Generates JSON Schema for a static enum type.\n *\n * When any member has a displayName, the output uses the `oneOf` form with\n * per-member `const`/`title` entries (per the JSON Schema vocabulary spec §2.3). Otherwise the\n * flat `enum` keyword is used (simpler, equally valid).\n */\nfunction generateEnumType(type: EnumTypeNode): JsonSchema2020 {\n const hasDisplayNames = type.members.some((m) => m.displayName !== undefined);\n\n if (hasDisplayNames) {\n return {\n oneOf: type.members.map((m) => {\n const entry: JsonSchema2020 = { const: m.value };\n if (m.displayName !== undefined) {\n entry.title = m.displayName;\n }\n return entry;\n }),\n };\n }\n\n return { enum: type.members.map((m) => m.value) };\n}\n\n/**\n * Generates JSON Schema for an array type.\n * Per 2020-12, `items` is a single schema (not an array); tuple types use\n * `prefixItems` + `items: false`.\n */\nfunction generateArrayType(type: ArrayTypeNode, ctx: GeneratorContext): JsonSchema2020 {\n return {\n type: \"array\",\n items: generateTypeNode(type.items, ctx),\n };\n}\n\n/**\n * Generates JSON Schema for an object type.\n *\n * `additionalProperties` is emitted only when the IR explicitly closes the\n * object. Ordinary static object types now canonicalize to\n * `additionalProperties: true`, which omits the keyword per spec 003 §2.5.\n */\nfunction generateObjectType(type: ObjectTypeNode, ctx: GeneratorContext): JsonSchema2020 {\n const properties: Record<string, JsonSchema2020> = {};\n const required: string[] = [];\n\n for (const prop of type.properties) {\n properties[prop.name] = generatePropertySchema(prop, ctx);\n if (!prop.optional) {\n required.push(prop.name);\n }\n }\n\n const schema: JsonSchema2020 = { type: \"object\", properties };\n\n if (required.length > 0) {\n schema.required = required;\n }\n\n if (!type.additionalProperties) {\n schema.additionalProperties = false;\n }\n\n return schema;\n}\n\n/**\n * Generates JSON Schema for a record (dictionary) type per spec 003 §2.5.\n *\n * `Record<string, T>` and `{ [k: string]: T }` both emit:\n * `{ \"type\": \"object\", \"additionalProperties\": <T schema> }`\n *\n * No `properties` key is emitted — the record has no named properties.\n */\nfunction generateRecordType(type: RecordTypeNode, ctx: GeneratorContext): JsonSchema2020 {\n return {\n type: \"object\",\n additionalProperties: generateTypeNode(type.valueType, ctx),\n };\n}\n\n/**\n * Generates a schema for an ObjectProperty, applying its use-site constraints\n * and annotations (per the JSON Schema vocabulary spec §5.4 — inline allOf at use site).\n */\nfunction generatePropertySchema(prop: ObjectProperty, ctx: GeneratorContext): JsonSchema2020 {\n const schema = generateTypeNode(prop.type, ctx);\n applyConstraints(schema, prop.constraints, ctx);\n applyAnnotations(schema, prop.annotations, ctx);\n return schema;\n}\n\n/**\n * Generates JSON Schema for a union type.\n *\n * Union handling strategy (per spec 003):\n * - Boolean shorthand: `true | false` → `{ type: \"boolean\" }` (not oneOf/anyOf)\n * - Nullable unions: `T | null` → `{ \"oneOf\": [<T schema>, { \"type\": \"null\" }] }` (§2.3)\n * - All other unions → `anyOf` (members may overlap; discriminated union\n * detection is deferred to a future phase per design doc 003 §7.4)\n */\nfunction generateUnionType(type: UnionTypeNode, ctx: GeneratorContext): JsonSchema2020 {\n // Boolean shorthand: union of true-literal and false-literal → type: \"boolean\"\n if (isBooleanUnion(type)) {\n return { type: \"boolean\" };\n }\n\n // Nullable union: `T | null` → oneOf per spec 003 §2.3.\n // A nullable union is any union where exactly one member is the null primitive.\n if (isNullableUnion(type)) {\n return {\n oneOf: type.members.map((m) => generateTypeNode(m, ctx)),\n };\n }\n\n // Default: anyOf for non-discriminated object unions (spec 003 §7.4).\n // Discriminated union detection (shared required property with distinct consts)\n // is deferred to a future phase.\n return {\n anyOf: type.members.map((m) => generateTypeNode(m, ctx)),\n };\n}\n\n/**\n * Returns true if the union is `true | false` (boolean shorthand).\n */\nfunction isBooleanUnion(type: UnionTypeNode): boolean {\n if (type.members.length !== 2) return false;\n const kinds = type.members.map((m) => m.kind);\n // Both must be primitives; check if both are \"boolean\" primitives.\n // The IR currently does not have a boolean literal node, so boolean union\n // is represented as two primitive boolean members.\n return (\n kinds.every((k) => k === \"primitive\") &&\n type.members.every((m) => m.kind === \"primitive\" && m.primitiveKind === \"boolean\")\n );\n}\n\n/**\n * Returns true if the union is a nullable wrapper union (`T | null` for any T).\n *\n * A nullable union is a two-member union where exactly one member is the `null`\n * primitive type and the other member is any non-null type.\n * Per spec 003 §2.3, nullable unions map to `oneOf` (not `anyOf`).\n */\nfunction isNullableUnion(type: UnionTypeNode): boolean {\n if (type.members.length !== 2) return false;\n const nullCount = type.members.filter(\n (m) => m.kind === \"primitive\" && m.primitiveKind === \"null\"\n ).length;\n return nullCount === 1;\n}\n\n/**\n * Generates JSON Schema for a reference type.\n *\n * The referenced type's schema is stored in `$defs` (seeded from the type\n * registry before traversal begins). The reference simply emits a `$ref`.\n */\nfunction generateReferenceType(type: ReferenceTypeNode): JsonSchema2020 {\n return { $ref: `#/$defs/${type.name}` };\n}\n\n/**\n * Generates JSON Schema for a dynamic type (runtime-resolved enum or schema).\n *\n * Dynamic enums emit `x-formspec-source` and optionally `x-formspec-params`.\n * Dynamic schemas emit `x-formspec-schemaSource` with `additionalProperties: true`\n * since the actual schema is determined at runtime (per the JSON Schema vocabulary spec §3.2).\n */\nfunction generateDynamicType(type: DynamicTypeNode): JsonSchema2020 {\n if (type.dynamicKind === \"enum\") {\n const schema: JsonSchema2020 = {\n type: \"string\",\n \"x-formspec-source\": type.sourceKey,\n };\n if (type.parameterFields.length > 0) {\n schema[\"x-formspec-params\"] = [...type.parameterFields];\n }\n return schema;\n }\n\n // dynamicKind === \"schema\"\n return {\n type: \"object\",\n additionalProperties: true,\n \"x-formspec-schemaSource\": type.sourceKey,\n };\n}\n\n// =============================================================================\n// CONSTRAINT APPLICATION\n// =============================================================================\n\n/**\n * Applies constraint nodes onto an existing JSON Schema object (mutates in place).\n *\n * All callers pass freshly-created objects so there is no aliasing risk.\n *\n * Special rule (per the JSON Schema vocabulary spec §2.1): `multipleOf: 1` on a `\"number\"` type\n * promotes to `\"integer\"` and suppresses the `multipleOf` keyword (integer is a\n * subtype of number; expressing it via multipleOf:1 is redundant).\n *\n * Path-targeted constraints are handled separately by `applyPathTargetedConstraints`.\n */\nfunction applyConstraints(\n schema: JsonSchema2020,\n constraints: readonly ConstraintNode[],\n ctx: GeneratorContext\n): void {\n for (const constraint of constraints) {\n switch (constraint.constraintKind) {\n case \"minimum\":\n schema.minimum = constraint.value;\n break;\n\n case \"maximum\":\n schema.maximum = constraint.value;\n break;\n\n case \"exclusiveMinimum\":\n schema.exclusiveMinimum = constraint.value;\n break;\n\n case \"exclusiveMaximum\":\n schema.exclusiveMaximum = constraint.value;\n break;\n\n case \"multipleOf\": {\n const { value } = constraint;\n if (value === 1 && schema.type === \"number\") {\n // Promote number → integer; omit the multipleOf keyword (redundant).\n schema.type = \"integer\";\n } else {\n schema.multipleOf = value;\n }\n break;\n }\n\n case \"minLength\":\n schema.minLength = constraint.value;\n break;\n\n case \"maxLength\":\n schema.maxLength = constraint.value;\n break;\n\n case \"minItems\":\n schema.minItems = constraint.value;\n break;\n\n case \"maxItems\":\n schema.maxItems = constraint.value;\n break;\n\n case \"pattern\":\n schema.pattern = constraint.pattern;\n break;\n\n case \"uniqueItems\":\n schema.uniqueItems = constraint.value;\n break;\n\n case \"const\":\n schema.const = constraint.value;\n break;\n\n case \"allowedMembers\":\n // EnumMemberConstraintNode — not yet emitted to JSON Schema (Phase 6 validation).\n break;\n\n case \"custom\":\n applyCustomConstraint(schema, constraint, ctx);\n break;\n\n default: {\n // TypeScript exhaustiveness guard.\n const _exhaustive: never = constraint;\n void _exhaustive;\n }\n }\n }\n}\n\n// =============================================================================\n// ANNOTATION APPLICATION\n// =============================================================================\n\n/**\n * Applies annotation nodes onto an existing JSON Schema object (mutates in place).\n *\n * Mapping per the JSON Schema vocabulary spec §2.8:\n * - `displayName` → `title`\n * - `description` → `description` (from summary text, spec 002 §2.3)\n * - `remarks` → `x-<vendor>-remarks` (from @remarks, spec 003 §3.2)\n * - `defaultValue` → `default`\n * - `deprecated` → `deprecated: true` (2020-12 standard annotation)\n * - `format` → `format`\n *\n * UI-only annotations (`placeholder`, `formatHint`) are silently ignored here —\n * they belong in the UI Schema, not the data schema.\n */\nfunction applyAnnotations(\n schema: JsonSchema2020,\n annotations: readonly AnnotationNode[],\n ctx: GeneratorContext\n): void {\n for (const annotation of annotations) {\n switch (annotation.annotationKind) {\n case \"displayName\":\n schema.title = annotation.value;\n break;\n\n case \"description\":\n schema.description = annotation.value;\n break;\n\n case \"remarks\":\n schema[`${ctx.vendorPrefix}-remarks` as `x-${string}`] = annotation.value;\n break;\n\n case \"defaultValue\":\n schema.default = annotation.value;\n break;\n\n case \"format\":\n schema.format = annotation.value;\n break;\n\n case \"deprecated\":\n schema.deprecated = true;\n if (annotation.message !== undefined && annotation.message !== \"\") {\n schema[`${ctx.vendorPrefix}-deprecation-description` as `x-${string}`] =\n annotation.message;\n }\n break;\n\n case \"placeholder\":\n // UI-only — belongs in UI Schema, not emitted here.\n break;\n\n case \"formatHint\":\n // UI-only — belongs in UI Schema, not emitted here.\n break;\n\n case \"custom\":\n applyCustomAnnotation(schema, annotation, ctx);\n break;\n\n default: {\n // TypeScript exhaustiveness guard.\n const _exhaustive: never = annotation;\n void _exhaustive;\n }\n }\n }\n}\n\nfunction generateCustomType(type: CustomTypeNode, ctx: GeneratorContext): JsonSchema2020 {\n const registration = ctx.extensionRegistry?.findType(type.typeId);\n if (registration === undefined) {\n throw new Error(\n `Cannot generate JSON Schema for custom type \"${type.typeId}\" without a matching extension registration`\n );\n }\n\n // Trust boundary: extensions are responsible for returning valid JSON Schema.\n // Core only depends on Record<string, unknown> here, so we cast at the edge.\n return registration.toJsonSchema(type.payload, ctx.vendorPrefix) as JsonSchema2020;\n}\n\nfunction applyCustomConstraint(\n schema: JsonSchema2020,\n constraint: Extract<ConstraintNode, { constraintKind: \"custom\" }>,\n ctx: GeneratorContext\n): void {\n const registration = ctx.extensionRegistry?.findConstraint(constraint.constraintId);\n if (registration === undefined) {\n throw new Error(\n `Cannot generate JSON Schema for custom constraint \"${constraint.constraintId}\" without a matching extension registration`\n );\n }\n\n assignVendorPrefixedExtensionKeywords(\n schema,\n registration.toJsonSchema(constraint.payload, ctx.vendorPrefix),\n ctx.vendorPrefix,\n `custom constraint \"${constraint.constraintId}\"`\n );\n}\n\nfunction applyCustomAnnotation(\n schema: JsonSchema2020,\n annotation: Extract<AnnotationNode, { annotationKind: \"custom\" }>,\n ctx: GeneratorContext\n): void {\n const registration = ctx.extensionRegistry?.findAnnotation(annotation.annotationId);\n if (registration === undefined) {\n throw new Error(\n `Cannot generate JSON Schema for custom annotation \"${annotation.annotationId}\" without a matching extension registration`\n );\n }\n\n if (registration.toJsonSchema === undefined) {\n return;\n }\n\n assignVendorPrefixedExtensionKeywords(\n schema,\n registration.toJsonSchema(annotation.value, ctx.vendorPrefix),\n ctx.vendorPrefix,\n `custom annotation \"${annotation.annotationId}\"`\n );\n}\n\nfunction assignVendorPrefixedExtensionKeywords(\n schema: JsonSchema2020,\n extensionSchema: Record<string, unknown>,\n vendorPrefix: string,\n source: string\n): void {\n for (const [key, value] of Object.entries(extensionSchema)) {\n if (!key.startsWith(`${vendorPrefix}-`)) {\n throw new Error(\n `Cannot apply ${source}: extension hooks may only emit \"${vendorPrefix}-*\" JSON Schema keywords`\n );\n }\n schema[key as `x-${string}`] = value;\n }\n}\n","/**\n * JSON Schema generator for FormSpec forms.\n *\n * Routes through the canonical IR pipeline: Chain DSL → FormIR → JSON Schema 2020-12.\n */\n\nimport type { FormElement, FormSpec } from \"@formspec/core\";\nimport { canonicalizeChainDSL } from \"../canonicalize/index.js\";\nimport {\n generateJsonSchemaFromIR,\n type GenerateJsonSchemaFromIROptions,\n type JsonSchema2020,\n} from \"./ir-generator.js\";\n\n/**\n * Options for generating JSON Schema from a Chain DSL form.\n *\n * @public\n */\nexport interface GenerateJsonSchemaOptions {\n /**\n * Vendor prefix for emitted extension keywords.\n * @defaultValue \"x-formspec\"\n */\n readonly vendorPrefix?: string | undefined;\n}\n\n/**\n * Generates a JSON Schema 2020-12 from a FormSpec.\n *\n * All generation routes through the canonical IR. The chain DSL is first\n * canonicalized to a FormIR, then the IR-based generator produces the schema.\n *\n * @example\n * ```typescript\n * const form = formspec(\n * field.text(\"name\", { label: \"Name\", required: true }),\n * field.number(\"age\", { min: 0 }),\n * );\n *\n * const schema = generateJsonSchema(form);\n * // {\n * // $schema: \"https://json-schema.org/draft/2020-12/schema\",\n * // type: \"object\",\n * // properties: {\n * // name: { type: \"string\", title: \"Name\" },\n * // age: { type: \"number\", minimum: 0 }\n * // },\n * // required: [\"name\"]\n * // }\n * ```\n *\n * @param form - The FormSpec to convert\n * @returns A JSON Schema 2020-12 object\n *\n * @public\n */\nexport function generateJsonSchema<E extends readonly FormElement[]>(\n form: FormSpec<E>,\n options?: GenerateJsonSchemaOptions\n): JsonSchema2020 {\n const ir = canonicalizeChainDSL(form);\n const internalOptions: GenerateJsonSchemaFromIROptions | undefined =\n options?.vendorPrefix === undefined ? undefined : { vendorPrefix: options.vendorPrefix };\n return generateJsonSchemaFromIR(ir, internalOptions);\n}\n","/**\n * Zod schemas for JSON Forms UI Schema.\n *\n * These schemas are the source of truth for UI Schema validation.\n * TypeScript types are derived from these schemas via `z.infer<>`.\n *\n * @see https://jsonforms.io/docs/uischema/\n */\n\nimport { z } from \"zod\";\nimport type { UISchema } from \"./types.js\";\n\n// =============================================================================\n// Primitive helpers\n// =============================================================================\n\n/** JSON Pointer string (e.g., \"#/properties/fieldName\") */\nconst jsonPointerSchema = z.string();\n\n// =============================================================================\n// Rule Effect and Element Type enums\n// =============================================================================\n\n/**\n * Zod schema for rule effect values.\n *\n * @internal\n */\nexport const ruleEffectSchema = z.enum([\"SHOW\", \"HIDE\", \"ENABLE\", \"DISABLE\"]);\n\n/**\n * Rule effect types for conditional visibility.\n *\n * @internal\n */\nexport type RuleEffect = z.infer<typeof ruleEffectSchema>;\n\n/**\n * Zod schema for UI Schema element type strings.\n *\n * @internal\n */\nexport const uiSchemaElementTypeSchema = z.enum([\n \"Control\",\n \"VerticalLayout\",\n \"HorizontalLayout\",\n \"Group\",\n \"Categorization\",\n \"Category\",\n \"Label\",\n]);\n\n/**\n * UI Schema element types.\n *\n * @internal\n */\nexport type UISchemaElementType = z.infer<typeof uiSchemaElementTypeSchema>;\n\n// =============================================================================\n// Rule Condition Schema (recursive)\n// =============================================================================\n\n// Forward-declare the recursive TypeScript type.\n// We use an interface here (rather than z.infer<>) because the recursive\n// z.lazy() type annotation requires us to pre-declare the shape.\n/**\n * JSON Schema subset used in rule conditions.\n *\n * @internal\n */\nexport interface RuleConditionSchema {\n const?: unknown;\n enum?: readonly unknown[];\n type?: string;\n not?: RuleConditionSchema;\n minimum?: number;\n maximum?: number;\n exclusiveMinimum?: number;\n exclusiveMaximum?: number;\n minLength?: number;\n properties?: Record<string, RuleConditionSchema>;\n required?: string[];\n allOf?: RuleConditionSchema[];\n}\n\n/**\n * Zod schema for the rule-condition JSON Schema subset.\n *\n * @internal\n */\nexport const ruleConditionSchema: z.ZodType<RuleConditionSchema> = z.lazy(() =>\n z\n .object({\n const: z.unknown().optional(),\n enum: z.array(z.unknown()).readonly().optional(),\n type: z.string().optional(),\n not: ruleConditionSchema.optional(),\n minimum: z.number().optional(),\n maximum: z.number().optional(),\n exclusiveMinimum: z.number().optional(),\n exclusiveMaximum: z.number().optional(),\n minLength: z.number().optional(),\n properties: z.record(z.string(), ruleConditionSchema).optional(),\n required: z.array(z.string()).optional(),\n allOf: z.array(ruleConditionSchema).optional(),\n })\n .strict()\n) as z.ZodType<RuleConditionSchema>;\n\n// =============================================================================\n// Schema-Based Condition and Rule\n// =============================================================================\n\n/**\n * Zod schema for a schema-based rule condition.\n *\n * @internal\n */\nexport const schemaBasedConditionSchema = z\n .object({\n scope: jsonPointerSchema,\n schema: ruleConditionSchema,\n })\n .strict();\n\n/**\n * Condition for a rule.\n *\n * @internal\n */\nexport type SchemaBasedCondition = z.infer<typeof schemaBasedConditionSchema>;\n\n/**\n * Zod schema for a UI Schema rule.\n *\n * @internal\n */\nexport const ruleSchema = z\n .object({\n effect: ruleEffectSchema,\n condition: schemaBasedConditionSchema,\n })\n .strict();\n\n/**\n * Rule for conditional element visibility/enablement.\n *\n * @internal\n */\nexport type Rule = z.infer<typeof ruleSchema>;\n\n// =============================================================================\n// UI Schema Element Schemas (recursive via z.lazy)\n// =============================================================================\n\n// Forward-declare UISchemaElement so layout schemas can reference it.\n// We declare the type up-front and wire the Zod schema below.\n/**\n * Union of all UI Schema element types.\n *\n * @internal\n */\nexport type UISchemaElement =\n | ControlElement\n | VerticalLayout\n | HorizontalLayout\n | GroupLayout\n | Categorization\n | Category\n | LabelElement;\n\n// The Zod schema for UISchemaElement is defined as a const using z.lazy(),\n// which defers evaluation until first use. This allows all element schemas\n// below to be referenced even though they are declared after this line.\n/**\n * Zod schema for any UI Schema element.\n *\n * @internal\n */\nexport const uiSchemaElementSchema: z.ZodType<UISchemaElement> = z.lazy(() =>\n z.union([\n controlSchema,\n verticalLayoutSchema,\n horizontalLayoutSchema,\n groupLayoutSchema,\n categorizationSchema,\n categorySchema,\n labelElementSchema,\n ])\n) as z.ZodType<UISchemaElement>;\n\n// -----------------------------------------------------------------------------\n// Control\n// -----------------------------------------------------------------------------\n\n/**\n * Zod schema for a Control element.\n *\n * @internal\n */\nexport const controlSchema = z\n .object({\n type: z.literal(\"Control\"),\n scope: jsonPointerSchema,\n label: z.union([z.string(), z.literal(false)]).optional(),\n rule: ruleSchema.optional(),\n options: z.record(z.string(), z.unknown()).optional(),\n })\n .passthrough();\n\n/**\n * A Control element that binds to a JSON Schema property.\n *\n * @internal\n */\nexport type ControlElement = z.infer<typeof controlSchema>;\n\n// -----------------------------------------------------------------------------\n// VerticalLayout\n// -----------------------------------------------------------------------------\n\n// Pre-declare the interface so the Zod schema can reference UISchemaElement.\n/**\n * A vertical layout element.\n *\n * @internal\n */\nexport interface VerticalLayout {\n type: \"VerticalLayout\";\n elements: UISchemaElement[];\n rule?: Rule | undefined;\n options?: Record<string, unknown> | undefined;\n [k: string]: unknown;\n}\n\n/**\n * Zod schema for a vertical layout element.\n *\n * @internal\n */\nexport const verticalLayoutSchema: z.ZodType<VerticalLayout> = z.lazy(() =>\n z\n .object({\n type: z.literal(\"VerticalLayout\"),\n elements: z.array(uiSchemaElementSchema),\n rule: ruleSchema.optional(),\n options: z.record(z.string(), z.unknown()).optional(),\n })\n .passthrough()\n);\n\n// -----------------------------------------------------------------------------\n// HorizontalLayout\n// -----------------------------------------------------------------------------\n\n/**\n * A horizontal layout element.\n *\n * @internal\n */\nexport interface HorizontalLayout {\n type: \"HorizontalLayout\";\n elements: UISchemaElement[];\n rule?: Rule | undefined;\n options?: Record<string, unknown> | undefined;\n [k: string]: unknown;\n}\n\n/**\n * Zod schema for a horizontal layout element.\n *\n * @internal\n */\nexport const horizontalLayoutSchema: z.ZodType<HorizontalLayout> = z.lazy(() =>\n z\n .object({\n type: z.literal(\"HorizontalLayout\"),\n elements: z.array(uiSchemaElementSchema),\n rule: ruleSchema.optional(),\n options: z.record(z.string(), z.unknown()).optional(),\n })\n .passthrough()\n);\n\n// -----------------------------------------------------------------------------\n// GroupLayout\n// -----------------------------------------------------------------------------\n\n/**\n * A group element with a label.\n *\n * @internal\n */\nexport interface GroupLayout {\n type: \"Group\";\n label: string;\n elements: UISchemaElement[];\n rule?: Rule | undefined;\n options?: Record<string, unknown> | undefined;\n [k: string]: unknown;\n}\n\n/**\n * Zod schema for a group layout element.\n *\n * @internal\n */\nexport const groupLayoutSchema: z.ZodType<GroupLayout> = z.lazy(() =>\n z\n .object({\n type: z.literal(\"Group\"),\n label: z.string(),\n elements: z.array(uiSchemaElementSchema),\n rule: ruleSchema.optional(),\n options: z.record(z.string(), z.unknown()).optional(),\n })\n .passthrough()\n);\n\n// -----------------------------------------------------------------------------\n// Category\n// -----------------------------------------------------------------------------\n\n/**\n * A Category element, used inside a Categorization layout.\n *\n * @internal\n */\nexport interface Category {\n type: \"Category\";\n label: string;\n elements: UISchemaElement[];\n rule?: Rule | undefined;\n options?: Record<string, unknown> | undefined;\n [k: string]: unknown;\n}\n\n/**\n * Zod schema for a category element.\n *\n * @internal\n */\nexport const categorySchema: z.ZodType<Category> = z.lazy(() =>\n z\n .object({\n type: z.literal(\"Category\"),\n label: z.string(),\n elements: z.array(uiSchemaElementSchema),\n rule: ruleSchema.optional(),\n options: z.record(z.string(), z.unknown()).optional(),\n })\n .passthrough()\n);\n\n// -----------------------------------------------------------------------------\n// Categorization\n// -----------------------------------------------------------------------------\n\n/**\n * A Categorization element (tab-based layout).\n *\n * @internal\n */\nexport interface Categorization {\n type: \"Categorization\";\n elements: Category[];\n label?: string | undefined;\n rule?: Rule | undefined;\n options?: Record<string, unknown> | undefined;\n [k: string]: unknown;\n}\n\n/**\n * Zod schema for a categorization element.\n *\n * @internal\n */\nexport const categorizationSchema: z.ZodType<Categorization> = z.lazy(() =>\n z\n .object({\n type: z.literal(\"Categorization\"),\n elements: z.array(categorySchema),\n label: z.string().optional(),\n rule: ruleSchema.optional(),\n options: z.record(z.string(), z.unknown()).optional(),\n })\n .passthrough()\n);\n\n// -----------------------------------------------------------------------------\n// LabelElement\n// -----------------------------------------------------------------------------\n\n/**\n * Zod schema for a Label element.\n *\n * @internal\n */\nexport const labelElementSchema = z\n .object({\n type: z.literal(\"Label\"),\n text: z.string(),\n rule: ruleSchema.optional(),\n options: z.record(z.string(), z.unknown()).optional(),\n })\n .passthrough();\n\n/**\n * A Label element for displaying static text.\n *\n * @internal\n */\nexport type LabelElement = z.infer<typeof labelElementSchema>;\n\n// =============================================================================\n// Root UISchema\n// =============================================================================\n\n/**\n * Zod schema for the root UI Schema (layout types only).\n *\n * @public\n */\nexport const uiSchema: z.ZodType<UISchema> = z.lazy(() =>\n z.union([verticalLayoutSchema, horizontalLayoutSchema, groupLayoutSchema, categorizationSchema])\n) as z.ZodType<UISchema>;\n","/**\n * JSON Forms UI Schema generator that operates on the canonical FormIR.\n *\n * This generator consumes the IR produced by the Canonicalize phase and\n * produces a JSON Forms UI Schema. All downstream UI Schema generation\n * should use this module for UI Schema generation.\n */\n\nimport type { FormIR, FormIRElement, FieldNode, GroupLayoutNode } from \"@formspec/core/internals\";\nimport type {\n UISchema,\n UISchemaElement,\n ControlElement,\n GroupLayout,\n Rule,\n RuleConditionSchema,\n} from \"./types.js\";\nimport { uiSchema as uiSchemaValidator } from \"./schema.js\";\nimport { z } from \"zod\";\n\n// =============================================================================\n// HELPERS\n// =============================================================================\n\n/**\n * Parses a value through a Zod schema, converting validation errors to a\n * descriptive Error.\n */\nfunction parseOrThrow<T>(schema: z.ZodType<T>, value: unknown, label: string): T {\n try {\n return schema.parse(value);\n } catch (error) {\n if (error instanceof z.ZodError) {\n throw new Error(\n `Generated ${label} failed validation:\\n${error.issues.map((i) => ` ${i.path.join(\".\")}: ${i.message}`).join(\"\\n\")}`\n );\n }\n throw error;\n }\n}\n\n/**\n * Converts a field name to a JSON Pointer scope string.\n */\nfunction fieldToScope(fieldName: string): string {\n return `#/properties/${fieldName}`;\n}\n\n/**\n * Creates a SHOW rule for a single conditional field/value pair.\n */\nfunction createShowRule(fieldName: string, value: unknown): Rule {\n return {\n effect: \"SHOW\",\n condition: {\n scope: fieldToScope(fieldName),\n schema: { const: value },\n },\n };\n}\n\n/**\n * Combines two SHOW rules into a single rule using an allOf condition.\n *\n * When elements are nested inside multiple conditionals, all parent conditions\n * must be met for the element to be visible. This function flattens both\n * conditions into a single rule using a top-level allOf so JSON Forms evaluates\n * every predicate simultaneously without nesting rule fragments.\n */\nfunction flattenConditionSchema(scope: string, schema: RuleConditionSchema): RuleConditionSchema[] {\n if (schema.allOf === undefined) {\n if (scope === \"#\") {\n return [schema];\n }\n\n const fieldName = scope.replace(\"#/properties/\", \"\");\n return [\n {\n properties: {\n [fieldName]: schema,\n },\n },\n ];\n }\n\n return schema.allOf.flatMap((member) => flattenConditionSchema(scope, member));\n}\n\nfunction combineRules(parentRule: Rule, childRule: Rule): Rule {\n return {\n effect: \"SHOW\",\n condition: {\n scope: \"#\",\n schema: {\n allOf: [\n ...flattenConditionSchema(parentRule.condition.scope, parentRule.condition.schema),\n ...flattenConditionSchema(childRule.condition.scope, childRule.condition.schema),\n ],\n },\n },\n };\n}\n\n// =============================================================================\n// ELEMENT CONVERSION\n// =============================================================================\n\n/**\n * Converts a FieldNode from the IR to a ControlElement.\n *\n * The label is sourced from the first `displayName` annotation on the field,\n * matching how the chain DSL propagates the `label` option through the\n * canonicalization phase.\n */\nfunction fieldNodeToControl(field: FieldNode, parentRule?: Rule): ControlElement {\n const displayNameAnnotation = field.annotations.find((a) => a.annotationKind === \"displayName\");\n const placeholderAnnotation = field.annotations.find((a) => a.annotationKind === \"placeholder\");\n\n const control: ControlElement = {\n type: \"Control\",\n scope: fieldToScope(field.name),\n ...(displayNameAnnotation !== undefined && { label: displayNameAnnotation.value }),\n ...(placeholderAnnotation !== undefined && {\n options: { placeholder: placeholderAnnotation.value },\n }),\n ...(parentRule !== undefined && { rule: parentRule }),\n };\n\n return control;\n}\n\n/**\n * Converts a GroupLayoutNode from the IR to a GroupLayout element.\n *\n * The group's children are recursively converted; the optional parent rule is\n * forwarded to nested elements so that a group inside a conditional inherits\n * the visibility rule.\n */\nfunction groupNodeToLayout(group: GroupLayoutNode, parentRule?: Rule): GroupLayout {\n return {\n type: \"Group\",\n label: group.label,\n elements: irElementsToUiSchema(group.elements, parentRule),\n ...(parentRule !== undefined && { rule: parentRule }),\n };\n}\n\n/**\n * Converts an array of IR elements to UI Schema elements.\n *\n * @param elements - The IR elements to convert\n * @param parentRule - Optional rule inherited from a parent ConditionalLayoutNode\n * @returns Array of UI Schema elements\n */\nfunction irElementsToUiSchema(\n elements: readonly FormIRElement[],\n parentRule?: Rule\n): UISchemaElement[] {\n const result: UISchemaElement[] = [];\n\n for (const element of elements) {\n switch (element.kind) {\n case \"field\": {\n result.push(fieldNodeToControl(element, parentRule));\n break;\n }\n\n case \"group\": {\n result.push(groupNodeToLayout(element, parentRule));\n break;\n }\n\n case \"conditional\": {\n // Build the rule for this conditional level.\n const newRule = createShowRule(element.fieldName, element.value);\n // Combine with the inherited parent rule for nested conditionals.\n const combinedRule = parentRule !== undefined ? combineRules(parentRule, newRule) : newRule;\n // Children are flattened into the parent container with the combined\n // rule attached.\n const childElements = irElementsToUiSchema(element.elements, combinedRule);\n result.push(...childElements);\n break;\n }\n\n default: {\n const _exhaustive: never = element;\n void _exhaustive;\n throw new Error(\"Unhandled IR element kind\");\n }\n }\n }\n\n return result;\n}\n\n// =============================================================================\n// PUBLIC API\n// =============================================================================\n\n/**\n * Generates a JSON Forms UI Schema from a canonical `FormIR`.\n *\n * Mapping rules:\n * - `FieldNode` → `ControlElement` with `scope: \"#/properties/<name>\"`\n * - `displayName` annotation → `label` on the `ControlElement`\n * - `GroupLayoutNode` → `GroupLayout` with recursively converted `elements`\n * - `ConditionalLayoutNode` → children flattened with a `SHOW` rule\n * - Nested conditionals → combined `allOf` rule\n * - Root wrapper is always `{ type: \"VerticalLayout\", elements: [...] }`\n *\n * @example\n * ```typescript\n * const ir = canonicalizeDSL(\n * formspec(\n * group(\"Customer\", field.text(\"name\", { label: \"Name\" })),\n * when(is(\"status\", \"draft\"), field.text(\"notes\", { label: \"Notes\" })),\n * )\n * );\n *\n * const uiSchema = generateUiSchemaFromIR(ir);\n * // {\n * // type: \"VerticalLayout\",\n * // elements: [\n * // {\n * // type: \"Group\",\n * // label: \"Customer\",\n * // elements: [{ type: \"Control\", scope: \"#/properties/name\", label: \"Name\" }]\n * // },\n * // {\n * // type: \"Control\",\n * // scope: \"#/properties/notes\",\n * // label: \"Notes\",\n * // rule: { effect: \"SHOW\", condition: { scope: \"#/properties/status\", schema: { const: \"draft\" } } }\n * // }\n * // ]\n * // }\n * ```\n *\n * @param ir - The canonical FormIR produced by the Canonicalize phase\n * @returns A validated JSON Forms UI Schema\n */\nexport function generateUiSchemaFromIR(ir: FormIR): UISchema {\n const result: UISchema = {\n type: \"VerticalLayout\",\n elements: irElementsToUiSchema(ir.elements),\n };\n\n return parseOrThrow(uiSchemaValidator, result, \"UI Schema\");\n}\n","/**\n * JSON Forms UI Schema generator for FormSpec forms.\n *\n * Routes through the canonical IR pipeline: Chain DSL → FormIR → UI Schema.\n */\n\nimport type { FormElement, FormSpec } from \"@formspec/core\";\nimport { canonicalizeChainDSL } from \"../canonicalize/index.js\";\nimport { generateUiSchemaFromIR } from \"./ir-generator.js\";\nimport type { UISchema } from \"./types.js\";\n\n/**\n * Generates a JSON Forms UI Schema from a FormSpec.\n *\n * All generation routes through the canonical IR. The chain DSL is first\n * canonicalized to a FormIR, then the IR-based generator produces the schema.\n *\n * @example\n * ```typescript\n * const form = formspec(\n * group(\"Customer\",\n * field.text(\"name\", { label: \"Name\" }),\n * ),\n * when(\"status\", \"draft\",\n * field.text(\"notes\", { label: \"Notes\" }),\n * ),\n * );\n *\n * const uiSchema = generateUiSchema(form);\n * // {\n * // type: \"VerticalLayout\",\n * // elements: [\n * // {\n * // type: \"Group\",\n * // label: \"Customer\",\n * // elements: [\n * // { type: \"Control\", scope: \"#/properties/name\", label: \"Name\" }\n * // ]\n * // },\n * // {\n * // type: \"Control\",\n * // scope: \"#/properties/notes\",\n * // label: \"Notes\",\n * // rule: {\n * // effect: \"SHOW\",\n * // condition: { scope: \"#/properties/status\", schema: { const: \"draft\" } }\n * // }\n * // }\n * // ]\n * // }\n * ```\n *\n * @param form - The FormSpec to convert\n * @returns A JSON Forms UI Schema\n *\n * @public\n */\nexport function generateUiSchema<E extends readonly FormElement[]>(form: FormSpec<E>): UISchema {\n const ir = canonicalizeChainDSL(form);\n return generateUiSchemaFromIR(ir);\n}\n","/**\n * JSON Schema type definitions.\n *\n * These types are a subset of JSON Schema sufficient for form generation.\n */\n\n/**\n * JSON Schema primitive types.\n *\n * @public\n */\nexport type JSONSchemaType =\n | \"string\"\n | \"number\"\n | \"integer\"\n | \"boolean\"\n | \"object\"\n | \"array\"\n | \"null\";\n\n/**\n * A JSON Schema definition (legacy subset used by Zod validator and types.ts).\n *\n * @public\n */\nexport interface JSONSchema7 {\n /** Declared JSON Schema dialect URI for the document root. */\n $schema?: string;\n /** Stable identifier for the schema document or sub-schema. */\n $id?: string;\n /** Reference to another schema location. */\n $ref?: string;\n\n // Metadata\n /** Human-readable title for the schema node. */\n title?: string;\n /** Human-readable description for the schema node. */\n description?: string;\n /** Whether the schema node is deprecated. */\n deprecated?: boolean;\n\n // Type\n /** JSON Schema type keyword for the current node. */\n type?: JSONSchemaType | JSONSchemaType[];\n\n // String validation\n /** Inclusive minimum string length. */\n minLength?: number;\n /** Inclusive maximum string length. */\n maxLength?: number;\n /** Regular expression pattern applied to string values. */\n pattern?: string;\n\n // Number validation\n /** Inclusive numeric lower bound. */\n minimum?: number;\n /** Inclusive numeric upper bound. */\n maximum?: number;\n /** Exclusive numeric lower bound. */\n exclusiveMinimum?: number;\n /** Exclusive numeric upper bound. */\n exclusiveMaximum?: number;\n\n // Enum\n /** Closed set of allowed scalar values. */\n enum?: readonly (string | number | boolean | null)[];\n /** Literal value the instance must equal. */\n const?: string | number | boolean | null;\n\n // Object\n /** Object properties keyed by property name. */\n properties?: Record<string, JSONSchema7>;\n /** Property names that must be present on object values. */\n required?: string[];\n /** Whether, or how, additional object properties are allowed. */\n additionalProperties?: boolean | JSONSchema7;\n\n // Array\n /** Item schema or tuple schemas applied to array elements. */\n items?: JSONSchema7 | JSONSchema7[];\n /** Inclusive minimum array length. */\n minItems?: number;\n /** Inclusive maximum array length. */\n maxItems?: number;\n\n // Composition\n /** Schemas that must all validate successfully. */\n allOf?: JSONSchema7[];\n /** Schemas of which at least one may validate successfully. */\n anyOf?: JSONSchema7[];\n /** Schemas of which exactly one should validate successfully. */\n oneOf?: JSONSchema7[];\n /** Schema that must not validate successfully. */\n not?: JSONSchema7;\n\n // Conditional\n /** Conditional branch predicate schema. */\n if?: JSONSchema7;\n /** Schema applied when the `if` branch matches. */\n then?: JSONSchema7;\n /** Schema applied when the `if` branch does not match. */\n else?: JSONSchema7;\n\n // Format\n /** Format hint for downstream validators and tooling. */\n format?: string;\n\n // Default\n /** Default value suggested for the schema node. */\n default?: unknown;\n\n // =============================================================================\n // FormSpec Extensions (x- prefixed)\n // =============================================================================\n\n /**\n * Data source key for dynamic enum fields.\n * Indicates that options should be fetched from a registered resolver.\n */\n \"x-formspec-source\"?: string;\n\n /**\n * Field names whose values are needed to fetch dynamic enum options.\n * Used for dependent/cascading dropdowns.\n */\n \"x-formspec-params\"?: readonly string[];\n\n /**\n * Schema source identifier for dynamic schema fields.\n * Indicates that the schema should be loaded dynamically at runtime.\n */\n \"x-formspec-schemaSource\"?: string;\n}\n\n/**\n * Extension properties for custom FormSpec constraint tags.\n *\n * @public\n */\nexport type FormSpecSchemaExtensions = Record<`x-formspec-${string}`, unknown>;\n\n/**\n * JSON Schema with FormSpec extension properties for arbitrary `x-formspec-*` keys.\n *\n * @public\n */\nexport type ExtendedJSONSchema7 = JSONSchema7 & FormSpecSchemaExtensions;\n\n/**\n * Sets a FormSpec extension property on a JSON Schema node.\n *\n * Use this to safely add `x-formspec-*` properties to any schema,\n * including nested schemas typed as `JSONSchema7` (which don't carry\n * the extension index signature).\n *\n * @param schema - Any JSON Schema node\n * @param key - Extension key (must start with `x-formspec-`)\n * @param value - Extension value\n *\n * @internal\n */\nexport function setSchemaExtension(\n schema: object,\n key: `x-formspec-${string}`,\n value: unknown\n): void {\n (schema as Record<string, unknown>)[key] = value;\n}\n\n/**\n * Reads a FormSpec extension property from a JSON Schema node.\n *\n * Accepts any schema object — `JSONSchema7`, `JsonSchema2020`, `ExtendedJSONSchema7`, etc.\n *\n * @param schema - Any JSON Schema node\n * @param key - Extension key (must start with `x-formspec-`)\n * @returns The extension value, or `undefined` if not present\n *\n * @internal\n */\nexport function getSchemaExtension(schema: object, key: `x-formspec-${string}`): unknown {\n return (schema as Record<string, unknown>)[key];\n}\n","/**\n * Extension registry for resolving custom types, constraints, and annotations\n * during JSON Schema generation and IR validation.\n *\n * The registry is created from a list of {@link ExtensionDefinition} objects\n * and provides O(1) lookup by fully-qualified ID (extensionId + \"/\" + name).\n *\n * @packageDocumentation\n */\n\nimport type {\n ExtensionDefinition,\n CustomTypeRegistration,\n CustomConstraintRegistration,\n CustomAnnotationRegistration,\n ConstraintTagRegistration,\n BuiltinConstraintBroadeningRegistration,\n} from \"@formspec/core\";\n\n// =============================================================================\n// PUBLIC API\n// =============================================================================\n\n/**\n * A registry of extensions that provides lookup by fully-qualified ID.\n *\n * Type IDs follow the format: `<extensionId>/<typeName>`\n * Constraint IDs follow the format: `<extensionId>/<constraintName>`\n * Annotation IDs follow the format: `<extensionId>/<annotationName>`\n *\n * @public\n */\nexport interface ExtensionRegistry {\n /** The extensions registered in this registry (in registration order). */\n readonly extensions: readonly ExtensionDefinition[];\n\n /**\n * Look up a custom type registration by its fully-qualified type ID.\n *\n * @param typeId - The fully-qualified type ID (e.g., \"x-stripe/monetary/Decimal\").\n * @returns The registration if found, otherwise `undefined`.\n */\n findType(typeId: string): CustomTypeRegistration | undefined;\n /**\n * Look up a custom type registration by a TypeScript-facing type name.\n *\n * This is used during TSDoc/class analysis to resolve extension-defined\n * custom types from source-level declarations.\n */\n findTypeByName(\n typeName: string\n ): { readonly extensionId: string; readonly registration: CustomTypeRegistration } | undefined;\n\n /**\n * Look up a custom constraint registration by its fully-qualified constraint ID.\n *\n * @param constraintId - The fully-qualified constraint ID.\n * @returns The registration if found, otherwise `undefined`.\n */\n findConstraint(constraintId: string): CustomConstraintRegistration | undefined;\n /**\n * Look up a TSDoc custom constraint-tag registration by tag name.\n */\n findConstraintTag(tagName: string):\n | {\n readonly extensionId: string;\n readonly registration: ConstraintTagRegistration;\n }\n | undefined;\n /**\n * Look up built-in tag broadening for a given custom type ID.\n */\n findBuiltinConstraintBroadening(\n typeId: string,\n tagName: string\n ):\n | {\n readonly extensionId: string;\n readonly registration: BuiltinConstraintBroadeningRegistration;\n }\n | undefined;\n\n /**\n * Look up a custom annotation registration by its fully-qualified annotation ID.\n *\n * @param annotationId - The fully-qualified annotation ID.\n * @returns The registration if found, otherwise `undefined`.\n */\n findAnnotation(annotationId: string): CustomAnnotationRegistration | undefined;\n}\n\n// =============================================================================\n// IMPLEMENTATION\n// =============================================================================\n\n/**\n * Creates an extension registry from a list of extension definitions.\n *\n * The registry indexes all types, constraints, and annotations by their\n * fully-qualified IDs (`<extensionId>/<name>`) for O(1) lookup during\n * generation and validation.\n *\n * @param extensions - The extension definitions to register.\n * @returns An {@link ExtensionRegistry} instance.\n * @throws If duplicate type/constraint/annotation IDs are detected across extensions.\n *\n * @public\n */\nexport function createExtensionRegistry(\n extensions: readonly ExtensionDefinition[]\n): ExtensionRegistry {\n const typeMap = new Map<string, CustomTypeRegistration>();\n const typeNameMap = new Map<\n string,\n { readonly extensionId: string; readonly registration: CustomTypeRegistration }\n >();\n const constraintMap = new Map<string, CustomConstraintRegistration>();\n const constraintTagMap = new Map<\n string,\n { readonly extensionId: string; readonly registration: ConstraintTagRegistration }\n >();\n const builtinBroadeningMap = new Map<\n string,\n { readonly extensionId: string; readonly registration: BuiltinConstraintBroadeningRegistration }\n >();\n const annotationMap = new Map<string, CustomAnnotationRegistration>();\n\n for (const ext of extensions) {\n if (ext.types !== undefined) {\n for (const type of ext.types) {\n const qualifiedId = `${ext.extensionId}/${type.typeName}`;\n if (typeMap.has(qualifiedId)) {\n throw new Error(`Duplicate custom type ID: \"${qualifiedId}\"`);\n }\n typeMap.set(qualifiedId, type);\n\n for (const sourceTypeName of type.tsTypeNames ?? [type.typeName]) {\n if (typeNameMap.has(sourceTypeName)) {\n throw new Error(`Duplicate custom type source name: \"${sourceTypeName}\"`);\n }\n typeNameMap.set(sourceTypeName, {\n extensionId: ext.extensionId,\n registration: type,\n });\n }\n\n if (type.builtinConstraintBroadenings !== undefined) {\n for (const broadening of type.builtinConstraintBroadenings) {\n const key = `${qualifiedId}:${broadening.tagName}`;\n if (builtinBroadeningMap.has(key)) {\n throw new Error(`Duplicate built-in constraint broadening: \"${key}\"`);\n }\n builtinBroadeningMap.set(key, {\n extensionId: ext.extensionId,\n registration: broadening,\n });\n }\n }\n }\n }\n\n if (ext.constraints !== undefined) {\n for (const constraint of ext.constraints) {\n const qualifiedId = `${ext.extensionId}/${constraint.constraintName}`;\n if (constraintMap.has(qualifiedId)) {\n throw new Error(`Duplicate custom constraint ID: \"${qualifiedId}\"`);\n }\n constraintMap.set(qualifiedId, constraint);\n }\n }\n\n if (ext.constraintTags !== undefined) {\n for (const tag of ext.constraintTags) {\n if (constraintTagMap.has(tag.tagName)) {\n throw new Error(`Duplicate custom constraint tag: \"@${tag.tagName}\"`);\n }\n constraintTagMap.set(tag.tagName, {\n extensionId: ext.extensionId,\n registration: tag,\n });\n }\n }\n\n if (ext.annotations !== undefined) {\n for (const annotation of ext.annotations) {\n const qualifiedId = `${ext.extensionId}/${annotation.annotationName}`;\n if (annotationMap.has(qualifiedId)) {\n throw new Error(`Duplicate custom annotation ID: \"${qualifiedId}\"`);\n }\n annotationMap.set(qualifiedId, annotation);\n }\n }\n }\n\n return {\n extensions,\n findType: (typeId: string) => typeMap.get(typeId),\n findTypeByName: (typeName: string) => typeNameMap.get(typeName),\n findConstraint: (constraintId: string) => constraintMap.get(constraintId),\n findConstraintTag: (tagName: string) => constraintTagMap.get(tagName),\n findBuiltinConstraintBroadening: (typeId: string, tagName: string) =>\n builtinBroadeningMap.get(`${typeId}:${tagName}`),\n findAnnotation: (annotationId: string) => annotationMap.get(annotationId),\n };\n}\n","/**\n * Zod schemas for JSON Schema output validation.\n *\n * These schemas cover the subset of JSON Schema that FormSpec generates,\n * plus the FormSpec-specific `x-formspec-*` extension properties.\n *\n * @see https://json-schema.org/draft/2020-12/schema\n */\n\nimport { z } from \"zod\";\nimport type { JSONSchema7 } from \"./types.js\";\n\n// =============================================================================\n// JSON Schema type enum\n// =============================================================================\n\n/**\n * Zod schema for JSON Schema primitive type strings.\n *\n * @public\n */\nexport const jsonSchemaTypeSchema = z.enum([\n \"string\",\n \"number\",\n \"integer\",\n \"boolean\",\n \"object\",\n \"array\",\n \"null\",\n]);\n\n// =============================================================================\n// JSON Schema validator schema (recursive)\n// =============================================================================\n\n// We annotate with z.ZodType<JSONSchema7> for the recursive self-reference.\n// The @ts-expect-error is required because exactOptionalPropertyTypes:true causes\n// Zod's inferred output type for optional fields (`T | undefined`) to be\n// incompatible with the JSONSchema7 interface's exact optional fields (`T?`).\n// The runtime behavior is correct: z.optional() will strip `undefined` values\n// during parsing and correctly handle absent keys.\n//\n/**\n * Zod schema for the legacy JSON Schema 7 subset used by `@formspec/build`.\n *\n * @public\n */\n// @ts-expect-error -- exactOptionalPropertyTypes: Zod optional infers `T | undefined`\n// but JSONSchema7 uses exact optional `?:` which disallows explicit undefined.\nexport const jsonSchema7Schema: z.ZodType<JSONSchema7> = z.lazy(() =>\n z\n .object({\n $schema: z.string().optional(),\n $id: z.string().optional(),\n $ref: z.string().optional(),\n\n // Metadata\n title: z.string().optional(),\n description: z.string().optional(),\n deprecated: z.boolean().optional(),\n\n // Type\n type: z.union([jsonSchemaTypeSchema, z.array(jsonSchemaTypeSchema)]).optional(),\n\n // String validation\n minLength: z.number().optional(),\n maxLength: z.number().optional(),\n pattern: z.string().optional(),\n\n // Number validation\n minimum: z.number().optional(),\n maximum: z.number().optional(),\n exclusiveMinimum: z.number().optional(),\n exclusiveMaximum: z.number().optional(),\n\n // Enum\n enum: z\n .array(z.union([z.string(), z.number(), z.boolean(), z.null()]))\n .readonly()\n .optional(),\n const: z.union([z.string(), z.number(), z.boolean(), z.null()]).optional(),\n\n // Object\n properties: z.record(z.string(), jsonSchema7Schema).optional(),\n required: z.array(z.string()).optional(),\n additionalProperties: z.union([z.boolean(), jsonSchema7Schema]).optional(),\n\n // Array\n items: z.union([jsonSchema7Schema, z.array(jsonSchema7Schema)]).optional(),\n minItems: z.number().optional(),\n maxItems: z.number().optional(),\n\n // Composition\n allOf: z.array(jsonSchema7Schema).optional(),\n anyOf: z.array(jsonSchema7Schema).optional(),\n oneOf: z.array(jsonSchema7Schema).optional(),\n not: jsonSchema7Schema.optional(),\n\n // Conditional\n if: jsonSchema7Schema.optional(),\n then: jsonSchema7Schema.optional(),\n else: jsonSchema7Schema.optional(),\n\n // Format\n format: z.string().optional(),\n\n // Default\n default: z.unknown().optional(),\n\n // FormSpec extensions\n \"x-formspec-source\": z.string().optional(),\n \"x-formspec-params\": z.array(z.string()).readonly().optional(),\n \"x-formspec-schemaSource\": z.string().optional(),\n })\n // passthrough preserves arbitrary x-formspec-* extension properties\n // added by custom constraint tags without causing validation failures\n .passthrough()\n);\n","/**\n * Constraint validator for the FormSpec IR.\n *\n * Delegates target-centric semantic analysis to `@formspec/analysis` so build\n * validation and editor tooling share the same inheritance, path-target,\n * contradiction, and broadening semantics.\n *\n * @packageDocumentation\n */\n\nimport {\n analyzeConstraintTargets,\n type ConstraintRegistryLike,\n type ConstraintSemanticDiagnostic,\n} from \"@formspec/analysis/internal\";\nimport type { FormIR, FormIRElement, FieldNode, ObjectProperty } from \"@formspec/core/internals\";\nimport type { ExtensionRegistry } from \"../extensions/index.js\";\n\nexport type ValidationDiagnostic = ConstraintSemanticDiagnostic;\n\nexport interface ValidationResult {\n readonly diagnostics: readonly ValidationDiagnostic[];\n readonly valid: boolean;\n}\n\nexport interface ValidateIROptions {\n readonly vendorPrefix?: string;\n readonly extensionRegistry?: ExtensionRegistry;\n}\n\ninterface ValidationContext {\n readonly diagnostics: ValidationDiagnostic[];\n readonly extensionRegistry: ConstraintRegistryLike | undefined;\n readonly typeRegistry: FormIR[\"typeRegistry\"];\n}\n\nfunction validateFieldNode(ctx: ValidationContext, field: FieldNode): void {\n const analysis = analyzeConstraintTargets(\n field.name,\n field.type,\n field.constraints,\n ctx.typeRegistry,\n ctx.extensionRegistry === undefined\n ? undefined\n : {\n extensionRegistry: ctx.extensionRegistry,\n }\n );\n ctx.diagnostics.push(...analysis.diagnostics);\n\n if (field.type.kind === \"object\") {\n for (const property of field.type.properties) {\n validateObjectProperty(ctx, field.name, property);\n }\n }\n}\n\nfunction validateObjectProperty(\n ctx: ValidationContext,\n parentName: string,\n property: ObjectProperty\n): void {\n const qualifiedName = `${parentName}.${property.name}`;\n const analysis = analyzeConstraintTargets(\n qualifiedName,\n property.type,\n property.constraints,\n ctx.typeRegistry,\n ctx.extensionRegistry === undefined\n ? undefined\n : {\n extensionRegistry: ctx.extensionRegistry,\n }\n );\n ctx.diagnostics.push(...analysis.diagnostics);\n\n if (property.type.kind === \"object\") {\n for (const nestedProperty of property.type.properties) {\n validateObjectProperty(ctx, qualifiedName, nestedProperty);\n }\n }\n}\n\nfunction validateElement(ctx: ValidationContext, element: FormIRElement): void {\n switch (element.kind) {\n case \"field\":\n validateFieldNode(ctx, element);\n break;\n case \"group\":\n for (const child of element.elements) {\n validateElement(ctx, child);\n }\n break;\n case \"conditional\":\n for (const child of element.elements) {\n validateElement(ctx, child);\n }\n break;\n default: {\n const exhaustive: never = element;\n throw new Error(`Unhandled element kind: ${String(exhaustive)}`);\n }\n }\n}\n\nexport function validateIR(ir: FormIR, options?: ValidateIROptions): ValidationResult {\n const ctx: ValidationContext = {\n diagnostics: [],\n extensionRegistry: options?.extensionRegistry,\n typeRegistry: ir.typeRegistry,\n };\n\n for (const element of ir.elements) {\n validateElement(ctx, element);\n }\n\n return {\n diagnostics: ctx.diagnostics,\n valid: ctx.diagnostics.every((diagnostic) => diagnostic.severity !== \"error\"),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACoDA,uBAA2B;AAO3B,IAAM,uBAAmC;AAAA,EACvC,SAAS;AAAA,EACT,MAAM;AAAA,EACN,MAAM;AAAA,EACN,QAAQ;AACV;AAMA,SAAS,QAAQ,IAAsD;AACrE,SAAO,GAAG,UAAU;AACtB;AAEA,SAAS,cACP,IAC4D;AAC5D,SAAO,GAAG,UAAU;AACtB;AAEA,SAAS,QAAQ,IAAiC;AAChD,SAAO,GAAG,UAAU;AACtB;AAYO,SAAS,qBAAqB,MAAgD;AACnF,SAAO;AAAA,IACL,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU,qBAAqB,KAAK,QAAQ;AAAA,IAC5C,iBAAiB,CAAC;AAAA,IAClB,cAAc,CAAC;AAAA,IACf,YAAY;AAAA,EACd;AACF;AASA,SAAS,qBAAqB,UAAmD;AAC/E,SAAO,SAAS,IAAI,mBAAmB;AACzC;AAKA,SAAS,oBAAoB,SAAqC;AAChE,MAAI,QAAQ,OAAO,GAAG;AACpB,WAAO,kBAAkB,OAAO;AAAA,EAClC;AACA,MAAI,QAAQ,OAAO,GAAG;AACpB,WAAO,kBAAkB,OAAO;AAAA,EAClC;AACA,MAAI,cAAc,OAAO,GAAG;AAC1B,WAAO,wBAAwB,OAAO;AAAA,EACxC;AACA,QAAM,cAAqB;AAC3B,QAAM,IAAI,MAAM,yBAAyB,KAAK,UAAU,WAAW,CAAC,EAAE;AACxE;AASA,SAAS,kBAAkB,OAA4B;AACrD,UAAQ,MAAM,QAAQ;AAAA,IACpB,KAAK;AACH,aAAO,sBAAsB,KAAK;AAAA,IACpC,KAAK;AACH,aAAO,wBAAwB,KAAK;AAAA,IACtC,KAAK;AACH,aAAO,yBAAyB,KAAK;AAAA,IACvC,KAAK;AACH,aAAO,4BAA4B,KAAK;AAAA,IAC1C,KAAK;AACH,aAAO,6BAA6B,KAAK;AAAA,IAC3C,KAAK;AACH,aAAO,+BAA+B,KAAK;AAAA,IAC7C,KAAK;AACH,aAAO,uBAAuB,KAAK;AAAA,IACrC,KAAK;AACH,aAAO,wBAAwB,KAAK;AAAA,IACtC,SAAS;AACP,YAAM,cAAqB;AAC3B,YAAM,IAAI,MAAM,uBAAuB,KAAK,UAAU,WAAW,CAAC,EAAE;AAAA,IACtE;AAAA,EACF;AACF;AAMA,SAAS,sBAAsB,OAAqC;AAClE,QAAM,OAA0B,EAAE,MAAM,aAAa,eAAe,SAAS;AAC7E,QAAM,cAAgC,CAAC;AAEvC,MAAI,MAAM,cAAc,QAAW;AACjC,UAAM,IAA0B;AAAA,MAC9B,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,OAAO,MAAM;AAAA,MACb,YAAY;AAAA,IACd;AACA,gBAAY,KAAK,CAAC;AAAA,EACpB;AAEA,MAAI,MAAM,cAAc,QAAW;AACjC,UAAM,IAA0B;AAAA,MAC9B,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,OAAO,MAAM;AAAA,MACb,YAAY;AAAA,IACd;AACA,gBAAY,KAAK,CAAC;AAAA,EACpB;AAEA,MAAI,MAAM,YAAY,QAAW;AAC/B,UAAM,IAA2B;AAAA,MAC/B,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,SAAS,MAAM;AAAA,MACf,YAAY;AAAA,IACd;AACA,gBAAY,KAAK,CAAC;AAAA,EACpB;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,MAAM;AAAA,IACN,iBAAiB,MAAM,OAAO,MAAM,WAAW;AAAA,IAC/C;AAAA,EACF;AACF;AAEA,SAAS,wBAAwB,OAAuC;AACtE,QAAM,OAA0B,EAAE,MAAM,aAAa,eAAe,SAAS;AAC7E,QAAM,cAAgC,CAAC;AAEvC,MAAI,MAAM,QAAQ,QAAW;AAC3B,UAAM,IAA2B;AAAA,MAC/B,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,OAAO,MAAM;AAAA,MACb,YAAY;AAAA,IACd;AACA,gBAAY,KAAK,CAAC;AAAA,EACpB;AAEA,MAAI,MAAM,QAAQ,QAAW;AAC3B,UAAM,IAA2B;AAAA,MAC/B,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,OAAO,MAAM;AAAA,MACb,YAAY;AAAA,IACd;AACA,gBAAY,KAAK,CAAC;AAAA,EACpB;AAEA,MAAI,MAAM,eAAe,QAAW;AAClC,UAAM,IAA2B;AAAA,MAC/B,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,OAAO,MAAM;AAAA,MACb,YAAY;AAAA,IACd;AACA,gBAAY,KAAK,CAAC;AAAA,EACpB;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,MAAM;AAAA,IACN,iBAAiB,MAAM,KAAK;AAAA,IAC5B;AAAA,EACF;AACF;AAEA,SAAS,yBAAyB,OAAwC;AACxE,QAAM,OAA0B,EAAE,MAAM,aAAa,eAAe,UAAU;AAC9E,SAAO,eAAe,MAAM,MAAM,MAAM,MAAM,UAAU,iBAAiB,MAAM,KAAK,CAAC;AACvF;AAEA,SAAS,4BACP,OACW;AACX,QAAM,UAAwB,MAAM,QAAQ,IAAI,CAAC,QAAQ;AACvD,QAAI,OAAO,QAAQ,UAAU;AAC3B,aAAO,EAAE,OAAO,IAAI;AAAA,IACtB;AAEA,WAAO,EAAE,OAAO,IAAI,IAAI,aAAa,IAAI,MAAM;AAAA,EACjD,CAAC;AAED,QAAM,OAAqB,EAAE,MAAM,QAAQ,QAAQ;AACnD,SAAO,eAAe,MAAM,MAAM,MAAM,MAAM,UAAU,iBAAiB,MAAM,KAAK,CAAC;AACvF;AAEA,SAAS,6BAA6B,OAAoD;AACxF,QAAM,OAAwB;AAAA,IAC5B,MAAM;AAAA,IACN,aAAa;AAAA,IACb,WAAW,MAAM;AAAA,IACjB,iBAAiB,MAAM,SAAS,CAAC,GAAG,MAAM,MAAM,IAAI,CAAC;AAAA,EACvD;AACA,SAAO,eAAe,MAAM,MAAM,MAAM,MAAM,UAAU,iBAAiB,MAAM,KAAK,CAAC;AACvF;AAEA,SAAS,+BAA+B,OAA8C;AACpF,QAAM,OAAwB;AAAA,IAC5B,MAAM;AAAA,IACN,aAAa;AAAA,IACb,WAAW,MAAM;AAAA,IACjB,iBAAiB,CAAC;AAAA,EACpB;AACA,SAAO,eAAe,MAAM,MAAM,MAAM,MAAM,UAAU,iBAAiB,MAAM,KAAK,CAAC;AACvF;AAEA,SAAS,uBAAuB,OAA8D;AAE5F,QAAM,iBAAiB,sBAAsB,MAAM,KAAK;AACxD,QAAM,YAA4B;AAAA,IAChC,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,sBAAsB;AAAA,EACxB;AACA,QAAM,OAAsB,EAAE,MAAM,SAAS,OAAO,UAAU;AAE9D,QAAM,cAAgC,CAAC;AACvC,MAAI,MAAM,aAAa,QAAW;AAChC,UAAM,IAA0B;AAAA,MAC9B,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,OAAO,MAAM;AAAA,MACb,YAAY;AAAA,IACd;AACA,gBAAY,KAAK,CAAC;AAAA,EACpB;AACA,MAAI,MAAM,aAAa,QAAW;AAChC,UAAM,IAA0B;AAAA,MAC9B,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,OAAO,MAAM;AAAA,MACb,YAAY;AAAA,IACd;AACA,gBAAY,KAAK,CAAC;AAAA,EACpB;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,MAAM;AAAA,IACN,iBAAiB,MAAM,KAAK;AAAA,IAC5B;AAAA,EACF;AACF;AAEA,SAAS,wBAAwB,OAA+D;AAC9F,QAAM,aAAa,sBAAsB,MAAM,UAAU;AACzD,QAAM,OAAuB;AAAA,IAC3B,MAAM;AAAA,IACN;AAAA,IACA,sBAAsB;AAAA,EACxB;AACA,SAAO,eAAe,MAAM,MAAM,MAAM,MAAM,UAAU,iBAAiB,MAAM,KAAK,CAAC;AACvF;AAMA,SAAS,kBAAkB,GAAmD;AAC5E,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO,EAAE;AAAA,IACT,UAAU,qBAAqB,EAAE,QAAQ;AAAA,IACzC,YAAY;AAAA,EACd;AACF;AAEA,SAAS,wBACP,GACuB;AACvB,SAAO;AAAA,IACL,MAAM;AAAA,IACN,WAAW,EAAE;AAAA;AAAA;AAAA,IAGb,OAAO,gBAAgB,EAAE,KAAK;AAAA,IAC9B,UAAU,qBAAqB,EAAE,QAAQ;AAAA,IACzC,YAAY;AAAA,EACd;AACF;AAYA,SAAS,gBAAgB,GAAuB;AAC9C,MAAI,MAAM,QAAQ,OAAO,MAAM,YAAY,OAAO,MAAM,YAAY,OAAO,MAAM,WAAW;AAC1F,WAAO;AAAA,EACT;AACA,MAAI,MAAM,QAAQ,CAAC,GAAG;AACpB,WAAO,EAAE,IAAI,eAAe;AAAA,EAC9B;AACA,MAAI,OAAO,MAAM,UAAU;AACzB,UAAM,SAAoC,CAAC;AAC3C,eAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,CAAC,GAAG;AAC1C,aAAO,GAAG,IAAI,gBAAgB,GAAG;AAAA,IACnC;AACA,WAAO;AAAA,EACT;AAEA,QAAM,IAAI,UAAU,+CAA+C,OAAO,CAAC,EAAE;AAC/E;AAKA,SAAS,eACP,MACA,MACA,UACA,aACA,cAAgC,CAAC,GACtB;AACX,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA,UAAU,aAAa;AAAA,IACvB;AAAA,IACA;AAAA,IACA,YAAY;AAAA,EACd;AACF;AAKA,SAAS,iBAAiB,OAAgB,aAAwC;AAChF,QAAM,cAAgC,CAAC;AAEvC,MAAI,UAAU,QAAW;AACvB,UAAM,IAA+B;AAAA,MACnC,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,OAAO;AAAA,MACP,YAAY;AAAA,IACd;AACA,gBAAY,KAAK,CAAC;AAAA,EACpB;AAEA,MAAI,gBAAgB,QAAW;AAC7B,UAAM,IAA+B;AAAA,MACnC,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,OAAO;AAAA,MACP,YAAY;AAAA,IACd;AACA,gBAAY,KAAK,CAAC;AAAA,EACpB;AAEA,SAAO;AACT;AAiBA,SAAS,sBACP,UACA,oBAAoB,OACF;AAClB,QAAM,aAA+B,CAAC;AAEtC,aAAW,MAAM,UAAU;AACzB,QAAI,QAAQ,EAAE,GAAG;AACf,YAAM,YAAY,kBAAkB,EAAE;AACtC,iBAAW,KAAK;AAAA,QACd,MAAM,UAAU;AAAA,QAChB,MAAM,UAAU;AAAA;AAAA;AAAA;AAAA,QAIhB,UAAU,qBAAqB,CAAC,UAAU;AAAA,QAC1C,aAAa,UAAU;AAAA,QACvB,aAAa,UAAU;AAAA,QACvB,YAAY;AAAA,MACd,CAAC;AAAA,IACH,WAAW,QAAQ,EAAE,GAAG;AAGtB,iBAAW,KAAK,GAAG,sBAAsB,GAAG,UAAU,iBAAiB,CAAC;AAAA,IAC1E,WAAW,cAAc,EAAE,GAAG;AAG5B,iBAAW,KAAK,GAAG,sBAAsB,GAAG,UAAU,IAAI,CAAC;AAAA,IAC7D;AAAA,EACF;AAEA,SAAO;AACT;;;AC7dA,IAAAA,oBAA2B;;;ACiI3B,SAAS,YAAY,SAA6D;AAChF,QAAM,eAAe,SAAS,gBAAgB;AAC9C,MAAI,CAAC,aAAa,WAAW,IAAI,GAAG;AAClC,UAAM,IAAI;AAAA,MACR,yBAAyB,YAAY;AAAA,IACvC;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM,CAAC;AAAA,IACP,mBAAmB,SAAS;AAAA,IAC5B;AAAA,EACF;AACF;AAgDO,SAAS,yBACd,IACA,SACgB;AAChB,QAAM,MAAM,YAAY,OAAO;AAK/B,aAAW,CAAC,MAAM,OAAO,KAAK,OAAO,QAAQ,GAAG,YAAY,GAAG;AAC7D,QAAI,KAAK,IAAI,IAAI,iBAAiB,QAAQ,MAAM,GAAG;AACnD,QAAI,QAAQ,eAAe,QAAQ,YAAY,SAAS,GAAG;AACzD,uBAAiB,IAAI,KAAK,IAAI,GAAG,QAAQ,aAAa,GAAG;AAAA,IAC3D;AACA,QAAI,QAAQ,eAAe,QAAQ,YAAY,SAAS,GAAG;AACzD,uBAAiB,IAAI,KAAK,IAAI,GAAG,QAAQ,aAAa,GAAG;AAAA,IAC3D;AAAA,EACF;AAEA,QAAM,aAA6C,CAAC;AACpD,QAAM,WAAqB,CAAC;AAE5B,gBAAc,GAAG,UAAU,YAAY,UAAU,GAAG;AAGpD,QAAM,iBAAiB,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC;AAE5C,QAAM,SAAyB;AAAA,IAC7B,SAAS;AAAA,IACT,MAAM;AAAA,IACN;AAAA,IACA,GAAI,eAAe,SAAS,KAAK,EAAE,UAAU,eAAe;AAAA,EAC9D;AAEA,MAAI,GAAG,eAAe,GAAG,YAAY,SAAS,GAAG;AAC/C,qBAAiB,QAAQ,GAAG,aAAa,GAAG;AAAA,EAC9C;AAEA,MAAI,OAAO,KAAK,IAAI,IAAI,EAAE,SAAS,GAAG;AACpC,WAAO,QAAQ,IAAI;AAAA,EACrB;AAEA,SAAO;AACT;AAYA,SAAS,cACP,UACA,YACA,UACA,KACM;AACN,aAAW,WAAW,UAAU;AAC9B,YAAQ,QAAQ,MAAM;AAAA,MACpB,KAAK;AACH,mBAAW,QAAQ,IAAI,IAAI,oBAAoB,SAAS,GAAG;AAC3D,YAAI,QAAQ,UAAU;AACpB,mBAAS,KAAK,QAAQ,IAAI;AAAA,QAC5B;AACA;AAAA,MAEF,KAAK;AAEH,sBAAc,QAAQ,UAAU,YAAY,UAAU,GAAG;AACzD;AAAA,MAEF,KAAK;AAEH,sBAAc,QAAQ,UAAU,YAAY,UAAU,GAAG;AACzD;AAAA,MAEF,SAAS;AACP,cAAM,cAAqB;AAC3B,aAAK;AAAA,MACP;AAAA,IACF;AAAA,EACF;AACF;AASA,SAAS,oBAAoB,OAAkB,KAAuC;AACpF,QAAM,SAAS,iBAAiB,MAAM,MAAM,GAAG;AAC/C,QAAM,mBACJ,OAAO,SAAS,WAAW,OAAO,OAAO,SAAS,WAAW,OAAO,QAAQ;AAG9E,QAAM,oBAAsC,CAAC;AAC7C,QAAM,kBAAoC,CAAC;AAC3C,QAAM,kBAAoC,CAAC;AAC3C,aAAW,KAAK,MAAM,aAAa;AACjC,QAAI,EAAE,MAAM;AACV,sBAAgB,KAAK,CAAC;AAAA,IACxB,WAAW,qBAAqB,UAAa,uBAAuB,CAAC,GAAG;AACtE,sBAAgB,KAAK,CAAC;AAAA,IACxB,OAAO;AACL,wBAAkB,KAAK,CAAC;AAAA,IAC1B;AAAA,EACF;AAIA,mBAAiB,QAAQ,mBAAmB,GAAG;AAE/C,MAAI,qBAAqB,QAAW;AAClC,qBAAiB,kBAAkB,iBAAiB,GAAG;AAAA,EACzD;AAGA,QAAM,kBAAoC,CAAC;AAC3C,QAAM,kBAAoC,CAAC;AAC3C,aAAW,cAAc,MAAM,aAAa;AAC1C,QAAI,qBAAqB,UAAa,WAAW,mBAAmB,UAAU;AAC5E,sBAAgB,KAAK,UAAU;AAAA,IACjC,OAAO;AACL,sBAAgB,KAAK,UAAU;AAAA,IACjC;AAAA,EACF;AAEA,mBAAiB,QAAQ,iBAAiB,GAAG;AAC7C,MAAI,qBAAqB,QAAW;AAClC,qBAAiB,kBAAkB,iBAAiB,GAAG;AAAA,EACzD;AAGA,MAAI,gBAAgB,WAAW,GAAG;AAChC,WAAO;AAAA,EACT;AAEA,SAAO,6BAA6B,QAAQ,iBAAiB,GAAG;AAClE;AAUA,SAAS,uBAAuB,YAAqC;AACnE,UAAQ,WAAW,gBAAgB;AAAA,IACjC,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AASA,SAAS,6BACP,QACA,iBACA,KACgB;AAEhB,MAAI,OAAO,SAAS,WAAW,OAAO,OAAO;AAC3C,WAAO,QAAQ,6BAA6B,OAAO,OAAO,iBAAiB,GAAG;AAC9E,WAAO;AAAA,EACT;AAIA,QAAM,WAAW,oBAAI,IAA8B;AACnD,aAAW,KAAK,iBAAiB;AAC/B,UAAM,SAAS,EAAE,MAAM,SAAS,CAAC;AACjC,QAAI,CAAC,OAAQ;AACb,UAAM,QAAQ,SAAS,IAAI,MAAM,KAAK,CAAC;AACvC,UAAM,KAAK,CAAC;AACZ,aAAS,IAAI,QAAQ,KAAK;AAAA,EAC5B;AAGA,QAAM,oBAAoD,CAAC;AAC3D,aAAW,CAAC,QAAQ,WAAW,KAAK,UAAU;AAC5C,UAAM,YAA4B,CAAC;AACnC,qBAAiB,WAAW,aAAa,GAAG;AAC5C,sBAAkB,MAAM,IAAI;AAAA,EAC9B;AAGA,MAAI,OAAO,MAAM;AACf,UAAM,EAAE,MAAM,GAAG,KAAK,IAAI;AAC1B,UAAM,UAA0B,EAAE,KAAK;AACvC,UAAM,eAA+B;AAAA,MACnC,YAAY;AAAA,MACZ,GAAG;AAAA,IACL;AACA,WAAO,EAAE,OAAO,CAAC,SAAS,YAAY,EAAE;AAAA,EAC1C;AAGA,MAAI,OAAO,SAAS,YAAY,OAAO,YAAY;AACjD,UAAM,mBAAmD,CAAC;AAE1D,eAAW,CAAC,QAAQ,cAAc,KAAK,OAAO,QAAQ,iBAAiB,GAAG;AACxE,UAAI,OAAO,WAAW,MAAM,GAAG;AAC7B,eAAO,OAAO,OAAO,WAAW,MAAM,GAAG,cAAc;AAAA,MACzD,OAAO;AAGL,yBAAiB,MAAM,IAAI;AAAA,MAC7B;AAAA,IACF;AAEA,QAAI,OAAO,KAAK,gBAAgB,EAAE,WAAW,GAAG;AAC9C,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,MACL,OAAO,CAAC,QAAQ,EAAE,YAAY,iBAAiB,CAAC;AAAA,IAClD;AAAA,EACF;AAGA,MAAI,OAAO,OAAO;AAChB,WAAO,QAAQ,CAAC,GAAG,OAAO,OAAO,EAAE,YAAY,kBAAkB,CAAC;AAClE,WAAO;AAAA,EACT;AAKA,SAAO;AACT;AAaA,SAAS,iBAAiB,MAAgB,KAAuC;AAC/E,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK;AACH,aAAO,sBAAsB,IAAI;AAAA,IAEnC,KAAK;AACH,aAAO,iBAAiB,IAAI;AAAA,IAE9B,KAAK;AACH,aAAO,kBAAkB,MAAM,GAAG;AAAA,IAEpC,KAAK;AACH,aAAO,mBAAmB,MAAM,GAAG;AAAA,IAErC,KAAK;AACH,aAAO,mBAAmB,MAAM,GAAG;AAAA,IAErC,KAAK;AACH,aAAO,kBAAkB,MAAM,GAAG;AAAA,IAEpC,KAAK;AACH,aAAO,sBAAsB,IAAI;AAAA,IAEnC,KAAK;AACH,aAAO,oBAAoB,IAAI;AAAA,IAEjC,KAAK;AACH,aAAO,mBAAmB,MAAM,GAAG;AAAA,IAErC,SAAS;AAEP,YAAM,cAAqB;AAC3B,aAAO;AAAA,IACT;AAAA,EACF;AACF;AASA,SAAS,sBAAsB,MAAyC;AACtE,SAAO;AAAA,IACL,MACE,KAAK,kBAAkB,aAAa,KAAK,kBAAkB,WACvD,YACA,KAAK;AAAA,EACb;AACF;AASA,SAAS,iBAAiB,MAAoC;AAC5D,QAAM,kBAAkB,KAAK,QAAQ,KAAK,CAAC,MAAM,EAAE,gBAAgB,MAAS;AAE5E,MAAI,iBAAiB;AACnB,WAAO;AAAA,MACL,OAAO,KAAK,QAAQ,IAAI,CAAC,MAAM;AAC7B,cAAM,QAAwB,EAAE,OAAO,EAAE,MAAM;AAC/C,YAAI,EAAE,gBAAgB,QAAW;AAC/B,gBAAM,QAAQ,EAAE;AAAA,QAClB;AACA,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE;AAClD;AAOA,SAAS,kBAAkB,MAAqB,KAAuC;AACrF,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO,iBAAiB,KAAK,OAAO,GAAG;AAAA,EACzC;AACF;AASA,SAAS,mBAAmB,MAAsB,KAAuC;AACvF,QAAM,aAA6C,CAAC;AACpD,QAAM,WAAqB,CAAC;AAE5B,aAAW,QAAQ,KAAK,YAAY;AAClC,eAAW,KAAK,IAAI,IAAI,uBAAuB,MAAM,GAAG;AACxD,QAAI,CAAC,KAAK,UAAU;AAClB,eAAS,KAAK,KAAK,IAAI;AAAA,IACzB;AAAA,EACF;AAEA,QAAM,SAAyB,EAAE,MAAM,UAAU,WAAW;AAE5D,MAAI,SAAS,SAAS,GAAG;AACvB,WAAO,WAAW;AAAA,EACpB;AAEA,MAAI,CAAC,KAAK,sBAAsB;AAC9B,WAAO,uBAAuB;AAAA,EAChC;AAEA,SAAO;AACT;AAUA,SAAS,mBAAmB,MAAsB,KAAuC;AACvF,SAAO;AAAA,IACL,MAAM;AAAA,IACN,sBAAsB,iBAAiB,KAAK,WAAW,GAAG;AAAA,EAC5D;AACF;AAMA,SAAS,uBAAuB,MAAsB,KAAuC;AAC3F,QAAM,SAAS,iBAAiB,KAAK,MAAM,GAAG;AAC9C,mBAAiB,QAAQ,KAAK,aAAa,GAAG;AAC9C,mBAAiB,QAAQ,KAAK,aAAa,GAAG;AAC9C,SAAO;AACT;AAWA,SAAS,kBAAkB,MAAqB,KAAuC;AAErF,MAAI,eAAe,IAAI,GAAG;AACxB,WAAO,EAAE,MAAM,UAAU;AAAA,EAC3B;AAIA,MAAI,gBAAgB,IAAI,GAAG;AACzB,WAAO;AAAA,MACL,OAAO,KAAK,QAAQ,IAAI,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAAA,IACzD;AAAA,EACF;AAKA,SAAO;AAAA,IACL,OAAO,KAAK,QAAQ,IAAI,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAAA,EACzD;AACF;AAKA,SAAS,eAAe,MAA8B;AACpD,MAAI,KAAK,QAAQ,WAAW,EAAG,QAAO;AACtC,QAAM,QAAQ,KAAK,QAAQ,IAAI,CAAC,MAAM,EAAE,IAAI;AAI5C,SACE,MAAM,MAAM,CAAC,MAAM,MAAM,WAAW,KACpC,KAAK,QAAQ,MAAM,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,kBAAkB,SAAS;AAErF;AASA,SAAS,gBAAgB,MAA8B;AACrD,MAAI,KAAK,QAAQ,WAAW,EAAG,QAAO;AACtC,QAAM,YAAY,KAAK,QAAQ;AAAA,IAC7B,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,kBAAkB;AAAA,EACvD,EAAE;AACF,SAAO,cAAc;AACvB;AAQA,SAAS,sBAAsB,MAAyC;AACtE,SAAO,EAAE,MAAM,WAAW,KAAK,IAAI,GAAG;AACxC;AASA,SAAS,oBAAoB,MAAuC;AAClE,MAAI,KAAK,gBAAgB,QAAQ;AAC/B,UAAM,SAAyB;AAAA,MAC7B,MAAM;AAAA,MACN,qBAAqB,KAAK;AAAA,IAC5B;AACA,QAAI,KAAK,gBAAgB,SAAS,GAAG;AACnC,aAAO,mBAAmB,IAAI,CAAC,GAAG,KAAK,eAAe;AAAA,IACxD;AACA,WAAO;AAAA,EACT;AAGA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,sBAAsB;AAAA,IACtB,2BAA2B,KAAK;AAAA,EAClC;AACF;AAiBA,SAAS,iBACP,QACA,aACA,KACM;AACN,aAAW,cAAc,aAAa;AACpC,YAAQ,WAAW,gBAAgB;AAAA,MACjC,KAAK;AACH,eAAO,UAAU,WAAW;AAC5B;AAAA,MAEF,KAAK;AACH,eAAO,UAAU,WAAW;AAC5B;AAAA,MAEF,KAAK;AACH,eAAO,mBAAmB,WAAW;AACrC;AAAA,MAEF,KAAK;AACH,eAAO,mBAAmB,WAAW;AACrC;AAAA,MAEF,KAAK,cAAc;AACjB,cAAM,EAAE,MAAM,IAAI;AAClB,YAAI,UAAU,KAAK,OAAO,SAAS,UAAU;AAE3C,iBAAO,OAAO;AAAA,QAChB,OAAO;AACL,iBAAO,aAAa;AAAA,QACtB;AACA;AAAA,MACF;AAAA,MAEA,KAAK;AACH,eAAO,YAAY,WAAW;AAC9B;AAAA,MAEF,KAAK;AACH,eAAO,YAAY,WAAW;AAC9B;AAAA,MAEF,KAAK;AACH,eAAO,WAAW,WAAW;AAC7B;AAAA,MAEF,KAAK;AACH,eAAO,WAAW,WAAW;AAC7B;AAAA,MAEF,KAAK;AACH,eAAO,UAAU,WAAW;AAC5B;AAAA,MAEF,KAAK;AACH,eAAO,cAAc,WAAW;AAChC;AAAA,MAEF,KAAK;AACH,eAAO,QAAQ,WAAW;AAC1B;AAAA,MAEF,KAAK;AAEH;AAAA,MAEF,KAAK;AACH,8BAAsB,QAAQ,YAAY,GAAG;AAC7C;AAAA,MAEF,SAAS;AAEP,cAAM,cAAqB;AAC3B,aAAK;AAAA,MACP;AAAA,IACF;AAAA,EACF;AACF;AAoBA,SAAS,iBACP,QACA,aACA,KACM;AACN,aAAW,cAAc,aAAa;AACpC,YAAQ,WAAW,gBAAgB;AAAA,MACjC,KAAK;AACH,eAAO,QAAQ,WAAW;AAC1B;AAAA,MAEF,KAAK;AACH,eAAO,cAAc,WAAW;AAChC;AAAA,MAEF,KAAK;AACH,eAAO,GAAG,IAAI,YAAY,UAA2B,IAAI,WAAW;AACpE;AAAA,MAEF,KAAK;AACH,eAAO,UAAU,WAAW;AAC5B;AAAA,MAEF,KAAK;AACH,eAAO,SAAS,WAAW;AAC3B;AAAA,MAEF,KAAK;AACH,eAAO,aAAa;AACpB,YAAI,WAAW,YAAY,UAAa,WAAW,YAAY,IAAI;AACjE,iBAAO,GAAG,IAAI,YAAY,0BAA2C,IACnE,WAAW;AAAA,QACf;AACA;AAAA,MAEF,KAAK;AAEH;AAAA,MAEF,KAAK;AAEH;AAAA,MAEF,KAAK;AACH,8BAAsB,QAAQ,YAAY,GAAG;AAC7C;AAAA,MAEF,SAAS;AAEP,cAAM,cAAqB;AAC3B,aAAK;AAAA,MACP;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,mBAAmB,MAAsB,KAAuC;AACvF,QAAM,eAAe,IAAI,mBAAmB,SAAS,KAAK,MAAM;AAChE,MAAI,iBAAiB,QAAW;AAC9B,UAAM,IAAI;AAAA,MACR,gDAAgD,KAAK,MAAM;AAAA,IAC7D;AAAA,EACF;AAIA,SAAO,aAAa,aAAa,KAAK,SAAS,IAAI,YAAY;AACjE;AAEA,SAAS,sBACP,QACA,YACA,KACM;AACN,QAAM,eAAe,IAAI,mBAAmB,eAAe,WAAW,YAAY;AAClF,MAAI,iBAAiB,QAAW;AAC9B,UAAM,IAAI;AAAA,MACR,sDAAsD,WAAW,YAAY;AAAA,IAC/E;AAAA,EACF;AAEA;AAAA,IACE;AAAA,IACA,aAAa,aAAa,WAAW,SAAS,IAAI,YAAY;AAAA,IAC9D,IAAI;AAAA,IACJ,sBAAsB,WAAW,YAAY;AAAA,EAC/C;AACF;AAEA,SAAS,sBACP,QACA,YACA,KACM;AACN,QAAM,eAAe,IAAI,mBAAmB,eAAe,WAAW,YAAY;AAClF,MAAI,iBAAiB,QAAW;AAC9B,UAAM,IAAI;AAAA,MACR,sDAAsD,WAAW,YAAY;AAAA,IAC/E;AAAA,EACF;AAEA,MAAI,aAAa,iBAAiB,QAAW;AAC3C;AAAA,EACF;AAEA;AAAA,IACE;AAAA,IACA,aAAa,aAAa,WAAW,OAAO,IAAI,YAAY;AAAA,IAC5D,IAAI;AAAA,IACJ,sBAAsB,WAAW,YAAY;AAAA,EAC/C;AACF;AAEA,SAAS,sCACP,QACA,iBACA,cACA,QACM;AACN,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,eAAe,GAAG;AAC1D,QAAI,CAAC,IAAI,WAAW,GAAG,YAAY,GAAG,GAAG;AACvC,YAAM,IAAI;AAAA,QACR,gBAAgB,MAAM,oCAAoC,YAAY;AAAA,MACxE;AAAA,IACF;AACA,WAAO,GAAoB,IAAI;AAAA,EACjC;AACF;;;AC/3BO,SAAS,mBACd,MACA,SACgB;AAChB,QAAM,KAAK,qBAAqB,IAAI;AACpC,QAAM,kBACJ,SAAS,iBAAiB,SAAY,SAAY,EAAE,cAAc,QAAQ,aAAa;AACzF,SAAO,yBAAyB,IAAI,eAAe;AACrD;;;ACxDA,iBAAkB;AAQlB,IAAM,oBAAoB,aAAE,OAAO;AAW5B,IAAM,mBAAmB,aAAE,KAAK,CAAC,QAAQ,QAAQ,UAAU,SAAS,CAAC;AAcrE,IAAM,4BAA4B,aAAE,KAAK;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAyCM,IAAM,sBAAsD,aAAE;AAAA,EAAK,MACxE,aACG,OAAO;AAAA,IACN,OAAO,aAAE,QAAQ,EAAE,SAAS;AAAA,IAC5B,MAAM,aAAE,MAAM,aAAE,QAAQ,CAAC,EAAE,SAAS,EAAE,SAAS;AAAA,IAC/C,MAAM,aAAE,OAAO,EAAE,SAAS;AAAA,IAC1B,KAAK,oBAAoB,SAAS;AAAA,IAClC,SAAS,aAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,SAAS,aAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,kBAAkB,aAAE,OAAO,EAAE,SAAS;AAAA,IACtC,kBAAkB,aAAE,OAAO,EAAE,SAAS;AAAA,IACtC,WAAW,aAAE,OAAO,EAAE,SAAS;AAAA,IAC/B,YAAY,aAAE,OAAO,aAAE,OAAO,GAAG,mBAAmB,EAAE,SAAS;AAAA,IAC/D,UAAU,aAAE,MAAM,aAAE,OAAO,CAAC,EAAE,SAAS;AAAA,IACvC,OAAO,aAAE,MAAM,mBAAmB,EAAE,SAAS;AAAA,EAC/C,CAAC,EACA,OAAO;AACZ;AAWO,IAAM,6BAA6B,aACvC,OAAO;AAAA,EACN,OAAO;AAAA,EACP,QAAQ;AACV,CAAC,EACA,OAAO;AAcH,IAAM,aAAa,aACvB,OAAO;AAAA,EACN,QAAQ;AAAA,EACR,WAAW;AACb,CAAC,EACA,OAAO;AAqCH,IAAM,wBAAoD,aAAE;AAAA,EAAK,MACtE,aAAE,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAWO,IAAM,gBAAgB,aAC1B,OAAO;AAAA,EACN,MAAM,aAAE,QAAQ,SAAS;AAAA,EACzB,OAAO;AAAA,EACP,OAAO,aAAE,MAAM,CAAC,aAAE,OAAO,GAAG,aAAE,QAAQ,KAAK,CAAC,CAAC,EAAE,SAAS;AAAA,EACxD,MAAM,WAAW,SAAS;AAAA,EAC1B,SAAS,aAAE,OAAO,aAAE,OAAO,GAAG,aAAE,QAAQ,CAAC,EAAE,SAAS;AACtD,CAAC,EACA,YAAY;AAgCR,IAAM,uBAAkD,aAAE;AAAA,EAAK,MACpE,aACG,OAAO;AAAA,IACN,MAAM,aAAE,QAAQ,gBAAgB;AAAA,IAChC,UAAU,aAAE,MAAM,qBAAqB;AAAA,IACvC,MAAM,WAAW,SAAS;AAAA,IAC1B,SAAS,aAAE,OAAO,aAAE,OAAO,GAAG,aAAE,QAAQ,CAAC,EAAE,SAAS;AAAA,EACtD,CAAC,EACA,YAAY;AACjB;AAwBO,IAAM,yBAAsD,aAAE;AAAA,EAAK,MACxE,aACG,OAAO;AAAA,IACN,MAAM,aAAE,QAAQ,kBAAkB;AAAA,IAClC,UAAU,aAAE,MAAM,qBAAqB;AAAA,IACvC,MAAM,WAAW,SAAS;AAAA,IAC1B,SAAS,aAAE,OAAO,aAAE,OAAO,GAAG,aAAE,QAAQ,CAAC,EAAE,SAAS;AAAA,EACtD,CAAC,EACA,YAAY;AACjB;AAyBO,IAAM,oBAA4C,aAAE;AAAA,EAAK,MAC9D,aACG,OAAO;AAAA,IACN,MAAM,aAAE,QAAQ,OAAO;AAAA,IACvB,OAAO,aAAE,OAAO;AAAA,IAChB,UAAU,aAAE,MAAM,qBAAqB;AAAA,IACvC,MAAM,WAAW,SAAS;AAAA,IAC1B,SAAS,aAAE,OAAO,aAAE,OAAO,GAAG,aAAE,QAAQ,CAAC,EAAE,SAAS;AAAA,EACtD,CAAC,EACA,YAAY;AACjB;AAyBO,IAAM,iBAAsC,aAAE;AAAA,EAAK,MACxD,aACG,OAAO;AAAA,IACN,MAAM,aAAE,QAAQ,UAAU;AAAA,IAC1B,OAAO,aAAE,OAAO;AAAA,IAChB,UAAU,aAAE,MAAM,qBAAqB;AAAA,IACvC,MAAM,WAAW,SAAS;AAAA,IAC1B,SAAS,aAAE,OAAO,aAAE,OAAO,GAAG,aAAE,QAAQ,CAAC,EAAE,SAAS;AAAA,EACtD,CAAC,EACA,YAAY;AACjB;AAyBO,IAAM,uBAAkD,aAAE;AAAA,EAAK,MACpE,aACG,OAAO;AAAA,IACN,MAAM,aAAE,QAAQ,gBAAgB;AAAA,IAChC,UAAU,aAAE,MAAM,cAAc;AAAA,IAChC,OAAO,aAAE,OAAO,EAAE,SAAS;AAAA,IAC3B,MAAM,WAAW,SAAS;AAAA,IAC1B,SAAS,aAAE,OAAO,aAAE,OAAO,GAAG,aAAE,QAAQ,CAAC,EAAE,SAAS;AAAA,EACtD,CAAC,EACA,YAAY;AACjB;AAWO,IAAM,qBAAqB,aAC/B,OAAO;AAAA,EACN,MAAM,aAAE,QAAQ,OAAO;AAAA,EACvB,MAAM,aAAE,OAAO;AAAA,EACf,MAAM,WAAW,SAAS;AAAA,EAC1B,SAAS,aAAE,OAAO,aAAE,OAAO,GAAG,aAAE,QAAQ,CAAC,EAAE,SAAS;AACtD,CAAC,EACA,YAAY;AAkBR,IAAM,WAAgC,aAAE;AAAA,EAAK,MAClD,aAAE,MAAM,CAAC,sBAAsB,wBAAwB,mBAAmB,oBAAoB,CAAC;AACjG;;;ACxZA,IAAAC,cAAkB;AAUlB,SAAS,aAAgB,QAAsB,OAAgB,OAAkB;AAC/E,MAAI;AACF,WAAO,OAAO,MAAM,KAAK;AAAA,EAC3B,SAAS,OAAO;AACd,QAAI,iBAAiB,cAAE,UAAU;AAC/B,YAAM,IAAI;AAAA,QACR,aAAa,KAAK;AAAA,EAAwB,MAAM,OAAO,IAAI,CAAC,MAAM,KAAK,EAAE,KAAK,KAAK,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,IAAI,CAAC;AAAA,MACrH;AAAA,IACF;AACA,UAAM;AAAA,EACR;AACF;AAKA,SAAS,aAAa,WAA2B;AAC/C,SAAO,gBAAgB,SAAS;AAClC;AAKA,SAAS,eAAe,WAAmB,OAAsB;AAC/D,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,WAAW;AAAA,MACT,OAAO,aAAa,SAAS;AAAA,MAC7B,QAAQ,EAAE,OAAO,MAAM;AAAA,IACzB;AAAA,EACF;AACF;AAUA,SAAS,uBAAuB,OAAe,QAAoD;AACjG,MAAI,OAAO,UAAU,QAAW;AAC9B,QAAI,UAAU,KAAK;AACjB,aAAO,CAAC,MAAM;AAAA,IAChB;AAEA,UAAM,YAAY,MAAM,QAAQ,iBAAiB,EAAE;AACnD,WAAO;AAAA,MACL;AAAA,QACE,YAAY;AAAA,UACV,CAAC,SAAS,GAAG;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,OAAO,MAAM,QAAQ,CAAC,WAAW,uBAAuB,OAAO,MAAM,CAAC;AAC/E;AAEA,SAAS,aAAa,YAAkB,WAAuB;AAC7D,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,WAAW;AAAA,MACT,OAAO;AAAA,MACP,QAAQ;AAAA,QACN,OAAO;AAAA,UACL,GAAG,uBAAuB,WAAW,UAAU,OAAO,WAAW,UAAU,MAAM;AAAA,UACjF,GAAG,uBAAuB,UAAU,UAAU,OAAO,UAAU,UAAU,MAAM;AAAA,QACjF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAaA,SAAS,mBAAmB,OAAkB,YAAmC;AAC/E,QAAM,wBAAwB,MAAM,YAAY,KAAK,CAAC,MAAM,EAAE,mBAAmB,aAAa;AAC9F,QAAM,wBAAwB,MAAM,YAAY,KAAK,CAAC,MAAM,EAAE,mBAAmB,aAAa;AAE9F,QAAM,UAA0B;AAAA,IAC9B,MAAM;AAAA,IACN,OAAO,aAAa,MAAM,IAAI;AAAA,IAC9B,GAAI,0BAA0B,UAAa,EAAE,OAAO,sBAAsB,MAAM;AAAA,IAChF,GAAI,0BAA0B,UAAa;AAAA,MACzC,SAAS,EAAE,aAAa,sBAAsB,MAAM;AAAA,IACtD;AAAA,IACA,GAAI,eAAe,UAAa,EAAE,MAAM,WAAW;AAAA,EACrD;AAEA,SAAO;AACT;AASA,SAAS,kBAAkB,OAAwB,YAAgC;AACjF,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO,MAAM;AAAA,IACb,UAAU,qBAAqB,MAAM,UAAU,UAAU;AAAA,IACzD,GAAI,eAAe,UAAa,EAAE,MAAM,WAAW;AAAA,EACrD;AACF;AASA,SAAS,qBACP,UACA,YACmB;AACnB,QAAM,SAA4B,CAAC;AAEnC,aAAW,WAAW,UAAU;AAC9B,YAAQ,QAAQ,MAAM;AAAA,MACpB,KAAK,SAAS;AACZ,eAAO,KAAK,mBAAmB,SAAS,UAAU,CAAC;AACnD;AAAA,MACF;AAAA,MAEA,KAAK,SAAS;AACZ,eAAO,KAAK,kBAAkB,SAAS,UAAU,CAAC;AAClD;AAAA,MACF;AAAA,MAEA,KAAK,eAAe;AAElB,cAAM,UAAU,eAAe,QAAQ,WAAW,QAAQ,KAAK;AAE/D,cAAM,eAAe,eAAe,SAAY,aAAa,YAAY,OAAO,IAAI;AAGpF,cAAM,gBAAgB,qBAAqB,QAAQ,UAAU,YAAY;AACzE,eAAO,KAAK,GAAG,aAAa;AAC5B;AAAA,MACF;AAAA,MAEA,SAAS;AACP,cAAM,cAAqB;AAC3B,aAAK;AACL,cAAM,IAAI,MAAM,2BAA2B;AAAA,MAC7C;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAgDO,SAAS,uBAAuB,IAAsB;AAC3D,QAAM,SAAmB;AAAA,IACvB,MAAM;AAAA,IACN,UAAU,qBAAqB,GAAG,QAAQ;AAAA,EAC5C;AAEA,SAAO,aAAa,UAAmB,QAAQ,WAAW;AAC5D;;;AC/LO,SAAS,iBAAmD,MAA6B;AAC9F,QAAM,KAAK,qBAAqB,IAAI;AACpC,SAAO,uBAAuB,EAAE;AAClC;;;ACqGO,SAAS,mBACd,QACA,KACA,OACM;AACN,EAAC,OAAmC,GAAG,IAAI;AAC7C;AAaO,SAAS,mBAAmB,QAAgB,KAAsC;AACvF,SAAQ,OAAmC,GAAG;AAChD;;;AC1EO,SAAS,wBACd,YACmB;AACnB,QAAM,UAAU,oBAAI,IAAoC;AACxD,QAAM,cAAc,oBAAI,IAGtB;AACF,QAAM,gBAAgB,oBAAI,IAA0C;AACpE,QAAM,mBAAmB,oBAAI,IAG3B;AACF,QAAM,uBAAuB,oBAAI,IAG/B;AACF,QAAM,gBAAgB,oBAAI,IAA0C;AAEpE,aAAW,OAAO,YAAY;AAC5B,QAAI,IAAI,UAAU,QAAW;AAC3B,iBAAW,QAAQ,IAAI,OAAO;AAC5B,cAAM,cAAc,GAAG,IAAI,WAAW,IAAI,KAAK,QAAQ;AACvD,YAAI,QAAQ,IAAI,WAAW,GAAG;AAC5B,gBAAM,IAAI,MAAM,8BAA8B,WAAW,GAAG;AAAA,QAC9D;AACA,gBAAQ,IAAI,aAAa,IAAI;AAE7B,mBAAW,kBAAkB,KAAK,eAAe,CAAC,KAAK,QAAQ,GAAG;AAChE,cAAI,YAAY,IAAI,cAAc,GAAG;AACnC,kBAAM,IAAI,MAAM,uCAAuC,cAAc,GAAG;AAAA,UAC1E;AACA,sBAAY,IAAI,gBAAgB;AAAA,YAC9B,aAAa,IAAI;AAAA,YACjB,cAAc;AAAA,UAChB,CAAC;AAAA,QACH;AAEA,YAAI,KAAK,iCAAiC,QAAW;AACnD,qBAAW,cAAc,KAAK,8BAA8B;AAC1D,kBAAM,MAAM,GAAG,WAAW,IAAI,WAAW,OAAO;AAChD,gBAAI,qBAAqB,IAAI,GAAG,GAAG;AACjC,oBAAM,IAAI,MAAM,8CAA8C,GAAG,GAAG;AAAA,YACtE;AACA,iCAAqB,IAAI,KAAK;AAAA,cAC5B,aAAa,IAAI;AAAA,cACjB,cAAc;AAAA,YAChB,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,IAAI,gBAAgB,QAAW;AACjC,iBAAW,cAAc,IAAI,aAAa;AACxC,cAAM,cAAc,GAAG,IAAI,WAAW,IAAI,WAAW,cAAc;AACnE,YAAI,cAAc,IAAI,WAAW,GAAG;AAClC,gBAAM,IAAI,MAAM,oCAAoC,WAAW,GAAG;AAAA,QACpE;AACA,sBAAc,IAAI,aAAa,UAAU;AAAA,MAC3C;AAAA,IACF;AAEA,QAAI,IAAI,mBAAmB,QAAW;AACpC,iBAAW,OAAO,IAAI,gBAAgB;AACpC,YAAI,iBAAiB,IAAI,IAAI,OAAO,GAAG;AACrC,gBAAM,IAAI,MAAM,sCAAsC,IAAI,OAAO,GAAG;AAAA,QACtE;AACA,yBAAiB,IAAI,IAAI,SAAS;AAAA,UAChC,aAAa,IAAI;AAAA,UACjB,cAAc;AAAA,QAChB,CAAC;AAAA,MACH;AAAA,IACF;AAEA,QAAI,IAAI,gBAAgB,QAAW;AACjC,iBAAW,cAAc,IAAI,aAAa;AACxC,cAAM,cAAc,GAAG,IAAI,WAAW,IAAI,WAAW,cAAc;AACnE,YAAI,cAAc,IAAI,WAAW,GAAG;AAClC,gBAAM,IAAI,MAAM,oCAAoC,WAAW,GAAG;AAAA,QACpE;AACA,sBAAc,IAAI,aAAa,UAAU;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,UAAU,CAAC,WAAmB,QAAQ,IAAI,MAAM;AAAA,IAChD,gBAAgB,CAAC,aAAqB,YAAY,IAAI,QAAQ;AAAA,IAC9D,gBAAgB,CAAC,iBAAyB,cAAc,IAAI,YAAY;AAAA,IACxE,mBAAmB,CAAC,YAAoB,iBAAiB,IAAI,OAAO;AAAA,IACpE,iCAAiC,CAAC,QAAgB,YAChD,qBAAqB,IAAI,GAAG,MAAM,IAAI,OAAO,EAAE;AAAA,IACjD,gBAAgB,CAAC,iBAAyB,cAAc,IAAI,YAAY;AAAA,EAC1E;AACF;;;ACnMA,IAAAC,cAAkB;AAYX,IAAM,uBAAuB,cAAE,KAAK;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAoBM,IAAM,oBAA4C,cAAE;AAAA,EAAK,MAC9D,cACG,OAAO;AAAA,IACN,SAAS,cAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,KAAK,cAAE,OAAO,EAAE,SAAS;AAAA,IACzB,MAAM,cAAE,OAAO,EAAE,SAAS;AAAA;AAAA,IAG1B,OAAO,cAAE,OAAO,EAAE,SAAS;AAAA,IAC3B,aAAa,cAAE,OAAO,EAAE,SAAS;AAAA,IACjC,YAAY,cAAE,QAAQ,EAAE,SAAS;AAAA;AAAA,IAGjC,MAAM,cAAE,MAAM,CAAC,sBAAsB,cAAE,MAAM,oBAAoB,CAAC,CAAC,EAAE,SAAS;AAAA;AAAA,IAG9E,WAAW,cAAE,OAAO,EAAE,SAAS;AAAA,IAC/B,WAAW,cAAE,OAAO,EAAE,SAAS;AAAA,IAC/B,SAAS,cAAE,OAAO,EAAE,SAAS;AAAA;AAAA,IAG7B,SAAS,cAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,SAAS,cAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,kBAAkB,cAAE,OAAO,EAAE,SAAS;AAAA,IACtC,kBAAkB,cAAE,OAAO,EAAE,SAAS;AAAA;AAAA,IAGtC,MAAM,cACH,MAAM,cAAE,MAAM,CAAC,cAAE,OAAO,GAAG,cAAE,OAAO,GAAG,cAAE,QAAQ,GAAG,cAAE,KAAK,CAAC,CAAC,CAAC,EAC9D,SAAS,EACT,SAAS;AAAA,IACZ,OAAO,cAAE,MAAM,CAAC,cAAE,OAAO,GAAG,cAAE,OAAO,GAAG,cAAE,QAAQ,GAAG,cAAE,KAAK,CAAC,CAAC,EAAE,SAAS;AAAA;AAAA,IAGzE,YAAY,cAAE,OAAO,cAAE,OAAO,GAAG,iBAAiB,EAAE,SAAS;AAAA,IAC7D,UAAU,cAAE,MAAM,cAAE,OAAO,CAAC,EAAE,SAAS;AAAA,IACvC,sBAAsB,cAAE,MAAM,CAAC,cAAE,QAAQ,GAAG,iBAAiB,CAAC,EAAE,SAAS;AAAA;AAAA,IAGzE,OAAO,cAAE,MAAM,CAAC,mBAAmB,cAAE,MAAM,iBAAiB,CAAC,CAAC,EAAE,SAAS;AAAA,IACzE,UAAU,cAAE,OAAO,EAAE,SAAS;AAAA,IAC9B,UAAU,cAAE,OAAO,EAAE,SAAS;AAAA;AAAA,IAG9B,OAAO,cAAE,MAAM,iBAAiB,EAAE,SAAS;AAAA,IAC3C,OAAO,cAAE,MAAM,iBAAiB,EAAE,SAAS;AAAA,IAC3C,OAAO,cAAE,MAAM,iBAAiB,EAAE,SAAS;AAAA,IAC3C,KAAK,kBAAkB,SAAS;AAAA;AAAA,IAGhC,IAAI,kBAAkB,SAAS;AAAA,IAC/B,MAAM,kBAAkB,SAAS;AAAA,IACjC,MAAM,kBAAkB,SAAS;AAAA;AAAA,IAGjC,QAAQ,cAAE,OAAO,EAAE,SAAS;AAAA;AAAA,IAG5B,SAAS,cAAE,QAAQ,EAAE,SAAS;AAAA;AAAA,IAG9B,qBAAqB,cAAE,OAAO,EAAE,SAAS;AAAA,IACzC,qBAAqB,cAAE,MAAM,cAAE,OAAO,CAAC,EAAE,SAAS,EAAE,SAAS;AAAA,IAC7D,2BAA2B,cAAE,OAAO,EAAE,SAAS;AAAA,EACjD,CAAC,EAGA,YAAY;AACjB;;;AC3GA,sBAIO;AAsBP,SAAS,kBAAkB,KAAwB,OAAwB;AACzE,QAAM,eAAW;AAAA,IACf,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,IAAI,sBAAsB,SACtB,SACA;AAAA,MACE,mBAAmB,IAAI;AAAA,IACzB;AAAA,EACN;AACA,MAAI,YAAY,KAAK,GAAG,SAAS,WAAW;AAE5C,MAAI,MAAM,KAAK,SAAS,UAAU;AAChC,eAAW,YAAY,MAAM,KAAK,YAAY;AAC5C,6BAAuB,KAAK,MAAM,MAAM,QAAQ;AAAA,IAClD;AAAA,EACF;AACF;AAEA,SAAS,uBACP,KACA,YACA,UACM;AACN,QAAM,gBAAgB,GAAG,UAAU,IAAI,SAAS,IAAI;AACpD,QAAM,eAAW;AAAA,IACf;AAAA,IACA,SAAS;AAAA,IACT,SAAS;AAAA,IACT,IAAI;AAAA,IACJ,IAAI,sBAAsB,SACtB,SACA;AAAA,MACE,mBAAmB,IAAI;AAAA,IACzB;AAAA,EACN;AACA,MAAI,YAAY,KAAK,GAAG,SAAS,WAAW;AAE5C,MAAI,SAAS,KAAK,SAAS,UAAU;AACnC,eAAW,kBAAkB,SAAS,KAAK,YAAY;AACrD,6BAAuB,KAAK,eAAe,cAAc;AAAA,IAC3D;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,KAAwB,SAA8B;AAC7E,UAAQ,QAAQ,MAAM;AAAA,IACpB,KAAK;AACH,wBAAkB,KAAK,OAAO;AAC9B;AAAA,IACF,KAAK;AACH,iBAAW,SAAS,QAAQ,UAAU;AACpC,wBAAgB,KAAK,KAAK;AAAA,MAC5B;AACA;AAAA,IACF,KAAK;AACH,iBAAW,SAAS,QAAQ,UAAU;AACpC,wBAAgB,KAAK,KAAK;AAAA,MAC5B;AACA;AAAA,IACF,SAAS;AACP,YAAM,aAAoB;AAC1B,YAAM,IAAI,MAAM,2BAA2B,OAAO,UAAU,CAAC,EAAE;AAAA,IACjE;AAAA,EACF;AACF;AAEO,SAAS,WAAW,IAAY,SAA+C;AACpF,QAAM,MAAyB;AAAA,IAC7B,aAAa,CAAC;AAAA,IACd,mBAAmB,SAAS;AAAA,IAC5B,cAAc,GAAG;AAAA,EACnB;AAEA,aAAW,WAAW,GAAG,UAAU;AACjC,oBAAgB,KAAK,OAAO;AAAA,EAC9B;AAEA,SAAO;AAAA,IACL,aAAa,IAAI;AAAA,IACjB,OAAO,IAAI,YAAY,MAAM,CAAC,eAAe,WAAW,aAAa,OAAO;AAAA,EAC9E;AACF;;;AXkBO,SAAS,iBACd,MACA,SACa;AACb,SAAO;AAAA,IACL,YAAY,mBAAmB,MAAM,OAAO;AAAA,IAC5C,UAAU,iBAAiB,IAAI;AAAA,EACjC;AACF;","names":["import_internals","import_zod","import_zod"]}
|
|
1
|
+
{"version":3,"sources":["../src/browser.ts","../src/canonicalize/chain-dsl-canonicalizer.ts","../src/metadata/policy.ts","../src/metadata/resolve.ts","../src/canonicalize/tsdoc-canonicalizer.ts","../src/metadata/collision-guards.ts","../src/json-schema/ir-generator.ts","../src/json-schema/generator.ts","../src/ui-schema/schema.ts","../src/ui-schema/ir-generator.ts","../src/ui-schema/generator.ts","../src/json-schema/types.ts","../src/extensions/registry.ts","../src/json-schema/schema.ts","../src/validate/constraint-validator.ts"],"sourcesContent":["/**\n * Browser-safe exports for `@formspec/build`.\n *\n * This entry point excludes Node.js-specific functions like `writeSchemas`\n * that use `node:fs` and `node:path`, making it suitable for browser environments.\n *\n * @example\n * ```typescript\n * // In browser code (e.g., playground)\n * import { buildFormSchemas, generateJsonSchema, generateUiSchema } from \"@formspec/build/browser\";\n *\n * const form = formspec(field.text(\"name\"));\n * const { jsonSchema, uiSchema } = buildFormSchemas(form);\n * ```\n *\n * @packageDocumentation\n */\n\nimport type { FormElement, FormSpec } from \"@formspec/core\";\nimport { generateJsonSchema, type GenerateJsonSchemaOptions } from \"./json-schema/generator.js\";\nimport { generateUiSchema } from \"./ui-schema/generator.js\";\nimport { type JsonSchema2020 } from \"./json-schema/ir-generator.js\";\nimport type { UISchema } from \"./ui-schema/types.js\";\n\n// Re-export types\nexport type { JsonSchema2020 } from \"./json-schema/ir-generator.js\";\nexport type { GenerateJsonSchemaFromIROptions } from \"./json-schema/ir-generator.js\";\nexport type { GenerateJsonSchemaOptions } from \"./json-schema/generator.js\";\nexport type {\n BuiltinConstraintBroadeningRegistration,\n ConstraintTagRegistration,\n CustomAnnotationRegistration,\n CustomConstraintRegistration,\n CustomTypeRegistration,\n ExtensionDefinition,\n} from \"@formspec/core\";\n\nexport type {\n JSONSchema7,\n JSONSchemaType,\n ExtendedJSONSchema7,\n FormSpecSchemaExtensions,\n} from \"./json-schema/types.js\";\n\nexport { setSchemaExtension, getSchemaExtension } from \"./json-schema/types.js\";\nexport { createExtensionRegistry } from \"./extensions/index.js\";\nexport type { ExtensionRegistry } from \"./extensions/index.js\";\n\nexport type {\n UISchema,\n UISchemaElement,\n UISchemaElementBase,\n UISchemaElementType,\n ControlElement,\n VerticalLayout,\n HorizontalLayout,\n GroupLayout,\n Categorization,\n Category,\n LabelElement,\n Rule,\n RuleEffect,\n RuleConditionSchema,\n SchemaBasedCondition,\n} from \"./ui-schema/types.js\";\n\n// Zod validation schemas\nexport {\n ruleEffectSchema,\n uiSchemaElementTypeSchema,\n ruleConditionSchema,\n schemaBasedConditionSchema,\n ruleSchema,\n controlSchema,\n verticalLayoutSchema,\n horizontalLayoutSchema,\n groupLayoutSchema,\n categorizationSchema,\n categorySchema,\n labelElementSchema,\n uiSchemaElementSchema,\n uiSchema as uiSchemaSchema,\n} from \"./ui-schema/schema.js\";\n\nexport { jsonSchemaTypeSchema, jsonSchema7Schema } from \"./json-schema/schema.js\";\n\n// Re-export individual generators\nexport { generateJsonSchema } from \"./json-schema/generator.js\";\nexport { generateJsonSchemaFromIR } from \"./json-schema/ir-generator.js\";\nexport { generateUiSchema } from \"./ui-schema/generator.js\";\n\n// IR canonicalization (browser-safe: no Node.js dependencies)\nexport { canonicalizeChainDSL } from \"./canonicalize/chain-dsl-canonicalizer.js\";\n\n// IR validation (browser-safe: no Node.js dependencies)\nexport { validateIR } from \"./validate/constraint-validator.js\";\nexport type {\n ValidationDiagnostic,\n ValidationResult,\n ValidateIROptions,\n} from \"./validate/constraint-validator.js\";\n\n/**\n * Result of building form schemas.\n */\nexport interface BuildResult {\n /** JSON Schema 2020-12 for validation */\n readonly jsonSchema: JsonSchema2020;\n /** JSON Forms UI Schema for rendering */\n readonly uiSchema: UISchema;\n}\n\n/**\n * Options for building schemas from a FormSpec in browser-safe code.\n *\n * Currently identical to `GenerateJsonSchemaOptions`. Defined separately so the\n * browser-safe surface can grow independently in the future if needed.\n */\nexport type BuildFormSchemasOptions = GenerateJsonSchemaOptions;\n\n/**\n * Builds both JSON Schema and UI Schema from a FormSpec.\n *\n * This is a browser-safe version that does not include file system operations.\n *\n * @example\n * ```typescript\n * const form = formspec(\n * field.text(\"name\", { required: true }),\n * field.number(\"age\", { min: 0 }),\n * );\n *\n * const { jsonSchema, uiSchema } = buildFormSchemas(form);\n * ```\n *\n * @param form - The FormSpec to build schemas from\n * @returns Object containing both jsonSchema and uiSchema\n */\nexport function buildFormSchemas<E extends readonly FormElement[]>(\n form: FormSpec<E>,\n options?: BuildFormSchemasOptions\n): BuildResult {\n return {\n jsonSchema: generateJsonSchema(form, options),\n uiSchema: generateUiSchema(form, options),\n };\n}\n","/**\n * Canonicalizer that translates chain DSL `FormSpec` objects into the\n * canonical FormIR intermediate representation.\n *\n * This module maps the runtime objects produced by `@formspec/dsl` builder\n * functions (`field.*`, `group`, `when`, `formspec`) into the IR that all\n * downstream phases (validation, JSON Schema generation, UI Schema generation)\n * consume.\n */\n\nimport type {\n // Source types (chain DSL)\n AnyField,\n ArrayField,\n BooleanField,\n Conditional,\n DynamicEnumField,\n DynamicSchemaField,\n EnumOptionValue,\n FormElement,\n FormSpec,\n Group,\n NumberField,\n ObjectField,\n StaticEnumField,\n TextField,\n MetadataPolicyInput,\n} from \"@formspec/core\";\nimport type {\n // IR types\n JsonValue,\n AnnotationNode,\n ArrayTypeNode,\n ConstraintNode,\n ConditionalLayoutNode,\n DisplayNameAnnotationNode,\n DynamicTypeNode,\n EnumMember,\n EnumTypeNode,\n FieldNode,\n FormIR,\n FormIRElement,\n GroupLayoutNode,\n LengthConstraintNode,\n NumericConstraintNode,\n ObjectProperty,\n PatternConstraintNode,\n ObjectTypeNode,\n PlaceholderAnnotationNode,\n PrimitiveTypeNode,\n Provenance,\n ResolvedMetadata,\n TypeNode,\n} from \"@formspec/core/internals\";\nimport { IR_VERSION, _getFormSpecMetadataPolicy } from \"@formspec/core/internals\";\nimport {\n getDeclarationMetadataPolicy,\n makeMetadataContext,\n normalizeMetadataPolicy,\n resolveMetadata,\n} from \"../metadata/index.js\";\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\n/** Default provenance for chain DSL nodes (no source location available). */\nconst CHAIN_DSL_PROVENANCE: Provenance = {\n surface: \"chain-dsl\",\n file: \"\",\n line: 0,\n column: 0,\n} as const;\n\n// =============================================================================\n// TYPE GUARDS\n// =============================================================================\n\nfunction isGroup(el: FormElement): el is Group<readonly FormElement[]> {\n return el._type === \"group\";\n}\n\nfunction isConditional(\n el: FormElement\n): el is Conditional<string, unknown, readonly FormElement[]> {\n return el._type === \"conditional\";\n}\n\nfunction isField(el: FormElement): el is AnyField {\n return el._type === \"field\";\n}\n\n// =============================================================================\n// PUBLIC API\n// =============================================================================\n\n/**\n * Translates a chain DSL `FormSpec` into the canonical `FormIR`.\n *\n * @param form - A form specification created via `formspec(...)` from `@formspec/dsl`\n * @returns The canonical intermediate representation\n */\nexport interface CanonicalizeChainDSLOptions {\n readonly metadata?: MetadataPolicyInput;\n}\n\nexport function canonicalizeChainDSL(\n form: FormSpec<readonly FormElement[]>,\n options?: CanonicalizeChainDSLOptions\n): FormIR {\n const metadataPolicy = normalizeMetadataPolicy(\n options?.metadata ?? _getFormSpecMetadataPolicy(form)\n );\n return {\n kind: \"form-ir\",\n irVersion: IR_VERSION,\n elements: canonicalizeElements(form.elements, metadataPolicy),\n rootAnnotations: [],\n typeRegistry: {},\n provenance: CHAIN_DSL_PROVENANCE,\n };\n}\n\n// =============================================================================\n// ELEMENT CANONICALIZATION\n// =============================================================================\n\n/**\n * Canonicalizes an array of chain DSL form elements into IR elements.\n */\nfunction canonicalizeElements(\n elements: readonly FormElement[],\n metadataPolicy: ReturnType<typeof normalizeMetadataPolicy>\n): FormIRElement[] {\n return elements.map((element) => canonicalizeElement(element, metadataPolicy));\n}\n\n/**\n * Dispatches a single form element to its specific canonicalization function.\n */\nfunction canonicalizeElement(\n element: FormElement,\n metadataPolicy: ReturnType<typeof normalizeMetadataPolicy>\n): FormIRElement {\n if (isField(element)) {\n return canonicalizeField(element, metadataPolicy);\n }\n if (isGroup(element)) {\n return canonicalizeGroup(element, metadataPolicy);\n }\n if (isConditional(element)) {\n return canonicalizeConditional(element, metadataPolicy);\n }\n const _exhaustive: never = element;\n throw new Error(`Unknown element type: ${JSON.stringify(_exhaustive)}`);\n}\n\n// =============================================================================\n// FIELD CANONICALIZATION\n// =============================================================================\n\n/**\n * Dispatches a field element to its type-specific canonicalization function.\n */\nfunction canonicalizeField(\n field: AnyField,\n metadataPolicy: ReturnType<typeof normalizeMetadataPolicy>\n): FieldNode {\n switch (field._field) {\n case \"text\":\n return canonicalizeTextField(field, metadataPolicy);\n case \"number\":\n return canonicalizeNumberField(field, metadataPolicy);\n case \"boolean\":\n return canonicalizeBooleanField(field, metadataPolicy);\n case \"enum\":\n return canonicalizeStaticEnumField(field, metadataPolicy);\n case \"dynamic_enum\":\n return canonicalizeDynamicEnumField(field, metadataPolicy);\n case \"dynamic_schema\":\n return canonicalizeDynamicSchemaField(field, metadataPolicy);\n case \"array\":\n return canonicalizeArrayField(field, metadataPolicy);\n case \"object\":\n return canonicalizeObjectField(field, metadataPolicy);\n default: {\n const _exhaustive: never = field;\n throw new Error(`Unknown field type: ${JSON.stringify(_exhaustive)}`);\n }\n }\n}\n\n// =============================================================================\n// SPECIFIC FIELD TYPE CANONICALIZERS\n// =============================================================================\n\nfunction canonicalizeTextField(\n field: TextField<string>,\n metadataPolicy: ReturnType<typeof normalizeMetadataPolicy>\n): FieldNode {\n const type: PrimitiveTypeNode = { kind: \"primitive\", primitiveKind: \"string\" };\n const constraints: ConstraintNode[] = [];\n\n if (field.minLength !== undefined) {\n const c: LengthConstraintNode = {\n kind: \"constraint\",\n constraintKind: \"minLength\",\n value: field.minLength,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n constraints.push(c);\n }\n\n if (field.maxLength !== undefined) {\n const c: LengthConstraintNode = {\n kind: \"constraint\",\n constraintKind: \"maxLength\",\n value: field.maxLength,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n constraints.push(c);\n }\n\n if (field.pattern !== undefined) {\n const c: PatternConstraintNode = {\n kind: \"constraint\",\n constraintKind: \"pattern\",\n pattern: field.pattern,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n constraints.push(c);\n }\n\n return buildFieldNode(\n field.name,\n resolveFieldMetadata(field.name, field, metadataPolicy),\n type,\n field.required,\n buildAnnotations(getExplicitDisplayName(field), field.placeholder),\n constraints\n );\n}\n\nfunction canonicalizeNumberField(\n field: NumberField<string>,\n metadataPolicy: ReturnType<typeof normalizeMetadataPolicy>\n): FieldNode {\n const type: PrimitiveTypeNode = { kind: \"primitive\", primitiveKind: \"number\" };\n const constraints: ConstraintNode[] = [];\n\n if (field.min !== undefined) {\n const c: NumericConstraintNode = {\n kind: \"constraint\",\n constraintKind: \"minimum\",\n value: field.min,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n constraints.push(c);\n }\n\n if (field.max !== undefined) {\n const c: NumericConstraintNode = {\n kind: \"constraint\",\n constraintKind: \"maximum\",\n value: field.max,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n constraints.push(c);\n }\n\n if (field.multipleOf !== undefined) {\n const c: NumericConstraintNode = {\n kind: \"constraint\",\n constraintKind: \"multipleOf\",\n value: field.multipleOf,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n constraints.push(c);\n }\n\n return buildFieldNode(\n field.name,\n resolveFieldMetadata(field.name, field, metadataPolicy),\n type,\n field.required,\n buildAnnotations(getExplicitDisplayName(field)),\n constraints\n );\n}\n\nfunction canonicalizeBooleanField(\n field: BooleanField<string>,\n metadataPolicy: ReturnType<typeof normalizeMetadataPolicy>\n): FieldNode {\n const type: PrimitiveTypeNode = { kind: \"primitive\", primitiveKind: \"boolean\" };\n return buildFieldNode(\n field.name,\n resolveFieldMetadata(field.name, field, metadataPolicy),\n type,\n field.required,\n buildAnnotations(getExplicitDisplayName(field))\n );\n}\n\nfunction canonicalizeStaticEnumField(\n field: StaticEnumField<string, readonly EnumOptionValue[]>,\n metadataPolicy: ReturnType<typeof normalizeMetadataPolicy>\n): FieldNode {\n const members: EnumMember[] = field.options.map((opt) => {\n if (typeof opt === \"string\") {\n return { value: opt } satisfies EnumMember;\n }\n // Object option with id/label\n return { value: opt.id, displayName: opt.label } satisfies EnumMember;\n });\n\n const type: EnumTypeNode = { kind: \"enum\", members };\n return buildFieldNode(\n field.name,\n resolveFieldMetadata(field.name, field, metadataPolicy),\n type,\n field.required,\n buildAnnotations(getExplicitDisplayName(field))\n );\n}\n\nfunction canonicalizeDynamicEnumField(\n field: DynamicEnumField<string, string>,\n metadataPolicy: ReturnType<typeof normalizeMetadataPolicy>\n): FieldNode {\n const type: DynamicTypeNode = {\n kind: \"dynamic\",\n dynamicKind: \"enum\",\n sourceKey: field.source,\n parameterFields: field.params ? [...field.params] : [],\n };\n return buildFieldNode(\n field.name,\n resolveFieldMetadata(field.name, field, metadataPolicy),\n type,\n field.required,\n buildAnnotations(getExplicitDisplayName(field))\n );\n}\n\nfunction canonicalizeDynamicSchemaField(\n field: DynamicSchemaField<string>,\n metadataPolicy: ReturnType<typeof normalizeMetadataPolicy>\n): FieldNode {\n const type: DynamicTypeNode = {\n kind: \"dynamic\",\n dynamicKind: \"schema\",\n sourceKey: field.schemaSource,\n parameterFields: [],\n };\n return buildFieldNode(\n field.name,\n resolveFieldMetadata(field.name, field, metadataPolicy),\n type,\n field.required,\n buildAnnotations(getExplicitDisplayName(field))\n );\n}\n\nfunction canonicalizeArrayField(\n field: ArrayField<string, readonly FormElement[]>,\n metadataPolicy: ReturnType<typeof normalizeMetadataPolicy>\n): FieldNode {\n // Array items form an object type from the sub-elements\n const itemProperties = buildObjectProperties(field.items, metadataPolicy);\n const itemsType: ObjectTypeNode = {\n kind: \"object\",\n properties: itemProperties,\n additionalProperties: true,\n };\n const type: ArrayTypeNode = { kind: \"array\", items: itemsType };\n\n const constraints: ConstraintNode[] = [];\n if (field.minItems !== undefined) {\n const c: LengthConstraintNode = {\n kind: \"constraint\",\n constraintKind: \"minItems\",\n value: field.minItems,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n constraints.push(c);\n }\n if (field.maxItems !== undefined) {\n const c: LengthConstraintNode = {\n kind: \"constraint\",\n constraintKind: \"maxItems\",\n value: field.maxItems,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n constraints.push(c);\n }\n\n return buildFieldNode(\n field.name,\n resolveFieldMetadata(field.name, field, metadataPolicy),\n type,\n field.required,\n buildAnnotations(getExplicitDisplayName(field)),\n constraints\n );\n}\n\nfunction canonicalizeObjectField(\n field: ObjectField<string, readonly FormElement[]>,\n metadataPolicy: ReturnType<typeof normalizeMetadataPolicy>\n): FieldNode {\n const properties = buildObjectProperties(field.properties, metadataPolicy);\n const type: ObjectTypeNode = {\n kind: \"object\",\n properties,\n additionalProperties: true,\n };\n return buildFieldNode(\n field.name,\n resolveFieldMetadata(field.name, field, metadataPolicy),\n type,\n field.required,\n buildAnnotations(getExplicitDisplayName(field))\n );\n}\n\n// =============================================================================\n// LAYOUT CANONICALIZATION\n// =============================================================================\n\nfunction canonicalizeGroup(\n g: Group<readonly FormElement[]>,\n metadataPolicy: ReturnType<typeof normalizeMetadataPolicy>\n): GroupLayoutNode {\n return {\n kind: \"group\",\n label: g.label,\n elements: canonicalizeElements(g.elements, metadataPolicy),\n provenance: CHAIN_DSL_PROVENANCE,\n };\n}\n\nfunction canonicalizeConditional(\n c: Conditional<string, unknown, readonly FormElement[]>,\n metadataPolicy: ReturnType<typeof normalizeMetadataPolicy>\n): ConditionalLayoutNode {\n return {\n kind: \"conditional\",\n fieldName: c.field,\n // Conditional values from the chain DSL are JSON-serializable primitives\n // (strings, numbers, booleans) produced by the `is()` predicate helper.\n value: assertJsonValue(c.value),\n elements: canonicalizeElements(c.elements, metadataPolicy),\n provenance: CHAIN_DSL_PROVENANCE,\n };\n}\n\n// =============================================================================\n// HELPERS\n// =============================================================================\n\n/**\n * Validates that a value is JSON-serializable (`JsonValue`).\n * The chain DSL's `is()` helper constrains conditional values to\n * JSON-compatible primitives, but the TypeScript type is `unknown`.\n * This runtime guard replaces an `as` cast with a validated assertion.\n */\nfunction assertJsonValue(v: unknown): JsonValue {\n if (v === null || typeof v === \"string\" || typeof v === \"number\" || typeof v === \"boolean\") {\n return v;\n }\n if (Array.isArray(v)) {\n return v.map(assertJsonValue);\n }\n if (typeof v === \"object\") {\n const result: Record<string, JsonValue> = {};\n for (const [key, val] of Object.entries(v)) {\n result[key] = assertJsonValue(val);\n }\n return result;\n }\n // Remaining types (function, symbol, bigint, undefined) are not JSON-serializable\n throw new TypeError(`Conditional value is not a valid JsonValue: ${typeof v}`);\n}\n\n/**\n * Builds a FieldNode from common field properties.\n */\nfunction buildFieldNode(\n name: string,\n metadata: ResolvedMetadata | undefined,\n type: TypeNode,\n required: boolean | undefined,\n annotations: AnnotationNode[],\n constraints: ConstraintNode[] = []\n): FieldNode {\n return {\n kind: \"field\",\n name,\n ...(metadata !== undefined && { metadata }),\n type,\n required: required === true,\n constraints,\n annotations,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n}\n\n/**\n * Builds annotation nodes from optional label and placeholder values.\n */\nfunction buildAnnotations(label?: string, placeholder?: string): AnnotationNode[] {\n const annotations: AnnotationNode[] = [];\n\n if (label !== undefined) {\n const a: DisplayNameAnnotationNode = {\n kind: \"annotation\",\n annotationKind: \"displayName\",\n value: label,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n annotations.push(a);\n }\n\n if (placeholder !== undefined) {\n const a: PlaceholderAnnotationNode = {\n kind: \"annotation\",\n annotationKind: \"placeholder\",\n value: placeholder,\n provenance: CHAIN_DSL_PROVENANCE,\n };\n annotations.push(a);\n }\n\n return annotations;\n}\n\n/**\n * Converts an array of form elements into ObjectProperty nodes.\n * Used for ObjectField properties and ArrayField items.\n *\n * Only field elements produce properties; groups and conditionals within\n * an object/array context are recursively flattened to extract their fields.\n *\n * Fields inside conditional branches are always marked `optional: true`\n * because their presence in the data depends on the condition being met.\n * This matches the DSL's type inference behavior where conditional fields\n * produce optional properties in `InferFormSchema`.\n *\n * @param elements - The form elements to convert\n * @param insideConditional - Whether these elements are inside a conditional branch\n */\nfunction buildObjectProperties(\n elements: readonly FormElement[],\n metadataPolicy: ReturnType<typeof normalizeMetadataPolicy>,\n insideConditional = false\n): ObjectProperty[] {\n const properties: ObjectProperty[] = [];\n\n for (const el of elements) {\n if (isField(el)) {\n const fieldNode = canonicalizeField(el, metadataPolicy);\n properties.push({\n name: fieldNode.name,\n ...(fieldNode.metadata !== undefined && { metadata: fieldNode.metadata }),\n type: fieldNode.type,\n // Fields inside a conditional branch are always optional in the\n // data schema, regardless of their `required` flag — the condition\n // may not be met, so the field may be absent.\n optional: insideConditional || !fieldNode.required,\n constraints: fieldNode.constraints,\n annotations: fieldNode.annotations,\n provenance: CHAIN_DSL_PROVENANCE,\n });\n } else if (isGroup(el)) {\n // Groups inside object/array items contribute their fields by flattening.\n // Groups do not affect optionality — pass through the current state.\n properties.push(...buildObjectProperties(el.elements, metadataPolicy, insideConditional));\n } else if (isConditional(el)) {\n // Conditionals inside object/array items contribute their fields by\n // flattening, but all fields inside are forced optional.\n properties.push(...buildObjectProperties(el.elements, metadataPolicy, true));\n }\n }\n\n return properties;\n}\n\nfunction getExplicitDisplayName(field: {\n readonly label?: string;\n readonly displayName?: string;\n}): string | undefined {\n if (field.label !== undefined && field.displayName !== undefined) {\n throw new Error('Chain DSL fields cannot specify both \"label\" and \"displayName\".');\n }\n return field.displayName ?? field.label;\n}\n\nfunction resolveFieldMetadata(\n logicalName: string,\n field: {\n readonly apiName?: string;\n readonly label?: string;\n readonly displayName?: string;\n },\n metadataPolicy: ReturnType<typeof normalizeMetadataPolicy>\n): ResolvedMetadata | undefined {\n const displayName = getExplicitDisplayName(field);\n return resolveMetadata(\n {\n ...(field.apiName !== undefined && { apiName: field.apiName }),\n ...(displayName !== undefined && { displayName }),\n },\n getDeclarationMetadataPolicy(metadataPolicy, \"field\"),\n makeMetadataContext(\"chain-dsl\", \"field\", logicalName)\n );\n}\n","import type {\n MetadataAuthoringSurface,\n MetadataDeclarationKind,\n MetadataInferenceContext,\n MetadataPluralizationFn,\n MetadataPluralizationPolicyInput,\n MetadataPolicyInput,\n MetadataValuePolicyInput,\n NormalizedDeclarationMetadataPolicy,\n NormalizedMetadataPolicy,\n NormalizedMetadataPluralizationPolicy,\n NormalizedMetadataValuePolicy,\n} from \"@formspec/core/internals\";\nexport type {\n NormalizedDeclarationMetadataPolicy,\n NormalizedMetadataPolicy,\n NormalizedMetadataPluralizationPolicy as NormalizedPluralizationPolicy,\n} from \"@formspec/core/internals\";\n\nexport type MetadataResolutionContext = MetadataInferenceContext;\nexport type NormalizedMetadataScalarPolicy = NormalizedMetadataValuePolicy;\n\nexport function defaultApiNameInference(\n _context: MetadataResolutionContext\n): string {\n return \"\";\n}\n\nexport function defaultDisplayNameInference(\n _context: MetadataResolutionContext\n): string {\n return \"\";\n}\n\nconst NOOP_INFLECT: MetadataPluralizationFn = () => \"\";\n\nfunction normalizePluralization(\n input: MetadataPluralizationPolicyInput | undefined\n): NormalizedMetadataPluralizationPolicy {\n if (input?.mode === \"infer-if-missing\") {\n return {\n mode: \"infer-if-missing\",\n infer: () => \"\",\n inflect: input.inflect,\n };\n }\n\n if (input?.mode === \"require-explicit\") {\n return {\n mode: \"require-explicit\",\n infer: () => \"\",\n inflect: NOOP_INFLECT,\n };\n }\n\n return {\n mode: \"disabled\",\n infer: () => \"\",\n inflect: NOOP_INFLECT,\n };\n}\n\nfunction normalizeScalarPolicy(\n input: MetadataValuePolicyInput | undefined\n): NormalizedMetadataValuePolicy {\n if (input?.mode === \"infer-if-missing\") {\n return {\n mode: \"infer-if-missing\",\n infer: input.infer,\n pluralization: normalizePluralization(input.pluralization),\n };\n }\n\n if (input?.mode === \"require-explicit\") {\n return {\n mode: \"require-explicit\",\n infer: () => \"\",\n pluralization: normalizePluralization(input.pluralization),\n };\n }\n\n return {\n mode: \"disabled\",\n infer: () => \"\",\n pluralization: normalizePluralization(input?.pluralization),\n };\n}\n\nfunction normalizeDeclarationPolicy(\n input: MetadataPolicyInput[MetadataDeclarationKind] | undefined\n): NormalizedDeclarationMetadataPolicy {\n return {\n apiName: normalizeScalarPolicy(input?.apiName),\n displayName: normalizeScalarPolicy(input?.displayName),\n };\n}\n\nexport function normalizeMetadataPolicy(\n input?: MetadataPolicyInput\n): NormalizedMetadataPolicy {\n return {\n type: normalizeDeclarationPolicy(input?.type),\n field: normalizeDeclarationPolicy(input?.field),\n method: normalizeDeclarationPolicy(input?.method),\n };\n}\n\nexport function getDeclarationMetadataPolicy(\n policy: NormalizedMetadataPolicy,\n declarationKind: MetadataDeclarationKind\n): NormalizedDeclarationMetadataPolicy {\n return policy[declarationKind];\n}\n\nexport function makeMetadataContext(\n surface: MetadataAuthoringSurface,\n declarationKind: MetadataDeclarationKind,\n logicalName: string,\n buildContext?: unknown\n): MetadataResolutionContext {\n return {\n surface,\n declarationKind,\n logicalName,\n ...(buildContext !== undefined && { buildContext }),\n };\n}\n\nexport function getDefaultMetadataPolicy(): NormalizedMetadataPolicy {\n return normalizeMetadataPolicy(undefined);\n}\n","import type {\n FieldNode,\n FormIR,\n FormIRElement,\n MetadataAuthoringSurface,\n ObjectProperty,\n ResolvedMetadata,\n ResolvedScalarMetadata,\n TypeDefinition,\n TypeNode,\n} from \"@formspec/core/internals\";\nimport type {\n MetadataResolutionContext,\n NormalizedDeclarationMetadataPolicy,\n NormalizedMetadataPolicy,\n} from \"./policy.js\";\n\nexport interface ExplicitMetadataInput {\n readonly apiName?: string;\n readonly displayName?: string;\n readonly apiNamePlural?: string;\n readonly displayNamePlural?: string;\n}\n\nexport interface ResolveFormIRMetadataOptions {\n readonly policy: NormalizedMetadataPolicy;\n readonly surface: MetadataAuthoringSurface;\n readonly buildContext?: unknown;\n readonly rootLogicalName?: string;\n}\n\nfunction toExplicitScalar(value: string | undefined): ResolvedScalarMetadata | undefined {\n return value !== undefined && value.trim() !== \"\" ? { value, source: \"explicit\" } : undefined;\n}\n\nfunction toExplicitResolvedMetadata(\n explicit: ExplicitMetadataInput | undefined\n): ResolvedMetadata | undefined {\n if (explicit === undefined) {\n return undefined;\n }\n\n const apiName = toExplicitScalar(explicit.apiName);\n const displayName = toExplicitScalar(explicit.displayName);\n const apiNamePlural = toExplicitScalar(explicit.apiNamePlural);\n const displayNamePlural = toExplicitScalar(explicit.displayNamePlural);\n const metadata: ResolvedMetadata = {\n ...(apiName !== undefined && { apiName }),\n ...(displayName !== undefined && { displayName }),\n ...(apiNamePlural !== undefined && { apiNamePlural }),\n ...(displayNamePlural !== undefined && { displayNamePlural }),\n };\n\n return Object.keys(metadata).length > 0 ? metadata : undefined;\n}\n\nfunction resolveScalar(\n current: ResolvedScalarMetadata | undefined,\n policy: NormalizedDeclarationMetadataPolicy[\"apiName\"],\n context: MetadataResolutionContext,\n metadataLabel: \"apiName\" | \"displayName\"\n): ResolvedScalarMetadata | undefined {\n if (current !== undefined) {\n return current;\n }\n\n if (policy.mode === \"require-explicit\") {\n throw new Error(\n `Metadata policy requires explicit ${metadataLabel} for ${context.declarationKind} \"${context.logicalName}\" on the ${context.surface} surface.`\n );\n }\n\n if (policy.mode !== \"infer-if-missing\") {\n return undefined;\n }\n\n const inferredValue = policy.infer(context);\n return inferredValue.trim() !== \"\"\n ? { value: inferredValue, source: \"inferred\" }\n : undefined;\n}\n\nfunction resolvePlural(\n current: ResolvedScalarMetadata | undefined,\n singular: ResolvedScalarMetadata | undefined,\n policy: NormalizedDeclarationMetadataPolicy[\"apiName\"][\"pluralization\"],\n context: MetadataResolutionContext,\n metadataLabel: \"apiNamePlural\" | \"displayNamePlural\"\n): ResolvedScalarMetadata | undefined {\n if (current !== undefined) {\n return current;\n }\n\n if (policy.mode === \"require-explicit\") {\n throw new Error(\n `Metadata policy requires explicit ${metadataLabel} for ${context.declarationKind} \"${context.logicalName}\" on the ${context.surface} surface.`\n );\n }\n\n if (singular === undefined || policy.mode !== \"infer-if-missing\") {\n return undefined;\n }\n\n const pluralValue = policy.inflect({ ...context, singular: singular.value });\n return pluralValue.trim() !== \"\"\n ? { value: pluralValue, source: \"inferred\" }\n : undefined;\n}\n\nfunction resolveResolvedMetadata(\n current: ResolvedMetadata | undefined,\n policy: NormalizedDeclarationMetadataPolicy,\n context: MetadataResolutionContext\n): ResolvedMetadata | undefined {\n const apiName = resolveScalar(current?.apiName, policy.apiName, context, \"apiName\");\n const displayName = resolveScalar(\n current?.displayName,\n policy.displayName,\n context,\n \"displayName\"\n );\n const apiNamePlural = resolvePlural(\n current?.apiNamePlural,\n apiName,\n policy.apiName.pluralization,\n context,\n \"apiNamePlural\"\n );\n const displayNamePlural = resolvePlural(\n current?.displayNamePlural,\n displayName,\n policy.displayName.pluralization,\n context,\n \"displayNamePlural\"\n );\n\n if (\n apiName === undefined &&\n displayName === undefined &&\n apiNamePlural === undefined &&\n displayNamePlural === undefined\n ) {\n return undefined;\n }\n\n return {\n ...(apiName !== undefined && { apiName }),\n ...(displayName !== undefined && { displayName }),\n ...(apiNamePlural !== undefined && { apiNamePlural }),\n ...(displayNamePlural !== undefined && { displayNamePlural }),\n };\n}\n\nfunction pickResolvedMetadataValue(\n baseValue: ResolvedScalarMetadata | undefined,\n overlayValue: ResolvedScalarMetadata | undefined\n): ResolvedScalarMetadata | undefined {\n if (overlayValue?.source === \"explicit\") {\n return overlayValue;\n }\n if (baseValue?.source === \"explicit\") {\n return baseValue;\n }\n return baseValue ?? overlayValue;\n}\n\nfunction resolveTypeNodeMetadata(\n type: TypeNode,\n options: ResolveFormIRMetadataOptions\n): TypeNode {\n switch (type.kind) {\n case \"array\":\n return {\n ...type,\n items: resolveTypeNodeMetadata(type.items, options),\n };\n\n case \"object\":\n return {\n ...type,\n properties: type.properties.map((property) => resolveObjectPropertyMetadata(property, options)),\n };\n\n case \"record\":\n return {\n ...type,\n valueType: resolveTypeNodeMetadata(type.valueType, options),\n };\n\n case \"union\":\n return {\n ...type,\n members: type.members.map((member) => resolveTypeNodeMetadata(member, options)),\n };\n\n case \"reference\":\n case \"primitive\":\n case \"enum\":\n case \"dynamic\":\n case \"custom\":\n return type;\n\n default: {\n const _exhaustive: never = type;\n return _exhaustive;\n }\n }\n}\n\nfunction resolveObjectPropertyMetadata(\n property: ObjectProperty,\n options: ResolveFormIRMetadataOptions\n): ObjectProperty {\n const metadata = resolveResolvedMetadata(property.metadata, options.policy.field, {\n surface: options.surface,\n declarationKind: \"field\",\n logicalName: property.name,\n ...(options.buildContext !== undefined && { buildContext: options.buildContext }),\n });\n return {\n ...property,\n ...(metadata !== undefined && { metadata }),\n type: resolveTypeNodeMetadata(property.type, options),\n };\n}\n\nfunction resolveFieldMetadataNode(\n field: FieldNode,\n options: ResolveFormIRMetadataOptions\n): FieldNode {\n const metadata = resolveResolvedMetadata(field.metadata, options.policy.field, {\n surface: options.surface,\n declarationKind: \"field\",\n logicalName: field.name,\n ...(options.buildContext !== undefined && { buildContext: options.buildContext }),\n });\n return {\n ...field,\n ...(metadata !== undefined && { metadata }),\n type: resolveTypeNodeMetadata(field.type, options),\n };\n}\n\nfunction resolveFormElementMetadata(\n element: FormIRElement,\n options: ResolveFormIRMetadataOptions\n): FormIRElement {\n switch (element.kind) {\n case \"field\":\n return resolveFieldMetadataNode(element, options);\n\n case \"group\":\n return {\n ...element,\n elements: element.elements.map((child) => resolveFormElementMetadata(child, options)),\n };\n\n case \"conditional\":\n return {\n ...element,\n elements: element.elements.map((child) => resolveFormElementMetadata(child, options)),\n };\n\n default: {\n const _exhaustive: never = element;\n return _exhaustive;\n }\n }\n}\n\nfunction resolveTypeDefinitionMetadata(\n typeDefinition: TypeDefinition,\n options: ResolveFormIRMetadataOptions\n): TypeDefinition {\n const metadata = resolveResolvedMetadata(typeDefinition.metadata, options.policy.type, {\n surface: options.surface,\n declarationKind: \"type\",\n logicalName: typeDefinition.name,\n ...(options.buildContext !== undefined && { buildContext: options.buildContext }),\n });\n return {\n ...typeDefinition,\n ...(metadata !== undefined && { metadata }),\n type: resolveTypeNodeMetadata(typeDefinition.type, options),\n };\n}\n\nexport function resolveMetadata(\n explicit: ExplicitMetadataInput | undefined,\n policy: NormalizedDeclarationMetadataPolicy,\n context: MetadataResolutionContext\n): ResolvedMetadata | undefined {\n return resolveResolvedMetadata(toExplicitResolvedMetadata(explicit), policy, context);\n}\n\nexport function mergeResolvedMetadata(\n baseMetadata: ResolvedMetadata | undefined,\n overlayMetadata: ResolvedMetadata | undefined\n): ResolvedMetadata | undefined {\n const apiName = pickResolvedMetadataValue(baseMetadata?.apiName, overlayMetadata?.apiName);\n const displayName = pickResolvedMetadataValue(\n baseMetadata?.displayName,\n overlayMetadata?.displayName\n );\n const apiNamePlural = pickResolvedMetadataValue(\n baseMetadata?.apiNamePlural,\n overlayMetadata?.apiNamePlural\n );\n const displayNamePlural = pickResolvedMetadataValue(\n baseMetadata?.displayNamePlural,\n overlayMetadata?.displayNamePlural\n );\n\n if (\n apiName === undefined &&\n displayName === undefined &&\n apiNamePlural === undefined &&\n displayNamePlural === undefined\n ) {\n return undefined;\n }\n\n return {\n ...(apiName !== undefined && { apiName }),\n ...(displayName !== undefined && { displayName }),\n ...(apiNamePlural !== undefined && { apiNamePlural }),\n ...(displayNamePlural !== undefined && { displayNamePlural }),\n };\n}\n\nexport function getSerializedName(\n logicalName: string,\n metadata: ResolvedMetadata | undefined\n): string {\n return metadata?.apiName?.value ?? logicalName;\n}\n\nexport function getDisplayName(metadata: ResolvedMetadata | undefined): string | undefined {\n return metadata?.displayName?.value;\n}\n\nexport function resolveFormIRMetadata(\n ir: FormIR,\n options: ResolveFormIRMetadataOptions\n): FormIR {\n const rootLogicalName = options.rootLogicalName ?? ir.name ?? \"FormSpec\";\n const metadata = resolveResolvedMetadata(ir.metadata, options.policy.type, {\n surface: options.surface,\n declarationKind: \"type\",\n logicalName: rootLogicalName,\n ...(options.buildContext !== undefined && { buildContext: options.buildContext }),\n });\n\n return {\n ...ir,\n ...(metadata !== undefined && { metadata }),\n elements: ir.elements.map((element) => resolveFormElementMetadata(element, options)),\n typeRegistry: Object.fromEntries(\n Object.entries(ir.typeRegistry).map(([name, definition]) => [\n name,\n resolveTypeDefinitionMetadata(definition, options),\n ])\n ),\n };\n}\n","/**\n * TSDoc canonicalizer — assembles an {@link IRClassAnalysis} into a canonical\n * {@link FormIR}, applying layout metadata from `@Group` and `@ShowWhen`\n * TSDoc tags.\n *\n * The analysis functions in `class-analyzer.ts` produce `FieldNode[]`,\n * `fieldLayouts`, and `typeRegistry` directly. This canonicalizer uses\n * the layout metadata to wrap fields in `GroupLayoutNode` and\n * `ConditionalLayoutNode` elements.\n */\n\nimport type {\n FormIR,\n FormIRElement,\n FieldNode,\n GroupLayoutNode,\n ConditionalLayoutNode,\n Provenance,\n} from \"@formspec/core/internals\";\nimport { IR_VERSION } from \"@formspec/core/internals\";\nimport type { IRClassAnalysis, FieldLayoutMetadata } from \"../analyzer/class-analyzer.js\";\nimport { normalizeMetadataPolicy, resolveFormIRMetadata } from \"../metadata/index.js\";\nimport type { MetadataPolicyInput } from \"@formspec/core\";\n\n/**\n * Source-level metadata for provenance tracking.\n */\nexport interface TSDocSource {\n /** Absolute path to the source file. */\n readonly file: string;\n}\n\nexport interface CanonicalizeTSDocOptions {\n readonly metadata?: MetadataPolicyInput;\n}\n\n/**\n * Wraps an {@link IRClassAnalysis} (from `analyzeClassToIR`,\n * `analyzeInterfaceToIR`, or `analyzeTypeAliasToIR`) into a canonical\n * {@link FormIR}.\n *\n * Fields with `@Group` TSDoc tags are grouped into `GroupLayoutNode` elements.\n * Fields with `@ShowWhen` TSDoc tags are wrapped in `ConditionalLayoutNode` elements.\n * When both are present, the conditional wraps the field inside the group.\n *\n * @param analysis - IR analysis result (fields are already FieldNode[])\n * @param source - Optional source file metadata for provenance\n * @returns The canonical FormIR\n */\nexport function canonicalizeTSDoc(\n analysis: IRClassAnalysis,\n source?: TSDocSource,\n options?: CanonicalizeTSDocOptions\n): FormIR {\n const file = source?.file ?? \"\";\n\n const provenance: Provenance = {\n surface: \"tsdoc\",\n file,\n line: 1,\n column: 0,\n };\n\n const elements = assembleElements(analysis.fields, analysis.fieldLayouts, provenance);\n\n const ir: FormIR = {\n kind: \"form-ir\",\n name: analysis.name,\n irVersion: IR_VERSION,\n elements,\n ...(analysis.metadata !== undefined && { metadata: analysis.metadata }),\n typeRegistry: analysis.typeRegistry,\n ...(analysis.annotations !== undefined &&\n analysis.annotations.length > 0 && { rootAnnotations: analysis.annotations }),\n ...(analysis.annotations !== undefined &&\n analysis.annotations.length > 0 && { annotations: analysis.annotations }),\n provenance,\n };\n\n return resolveFormIRMetadata(ir, {\n policy: normalizeMetadataPolicy(options?.metadata),\n surface: \"tsdoc\",\n });\n}\n\n/**\n * Assembles flat fields and their layout metadata into a tree of\n * `FormIRElement[]` with groups and conditionals.\n *\n * Fields are processed in order. Consecutive fields with the same\n * `@Group` label are collected into a single `GroupLayoutNode`.\n * Fields with `@ShowWhen` are wrapped in `ConditionalLayoutNode`.\n */\nfunction assembleElements(\n fields: readonly FieldNode[],\n layouts: readonly FieldLayoutMetadata[],\n provenance: Provenance\n): readonly FormIRElement[] {\n const elements: FormIRElement[] = [];\n\n // Group consecutive fields with the same group label together.\n // We use an ordered map to preserve insertion order of groups.\n const groupMap = new Map<string, FormIRElement[]>();\n const topLevelOrder: (\n | { type: \"group\"; label: string }\n | { type: \"element\"; element: FormIRElement }\n )[] = [];\n\n for (let i = 0; i < fields.length; i++) {\n const field = fields[i];\n const layout = layouts[i];\n if (!field || !layout) continue;\n\n // Wrap in conditional if @ShowWhen is present\n const element = wrapInConditional(field, layout, provenance);\n\n if (layout.groupLabel !== undefined) {\n const label = layout.groupLabel;\n let groupElements = groupMap.get(label);\n if (!groupElements) {\n groupElements = [];\n groupMap.set(label, groupElements);\n topLevelOrder.push({ type: \"group\", label });\n }\n groupElements.push(element);\n } else {\n topLevelOrder.push({ type: \"element\", element });\n }\n }\n\n // Assemble the final element array in order\n for (const entry of topLevelOrder) {\n if (entry.type === \"group\") {\n const groupElements = groupMap.get(entry.label);\n if (groupElements) {\n const groupNode: GroupLayoutNode = {\n kind: \"group\",\n label: entry.label,\n elements: groupElements,\n provenance,\n };\n elements.push(groupNode);\n // Clear so duplicate group labels in topLevelOrder don't re-emit\n groupMap.delete(entry.label);\n }\n } else {\n elements.push(entry.element);\n }\n }\n\n return elements;\n}\n\n/**\n * Wraps a field in a `ConditionalLayoutNode` if the layout has `showWhen` metadata.\n */\nfunction wrapInConditional(\n field: FieldNode,\n layout: FieldLayoutMetadata,\n provenance: Provenance\n): FormIRElement {\n if (layout.showWhen === undefined) {\n return field;\n }\n\n const conditional: ConditionalLayoutNode = {\n kind: \"conditional\",\n fieldName: layout.showWhen.field,\n value: layout.showWhen.value,\n elements: [field],\n provenance,\n };\n\n return conditional;\n}\n","import type {\n FieldNode,\n FormIR,\n FormIRElement,\n ObjectProperty,\n TypeDefinition,\n TypeNode,\n} from \"@formspec/core/internals\";\nimport { getSerializedName } from \"./resolve.js\";\n\ninterface SerializedNameEntry {\n readonly logicalName: string;\n readonly serializedName: string;\n readonly category: \"field\" | \"object property\" | \"type definition\";\n}\n\nfunction assertUniqueSerializedNames(\n entries: readonly SerializedNameEntry[],\n scope: string\n): void {\n const seen = new Map<string, SerializedNameEntry>();\n\n for (const entry of entries) {\n const previous = seen.get(entry.serializedName);\n if (previous !== undefined) {\n if (\n previous.logicalName === entry.logicalName &&\n previous.category === entry.category\n ) {\n continue;\n }\n throw new Error(\n `Serialized name collision in ${scope}: ${previous.category} \"${previous.logicalName}\" and ${entry.category} \"${entry.logicalName}\" both resolve to \"${entry.serializedName}\".`\n );\n }\n seen.set(entry.serializedName, entry);\n }\n}\n\nfunction collectFlattenedFields(elements: readonly FormIRElement[]): FieldNode[] {\n const fields: FieldNode[] = [];\n\n for (const element of elements) {\n switch (element.kind) {\n case \"field\":\n fields.push(element);\n break;\n case \"group\":\n case \"conditional\":\n fields.push(...collectFlattenedFields(element.elements));\n break;\n default: {\n const exhaustive: never = element;\n void exhaustive;\n }\n }\n }\n\n return fields;\n}\n\nfunction validateObjectProperties(properties: readonly ObjectProperty[], scope: string): void {\n assertUniqueSerializedNames(\n properties.map((property) => ({\n logicalName: property.name,\n serializedName: getSerializedName(property.name, property.metadata),\n category: \"object property\" as const,\n })),\n scope\n );\n\n for (const property of properties) {\n validateTypeNode(\n property.type,\n `${scope}.${getSerializedName(property.name, property.metadata)}`\n );\n }\n}\n\nfunction validateTypeNode(type: TypeNode, scope: string): void {\n switch (type.kind) {\n case \"array\":\n validateTypeNode(type.items, `${scope}[]`);\n break;\n case \"object\":\n validateObjectProperties(type.properties, scope);\n break;\n case \"record\":\n validateTypeNode(type.valueType, `${scope}.*`);\n break;\n case \"union\":\n type.members.forEach((member, index) => {\n validateTypeNode(member, `${scope}|${String(index)}`);\n });\n break;\n case \"reference\":\n case \"primitive\":\n case \"enum\":\n case \"dynamic\":\n case \"custom\":\n break;\n default: {\n const exhaustive: never = type;\n void exhaustive;\n }\n }\n}\n\nfunction validateTypeDefinitions(typeRegistry: FormIR[\"typeRegistry\"]): void {\n const definitions = Object.values(typeRegistry);\n assertUniqueSerializedNames(\n definitions.map((definition) => ({\n logicalName: definition.name,\n serializedName: getSerializedName(definition.name, definition.metadata),\n category: \"type definition\" as const,\n })),\n \"$defs\"\n );\n\n for (const definition of definitions) {\n validateTypeDefinition(definition);\n }\n}\n\nfunction validateTypeDefinition(definition: TypeDefinition): void {\n validateTypeNode(\n definition.type,\n `type \"${getSerializedName(definition.name, definition.metadata)}\"`\n );\n}\n\nexport function assertNoSerializedNameCollisions(ir: FormIR): void {\n assertUniqueSerializedNames(\n collectFlattenedFields(ir.elements).map((field) => ({\n logicalName: field.name,\n serializedName: getSerializedName(field.name, field.metadata),\n category: \"field\" as const,\n })),\n \"form root\"\n );\n\n for (const field of collectFlattenedFields(ir.elements)) {\n validateTypeNode(field.type, `field \"${getSerializedName(field.name, field.metadata)}\"`);\n }\n\n validateTypeDefinitions(ir.typeRegistry);\n}\n","/**\n * JSON Schema 2020-12 generator that consumes the canonical FormIR.\n *\n * This generator is a pure function of the IR. It never consults the TypeScript\n * AST or surface syntax directly — only the IR (per the JSON Schema vocabulary spec §1.2).\n *\n * @see https://json-schema.org/draft/2020-12/schema\n * @see https://json-schema.org/draft/2020-12/schema\n */\n\nimport type {\n FormIR,\n FormIRElement,\n FieldNode,\n TypeNode,\n PrimitiveTypeNode,\n EnumTypeNode,\n ArrayTypeNode,\n ObjectTypeNode,\n RecordTypeNode,\n UnionTypeNode,\n ReferenceTypeNode,\n DynamicTypeNode,\n CustomTypeNode,\n ConstraintNode,\n AnnotationNode,\n ObjectProperty,\n} from \"@formspec/core/internals\";\nimport type { ResolvedMetadata } from \"@formspec/core\";\nimport type { ExtensionRegistry } from \"../extensions/index.js\";\nimport { getDisplayName, getSerializedName } from \"../metadata/index.js\";\nimport { assertNoSerializedNameCollisions } from \"../metadata/collision-guards.js\";\n\n// =============================================================================\n// OUTPUT TYPE\n// =============================================================================\n\n/**\n * A JSON Schema 2020-12 document, sub-schema, or keyword collection.\n *\n * This interface covers the subset of JSON Schema 2020-12 that this generator\n * emits, plus an index signature for custom `x-formspec-*` extension keywords.\n *\n * @public\n */\nexport interface JsonSchema2020 {\n /** Declared JSON Schema dialect URI for the document root. */\n $schema?: string;\n /** Reference to another schema location. */\n $ref?: string;\n /** Named reusable schema definitions keyed by definition name. */\n $defs?: Record<string, JsonSchema2020>;\n /** JSON Schema type keyword for the current node. */\n type?: string;\n /** Object properties keyed by property name. */\n properties?: Record<string, JsonSchema2020>;\n /** Property names that must be present on object values. */\n required?: string[];\n /** Item schema applied to array elements. */\n items?: JsonSchema2020;\n /** Whether, or how, additional object properties are allowed. */\n additionalProperties?: boolean | JsonSchema2020;\n /** Closed set of allowed scalar values. */\n enum?: readonly (string | number)[];\n /** Literal value the instance must equal. */\n const?: unknown;\n /** Schemas that must all validate successfully. */\n allOf?: readonly JsonSchema2020[];\n /** Schemas of which exactly one should validate successfully. */\n oneOf?: readonly JsonSchema2020[];\n /** Schemas of which at least one may validate successfully. */\n anyOf?: readonly JsonSchema2020[];\n // Constraints\n /** Inclusive numeric lower bound. */\n minimum?: number;\n /** Inclusive numeric upper bound. */\n maximum?: number;\n /** Exclusive numeric lower bound. */\n exclusiveMinimum?: number;\n /** Exclusive numeric upper bound. */\n exclusiveMaximum?: number;\n /** Required numeric step interval. */\n multipleOf?: number;\n /** Inclusive minimum string length. */\n minLength?: number;\n /** Inclusive maximum string length. */\n maxLength?: number;\n /** Inclusive minimum array length. */\n minItems?: number;\n /** Inclusive maximum array length. */\n maxItems?: number;\n /** Regular expression pattern applied to string values. */\n pattern?: string;\n /** Whether array elements must be unique. */\n uniqueItems?: boolean;\n /** Format hint for downstream validators and tooling. */\n format?: string;\n // Annotations\n /** Human-readable title for the schema node. */\n title?: string;\n /** Human-readable description for the schema node. */\n description?: string;\n /** Default value suggested for the schema node. */\n default?: unknown;\n /** Whether the schema node is deprecated. */\n deprecated?: boolean;\n // Extensions (open for vendor-prefixed keywords, e.g., x-formspec-*, x-stripe-*)\n // The vendor prefix is configurable (white-labelable).\n /** Additional vendor-prefixed extension keywords. */\n [key: `x-${string}`]: unknown;\n}\n\n// =============================================================================\n// CONTEXT\n// =============================================================================\n\n/**\n * Mutable accumulator passed through the generation traversal.\n *\n * Using a context object rather than return-value threading keeps the\n * recursive generators simple and avoids repeated object spreading.\n */\ninterface GeneratorContext {\n /** Named type schemas collected during traversal, keyed by reference name. */\n readonly defs: Record<string, JsonSchema2020>;\n /** Logical type name to serialized `$defs` key. */\n readonly typeNameMap: Readonly<Record<string, string>>;\n /** Original type registry for reference lookups and property-name mapping. */\n readonly typeRegistry: Readonly<FormIR[\"typeRegistry\"]>;\n /** Optional extension registry for resolving custom IR nodes. */\n readonly extensionRegistry: ExtensionRegistry | undefined;\n /** Vendor prefix passed through to extension toJsonSchema handlers. */\n readonly vendorPrefix: string;\n}\n\n/**\n * Options for generating JSON Schema from a canonical FormIR.\n *\n * @internal\n */\nexport interface GenerateJsonSchemaFromIROptions {\n /**\n * Registry used to resolve custom types, constraints, and annotations.\n *\n * JSON Schema generation throws when custom IR nodes are present without a\n * matching registration in this registry.\n */\n readonly extensionRegistry?: ExtensionRegistry | undefined;\n /**\n * Vendor prefix passed to extension `toJsonSchema` hooks.\n * @defaultValue \"x-formspec\"\n */\n readonly vendorPrefix?: string | undefined;\n}\n\nfunction makeContext(options?: GenerateJsonSchemaFromIROptions): GeneratorContext {\n const vendorPrefix = options?.vendorPrefix ?? \"x-formspec\";\n if (!vendorPrefix.startsWith(\"x-\")) {\n throw new Error(\n `Invalid vendorPrefix \"${vendorPrefix}\". Extension JSON Schema keywords must start with \"x-\".`\n );\n }\n\n return {\n defs: {},\n typeNameMap: {},\n typeRegistry: {},\n extensionRegistry: options?.extensionRegistry,\n vendorPrefix,\n };\n}\n\n// =============================================================================\n// PUBLIC API\n// =============================================================================\n\n/**\n * Generates a JSON Schema 2020-12 object from a canonical FormIR.\n *\n * Groups and conditionals are flattened — they influence UI layout but do not\n * affect the data schema. All fields appear at the level they would occupy in\n * the output data.\n *\n * Named types in the `typeRegistry` are emitted as `$defs` entries and\n * referenced via `$ref` (per PP7 — high-fidelity output).\n *\n * @example\n * ```typescript\n * import { canonicalizeDSL } from \"./canonicalize/index.js\";\n * import { generateJsonSchemaFromIR } from \"./json-schema/ir-generator.js\";\n * import { formspec, field } from \"@formspec/dsl\";\n *\n * const form = formspec(\n * field.text(\"name\", { label: \"Name\", required: true }),\n * field.number(\"age\", { min: 0 }),\n * );\n * const ir = canonicalizeDSL(form);\n * const schema = generateJsonSchemaFromIR(ir);\n * // {\n * // $schema: \"https://json-schema.org/draft/2020-12/schema\",\n * // type: \"object\",\n * // properties: {\n * // name: { type: \"string\", title: \"Name\" },\n * // age: { type: \"number\", minimum: 0 }\n * // },\n * // required: [\"name\"]\n * // }\n * ```\n *\n * Advanced API — most consumers should use `generateJsonSchema()` or\n * `buildFormSchemas()`, which canonicalize form definitions automatically.\n * Callers of this function are responsible for providing pre-canonicalized IR.\n *\n * @param ir - The canonical FormIR produced by a canonicalizer\n * @returns A plain JSON-serializable JSON Schema 2020-12 object\n *\n * @internal\n */\nexport function generateJsonSchemaFromIR(\n ir: FormIR,\n options?: GenerateJsonSchemaFromIROptions\n): JsonSchema2020 {\n assertNoSerializedNameCollisions(ir);\n\n const ctx = {\n ...makeContext(options),\n typeRegistry: ir.typeRegistry,\n typeNameMap: Object.fromEntries(\n Object.entries(ir.typeRegistry).map(([name, typeDef]) => [\n name,\n getSerializedName(name, typeDef.metadata),\n ])\n ),\n };\n\n // Seed $defs from the type registry so referenced types are available even if\n // the field tree traversal never visits them (e.g., unreferenced types added\n // by a TSDoc canonicalizer pass).\n for (const [name, typeDef] of Object.entries(ir.typeRegistry)) {\n const schemaName = ctx.typeNameMap[name] ?? name;\n ctx.defs[schemaName] = generateTypeNode(typeDef.type, ctx);\n applyResolvedMetadata(ctx.defs[schemaName], typeDef.metadata);\n if (typeDef.constraints && typeDef.constraints.length > 0) {\n applyConstraints(ctx.defs[schemaName], typeDef.constraints, ctx);\n }\n if (typeDef.annotations && typeDef.annotations.length > 0) {\n applyAnnotations(ctx.defs[schemaName], typeDef.annotations, ctx);\n }\n }\n\n const properties: Record<string, JsonSchema2020> = {};\n const required: string[] = [];\n\n collectFields(ir.elements, properties, required, ctx);\n\n // Deduplicate required (same field can appear across conditional branches).\n const uniqueRequired = [...new Set(required)];\n\n const result: JsonSchema2020 = {\n $schema: \"https://json-schema.org/draft/2020-12/schema\",\n type: \"object\",\n properties,\n ...(uniqueRequired.length > 0 && { required: uniqueRequired }),\n };\n applyResolvedMetadata(result, ir.metadata);\n\n if (ir.annotations && ir.annotations.length > 0) {\n applyAnnotations(result, ir.annotations, ctx);\n }\n\n if (Object.keys(ctx.defs).length > 0) {\n result.$defs = ctx.defs;\n }\n\n return result;\n}\n\n// =============================================================================\n// ELEMENT TRAVERSAL\n// =============================================================================\n\n/**\n * Recursively visits all IR elements, collecting field schemas and required names.\n *\n * Groups and conditionals are transparent to the schema — their children are\n * lifted to the enclosing level (per the JSON Schema vocabulary spec §1.2).\n */\nfunction collectFields(\n elements: readonly FormIRElement[],\n properties: Record<string, JsonSchema2020>,\n required: string[],\n ctx: GeneratorContext\n): void {\n for (const element of elements) {\n switch (element.kind) {\n case \"field\":\n properties[getSerializedName(element.name, element.metadata)] = generateFieldSchema(element, ctx);\n if (element.required) {\n required.push(getSerializedName(element.name, element.metadata));\n }\n break;\n\n case \"group\":\n // Groups are UI-only; flatten children into the enclosing schema.\n collectFields(element.elements, properties, required, ctx);\n break;\n\n case \"conditional\":\n // Conditional visibility is UI-only; all fields remain in the schema.\n collectFields(element.elements, properties, required, ctx);\n break;\n\n default: {\n const _exhaustive: never = element;\n void _exhaustive;\n }\n }\n }\n}\n\n// =============================================================================\n// FIELD SCHEMA GENERATION\n// =============================================================================\n\n/**\n * Generates the JSON Schema sub-schema for a single FieldNode.\n */\nfunction generateFieldSchema(field: FieldNode, ctx: GeneratorContext): JsonSchema2020 {\n const schema = generateTypeNode(field.type, ctx);\n const itemStringSchema =\n schema.type === \"array\" && schema.items?.type === \"string\" ? schema.items : undefined;\n\n // Partition constraints into direct (no path) and path-targeted.\n const directConstraints: ConstraintNode[] = [];\n const itemConstraints: ConstraintNode[] = [];\n const pathConstraints: ConstraintNode[] = [];\n for (const c of field.constraints) {\n if (c.path) {\n pathConstraints.push(c);\n } else if (itemStringSchema !== undefined && isStringItemConstraint(c)) {\n itemConstraints.push(c);\n } else {\n directConstraints.push(c);\n }\n }\n\n // Apply direct constraints. multipleOf:1 on a number type is a special case:\n // it promotes the type to \"integer\" and removes the multipleOf keyword.\n applyConstraints(schema, directConstraints, ctx);\n\n if (itemStringSchema !== undefined) {\n applyConstraints(itemStringSchema, itemConstraints, ctx);\n }\n\n // Apply annotations (title, description, default, deprecated, etc.).\n const rootAnnotations: AnnotationNode[] = [];\n const itemAnnotations: AnnotationNode[] = [];\n for (const annotation of field.annotations) {\n if (itemStringSchema !== undefined && annotation.annotationKind === \"format\") {\n itemAnnotations.push(annotation);\n } else {\n rootAnnotations.push(annotation);\n }\n }\n\n applyResolvedMetadata(schema, field.metadata);\n applyAnnotations(schema, rootAnnotations, ctx);\n if (itemStringSchema !== undefined) {\n applyAnnotations(itemStringSchema, itemAnnotations, ctx);\n }\n\n // If no path-targeted constraints, return as-is.\n if (pathConstraints.length === 0) {\n return schema;\n }\n\n return applyPathTargetedConstraints(schema, pathConstraints, ctx, field.type);\n}\n\n/**\n * Returns true if a constraint should be applied to the `items` schema of a\n * primitive `string[]` rather than the array itself.\n *\n * `@const` is intentionally excluded: arrays cannot carry primitive const\n * constraints in FormSpec, so `@const` on `string[]` remains a validation\n * error instead of targeting the item schema.\n */\nfunction isStringItemConstraint(constraint: ConstraintNode): boolean {\n switch (constraint.constraintKind) {\n case \"minLength\":\n case \"maxLength\":\n case \"pattern\":\n return true;\n default:\n return false;\n }\n}\n\n/**\n * Applies path-targeted constraints to a schema via allOf composition.\n *\n * For $ref schemas: wraps in allOf with property overrides.\n * For inline object schemas: applies directly to nested properties.\n * For array schemas: applies path constraints to the items sub-schema.\n */\nfunction applyPathTargetedConstraints(\n schema: JsonSchema2020,\n pathConstraints: readonly ConstraintNode[],\n ctx: GeneratorContext,\n typeNode?: TypeNode\n): JsonSchema2020 {\n // Array transparency: path-targeted constraints target the item type.\n if (schema.type === \"array\" && schema.items) {\n const referencedType = typeNode?.kind === \"reference\" ? resolveReferencedType(typeNode, ctx) : undefined;\n const nestedType =\n typeNode?.kind === \"array\"\n ? typeNode.items\n : referencedType?.kind === \"array\"\n ? referencedType.items\n : undefined\n ;\n schema.items = applyPathTargetedConstraints(schema.items, pathConstraints, ctx, nestedType);\n return schema;\n }\n\n // Group path constraints by target field name (first path segment).\n // Callers guarantee all entries have a defined `path` (filtered upstream).\n const byTarget = new Map<string, ConstraintNode[]>();\n for (const c of pathConstraints) {\n const target = c.path?.segments[0];\n if (!target) continue;\n const group = byTarget.get(target) ?? [];\n group.push(c);\n byTarget.set(target, group);\n }\n\n // Build the property overrides object.\n const propertyOverrides: Record<string, JsonSchema2020> = {};\n for (const [target, constraints] of byTarget) {\n const subSchema: JsonSchema2020 = {};\n applyConstraints(subSchema, constraints, ctx);\n propertyOverrides[resolveSerializedPropertyName(target, typeNode, ctx)] = subSchema;\n }\n\n // $ref schema: wrap in allOf to preserve $ref semantics while adding overrides.\n if (schema.$ref) {\n const { $ref, ...rest } = schema;\n const refPart: JsonSchema2020 = { $ref };\n const overridePart: JsonSchema2020 = {\n properties: propertyOverrides,\n ...rest,\n };\n return { allOf: [refPart, overridePart] };\n }\n\n // Inline object schema: merge property overrides directly where possible.\n if (schema.type === \"object\" && schema.properties) {\n const missingOverrides: Record<string, JsonSchema2020> = {};\n\n for (const [target, overrideSchema] of Object.entries(propertyOverrides)) {\n if (schema.properties[target]) {\n Object.assign(schema.properties[target], overrideSchema);\n } else {\n // Do not introduce new properties directly; compose via allOf instead\n // to preserve additionalProperties semantics on the base object.\n missingOverrides[target] = overrideSchema;\n }\n }\n\n if (Object.keys(missingOverrides).length === 0) {\n return schema;\n }\n\n return {\n allOf: [schema, { properties: missingOverrides }],\n };\n }\n\n // allOf schema (already composed): add property overrides as another member.\n if (schema.allOf) {\n schema.allOf = [...schema.allOf, { properties: propertyOverrides }];\n return schema;\n }\n\n // Fallback: for non-object/non-$ref schemas, path-targeted constraints do not\n // apply in a meaningful way. Return the original schema unchanged and rely\n // on validation diagnostics to surface misuse of path-based constraints.\n return schema;\n}\n\n// =============================================================================\n// TYPE NODE GENERATION\n// =============================================================================\n\n/**\n * Converts a TypeNode to a JSON Schema sub-schema.\n *\n * This function is intentionally exhaustive — all TypeNode variants are handled.\n * TypeScript's exhaustiveness check via the default branch ensures new variants\n * added to the IR are caught at compile time.\n */\nfunction generateTypeNode(type: TypeNode, ctx: GeneratorContext): JsonSchema2020 {\n switch (type.kind) {\n case \"primitive\":\n return generatePrimitiveType(type);\n\n case \"enum\":\n return generateEnumType(type);\n\n case \"array\":\n return generateArrayType(type, ctx);\n\n case \"object\":\n return generateObjectType(type, ctx);\n\n case \"record\":\n return generateRecordType(type, ctx);\n\n case \"union\":\n return generateUnionType(type, ctx);\n\n case \"reference\":\n return generateReferenceType(type, ctx);\n\n case \"dynamic\":\n return generateDynamicType(type);\n\n case \"custom\":\n return generateCustomType(type, ctx);\n\n default: {\n // TypeScript exhaustiveness guard.\n const _exhaustive: never = type;\n return _exhaustive;\n }\n }\n}\n\n/**\n * Maps primitive IR types to JSON Schema type keywords.\n *\n * Note: `integer` is NOT a primitive kind in the IR. Integer semantics are\n * expressed via a `multipleOf: 1` constraint on a number type; `applyConstraints`\n * handles the promotion (per the JSON Schema vocabulary spec §2.1).\n */\nfunction generatePrimitiveType(type: PrimitiveTypeNode): JsonSchema2020 {\n return {\n type:\n type.primitiveKind === \"integer\" || type.primitiveKind === \"bigint\"\n ? \"integer\"\n : type.primitiveKind,\n };\n}\n\n/**\n * Generates JSON Schema for a static enum type.\n *\n * When any member has a displayName, the output uses the `oneOf` form with\n * per-member `const`/`title` entries (per the JSON Schema vocabulary spec §2.3). Otherwise the\n * flat `enum` keyword is used (simpler, equally valid).\n */\nfunction generateEnumType(type: EnumTypeNode): JsonSchema2020 {\n const hasDisplayNames = type.members.some((m) => m.displayName !== undefined);\n\n if (hasDisplayNames) {\n return {\n oneOf: type.members.map((m) => {\n const entry: JsonSchema2020 = { const: m.value };\n if (m.displayName !== undefined) {\n entry.title = m.displayName;\n }\n return entry;\n }),\n };\n }\n\n return { enum: type.members.map((m) => m.value) };\n}\n\n/**\n * Generates JSON Schema for an array type.\n * Per 2020-12, `items` is a single schema (not an array); tuple types use\n * `prefixItems` + `items: false`.\n */\nfunction generateArrayType(type: ArrayTypeNode, ctx: GeneratorContext): JsonSchema2020 {\n return {\n type: \"array\",\n items: generateTypeNode(type.items, ctx),\n };\n}\n\n/**\n * Generates JSON Schema for an object type.\n *\n * `additionalProperties` is emitted only when the IR explicitly closes the\n * object. Ordinary static object types now canonicalize to\n * `additionalProperties: true`, which omits the keyword per spec 003 §2.5.\n */\nfunction generateObjectType(type: ObjectTypeNode, ctx: GeneratorContext): JsonSchema2020 {\n const properties: Record<string, JsonSchema2020> = {};\n const required: string[] = [];\n\n for (const prop of type.properties) {\n const propertyName = getSerializedName(prop.name, prop.metadata);\n properties[propertyName] = generatePropertySchema(prop, ctx);\n if (!prop.optional) {\n required.push(propertyName);\n }\n }\n\n const schema: JsonSchema2020 = { type: \"object\", properties };\n\n if (required.length > 0) {\n schema.required = required;\n }\n\n if (!type.additionalProperties) {\n schema.additionalProperties = false;\n }\n\n return schema;\n}\n\n/**\n * Generates JSON Schema for a record (dictionary) type per spec 003 §2.5.\n *\n * `Record<string, T>` and `{ [k: string]: T }` both emit:\n * `{ \"type\": \"object\", \"additionalProperties\": <T schema> }`\n *\n * No `properties` key is emitted — the record has no named properties.\n */\nfunction generateRecordType(type: RecordTypeNode, ctx: GeneratorContext): JsonSchema2020 {\n return {\n type: \"object\",\n additionalProperties: generateTypeNode(type.valueType, ctx),\n };\n}\n\n/**\n * Generates a schema for an ObjectProperty, applying its use-site constraints\n * and annotations (per the JSON Schema vocabulary spec §5.4 — inline allOf at use site).\n */\nfunction generatePropertySchema(prop: ObjectProperty, ctx: GeneratorContext): JsonSchema2020 {\n const schema = generateTypeNode(prop.type, ctx);\n applyConstraints(schema, prop.constraints, ctx);\n applyResolvedMetadata(schema, prop.metadata);\n applyAnnotations(schema, prop.annotations, ctx);\n return schema;\n}\n\n/**\n * Generates JSON Schema for a union type.\n *\n * Union handling strategy (per spec 003):\n * - Boolean shorthand: `true | false` → `{ type: \"boolean\" }` (not oneOf/anyOf)\n * - Nullable unions: `T | null` → `{ \"oneOf\": [<T schema>, { \"type\": \"null\" }] }` (§2.3)\n * - All other unions → `anyOf` (members may overlap; discriminated union\n * detection is deferred to a future phase per design doc 003 §7.4)\n */\nfunction generateUnionType(type: UnionTypeNode, ctx: GeneratorContext): JsonSchema2020 {\n // Boolean shorthand: union of true-literal and false-literal → type: \"boolean\"\n if (isBooleanUnion(type)) {\n return { type: \"boolean\" };\n }\n\n // Nullable union: `T | null` → oneOf per spec 003 §2.3.\n // A nullable union is any union where exactly one member is the null primitive.\n if (isNullableUnion(type)) {\n return {\n oneOf: type.members.map((m) => generateTypeNode(m, ctx)),\n };\n }\n\n // Default: anyOf for non-discriminated object unions (spec 003 §7.4).\n // Discriminated union detection (shared required property with distinct consts)\n // is deferred to a future phase.\n return {\n anyOf: type.members.map((m) => generateTypeNode(m, ctx)),\n };\n}\n\n/**\n * Returns true if the union is `true | false` (boolean shorthand).\n */\nfunction isBooleanUnion(type: UnionTypeNode): boolean {\n if (type.members.length !== 2) return false;\n const kinds = type.members.map((m) => m.kind);\n // Both must be primitives; check if both are \"boolean\" primitives.\n // The IR currently does not have a boolean literal node, so boolean union\n // is represented as two primitive boolean members.\n return (\n kinds.every((k) => k === \"primitive\") &&\n type.members.every((m) => m.kind === \"primitive\" && m.primitiveKind === \"boolean\")\n );\n}\n\n/**\n * Returns true if the union is a nullable wrapper union (`T | null` for any T).\n *\n * A nullable union is a two-member union where exactly one member is the `null`\n * primitive type and the other member is any non-null type.\n * Per spec 003 §2.3, nullable unions map to `oneOf` (not `anyOf`).\n */\nfunction isNullableUnion(type: UnionTypeNode): boolean {\n if (type.members.length !== 2) return false;\n const nullCount = type.members.filter(\n (m) => m.kind === \"primitive\" && m.primitiveKind === \"null\"\n ).length;\n return nullCount === 1;\n}\n\n/**\n * Generates JSON Schema for a reference type.\n *\n * The referenced type's schema is stored in `$defs` (seeded from the type\n * registry before traversal begins). The reference simply emits a `$ref`.\n */\nfunction generateReferenceType(type: ReferenceTypeNode, ctx: GeneratorContext): JsonSchema2020 {\n return { $ref: `#/$defs/${ctx.typeNameMap[type.name] ?? type.name}` };\n}\n\nfunction applyResolvedMetadata(\n schema: JsonSchema2020,\n metadata: ResolvedMetadata | undefined\n): void {\n const displayName = getDisplayName(metadata);\n if (displayName !== undefined) {\n schema.title = displayName;\n }\n}\n\nfunction resolveReferencedType(\n type: ReferenceTypeNode,\n ctx: GeneratorContext\n): TypeNode | undefined {\n return ctx.typeRegistry[type.name]?.type;\n}\n\nfunction resolveSerializedPropertyName(\n logicalName: string,\n typeNode: TypeNode | undefined,\n ctx: GeneratorContext\n): string {\n if (typeNode?.kind === \"object\") {\n const property = typeNode.properties.find((candidate) => candidate.name === logicalName);\n return property === undefined ? logicalName : getSerializedName(property.name, property.metadata);\n }\n\n if (typeNode?.kind === \"reference\") {\n const referencedType = resolveReferencedType(typeNode, ctx);\n return referencedType === undefined\n ? logicalName\n : resolveSerializedPropertyName(logicalName, referencedType, ctx);\n }\n\n return logicalName;\n}\n\n/**\n * Generates JSON Schema for a dynamic type (runtime-resolved enum or schema).\n *\n * Dynamic enums emit `x-formspec-source` and optionally `x-formspec-params`.\n * Dynamic schemas emit `x-formspec-schemaSource` with `additionalProperties: true`\n * since the actual schema is determined at runtime (per the JSON Schema vocabulary spec §3.2).\n */\nfunction generateDynamicType(type: DynamicTypeNode): JsonSchema2020 {\n if (type.dynamicKind === \"enum\") {\n const schema: JsonSchema2020 = {\n type: \"string\",\n \"x-formspec-source\": type.sourceKey,\n };\n if (type.parameterFields.length > 0) {\n schema[\"x-formspec-params\"] = [...type.parameterFields];\n }\n return schema;\n }\n\n // dynamicKind === \"schema\"\n return {\n type: \"object\",\n additionalProperties: true,\n \"x-formspec-schemaSource\": type.sourceKey,\n };\n}\n\n// =============================================================================\n// CONSTRAINT APPLICATION\n// =============================================================================\n\n/**\n * Applies constraint nodes onto an existing JSON Schema object (mutates in place).\n *\n * All callers pass freshly-created objects so there is no aliasing risk.\n *\n * Special rule (per the JSON Schema vocabulary spec §2.1): `multipleOf: 1` on a `\"number\"` type\n * promotes to `\"integer\"` and suppresses the `multipleOf` keyword (integer is a\n * subtype of number; expressing it via multipleOf:1 is redundant).\n *\n * Path-targeted constraints are handled separately by `applyPathTargetedConstraints`.\n */\nfunction applyConstraints(\n schema: JsonSchema2020,\n constraints: readonly ConstraintNode[],\n ctx: GeneratorContext\n): void {\n for (const constraint of constraints) {\n switch (constraint.constraintKind) {\n case \"minimum\":\n schema.minimum = constraint.value;\n break;\n\n case \"maximum\":\n schema.maximum = constraint.value;\n break;\n\n case \"exclusiveMinimum\":\n schema.exclusiveMinimum = constraint.value;\n break;\n\n case \"exclusiveMaximum\":\n schema.exclusiveMaximum = constraint.value;\n break;\n\n case \"multipleOf\": {\n const { value } = constraint;\n if (value === 1 && schema.type === \"number\") {\n // Promote number → integer; omit the multipleOf keyword (redundant).\n schema.type = \"integer\";\n } else {\n schema.multipleOf = value;\n }\n break;\n }\n\n case \"minLength\":\n schema.minLength = constraint.value;\n break;\n\n case \"maxLength\":\n schema.maxLength = constraint.value;\n break;\n\n case \"minItems\":\n schema.minItems = constraint.value;\n break;\n\n case \"maxItems\":\n schema.maxItems = constraint.value;\n break;\n\n case \"pattern\":\n schema.pattern = constraint.pattern;\n break;\n\n case \"uniqueItems\":\n schema.uniqueItems = constraint.value;\n break;\n\n case \"const\":\n schema.const = constraint.value;\n break;\n\n case \"allowedMembers\":\n // EnumMemberConstraintNode — not yet emitted to JSON Schema (Phase 6 validation).\n break;\n\n case \"custom\":\n applyCustomConstraint(schema, constraint, ctx);\n break;\n\n default: {\n // TypeScript exhaustiveness guard.\n const _exhaustive: never = constraint;\n void _exhaustive;\n }\n }\n }\n}\n\n// =============================================================================\n// ANNOTATION APPLICATION\n// =============================================================================\n\n/**\n * Applies annotation nodes onto an existing JSON Schema object (mutates in place).\n *\n * Mapping per the JSON Schema vocabulary spec §2.8:\n * - `displayName` → `title`\n * - `description` → `description` (from summary text, spec 002 §2.3)\n * - `remarks` → `x-<vendor>-remarks` (from @remarks, spec 003 §3.2)\n * - `defaultValue` → `default`\n * - `deprecated` → `deprecated: true` (2020-12 standard annotation)\n * - `format` → `format`\n *\n * UI-only annotations (`placeholder`, `formatHint`) are silently ignored here —\n * they belong in the UI Schema, not the data schema.\n */\nfunction applyAnnotations(\n schema: JsonSchema2020,\n annotations: readonly AnnotationNode[],\n ctx: GeneratorContext\n): void {\n for (const annotation of annotations) {\n switch (annotation.annotationKind) {\n case \"displayName\":\n schema.title ??= annotation.value;\n break;\n\n case \"description\":\n schema.description = annotation.value;\n break;\n\n case \"remarks\":\n schema[`${ctx.vendorPrefix}-remarks` as `x-${string}`] = annotation.value;\n break;\n\n case \"defaultValue\":\n schema.default = annotation.value;\n break;\n\n case \"format\":\n schema.format = annotation.value;\n break;\n\n case \"deprecated\":\n schema.deprecated = true;\n if (annotation.message !== undefined && annotation.message !== \"\") {\n schema[`${ctx.vendorPrefix}-deprecation-description` as `x-${string}`] =\n annotation.message;\n }\n break;\n\n case \"placeholder\":\n // UI-only — belongs in UI Schema, not emitted here.\n break;\n\n case \"formatHint\":\n // UI-only — belongs in UI Schema, not emitted here.\n break;\n\n case \"custom\":\n applyCustomAnnotation(schema, annotation, ctx);\n break;\n\n default: {\n // TypeScript exhaustiveness guard.\n const _exhaustive: never = annotation;\n void _exhaustive;\n }\n }\n }\n}\n\nfunction generateCustomType(type: CustomTypeNode, ctx: GeneratorContext): JsonSchema2020 {\n const registration = ctx.extensionRegistry?.findType(type.typeId);\n if (registration === undefined) {\n throw new Error(\n `Cannot generate JSON Schema for custom type \"${type.typeId}\" without a matching extension registration`\n );\n }\n\n // Trust boundary: extensions are responsible for returning valid JSON Schema.\n // Core only depends on Record<string, unknown> here, so we cast at the edge.\n return registration.toJsonSchema(type.payload, ctx.vendorPrefix) as JsonSchema2020;\n}\n\nfunction applyCustomConstraint(\n schema: JsonSchema2020,\n constraint: Extract<ConstraintNode, { constraintKind: \"custom\" }>,\n ctx: GeneratorContext\n): void {\n const registration = ctx.extensionRegistry?.findConstraint(constraint.constraintId);\n if (registration === undefined) {\n throw new Error(\n `Cannot generate JSON Schema for custom constraint \"${constraint.constraintId}\" without a matching extension registration`\n );\n }\n\n assignVendorPrefixedExtensionKeywords(\n schema,\n registration.toJsonSchema(constraint.payload, ctx.vendorPrefix),\n ctx.vendorPrefix,\n `custom constraint \"${constraint.constraintId}\"`\n );\n}\n\nfunction applyCustomAnnotation(\n schema: JsonSchema2020,\n annotation: Extract<AnnotationNode, { annotationKind: \"custom\" }>,\n ctx: GeneratorContext\n): void {\n const registration = ctx.extensionRegistry?.findAnnotation(annotation.annotationId);\n if (registration === undefined) {\n throw new Error(\n `Cannot generate JSON Schema for custom annotation \"${annotation.annotationId}\" without a matching extension registration`\n );\n }\n\n if (registration.toJsonSchema === undefined) {\n return;\n }\n\n assignVendorPrefixedExtensionKeywords(\n schema,\n registration.toJsonSchema(annotation.value, ctx.vendorPrefix),\n ctx.vendorPrefix,\n `custom annotation \"${annotation.annotationId}\"`\n );\n}\n\nfunction assignVendorPrefixedExtensionKeywords(\n schema: JsonSchema2020,\n extensionSchema: Record<string, unknown>,\n vendorPrefix: string,\n source: string\n): void {\n for (const [key, value] of Object.entries(extensionSchema)) {\n if (!key.startsWith(`${vendorPrefix}-`)) {\n throw new Error(\n `Cannot apply ${source}: extension hooks may only emit \"${vendorPrefix}-*\" JSON Schema keywords`\n );\n }\n schema[key as `x-${string}`] = value;\n }\n}\n","/**\n * JSON Schema generator for FormSpec forms.\n *\n * Routes through the canonical IR pipeline: Chain DSL → FormIR → JSON Schema 2020-12.\n */\n\nimport type { FormElement, FormSpec, MetadataPolicyInput } from \"@formspec/core\";\nimport { canonicalizeChainDSL } from \"../canonicalize/index.js\";\nimport {\n generateJsonSchemaFromIR,\n type GenerateJsonSchemaFromIROptions,\n type JsonSchema2020,\n} from \"./ir-generator.js\";\n\n/**\n * Options for generating JSON Schema from a Chain DSL form.\n *\n * @public\n */\nexport interface GenerateJsonSchemaOptions {\n /**\n * Vendor prefix for emitted extension keywords.\n * @defaultValue \"x-formspec\"\n */\n readonly vendorPrefix?: string | undefined;\n /** Metadata resolution policy for chain DSL generation. */\n readonly metadata?: MetadataPolicyInput | undefined;\n}\n\n/**\n * Generates a JSON Schema 2020-12 from a FormSpec.\n *\n * All generation routes through the canonical IR. The chain DSL is first\n * canonicalized to a FormIR, then the IR-based generator produces the schema.\n *\n * @example\n * ```typescript\n * const form = formspec(\n * field.text(\"name\", { label: \"Name\", required: true }),\n * field.number(\"age\", { min: 0 }),\n * );\n *\n * const schema = generateJsonSchema(form);\n * // {\n * // $schema: \"https://json-schema.org/draft/2020-12/schema\",\n * // type: \"object\",\n * // properties: {\n * // name: { type: \"string\", title: \"Name\" },\n * // age: { type: \"number\", minimum: 0 }\n * // },\n * // required: [\"name\"]\n * // }\n * ```\n *\n * @param form - The FormSpec to convert\n * @returns A JSON Schema 2020-12 object\n *\n * @public\n */\nexport function generateJsonSchema<E extends readonly FormElement[]>(\n form: FormSpec<E>,\n options?: GenerateJsonSchemaOptions\n): JsonSchema2020 {\n const ir = canonicalizeChainDSL(\n form,\n options?.metadata !== undefined ? { metadata: options.metadata } : undefined\n );\n const internalOptions: GenerateJsonSchemaFromIROptions | undefined =\n options?.vendorPrefix === undefined ? undefined : { vendorPrefix: options.vendorPrefix };\n return generateJsonSchemaFromIR(ir, internalOptions);\n}\n","/**\n * Zod schemas for JSON Forms UI Schema.\n *\n * These schemas are the source of truth for UI Schema validation.\n * TypeScript types are derived from these schemas via `z.infer<>`.\n *\n * @see https://jsonforms.io/docs/uischema/\n */\n\nimport { z } from \"zod\";\nimport type { UISchema } from \"./types.js\";\n\n// =============================================================================\n// Primitive helpers\n// =============================================================================\n\n/** JSON Pointer string (e.g., \"#/properties/fieldName\") */\nconst jsonPointerSchema = z.string();\n\n// =============================================================================\n// Rule Effect and Element Type enums\n// =============================================================================\n\n/**\n * Zod schema for rule effect values.\n *\n * @internal\n */\nexport const ruleEffectSchema = z.enum([\"SHOW\", \"HIDE\", \"ENABLE\", \"DISABLE\"]);\n\n/**\n * Rule effect types for conditional visibility.\n *\n * @internal\n */\nexport type RuleEffect = z.infer<typeof ruleEffectSchema>;\n\n/**\n * Zod schema for UI Schema element type strings.\n *\n * @internal\n */\nexport const uiSchemaElementTypeSchema = z.enum([\n \"Control\",\n \"VerticalLayout\",\n \"HorizontalLayout\",\n \"Group\",\n \"Categorization\",\n \"Category\",\n \"Label\",\n]);\n\n/**\n * UI Schema element types.\n *\n * @internal\n */\nexport type UISchemaElementType = z.infer<typeof uiSchemaElementTypeSchema>;\n\n// =============================================================================\n// Rule Condition Schema (recursive)\n// =============================================================================\n\n// Forward-declare the recursive TypeScript type.\n// We use an interface here (rather than z.infer<>) because the recursive\n// z.lazy() type annotation requires us to pre-declare the shape.\n/**\n * JSON Schema subset used in rule conditions.\n *\n * @internal\n */\nexport interface RuleConditionSchema {\n const?: unknown;\n enum?: readonly unknown[];\n type?: string;\n not?: RuleConditionSchema;\n minimum?: number;\n maximum?: number;\n exclusiveMinimum?: number;\n exclusiveMaximum?: number;\n minLength?: number;\n properties?: Record<string, RuleConditionSchema>;\n required?: string[];\n allOf?: RuleConditionSchema[];\n}\n\n/**\n * Zod schema for the rule-condition JSON Schema subset.\n *\n * @internal\n */\nexport const ruleConditionSchema: z.ZodType<RuleConditionSchema> = z.lazy(() =>\n z\n .object({\n const: z.unknown().optional(),\n enum: z.array(z.unknown()).readonly().optional(),\n type: z.string().optional(),\n not: ruleConditionSchema.optional(),\n minimum: z.number().optional(),\n maximum: z.number().optional(),\n exclusiveMinimum: z.number().optional(),\n exclusiveMaximum: z.number().optional(),\n minLength: z.number().optional(),\n properties: z.record(z.string(), ruleConditionSchema).optional(),\n required: z.array(z.string()).optional(),\n allOf: z.array(ruleConditionSchema).optional(),\n })\n .strict()\n) as z.ZodType<RuleConditionSchema>;\n\n// =============================================================================\n// Schema-Based Condition and Rule\n// =============================================================================\n\n/**\n * Zod schema for a schema-based rule condition.\n *\n * @internal\n */\nexport const schemaBasedConditionSchema = z\n .object({\n scope: jsonPointerSchema,\n schema: ruleConditionSchema,\n })\n .strict();\n\n/**\n * Condition for a rule.\n *\n * @internal\n */\nexport type SchemaBasedCondition = z.infer<typeof schemaBasedConditionSchema>;\n\n/**\n * Zod schema for a UI Schema rule.\n *\n * @internal\n */\nexport const ruleSchema = z\n .object({\n effect: ruleEffectSchema,\n condition: schemaBasedConditionSchema,\n })\n .strict();\n\n/**\n * Rule for conditional element visibility/enablement.\n *\n * @internal\n */\nexport type Rule = z.infer<typeof ruleSchema>;\n\n// =============================================================================\n// UI Schema Element Schemas (recursive via z.lazy)\n// =============================================================================\n\n// Forward-declare UISchemaElement so layout schemas can reference it.\n// We declare the type up-front and wire the Zod schema below.\n/**\n * Union of all UI Schema element types.\n *\n * @internal\n */\nexport type UISchemaElement =\n | ControlElement\n | VerticalLayout\n | HorizontalLayout\n | GroupLayout\n | Categorization\n | Category\n | LabelElement;\n\n// The Zod schema for UISchemaElement is defined as a const using z.lazy(),\n// which defers evaluation until first use. This allows all element schemas\n// below to be referenced even though they are declared after this line.\n/**\n * Zod schema for any UI Schema element.\n *\n * @internal\n */\nexport const uiSchemaElementSchema: z.ZodType<UISchemaElement> = z.lazy(() =>\n z.union([\n controlSchema,\n verticalLayoutSchema,\n horizontalLayoutSchema,\n groupLayoutSchema,\n categorizationSchema,\n categorySchema,\n labelElementSchema,\n ])\n) as z.ZodType<UISchemaElement>;\n\n// -----------------------------------------------------------------------------\n// Control\n// -----------------------------------------------------------------------------\n\n/**\n * Zod schema for a Control element.\n *\n * @internal\n */\nexport const controlSchema = z\n .object({\n type: z.literal(\"Control\"),\n scope: jsonPointerSchema,\n label: z.union([z.string(), z.literal(false)]).optional(),\n rule: ruleSchema.optional(),\n options: z.record(z.string(), z.unknown()).optional(),\n })\n .passthrough();\n\n/**\n * A Control element that binds to a JSON Schema property.\n *\n * @internal\n */\nexport type ControlElement = z.infer<typeof controlSchema>;\n\n// -----------------------------------------------------------------------------\n// VerticalLayout\n// -----------------------------------------------------------------------------\n\n// Pre-declare the interface so the Zod schema can reference UISchemaElement.\n/**\n * A vertical layout element.\n *\n * @internal\n */\nexport interface VerticalLayout {\n type: \"VerticalLayout\";\n elements: UISchemaElement[];\n rule?: Rule | undefined;\n options?: Record<string, unknown> | undefined;\n [k: string]: unknown;\n}\n\n/**\n * Zod schema for a vertical layout element.\n *\n * @internal\n */\nexport const verticalLayoutSchema: z.ZodType<VerticalLayout> = z.lazy(() =>\n z\n .object({\n type: z.literal(\"VerticalLayout\"),\n elements: z.array(uiSchemaElementSchema),\n rule: ruleSchema.optional(),\n options: z.record(z.string(), z.unknown()).optional(),\n })\n .passthrough()\n);\n\n// -----------------------------------------------------------------------------\n// HorizontalLayout\n// -----------------------------------------------------------------------------\n\n/**\n * A horizontal layout element.\n *\n * @internal\n */\nexport interface HorizontalLayout {\n type: \"HorizontalLayout\";\n elements: UISchemaElement[];\n rule?: Rule | undefined;\n options?: Record<string, unknown> | undefined;\n [k: string]: unknown;\n}\n\n/**\n * Zod schema for a horizontal layout element.\n *\n * @internal\n */\nexport const horizontalLayoutSchema: z.ZodType<HorizontalLayout> = z.lazy(() =>\n z\n .object({\n type: z.literal(\"HorizontalLayout\"),\n elements: z.array(uiSchemaElementSchema),\n rule: ruleSchema.optional(),\n options: z.record(z.string(), z.unknown()).optional(),\n })\n .passthrough()\n);\n\n// -----------------------------------------------------------------------------\n// GroupLayout\n// -----------------------------------------------------------------------------\n\n/**\n * A group element with a label.\n *\n * @internal\n */\nexport interface GroupLayout {\n type: \"Group\";\n label: string;\n elements: UISchemaElement[];\n rule?: Rule | undefined;\n options?: Record<string, unknown> | undefined;\n [k: string]: unknown;\n}\n\n/**\n * Zod schema for a group layout element.\n *\n * @internal\n */\nexport const groupLayoutSchema: z.ZodType<GroupLayout> = z.lazy(() =>\n z\n .object({\n type: z.literal(\"Group\"),\n label: z.string(),\n elements: z.array(uiSchemaElementSchema),\n rule: ruleSchema.optional(),\n options: z.record(z.string(), z.unknown()).optional(),\n })\n .passthrough()\n);\n\n// -----------------------------------------------------------------------------\n// Category\n// -----------------------------------------------------------------------------\n\n/**\n * A Category element, used inside a Categorization layout.\n *\n * @internal\n */\nexport interface Category {\n type: \"Category\";\n label: string;\n elements: UISchemaElement[];\n rule?: Rule | undefined;\n options?: Record<string, unknown> | undefined;\n [k: string]: unknown;\n}\n\n/**\n * Zod schema for a category element.\n *\n * @internal\n */\nexport const categorySchema: z.ZodType<Category> = z.lazy(() =>\n z\n .object({\n type: z.literal(\"Category\"),\n label: z.string(),\n elements: z.array(uiSchemaElementSchema),\n rule: ruleSchema.optional(),\n options: z.record(z.string(), z.unknown()).optional(),\n })\n .passthrough()\n);\n\n// -----------------------------------------------------------------------------\n// Categorization\n// -----------------------------------------------------------------------------\n\n/**\n * A Categorization element (tab-based layout).\n *\n * @internal\n */\nexport interface Categorization {\n type: \"Categorization\";\n elements: Category[];\n label?: string | undefined;\n rule?: Rule | undefined;\n options?: Record<string, unknown> | undefined;\n [k: string]: unknown;\n}\n\n/**\n * Zod schema for a categorization element.\n *\n * @internal\n */\nexport const categorizationSchema: z.ZodType<Categorization> = z.lazy(() =>\n z\n .object({\n type: z.literal(\"Categorization\"),\n elements: z.array(categorySchema),\n label: z.string().optional(),\n rule: ruleSchema.optional(),\n options: z.record(z.string(), z.unknown()).optional(),\n })\n .passthrough()\n);\n\n// -----------------------------------------------------------------------------\n// LabelElement\n// -----------------------------------------------------------------------------\n\n/**\n * Zod schema for a Label element.\n *\n * @internal\n */\nexport const labelElementSchema = z\n .object({\n type: z.literal(\"Label\"),\n text: z.string(),\n rule: ruleSchema.optional(),\n options: z.record(z.string(), z.unknown()).optional(),\n })\n .passthrough();\n\n/**\n * A Label element for displaying static text.\n *\n * @internal\n */\nexport type LabelElement = z.infer<typeof labelElementSchema>;\n\n// =============================================================================\n// Root UISchema\n// =============================================================================\n\n/**\n * Zod schema for the root UI Schema (layout types only).\n *\n * @public\n */\nexport const uiSchema: z.ZodType<UISchema> = z.lazy(() =>\n z.union([verticalLayoutSchema, horizontalLayoutSchema, groupLayoutSchema, categorizationSchema])\n) as z.ZodType<UISchema>;\n","/**\n * JSON Forms UI Schema generator that operates on the canonical FormIR.\n *\n * This generator consumes the IR produced by the Canonicalize phase and\n * produces a JSON Forms UI Schema. All downstream UI Schema generation\n * should use this module for UI Schema generation.\n */\n\nimport type { FormIR, FormIRElement, FieldNode, GroupLayoutNode } from \"@formspec/core/internals\";\nimport { getDisplayName, getSerializedName } from \"../metadata/index.js\";\nimport { assertNoSerializedNameCollisions } from \"../metadata/collision-guards.js\";\nimport type {\n UISchema,\n UISchemaElement,\n ControlElement,\n GroupLayout,\n Rule,\n RuleConditionSchema,\n} from \"./types.js\";\nimport { uiSchema as uiSchemaValidator } from \"./schema.js\";\nimport { z } from \"zod\";\n\n// =============================================================================\n// HELPERS\n// =============================================================================\n\n/**\n * Parses a value through a Zod schema, converting validation errors to a\n * descriptive Error.\n */\nfunction parseOrThrow<T>(schema: z.ZodType<T>, value: unknown, label: string): T {\n try {\n return schema.parse(value);\n } catch (error) {\n if (error instanceof z.ZodError) {\n throw new Error(\n `Generated ${label} failed validation:\\n${error.issues.map((i) => ` ${i.path.join(\".\")}: ${i.message}`).join(\"\\n\")}`\n );\n }\n throw error;\n }\n}\n\n/**\n * Converts a field name to a JSON Pointer scope string.\n */\nfunction fieldToScope(fieldName: string): string {\n return `#/properties/${fieldName}`;\n}\n\n/**\n * Creates a SHOW rule for a single conditional field/value pair.\n */\nfunction createShowRule(fieldName: string, value: unknown): Rule {\n return {\n effect: \"SHOW\",\n condition: {\n scope: fieldToScope(fieldName),\n schema: { const: value },\n },\n };\n}\n\n/**\n * Combines two SHOW rules into a single rule using an allOf condition.\n *\n * When elements are nested inside multiple conditionals, all parent conditions\n * must be met for the element to be visible. This function flattens both\n * conditions into a single rule using a top-level allOf so JSON Forms evaluates\n * every predicate simultaneously without nesting rule fragments.\n */\nfunction flattenConditionSchema(scope: string, schema: RuleConditionSchema): RuleConditionSchema[] {\n if (schema.allOf === undefined) {\n if (scope === \"#\") {\n return [schema];\n }\n\n const fieldName = scope.replace(\"#/properties/\", \"\");\n return [\n {\n properties: {\n [fieldName]: schema,\n },\n },\n ];\n }\n\n return schema.allOf.flatMap((member) => flattenConditionSchema(scope, member));\n}\n\nfunction combineRules(parentRule: Rule, childRule: Rule): Rule {\n return {\n effect: \"SHOW\",\n condition: {\n scope: \"#\",\n schema: {\n allOf: [\n ...flattenConditionSchema(parentRule.condition.scope, parentRule.condition.schema),\n ...flattenConditionSchema(childRule.condition.scope, childRule.condition.schema),\n ],\n },\n },\n };\n}\n\nfunction getFieldDisplayName(field: FieldNode): string | undefined {\n const resolvedDisplayName = getDisplayName(field.metadata);\n if (resolvedDisplayName !== undefined) {\n return resolvedDisplayName;\n }\n\n return field.annotations.find((annotation) => annotation.annotationKind === \"displayName\")?.value;\n}\n\n// =============================================================================\n// ELEMENT CONVERSION\n// =============================================================================\n\n/**\n * Converts a FieldNode from the IR to a ControlElement.\n *\n * The label prefers resolved metadata, with annotation fallback for callers\n * that still construct IR without the metadata resolver pass.\n */\nfunction fieldNodeToControl(field: FieldNode, fieldNameMap: ReadonlyMap<string, string>, parentRule?: Rule): ControlElement {\n const placeholderAnnotation = field.annotations.find((a) => a.annotationKind === \"placeholder\");\n const serializedName = fieldNameMap.get(field.name) ?? getSerializedName(field.name, field.metadata);\n const displayName = getFieldDisplayName(field);\n\n const control: ControlElement = {\n type: \"Control\",\n scope: fieldToScope(serializedName),\n ...(displayName !== undefined && { label: displayName }),\n ...(placeholderAnnotation !== undefined && {\n options: { placeholder: placeholderAnnotation.value },\n }),\n ...(parentRule !== undefined && { rule: parentRule }),\n };\n\n return control;\n}\n\n/**\n * Converts a GroupLayoutNode from the IR to a GroupLayout element.\n *\n * The group's children are recursively converted; the optional parent rule is\n * forwarded to nested elements so that a group inside a conditional inherits\n * the visibility rule.\n */\nfunction groupNodeToLayout(\n group: GroupLayoutNode,\n fieldNameMap: ReadonlyMap<string, string>,\n parentRule?: Rule\n): GroupLayout {\n return {\n type: \"Group\",\n label: group.label,\n elements: irElementsToUiSchema(group.elements, fieldNameMap, parentRule),\n ...(parentRule !== undefined && { rule: parentRule }),\n };\n}\n\n/**\n * Converts an array of IR elements to UI Schema elements.\n *\n * @param elements - The IR elements to convert\n * @param parentRule - Optional rule inherited from a parent ConditionalLayoutNode\n * @returns Array of UI Schema elements\n */\nfunction irElementsToUiSchema(\n elements: readonly FormIRElement[],\n fieldNameMap: ReadonlyMap<string, string>,\n parentRule?: Rule\n): UISchemaElement[] {\n const result: UISchemaElement[] = [];\n\n for (const element of elements) {\n switch (element.kind) {\n case \"field\": {\n result.push(fieldNodeToControl(element, fieldNameMap, parentRule));\n break;\n }\n\n case \"group\": {\n result.push(groupNodeToLayout(element, fieldNameMap, parentRule));\n break;\n }\n\n case \"conditional\": {\n // Build the rule for this conditional level.\n const newRule = createShowRule(fieldNameMap.get(element.fieldName) ?? element.fieldName, element.value);\n // Combine with the inherited parent rule for nested conditionals.\n const combinedRule = parentRule !== undefined ? combineRules(parentRule, newRule) : newRule;\n // Children are flattened into the parent container with the combined\n // rule attached.\n const childElements = irElementsToUiSchema(element.elements, fieldNameMap, combinedRule);\n result.push(...childElements);\n break;\n }\n\n default: {\n const _exhaustive: never = element;\n void _exhaustive;\n throw new Error(\"Unhandled IR element kind\");\n }\n }\n }\n\n return result;\n}\n\n// =============================================================================\n// PUBLIC API\n// =============================================================================\n\n/**\n * Generates a JSON Forms UI Schema from a canonical `FormIR`.\n *\n * Mapping rules:\n * - `FieldNode` → `ControlElement` with `scope: \"#/properties/<name>\"`\n * - resolved `displayName` metadata → `label` on the `ControlElement`\n * - `displayName` annotation → fallback `label` when metadata is absent\n * - `GroupLayoutNode` → `GroupLayout` with recursively converted `elements`\n * - `ConditionalLayoutNode` → children flattened with a `SHOW` rule\n * - Nested conditionals → combined `allOf` rule\n * - Root wrapper is always `{ type: \"VerticalLayout\", elements: [...] }`\n *\n * @example\n * ```typescript\n * const ir = canonicalizeDSL(\n * formspec(\n * group(\"Customer\", field.text(\"name\", { label: \"Name\" })),\n * when(is(\"status\", \"draft\"), field.text(\"notes\", { label: \"Notes\" })),\n * )\n * );\n *\n * const uiSchema = generateUiSchemaFromIR(ir);\n * // {\n * // type: \"VerticalLayout\",\n * // elements: [\n * // {\n * // type: \"Group\",\n * // label: \"Customer\",\n * // elements: [{ type: \"Control\", scope: \"#/properties/name\", label: \"Name\" }]\n * // },\n * // {\n * // type: \"Control\",\n * // scope: \"#/properties/notes\",\n * // label: \"Notes\",\n * // rule: { effect: \"SHOW\", condition: { scope: \"#/properties/status\", schema: { const: \"draft\" } } }\n * // }\n * // ]\n * // }\n * ```\n *\n * @param ir - The canonical FormIR produced by the Canonicalize phase\n * @returns A validated JSON Forms UI Schema\n */\nexport function generateUiSchemaFromIR(ir: FormIR): UISchema {\n assertNoSerializedNameCollisions(ir);\n const fieldNameMap = collectFieldNameMap(ir.elements);\n const result: UISchema = {\n type: \"VerticalLayout\",\n elements: irElementsToUiSchema(ir.elements, fieldNameMap),\n };\n\n return parseOrThrow(uiSchemaValidator, result, \"UI Schema\");\n}\n\nfunction collectFieldNameMap(elements: readonly FormIRElement[]): ReadonlyMap<string, string> {\n const map = new Map<string, string>();\n\n for (const element of elements) {\n switch (element.kind) {\n case \"field\":\n map.set(element.name, getSerializedName(element.name, element.metadata));\n break;\n case \"group\":\n case \"conditional\":\n for (const [key, value] of collectFieldNameMap(element.elements)) {\n map.set(key, value);\n }\n break;\n default: {\n const _exhaustive: never = element;\n void _exhaustive;\n }\n }\n }\n\n return map;\n}\n","/**\n * JSON Forms UI Schema generator for FormSpec forms.\n *\n * Routes through the canonical IR pipeline: Chain DSL → FormIR → UI Schema.\n */\n\nimport type { FormElement, FormSpec, MetadataPolicyInput } from \"@formspec/core\";\nimport { canonicalizeChainDSL } from \"../canonicalize/index.js\";\nimport { generateUiSchemaFromIR } from \"./ir-generator.js\";\nimport type { UISchema } from \"./types.js\";\n\n/**\n * Options for generating a UI Schema from a Chain DSL form.\n *\n * @public\n */\nexport interface GenerateUiSchemaOptions {\n /** Metadata resolution policy for chain DSL UI generation. */\n readonly metadata?: MetadataPolicyInput | undefined;\n}\n\n/**\n * Generates a JSON Forms UI Schema from a FormSpec.\n *\n * All generation routes through the canonical IR. The chain DSL is first\n * canonicalized to a FormIR, then the IR-based generator produces the schema.\n *\n * @example\n * ```typescript\n * const form = formspec(\n * group(\"Customer\",\n * field.text(\"name\", { label: \"Name\" }),\n * ),\n * when(\"status\", \"draft\",\n * field.text(\"notes\", { label: \"Notes\" }),\n * ),\n * );\n *\n * const uiSchema = generateUiSchema(form);\n * // {\n * // type: \"VerticalLayout\",\n * // elements: [\n * // {\n * // type: \"Group\",\n * // label: \"Customer\",\n * // elements: [\n * // { type: \"Control\", scope: \"#/properties/name\", label: \"Name\" }\n * // ]\n * // },\n * // {\n * // type: \"Control\",\n * // scope: \"#/properties/notes\",\n * // label: \"Notes\",\n * // rule: {\n * // effect: \"SHOW\",\n * // condition: { scope: \"#/properties/status\", schema: { const: \"draft\" } }\n * // }\n * // }\n * // ]\n * // }\n * ```\n *\n * @param form - The FormSpec to convert\n * @returns A JSON Forms UI Schema\n *\n * @public\n */\nexport function generateUiSchema<E extends readonly FormElement[]>(\n form: FormSpec<E>,\n options?: GenerateUiSchemaOptions\n): UISchema {\n const ir = canonicalizeChainDSL(\n form,\n options?.metadata !== undefined ? { metadata: options.metadata } : undefined\n );\n return generateUiSchemaFromIR(ir);\n}\n","/**\n * JSON Schema type definitions.\n *\n * These types are a subset of JSON Schema sufficient for form generation.\n */\n\n/**\n * JSON Schema primitive types.\n *\n * @public\n */\nexport type JSONSchemaType =\n | \"string\"\n | \"number\"\n | \"integer\"\n | \"boolean\"\n | \"object\"\n | \"array\"\n | \"null\";\n\n/**\n * A JSON Schema definition (legacy subset used by Zod validator and types.ts).\n *\n * @public\n */\nexport interface JSONSchema7 {\n /** Declared JSON Schema dialect URI for the document root. */\n $schema?: string;\n /** Stable identifier for the schema document or sub-schema. */\n $id?: string;\n /** Reference to another schema location. */\n $ref?: string;\n\n // Metadata\n /** Human-readable title for the schema node. */\n title?: string;\n /** Human-readable description for the schema node. */\n description?: string;\n /** Whether the schema node is deprecated. */\n deprecated?: boolean;\n\n // Type\n /** JSON Schema type keyword for the current node. */\n type?: JSONSchemaType | JSONSchemaType[];\n\n // String validation\n /** Inclusive minimum string length. */\n minLength?: number;\n /** Inclusive maximum string length. */\n maxLength?: number;\n /** Regular expression pattern applied to string values. */\n pattern?: string;\n\n // Number validation\n /** Inclusive numeric lower bound. */\n minimum?: number;\n /** Inclusive numeric upper bound. */\n maximum?: number;\n /** Exclusive numeric lower bound. */\n exclusiveMinimum?: number;\n /** Exclusive numeric upper bound. */\n exclusiveMaximum?: number;\n\n // Enum\n /** Closed set of allowed scalar values. */\n enum?: readonly (string | number | boolean | null)[];\n /** Literal value the instance must equal. */\n const?: string | number | boolean | null;\n\n // Object\n /** Object properties keyed by property name. */\n properties?: Record<string, JSONSchema7>;\n /** Property names that must be present on object values. */\n required?: string[];\n /** Whether, or how, additional object properties are allowed. */\n additionalProperties?: boolean | JSONSchema7;\n\n // Array\n /** Item schema or tuple schemas applied to array elements. */\n items?: JSONSchema7 | JSONSchema7[];\n /** Inclusive minimum array length. */\n minItems?: number;\n /** Inclusive maximum array length. */\n maxItems?: number;\n\n // Composition\n /** Schemas that must all validate successfully. */\n allOf?: JSONSchema7[];\n /** Schemas of which at least one may validate successfully. */\n anyOf?: JSONSchema7[];\n /** Schemas of which exactly one should validate successfully. */\n oneOf?: JSONSchema7[];\n /** Schema that must not validate successfully. */\n not?: JSONSchema7;\n\n // Conditional\n /** Conditional branch predicate schema. */\n if?: JSONSchema7;\n /** Schema applied when the `if` branch matches. */\n then?: JSONSchema7;\n /** Schema applied when the `if` branch does not match. */\n else?: JSONSchema7;\n\n // Format\n /** Format hint for downstream validators and tooling. */\n format?: string;\n\n // Default\n /** Default value suggested for the schema node. */\n default?: unknown;\n\n // =============================================================================\n // FormSpec Extensions (x- prefixed)\n // =============================================================================\n\n /**\n * Data source key for dynamic enum fields.\n * Indicates that options should be fetched from a registered resolver.\n */\n \"x-formspec-source\"?: string;\n\n /**\n * Field names whose values are needed to fetch dynamic enum options.\n * Used for dependent/cascading dropdowns.\n */\n \"x-formspec-params\"?: readonly string[];\n\n /**\n * Schema source identifier for dynamic schema fields.\n * Indicates that the schema should be loaded dynamically at runtime.\n */\n \"x-formspec-schemaSource\"?: string;\n}\n\n/**\n * Extension properties for custom FormSpec constraint tags.\n *\n * @public\n */\nexport type FormSpecSchemaExtensions = Record<`x-formspec-${string}`, unknown>;\n\n/**\n * JSON Schema with FormSpec extension properties for arbitrary `x-formspec-*` keys.\n *\n * @public\n */\nexport type ExtendedJSONSchema7 = JSONSchema7 & FormSpecSchemaExtensions;\n\n/**\n * Sets a FormSpec extension property on a JSON Schema node.\n *\n * Use this to safely add `x-formspec-*` properties to any schema,\n * including nested schemas typed as `JSONSchema7` (which don't carry\n * the extension index signature).\n *\n * @param schema - Any JSON Schema node\n * @param key - Extension key (must start with `x-formspec-`)\n * @param value - Extension value\n *\n * @internal\n */\nexport function setSchemaExtension(\n schema: object,\n key: `x-formspec-${string}`,\n value: unknown\n): void {\n (schema as Record<string, unknown>)[key] = value;\n}\n\n/**\n * Reads a FormSpec extension property from a JSON Schema node.\n *\n * Accepts any schema object — `JSONSchema7`, `JsonSchema2020`, `ExtendedJSONSchema7`, etc.\n *\n * @param schema - Any JSON Schema node\n * @param key - Extension key (must start with `x-formspec-`)\n * @returns The extension value, or `undefined` if not present\n *\n * @internal\n */\nexport function getSchemaExtension(schema: object, key: `x-formspec-${string}`): unknown {\n return (schema as Record<string, unknown>)[key];\n}\n","/**\n * Extension registry for resolving custom types, constraints, and annotations\n * during JSON Schema generation and IR validation.\n *\n * The registry is created from a list of {@link ExtensionDefinition} objects\n * and provides O(1) lookup by fully-qualified ID (extensionId + \"/\" + name).\n *\n * @packageDocumentation\n */\n\nimport type {\n ExtensionDefinition,\n CustomTypeRegistration,\n CustomConstraintRegistration,\n CustomAnnotationRegistration,\n ConstraintTagRegistration,\n BuiltinConstraintBroadeningRegistration,\n} from \"@formspec/core\";\n\n// =============================================================================\n// PUBLIC API\n// =============================================================================\n\n/**\n * A registry of extensions that provides lookup by fully-qualified ID.\n *\n * Type IDs follow the format: `<extensionId>/<typeName>`\n * Constraint IDs follow the format: `<extensionId>/<constraintName>`\n * Annotation IDs follow the format: `<extensionId>/<annotationName>`\n *\n * @public\n */\nexport interface ExtensionRegistry {\n /** The extensions registered in this registry (in registration order). */\n readonly extensions: readonly ExtensionDefinition[];\n\n /**\n * Look up a custom type registration by its fully-qualified type ID.\n *\n * @param typeId - The fully-qualified type ID (e.g., \"x-stripe/monetary/Decimal\").\n * @returns The registration if found, otherwise `undefined`.\n */\n findType(typeId: string): CustomTypeRegistration | undefined;\n /**\n * Look up a custom type registration by a TypeScript-facing type name.\n *\n * This is used during TSDoc/class analysis to resolve extension-defined\n * custom types from source-level declarations.\n */\n findTypeByName(\n typeName: string\n ): { readonly extensionId: string; readonly registration: CustomTypeRegistration } | undefined;\n\n /**\n * Look up a custom constraint registration by its fully-qualified constraint ID.\n *\n * @param constraintId - The fully-qualified constraint ID.\n * @returns The registration if found, otherwise `undefined`.\n */\n findConstraint(constraintId: string): CustomConstraintRegistration | undefined;\n /**\n * Look up a TSDoc custom constraint-tag registration by tag name.\n */\n findConstraintTag(tagName: string):\n | {\n readonly extensionId: string;\n readonly registration: ConstraintTagRegistration;\n }\n | undefined;\n /**\n * Look up built-in tag broadening for a given custom type ID.\n */\n findBuiltinConstraintBroadening(\n typeId: string,\n tagName: string\n ):\n | {\n readonly extensionId: string;\n readonly registration: BuiltinConstraintBroadeningRegistration;\n }\n | undefined;\n\n /**\n * Look up a custom annotation registration by its fully-qualified annotation ID.\n *\n * @param annotationId - The fully-qualified annotation ID.\n * @returns The registration if found, otherwise `undefined`.\n */\n findAnnotation(annotationId: string): CustomAnnotationRegistration | undefined;\n}\n\n// =============================================================================\n// IMPLEMENTATION\n// =============================================================================\n\n/**\n * Creates an extension registry from a list of extension definitions.\n *\n * The registry indexes all types, constraints, and annotations by their\n * fully-qualified IDs (`<extensionId>/<name>`) for O(1) lookup during\n * generation and validation.\n *\n * @param extensions - The extension definitions to register.\n * @returns An {@link ExtensionRegistry} instance.\n * @throws If duplicate type/constraint/annotation IDs are detected across extensions.\n *\n * @public\n */\nexport function createExtensionRegistry(\n extensions: readonly ExtensionDefinition[]\n): ExtensionRegistry {\n const typeMap = new Map<string, CustomTypeRegistration>();\n const typeNameMap = new Map<\n string,\n { readonly extensionId: string; readonly registration: CustomTypeRegistration }\n >();\n const constraintMap = new Map<string, CustomConstraintRegistration>();\n const constraintTagMap = new Map<\n string,\n { readonly extensionId: string; readonly registration: ConstraintTagRegistration }\n >();\n const builtinBroadeningMap = new Map<\n string,\n { readonly extensionId: string; readonly registration: BuiltinConstraintBroadeningRegistration }\n >();\n const annotationMap = new Map<string, CustomAnnotationRegistration>();\n\n for (const ext of extensions) {\n if (ext.types !== undefined) {\n for (const type of ext.types) {\n const qualifiedId = `${ext.extensionId}/${type.typeName}`;\n if (typeMap.has(qualifiedId)) {\n throw new Error(`Duplicate custom type ID: \"${qualifiedId}\"`);\n }\n typeMap.set(qualifiedId, type);\n\n for (const sourceTypeName of type.tsTypeNames ?? [type.typeName]) {\n if (typeNameMap.has(sourceTypeName)) {\n throw new Error(`Duplicate custom type source name: \"${sourceTypeName}\"`);\n }\n typeNameMap.set(sourceTypeName, {\n extensionId: ext.extensionId,\n registration: type,\n });\n }\n\n if (type.builtinConstraintBroadenings !== undefined) {\n for (const broadening of type.builtinConstraintBroadenings) {\n const key = `${qualifiedId}:${broadening.tagName}`;\n if (builtinBroadeningMap.has(key)) {\n throw new Error(`Duplicate built-in constraint broadening: \"${key}\"`);\n }\n builtinBroadeningMap.set(key, {\n extensionId: ext.extensionId,\n registration: broadening,\n });\n }\n }\n }\n }\n\n if (ext.constraints !== undefined) {\n for (const constraint of ext.constraints) {\n const qualifiedId = `${ext.extensionId}/${constraint.constraintName}`;\n if (constraintMap.has(qualifiedId)) {\n throw new Error(`Duplicate custom constraint ID: \"${qualifiedId}\"`);\n }\n constraintMap.set(qualifiedId, constraint);\n }\n }\n\n if (ext.constraintTags !== undefined) {\n for (const tag of ext.constraintTags) {\n if (constraintTagMap.has(tag.tagName)) {\n throw new Error(`Duplicate custom constraint tag: \"@${tag.tagName}\"`);\n }\n constraintTagMap.set(tag.tagName, {\n extensionId: ext.extensionId,\n registration: tag,\n });\n }\n }\n\n if (ext.annotations !== undefined) {\n for (const annotation of ext.annotations) {\n const qualifiedId = `${ext.extensionId}/${annotation.annotationName}`;\n if (annotationMap.has(qualifiedId)) {\n throw new Error(`Duplicate custom annotation ID: \"${qualifiedId}\"`);\n }\n annotationMap.set(qualifiedId, annotation);\n }\n }\n }\n\n return {\n extensions,\n findType: (typeId: string) => typeMap.get(typeId),\n findTypeByName: (typeName: string) => typeNameMap.get(typeName),\n findConstraint: (constraintId: string) => constraintMap.get(constraintId),\n findConstraintTag: (tagName: string) => constraintTagMap.get(tagName),\n findBuiltinConstraintBroadening: (typeId: string, tagName: string) =>\n builtinBroadeningMap.get(`${typeId}:${tagName}`),\n findAnnotation: (annotationId: string) => annotationMap.get(annotationId),\n };\n}\n","/**\n * Zod schemas for JSON Schema output validation.\n *\n * These schemas cover the subset of JSON Schema that FormSpec generates,\n * plus the FormSpec-specific `x-formspec-*` extension properties.\n *\n * @see https://json-schema.org/draft/2020-12/schema\n */\n\nimport { z } from \"zod\";\nimport type { JSONSchema7 } from \"./types.js\";\n\n// =============================================================================\n// JSON Schema type enum\n// =============================================================================\n\n/**\n * Zod schema for JSON Schema primitive type strings.\n *\n * @public\n */\nexport const jsonSchemaTypeSchema = z.enum([\n \"string\",\n \"number\",\n \"integer\",\n \"boolean\",\n \"object\",\n \"array\",\n \"null\",\n]);\n\n// =============================================================================\n// JSON Schema validator schema (recursive)\n// =============================================================================\n\n// We annotate with z.ZodType<JSONSchema7> for the recursive self-reference.\n// The @ts-expect-error is required because exactOptionalPropertyTypes:true causes\n// Zod's inferred output type for optional fields (`T | undefined`) to be\n// incompatible with the JSONSchema7 interface's exact optional fields (`T?`).\n// The runtime behavior is correct: z.optional() will strip `undefined` values\n// during parsing and correctly handle absent keys.\n//\n/**\n * Zod schema for the legacy JSON Schema 7 subset used by `@formspec/build`.\n *\n * @public\n */\n// @ts-expect-error -- exactOptionalPropertyTypes: Zod optional infers `T | undefined`\n// but JSONSchema7 uses exact optional `?:` which disallows explicit undefined.\nexport const jsonSchema7Schema: z.ZodType<JSONSchema7> = z.lazy(() =>\n z\n .object({\n $schema: z.string().optional(),\n $id: z.string().optional(),\n $ref: z.string().optional(),\n\n // Metadata\n title: z.string().optional(),\n description: z.string().optional(),\n deprecated: z.boolean().optional(),\n\n // Type\n type: z.union([jsonSchemaTypeSchema, z.array(jsonSchemaTypeSchema)]).optional(),\n\n // String validation\n minLength: z.number().optional(),\n maxLength: z.number().optional(),\n pattern: z.string().optional(),\n\n // Number validation\n minimum: z.number().optional(),\n maximum: z.number().optional(),\n exclusiveMinimum: z.number().optional(),\n exclusiveMaximum: z.number().optional(),\n\n // Enum\n enum: z\n .array(z.union([z.string(), z.number(), z.boolean(), z.null()]))\n .readonly()\n .optional(),\n const: z.union([z.string(), z.number(), z.boolean(), z.null()]).optional(),\n\n // Object\n properties: z.record(z.string(), jsonSchema7Schema).optional(),\n required: z.array(z.string()).optional(),\n additionalProperties: z.union([z.boolean(), jsonSchema7Schema]).optional(),\n\n // Array\n items: z.union([jsonSchema7Schema, z.array(jsonSchema7Schema)]).optional(),\n minItems: z.number().optional(),\n maxItems: z.number().optional(),\n\n // Composition\n allOf: z.array(jsonSchema7Schema).optional(),\n anyOf: z.array(jsonSchema7Schema).optional(),\n oneOf: z.array(jsonSchema7Schema).optional(),\n not: jsonSchema7Schema.optional(),\n\n // Conditional\n if: jsonSchema7Schema.optional(),\n then: jsonSchema7Schema.optional(),\n else: jsonSchema7Schema.optional(),\n\n // Format\n format: z.string().optional(),\n\n // Default\n default: z.unknown().optional(),\n\n // FormSpec extensions\n \"x-formspec-source\": z.string().optional(),\n \"x-formspec-params\": z.array(z.string()).readonly().optional(),\n \"x-formspec-schemaSource\": z.string().optional(),\n })\n // passthrough preserves arbitrary x-formspec-* extension properties\n // added by custom constraint tags without causing validation failures\n .passthrough()\n);\n","/**\n * Constraint validator for the FormSpec IR.\n *\n * Delegates target-centric semantic analysis to `@formspec/analysis` so build\n * validation and editor tooling share the same inheritance, path-target,\n * contradiction, and broadening semantics.\n *\n * @packageDocumentation\n */\n\nimport {\n analyzeConstraintTargets,\n type ConstraintRegistryLike,\n type ConstraintSemanticDiagnostic,\n} from \"@formspec/analysis/internal\";\nimport type { FormIR, FormIRElement, FieldNode, ObjectProperty } from \"@formspec/core/internals\";\nimport type { ExtensionRegistry } from \"../extensions/index.js\";\n\nexport type ValidationDiagnostic = ConstraintSemanticDiagnostic;\n\nexport interface ValidationResult {\n readonly diagnostics: readonly ValidationDiagnostic[];\n readonly valid: boolean;\n}\n\nexport interface ValidateIROptions {\n readonly vendorPrefix?: string;\n readonly extensionRegistry?: ExtensionRegistry;\n}\n\ninterface ValidationContext {\n readonly diagnostics: ValidationDiagnostic[];\n readonly extensionRegistry: ConstraintRegistryLike | undefined;\n readonly typeRegistry: FormIR[\"typeRegistry\"];\n}\n\nfunction validateFieldNode(ctx: ValidationContext, field: FieldNode): void {\n const analysis = analyzeConstraintTargets(\n field.name,\n field.type,\n field.constraints,\n ctx.typeRegistry,\n ctx.extensionRegistry === undefined\n ? undefined\n : {\n extensionRegistry: ctx.extensionRegistry,\n }\n );\n ctx.diagnostics.push(...analysis.diagnostics);\n\n if (field.type.kind === \"object\") {\n for (const property of field.type.properties) {\n validateObjectProperty(ctx, field.name, property);\n }\n }\n}\n\nfunction validateObjectProperty(\n ctx: ValidationContext,\n parentName: string,\n property: ObjectProperty\n): void {\n const qualifiedName = `${parentName}.${property.name}`;\n const analysis = analyzeConstraintTargets(\n qualifiedName,\n property.type,\n property.constraints,\n ctx.typeRegistry,\n ctx.extensionRegistry === undefined\n ? undefined\n : {\n extensionRegistry: ctx.extensionRegistry,\n }\n );\n ctx.diagnostics.push(...analysis.diagnostics);\n\n if (property.type.kind === \"object\") {\n for (const nestedProperty of property.type.properties) {\n validateObjectProperty(ctx, qualifiedName, nestedProperty);\n }\n }\n}\n\nfunction validateElement(ctx: ValidationContext, element: FormIRElement): void {\n switch (element.kind) {\n case \"field\":\n validateFieldNode(ctx, element);\n break;\n case \"group\":\n for (const child of element.elements) {\n validateElement(ctx, child);\n }\n break;\n case \"conditional\":\n for (const child of element.elements) {\n validateElement(ctx, child);\n }\n break;\n default: {\n const exhaustive: never = element;\n throw new Error(`Unhandled element kind: ${String(exhaustive)}`);\n }\n }\n}\n\nexport function validateIR(ir: FormIR, options?: ValidateIROptions): ValidationResult {\n const ctx: ValidationContext = {\n diagnostics: [],\n extensionRegistry: options?.extensionRegistry,\n typeRegistry: ir.typeRegistry,\n };\n\n for (const element of ir.elements) {\n validateElement(ctx, element);\n }\n\n return {\n diagnostics: ctx.diagnostics,\n valid: ctx.diagnostics.every((diagnostic) => diagnostic.severity !== \"error\"),\n };\n}\n"],"mappings":"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","names":["import_internals","import_zod","import_zod"]}
|