@formspec/build 0.1.0-alpha.10 → 0.1.0-alpha.11

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.
Files changed (107) hide show
  1. package/dist/browser.cjs +549 -0
  2. package/dist/browser.cjs.map +1 -0
  3. package/dist/browser.d.ts +4 -2
  4. package/dist/browser.d.ts.map +1 -1
  5. package/dist/browser.js +498 -45
  6. package/dist/browser.js.map +1 -1
  7. package/dist/build.d.ts +343 -33
  8. package/dist/cli.cjs +2267 -0
  9. package/dist/cli.cjs.map +1 -0
  10. package/dist/cli.js +2204 -101
  11. package/dist/cli.js.map +1 -1
  12. package/dist/generators/class-schema.d.ts +5 -9
  13. package/dist/generators/class-schema.d.ts.map +1 -1
  14. package/dist/index.cjs +2093 -0
  15. package/dist/index.cjs.map +1 -0
  16. package/dist/index.d.ts +4 -2
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +2024 -114
  19. package/dist/index.js.map +1 -1
  20. package/dist/internals.cjs +1345 -0
  21. package/dist/internals.cjs.map +1 -0
  22. package/dist/internals.d.ts +1 -0
  23. package/dist/internals.d.ts.map +1 -1
  24. package/dist/internals.js +1297 -21
  25. package/dist/internals.js.map +1 -1
  26. package/dist/json-schema/generator.d.ts.map +1 -1
  27. package/dist/json-schema/schema.d.ts +16 -0
  28. package/dist/json-schema/schema.d.ts.map +1 -0
  29. package/dist/ui-schema/generator.d.ts +15 -0
  30. package/dist/ui-schema/generator.d.ts.map +1 -1
  31. package/dist/ui-schema/schema.d.ts +357 -0
  32. package/dist/ui-schema/schema.d.ts.map +1 -0
  33. package/dist/ui-schema/types.d.ts +8 -73
  34. package/dist/ui-schema/types.d.ts.map +1 -1
  35. package/package.json +14 -9
  36. package/dist/__tests__/analyzer-edge-cases.test.js +0 -376
  37. package/dist/__tests__/analyzer-edge-cases.test.js.map +0 -1
  38. package/dist/__tests__/analyzer.test.js +0 -190
  39. package/dist/__tests__/analyzer.test.js.map +0 -1
  40. package/dist/__tests__/cli.test.js +0 -178
  41. package/dist/__tests__/cli.test.js.map +0 -1
  42. package/dist/__tests__/codegen.test.js +0 -506
  43. package/dist/__tests__/codegen.test.js.map +0 -1
  44. package/dist/__tests__/decorator-pipeline.test.js +0 -460
  45. package/dist/__tests__/decorator-pipeline.test.js.map +0 -1
  46. package/dist/__tests__/edge-cases.test.js +0 -215
  47. package/dist/__tests__/edge-cases.test.js.map +0 -1
  48. package/dist/__tests__/fixtures/edge-cases.js +0 -137
  49. package/dist/__tests__/fixtures/edge-cases.js.map +0 -1
  50. package/dist/__tests__/fixtures/example-a-builtins.js +0 -100
  51. package/dist/__tests__/fixtures/example-a-builtins.js.map +0 -1
  52. package/dist/__tests__/fixtures/example-b-decorators.js +0 -5
  53. package/dist/__tests__/fixtures/example-b-decorators.js.map +0 -1
  54. package/dist/__tests__/fixtures/example-b-extended.js +0 -60
  55. package/dist/__tests__/fixtures/example-b-extended.js.map +0 -1
  56. package/dist/__tests__/fixtures/example-c-custom.js +0 -61
  57. package/dist/__tests__/fixtures/example-c-custom.js.map +0 -1
  58. package/dist/__tests__/fixtures/example-c-decorators.js +0 -4
  59. package/dist/__tests__/fixtures/example-c-decorators.js.map +0 -1
  60. package/dist/__tests__/fixtures/example-d-mixed-decorators.js +0 -75
  61. package/dist/__tests__/fixtures/example-d-mixed-decorators.js.map +0 -1
  62. package/dist/__tests__/fixtures/example-e-decorators.js +0 -10
  63. package/dist/__tests__/fixtures/example-e-decorators.js.map +0 -1
  64. package/dist/__tests__/fixtures/example-e-no-namespace.js +0 -61
  65. package/dist/__tests__/fixtures/example-e-no-namespace.js.map +0 -1
  66. package/dist/__tests__/fixtures/example-interface-types.js +0 -8
  67. package/dist/__tests__/fixtures/example-interface-types.js.map +0 -1
  68. package/dist/__tests__/fixtures/example-jsdoc-constraints.js +0 -98
  69. package/dist/__tests__/fixtures/example-jsdoc-constraints.js.map +0 -1
  70. package/dist/__tests__/fixtures/example-nested-class.js +0 -248
  71. package/dist/__tests__/fixtures/example-nested-class.js.map +0 -1
  72. package/dist/__tests__/fixtures/sample-forms.js +0 -78
  73. package/dist/__tests__/fixtures/sample-forms.js.map +0 -1
  74. package/dist/__tests__/generator.test.js +0 -234
  75. package/dist/__tests__/generator.test.js.map +0 -1
  76. package/dist/__tests__/integration.test.js +0 -161
  77. package/dist/__tests__/integration.test.js.map +0 -1
  78. package/dist/__tests__/interface-types.test.js +0 -404
  79. package/dist/__tests__/interface-types.test.js.map +0 -1
  80. package/dist/__tests__/jsdoc-constraints.test.js +0 -465
  81. package/dist/__tests__/jsdoc-constraints.test.js.map +0 -1
  82. package/dist/__tests__/write-schemas.test.js +0 -198
  83. package/dist/__tests__/write-schemas.test.js.map +0 -1
  84. package/dist/analyzer/class-analyzer.js +0 -377
  85. package/dist/analyzer/class-analyzer.js.map +0 -1
  86. package/dist/analyzer/decorator-extractor.js +0 -336
  87. package/dist/analyzer/decorator-extractor.js.map +0 -1
  88. package/dist/analyzer/jsdoc-constraints.js +0 -153
  89. package/dist/analyzer/jsdoc-constraints.js.map +0 -1
  90. package/dist/analyzer/program.js +0 -114
  91. package/dist/analyzer/program.js.map +0 -1
  92. package/dist/analyzer/type-converter.js +0 -474
  93. package/dist/analyzer/type-converter.js.map +0 -1
  94. package/dist/codegen/index.js +0 -597
  95. package/dist/codegen/index.js.map +0 -1
  96. package/dist/generators/class-schema.js +0 -140
  97. package/dist/generators/class-schema.js.map +0 -1
  98. package/dist/generators/method-schema.js +0 -108
  99. package/dist/generators/method-schema.js.map +0 -1
  100. package/dist/json-schema/generator.js +0 -166
  101. package/dist/json-schema/generator.js.map +0 -1
  102. package/dist/json-schema/types.js +0 -33
  103. package/dist/json-schema/types.js.map +0 -1
  104. package/dist/ui-schema/generator.js +0 -148
  105. package/dist/ui-schema/generator.js.map +0 -1
  106. package/dist/ui-schema/types.js +0 -8
  107. package/dist/ui-schema/types.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"internals.js","sourceRoot":"","sources":["../src/internals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,4CAA4C;AAC5C,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAE/B,sDAAsD;AACtD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGhG,2BAA2B;AAC3B,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAEpE,4BAA4B;AAC5B,OAAO,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC"}
1
+ {"version":3,"sources":["../src/analyzer/program.ts","../src/analyzer/class-analyzer.ts","../src/analyzer/decorator-extractor.ts","../src/analyzer/jsdoc-constraints.ts","../src/analyzer/type-converter.ts","../src/json-schema/types.ts","../src/ui-schema/schema.ts","../src/ui-schema/generator.ts","../src/generators/class-schema.ts","../src/generators/method-schema.ts"],"sourcesContent":["/**\n * TypeScript program setup for static analysis.\n *\n * Creates a TypeScript program with type checker from a source file,\n * using the project's tsconfig.json for compiler options.\n */\n\nimport * as ts from \"typescript\";\nimport * as path from \"node:path\";\n\n/**\n * Result of creating a TypeScript program for analysis.\n */\nexport interface ProgramContext {\n /** The TypeScript program */\n program: ts.Program;\n /** Type checker for resolving types */\n checker: ts.TypeChecker;\n /** The source file being analyzed */\n sourceFile: ts.SourceFile;\n}\n\n/**\n * Creates a TypeScript program for analyzing a source file.\n *\n * Looks for tsconfig.json in the file's directory or parent directories.\n * Falls back to default compiler options if no config is found.\n *\n * @param filePath - Absolute path to the TypeScript source file\n * @returns Program context with checker and source file\n */\nexport function createProgramContext(filePath: string): ProgramContext {\n const absolutePath = path.resolve(filePath);\n const fileDir = path.dirname(absolutePath);\n\n // Find tsconfig.json - using ts.sys.fileExists which has `this: void` requirement\n const configPath = ts.findConfigFile(fileDir, ts.sys.fileExists.bind(ts.sys), \"tsconfig.json\");\n\n let compilerOptions: ts.CompilerOptions;\n let fileNames: string[];\n\n if (configPath) {\n const configFile = ts.readConfigFile(configPath, ts.sys.readFile.bind(ts.sys));\n if (configFile.error) {\n throw new Error(\n `Error reading tsconfig.json: ${ts.flattenDiagnosticMessageText(configFile.error.messageText, \"\\n\")}`\n );\n }\n\n const parsed = ts.parseJsonConfigFileContent(\n configFile.config,\n ts.sys,\n path.dirname(configPath)\n );\n\n if (parsed.errors.length > 0) {\n const errorMessages = parsed.errors\n .map((e) => ts.flattenDiagnosticMessageText(e.messageText, \"\\n\"))\n .join(\"\\n\");\n throw new Error(`Error parsing tsconfig.json: ${errorMessages}`);\n }\n\n compilerOptions = parsed.options;\n // Include the target file in the program\n fileNames = parsed.fileNames.includes(absolutePath)\n ? parsed.fileNames\n : [...parsed.fileNames, absolutePath];\n } else {\n // Fallback to default options\n compilerOptions = {\n target: ts.ScriptTarget.ES2022,\n module: ts.ModuleKind.NodeNext,\n moduleResolution: ts.ModuleResolutionKind.NodeNext,\n strict: true,\n skipLibCheck: true,\n declaration: true,\n };\n fileNames = [absolutePath];\n }\n\n const program = ts.createProgram(fileNames, compilerOptions);\n const sourceFile = program.getSourceFile(absolutePath);\n\n if (!sourceFile) {\n throw new Error(`Could not find source file: ${absolutePath}`);\n }\n\n return {\n program,\n checker: program.getTypeChecker(),\n sourceFile,\n };\n}\n\n/**\n * Generic AST node finder by name. Walks the source file tree and returns\n * the first node matching the predicate with the given name.\n */\nfunction findNodeByName<T extends ts.Node>(\n sourceFile: ts.SourceFile,\n name: string,\n predicate: (node: ts.Node) => node is T,\n getName: (node: T) => string | undefined\n): T | null {\n let result: T | null = null;\n\n function visit(node: ts.Node): void {\n if (result) return;\n\n if (predicate(node) && getName(node) === name) {\n result = node;\n return;\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return result;\n}\n\n/**\n * Finds a class declaration by name in a source file.\n *\n * @param sourceFile - The source file to search\n * @param className - Name of the class to find\n * @returns The class declaration node, or null if not found\n */\nexport function findClassByName(\n sourceFile: ts.SourceFile,\n className: string\n): ts.ClassDeclaration | null {\n return findNodeByName(sourceFile, className, ts.isClassDeclaration, (n) => n.name?.text);\n}\n\n/**\n * Finds an interface declaration by name in a source file.\n *\n * @param sourceFile - The source file to search\n * @param interfaceName - Name of the interface to find\n * @returns The interface declaration node, or null if not found\n */\nexport function findInterfaceByName(\n sourceFile: ts.SourceFile,\n interfaceName: string\n): ts.InterfaceDeclaration | null {\n return findNodeByName(sourceFile, interfaceName, ts.isInterfaceDeclaration, (n) => n.name.text);\n}\n\n/**\n * Finds a type alias declaration by name in a source file.\n *\n * @param sourceFile - The source file to search\n * @param aliasName - Name of the type alias to find\n * @returns The type alias declaration node, or null if not found\n */\nexport function findTypeAliasByName(\n sourceFile: ts.SourceFile,\n aliasName: string\n): ts.TypeAliasDeclaration | null {\n return findNodeByName(sourceFile, aliasName, ts.isTypeAliasDeclaration, (n) => n.name.text);\n}\n","/**\n * Class analyzer for extracting fields, types, and decorators.\n *\n * Analyzes a TypeScript class declaration to extract:\n * - Field names and TypeScript types\n * - Decorator metadata (Field, Minimum, Maximum, etc.)\n * - Field optionality\n * - TSDoc @deprecated tags\n * - Default values from property initializers\n */\n\nimport * as ts from \"typescript\";\nimport { extractDecorators, resolveDecorator, type DecoratorInfo } from \"./decorator-extractor.js\";\nimport { extractJSDocConstraints, extractJSDocFieldMetadata } from \"./jsdoc-constraints.js\";\n\n/**\n * Analyzed field information from a class.\n */\nexport interface FieldInfo {\n /** Field name */\n name: string;\n /** TypeScript type node for the field */\n typeNode: ts.TypeNode | undefined;\n /** Resolved type from the type checker */\n type: ts.Type;\n /** Whether the field is optional (has ? modifier) */\n optional: boolean;\n /** Decorators applied to the field */\n decorators: DecoratorInfo[];\n /** Whether the field has a TSDoc @deprecated tag */\n deprecated: boolean;\n /** Default value extracted from the property initializer (literal values only) */\n defaultValue: unknown;\n}\n\n/**\n * Result of analyzing a class declaration.\n */\nexport interface ClassAnalysis {\n /** Class name */\n name: string;\n /** Analyzed fields */\n fields: FieldInfo[];\n /** Instance methods */\n instanceMethods: MethodInfo[];\n /** Static methods */\n staticMethods: MethodInfo[];\n}\n\n/**\n * Analyzed method information.\n */\nexport interface MethodInfo {\n /** Method name */\n name: string;\n /** Method parameters */\n parameters: ParameterInfo[];\n /** Return type node */\n returnTypeNode: ts.TypeNode | undefined;\n /** Resolved return type */\n returnType: ts.Type;\n}\n\n/**\n * Analyzed parameter information.\n */\nexport interface ParameterInfo {\n /** Parameter name */\n name: string;\n /** TypeScript type node */\n typeNode: ts.TypeNode | undefined;\n /** Resolved type */\n type: ts.Type;\n /** If this is InferSchema<typeof X>, the export name X */\n formSpecExportName: string | null;\n /** Whether the parameter is optional (has ? or default value) */\n optional: boolean;\n}\n\n/**\n * Analyzes a class declaration to extract fields and methods.\n *\n * @param classDecl - The class declaration to analyze\n * @param checker - TypeScript type checker\n * @returns Analysis result with fields and methods\n */\nexport function analyzeClass(\n classDecl: ts.ClassDeclaration,\n checker: ts.TypeChecker\n): ClassAnalysis {\n const name = classDecl.name?.text ?? \"AnonymousClass\";\n const fields: FieldInfo[] = [];\n const instanceMethods: MethodInfo[] = [];\n const staticMethods: MethodInfo[] = [];\n\n for (const member of classDecl.members) {\n if (ts.isPropertyDeclaration(member)) {\n const fieldInfo = analyzeField(member, checker);\n if (fieldInfo) {\n fields.push(fieldInfo);\n }\n } else if (ts.isMethodDeclaration(member)) {\n const methodInfo = analyzeMethod(member, checker);\n if (methodInfo) {\n const isStatic = member.modifiers?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword);\n if (isStatic) {\n staticMethods.push(methodInfo);\n } else {\n instanceMethods.push(methodInfo);\n }\n }\n }\n }\n\n return {\n name,\n fields,\n instanceMethods,\n staticMethods,\n };\n}\n\n/**\n * Analyzes a property declaration to extract field info.\n */\nexport function analyzeField(\n prop: ts.PropertyDeclaration,\n checker: ts.TypeChecker\n): FieldInfo | null {\n // Skip computed property names\n if (!ts.isIdentifier(prop.name)) {\n return null;\n }\n\n const name = prop.name.text;\n const typeNode = prop.type;\n const type = checker.getTypeAtLocation(prop);\n const optional = prop.questionToken !== undefined;\n const decorators = extractDecorators(prop);\n\n // Resolve each decorator via the type checker to detect extended/custom decorators\n for (const dec of decorators) {\n if (dec.node) {\n const resolved = resolveDecorator(dec.node, checker);\n if (resolved) {\n dec.resolved = resolved;\n }\n }\n }\n\n // Inherit constraints from type alias declarations first (as defaults).\n // Field-level decorators and JSDoc are applied after, so they take precedence.\n if (prop.type) {\n const aliasConstraints = extractTypeAliasConstraints(prop.type, checker);\n decorators.push(...aliasConstraints);\n }\n\n // Merge JSDoc constraint tags (e.g., /** @Minimum 0 @Maximum 100 */)\n const jsdocConstraints = extractJSDocConstraints(prop);\n decorators.push(...jsdocConstraints);\n\n const deprecated = hasDeprecatedTag(prop);\n const defaultValue = extractDefaultValue(prop.initializer);\n\n return {\n name,\n typeNode,\n type,\n optional,\n decorators,\n deprecated,\n defaultValue,\n };\n}\n\n/**\n * Given a type node, checks if it references a type alias and extracts\n * JSDoc constraint tags from the alias declaration.\n *\n * Only constraint tags (`@Minimum`, `@Maximum`, `@Pattern`, etc.) are\n * propagated — display metadata (`@Field_displayName`, `@Field_description`)\n * is intentionally excluded because display metadata is a field-level\n * concern, not a type-level one.\n *\n * This makes `type Percent = number` with `@Minimum 0 @Maximum 100`\n * propagate constraints to any field typed as `Percent`.\n */\nfunction extractTypeAliasConstraints(\n typeNode: ts.TypeNode,\n checker: ts.TypeChecker\n): DecoratorInfo[] {\n // Only handle type references (e.g., `Percent`, not `number` directly)\n if (!ts.isTypeReferenceNode(typeNode)) return [];\n\n const symbol = checker.getSymbolAtLocation(typeNode.typeName);\n if (!symbol?.declarations) return [];\n\n const aliasDecl = symbol.declarations.find(ts.isTypeAliasDeclaration);\n if (!aliasDecl) return [];\n\n // Don't extract from object type aliases — those are handled by\n // the nested object analysis pipeline in type-converter.ts\n if (ts.isTypeLiteralNode(aliasDecl.type)) return [];\n\n // Only propagate constraint tags, not display metadata (@Field_displayName,\n // @Field_description). Display metadata on the alias shouldn't override the\n // field's own title/description — those are field-level concerns.\n return extractJSDocConstraints(aliasDecl);\n}\n\n/**\n * Checks if a node has a TSDoc `@deprecated` tag.\n */\nfunction hasDeprecatedTag(node: ts.Node): boolean {\n const jsDocTags = ts.getJSDocTags(node);\n return jsDocTags.some((tag) => tag.tagName.text === \"deprecated\");\n}\n\n/**\n * Extracts a default value from a property initializer.\n *\n * Only extracts literal values (strings, numbers, booleans, null).\n * Non-literal initializers (function calls, expressions, etc.) return undefined.\n */\nfunction extractDefaultValue(initializer: ts.Expression | undefined): unknown {\n if (!initializer) return undefined;\n\n // String literal\n if (ts.isStringLiteral(initializer)) {\n return initializer.text;\n }\n\n // Numeric literal\n if (ts.isNumericLiteral(initializer)) {\n return Number(initializer.text);\n }\n\n // Boolean literals\n if (initializer.kind === ts.SyntaxKind.TrueKeyword) {\n return true;\n }\n if (initializer.kind === ts.SyntaxKind.FalseKeyword) {\n return false;\n }\n\n // Null literal\n if (initializer.kind === ts.SyntaxKind.NullKeyword) {\n return null;\n }\n\n // Negative number\n if (ts.isPrefixUnaryExpression(initializer)) {\n if (\n initializer.operator === ts.SyntaxKind.MinusToken &&\n ts.isNumericLiteral(initializer.operand)\n ) {\n return -Number(initializer.operand.text);\n }\n }\n\n // Non-literal initializer — can't extract statically\n return undefined;\n}\n\n/**\n * Analyzes a method declaration to extract method info.\n */\nfunction analyzeMethod(method: ts.MethodDeclaration, checker: ts.TypeChecker): MethodInfo | null {\n // Skip computed method names\n if (!ts.isIdentifier(method.name)) {\n return null;\n }\n\n const name = method.name.text;\n const parameters: ParameterInfo[] = [];\n\n for (const param of method.parameters) {\n if (ts.isIdentifier(param.name)) {\n const paramInfo = analyzeParameter(param, checker);\n parameters.push(paramInfo);\n }\n }\n\n const returnTypeNode = method.type;\n const signature = checker.getSignatureFromDeclaration(method);\n const returnType = signature\n ? checker.getReturnTypeOfSignature(signature)\n : checker.getTypeAtLocation(method);\n\n return {\n name,\n parameters,\n returnTypeNode,\n returnType,\n };\n}\n\n/**\n * Analyzes a parameter declaration.\n */\nfunction analyzeParameter(param: ts.ParameterDeclaration, checker: ts.TypeChecker): ParameterInfo {\n const name = ts.isIdentifier(param.name) ? param.name.text : \"param\";\n const typeNode = param.type;\n const type = checker.getTypeAtLocation(param);\n const formSpecExportName = detectFormSpecReference(typeNode);\n // Parameter is optional if it has a question token or a default value\n const optional = param.questionToken !== undefined || param.initializer !== undefined;\n\n return {\n name,\n typeNode,\n type,\n formSpecExportName,\n optional,\n };\n}\n\n/**\n * Detects if a type node is InferSchema<typeof X> or InferFormSchema<typeof X> and extracts X.\n *\n * @param typeNode - The type node to check\n * @returns The export name X, or null if not a FormSpec inference pattern\n */\nfunction detectFormSpecReference(typeNode: ts.TypeNode | undefined): string | null {\n if (!typeNode) return null;\n\n // Looking for: InferSchema<typeof X> or InferFormSchema<typeof X>\n if (!ts.isTypeReferenceNode(typeNode)) return null;\n\n // Get the type name - could be Identifier or QualifiedName\n const typeName = ts.isIdentifier(typeNode.typeName)\n ? typeNode.typeName.text\n : ts.isQualifiedName(typeNode.typeName)\n ? typeNode.typeName.right.text\n : null;\n\n // Support both InferSchema (for elements) and InferFormSchema (for FormSpec)\n if (typeName !== \"InferSchema\" && typeName !== \"InferFormSchema\") return null;\n\n const typeArg = typeNode.typeArguments?.[0];\n if (!typeArg || !ts.isTypeQueryNode(typeArg)) return null;\n\n // typeArg.exprName is the identifier (e.g., \"ActivateParams\")\n if (ts.isIdentifier(typeArg.exprName)) {\n return typeArg.exprName.text;\n }\n\n // Could be qualified name like Namespace.ActivateParams\n if (ts.isQualifiedName(typeArg.exprName)) {\n return typeArg.exprName.right.text;\n }\n\n return null;\n}\n\n/**\n * Analyzes an interface declaration to extract field information.\n *\n * Similar to {@link analyzeClass} but for interface declarations.\n * Extracts JSDoc constraint tags (`@Minimum`, `@MaxLength`, etc.) and\n * display metadata (`@Field_displayName`, `@Field_description`) from\n * property signatures, producing the same {@link ClassAnalysis}\n * structure for downstream schema generation.\n *\n * @param interfaceDecl - The interface declaration to analyze\n * @param checker - TypeScript type checker\n * @returns Analysis result with fields (no methods — interfaces have no implementations)\n */\nexport function analyzeInterface(\n interfaceDecl: ts.InterfaceDeclaration,\n checker: ts.TypeChecker\n): ClassAnalysis {\n const name = interfaceDecl.name.text;\n const fields: FieldInfo[] = [];\n\n for (const member of interfaceDecl.members) {\n if (ts.isPropertySignature(member)) {\n const fieldInfo = analyzeInterfaceProperty(member, checker);\n if (fieldInfo) {\n fields.push(fieldInfo);\n }\n }\n }\n\n return {\n name,\n fields,\n instanceMethods: [],\n staticMethods: [],\n };\n}\n\n/**\n * Result of analyzing a type alias — either a successful analysis or\n * an error describing why the alias can't be analyzed.\n */\nexport type AnalyzeTypeAliasResult =\n | { ok: true; analysis: ClassAnalysis }\n | { ok: false; error: string };\n\n/**\n * Analyzes a type alias declaration to extract field information.\n *\n * Supports type aliases whose body is a type literal (object type):\n *\n * ```typescript\n * type Config = {\n * // @Field_displayName Name @Minimum 1\n * name: string;\n * };\n * ```\n *\n * Returns an error result (not an exception) for non-object-literal aliases,\n * allowing callers to accumulate diagnostics across multiple types.\n *\n * @param typeAlias - The type alias declaration to analyze\n * @param checker - TypeScript type checker\n * @returns Success with analysis, or error with a diagnostic message including line number\n */\nexport function analyzeTypeAlias(\n typeAlias: ts.TypeAliasDeclaration,\n checker: ts.TypeChecker\n): AnalyzeTypeAliasResult {\n // Only handle type literals: type X = { ... }\n if (!ts.isTypeLiteralNode(typeAlias.type)) {\n const sourceFile = typeAlias.getSourceFile();\n const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- enum reverse mapping can be undefined for compiler-internal kinds\n const kindDesc = ts.SyntaxKind[typeAlias.type.kind] ?? \"unknown\";\n return {\n ok: false,\n error: `Type alias \"${typeAlias.name.text}\" at line ${String(line + 1)} is not an object type literal (found ${kindDesc})`,\n };\n }\n\n const name = typeAlias.name.text;\n const fields: FieldInfo[] = [];\n\n for (const member of typeAlias.type.members) {\n if (ts.isPropertySignature(member)) {\n const fieldInfo = analyzeInterfaceProperty(member, checker);\n if (fieldInfo) {\n fields.push(fieldInfo);\n }\n }\n }\n\n return {\n ok: true,\n analysis: {\n name,\n fields,\n instanceMethods: [],\n staticMethods: [],\n },\n };\n}\n\n/**\n * Analyzes an interface property signature to extract field info.\n *\n * Extracts JSDoc constraint tags (`@Minimum`, `@MaxLength`, etc.) and\n * display metadata (`@DisplayName`, `@Description`) from the property's\n * TSDoc comments. Also used by the type converter for nested interface/type\n * alias constraint propagation.\n */\nexport function analyzeInterfaceProperty(\n prop: ts.PropertySignature,\n checker: ts.TypeChecker\n): FieldInfo | null {\n if (!ts.isIdentifier(prop.name)) {\n return null;\n }\n\n const name = prop.name.text;\n const typeNode = prop.type;\n const type = checker.getTypeAtLocation(prop);\n const optional = prop.questionToken !== undefined;\n\n // Interface properties have no decorators — only JSDoc tags\n const decorators: DecoratorInfo[] = [];\n\n // Inherit constraints from type alias declarations first (as defaults).\n // Field-level tags are applied after, so they take precedence.\n if (typeNode) {\n const aliasConstraints = extractTypeAliasConstraints(typeNode, checker);\n decorators.push(...aliasConstraints);\n }\n\n // Extract display metadata (@Field_displayName, @Field_description) as synthetic Field decorator\n const fieldMetadata = extractJSDocFieldMetadata(prop);\n if (fieldMetadata) {\n decorators.push(fieldMetadata);\n }\n\n // Extract constraint tags (@Minimum, @MaxLength, @Pattern, etc.)\n const jsdocConstraints = extractJSDocConstraints(prop);\n decorators.push(...jsdocConstraints);\n\n const deprecated = hasDeprecatedTag(prop);\n\n return {\n name,\n typeNode,\n type,\n optional,\n decorators,\n deprecated,\n defaultValue: undefined,\n };\n}\n","/**\n * Decorator extractor for parsing decorator AST nodes.\n *\n * Extracts decorator names and arguments from class field decorators,\n * supporting the FormSpec decorator DSL (@Field, @Minimum, @Maximum, etc.).\n *\n * Also supports branded type resolution via the TypeScript type checker\n * to detect custom decorators created with `extendDecorator` and\n * `customDecorator` from `@formspec/decorators`.\n */\n\nimport * as ts from \"typescript\";\nimport { type FormSpecDecoratorName } from \"@formspec/core\";\n\n/**\n * Extracted decorator information.\n */\nexport interface DecoratorInfo {\n /** Decorator name (e.g., \"Field\", \"Minimum\") */\n name: string;\n /** Decorator arguments as literal values */\n args: DecoratorArg[];\n /** Raw AST node for the decorator (undefined for synthetic JSDoc constraint entries) */\n node: ts.Decorator | undefined;\n /** Resolved brand information from the type checker (populated by analyzeField) */\n resolved?: ResolvedDecorator;\n}\n\n/**\n * A decorator argument value.\n * Can be a primitive, array, or object literal.\n */\nexport type DecoratorArg =\n | string\n | number\n | boolean\n | null\n | DecoratorArg[]\n | { [key: string]: DecoratorArg };\n\n/**\n * Result of resolving a decorator via the type checker.\n */\nexport interface ResolvedDecorator {\n /** Decorator name as it appears in source */\n name: string;\n /** If this extends a built-in, the built-in name (e.g., \"Field\") */\n extendsBuiltin?: string;\n /** If this belongs to a CLI extension namespace, the namespace name */\n extensionName?: string;\n /** Whether this is a known FormSpec decorator (built-in or factory-created) */\n isFormSpec: boolean;\n /** Whether this is a marker (zero-arg) decorator */\n isMarker: boolean;\n}\n\n/**\n * Extracts decorators from a class member (property or method).\n *\n * @param member - The class member to extract decorators from\n * @returns Array of extracted decorator info\n */\nexport function extractDecorators(\n member: ts.PropertyDeclaration | ts.MethodDeclaration\n): DecoratorInfo[] {\n const decorators: DecoratorInfo[] = [];\n\n // TC39 decorators are in the modifiers array\n const modifiers = ts.canHaveDecorators(member) ? ts.getDecorators(member) : undefined;\n\n if (!modifiers) return decorators;\n\n for (const decorator of modifiers) {\n const info = parseDecorator(decorator);\n if (info) {\n decorators.push(info);\n }\n }\n\n return decorators;\n}\n\n/**\n * Parses a single decorator node.\n */\nfunction parseDecorator(decorator: ts.Decorator): DecoratorInfo | null {\n const expr = decorator.expression;\n\n // Simple decorator: @Decorator\n if (ts.isIdentifier(expr)) {\n return {\n name: expr.text,\n args: [],\n node: decorator,\n };\n }\n\n // Call expression: @Decorator(args)\n if (ts.isCallExpression(expr)) {\n const callee = expr.expression;\n\n // Get decorator name\n let name: string | null = null;\n if (ts.isIdentifier(callee)) {\n name = callee.text;\n } else if (ts.isPropertyAccessExpression(callee)) {\n // For namespaced decorators like @formspec.Field()\n name = callee.name.text;\n }\n\n if (!name) return null;\n\n // Extract arguments\n const args = expr.arguments.map(extractArgValue);\n\n return {\n name,\n args,\n node: decorator,\n };\n }\n\n return null;\n}\n\n/**\n * Extracts the value from an expression node.\n * Supports literals, arrays, object literals, and RegExp.\n */\nfunction extractArgValue(node: ts.Expression): DecoratorArg {\n // String literal\n if (ts.isStringLiteral(node)) {\n return node.text;\n }\n\n // Numeric literal\n if (ts.isNumericLiteral(node)) {\n return Number(node.text);\n }\n\n // Boolean literals (true/false are identifiers in TS AST)\n if (node.kind === ts.SyntaxKind.TrueKeyword) {\n return true;\n }\n if (node.kind === ts.SyntaxKind.FalseKeyword) {\n return false;\n }\n\n // Null literal\n if (node.kind === ts.SyntaxKind.NullKeyword) {\n return null;\n }\n\n // Prefix unary expression (for negative numbers)\n if (ts.isPrefixUnaryExpression(node)) {\n if (node.operator === ts.SyntaxKind.MinusToken && ts.isNumericLiteral(node.operand)) {\n return -Number(node.operand.text);\n }\n if (node.operator === ts.SyntaxKind.PlusToken && ts.isNumericLiteral(node.operand)) {\n return Number(node.operand.text);\n }\n }\n\n // Array literal\n if (ts.isArrayLiteralExpression(node)) {\n return node.elements.map((el) => {\n if (ts.isSpreadElement(el)) {\n // Can't evaluate spread at compile time\n return null;\n }\n return extractArgValue(el);\n });\n }\n\n // Object literal\n if (ts.isObjectLiteralExpression(node)) {\n const obj: Record<string, DecoratorArg> = {};\n for (const prop of node.properties) {\n if (ts.isPropertyAssignment(prop)) {\n const key = getPropertyName(prop.name);\n if (key) {\n obj[key] = extractArgValue(prop.initializer);\n }\n } else if (ts.isShorthandPropertyAssignment(prop)) {\n // { foo } shorthand - we can't resolve the value\n const key = prop.name.text;\n obj[key] = null;\n }\n }\n return obj;\n }\n\n // Template literal (simple case)\n if (ts.isNoSubstitutionTemplateLiteral(node)) {\n return node.text;\n }\n\n // RegExp literal: extract the source pattern string\n if (ts.isRegularExpressionLiteral(node)) {\n const regexText = node.text;\n // RegExp literal format is /pattern/flags\n const lastSlash = regexText.lastIndexOf(\"/\");\n if (lastSlash > 0) {\n return regexText.substring(1, lastSlash);\n }\n return regexText;\n }\n\n // new RegExp(\"pattern\") — extract pattern from constructor call\n if (ts.isNewExpression(node)) {\n if (\n ts.isIdentifier(node.expression) &&\n node.expression.text === \"RegExp\" &&\n node.arguments &&\n node.arguments.length > 0\n ) {\n const firstArg = node.arguments[0];\n if (firstArg && ts.isStringLiteral(firstArg)) {\n return firstArg.text;\n }\n }\n }\n\n // Identifier - could be an enum member or constant\n // We can't resolve it statically, return null\n if (ts.isIdentifier(node)) {\n return null;\n }\n\n // For other expressions, return null\n return null;\n}\n\n/**\n * Gets the property name from a property name node.\n */\nfunction getPropertyName(name: ts.PropertyName): string | null {\n if (ts.isIdentifier(name)) {\n return name.text;\n }\n if (ts.isStringLiteral(name)) {\n return name.text;\n }\n if (ts.isNumericLiteral(name)) {\n return name.text;\n }\n // Computed property names can't be resolved statically\n return null;\n}\n\n/**\n * Known FormSpec decorators and their expected argument types.\n *\n * This metadata object provides additional information about each decorator's\n * expected argument types. The keys are constrained to match FormSpecDecoratorName.\n */\nexport const FORMSPEC_DECORATORS: Record<FormSpecDecoratorName, { argTypes: readonly string[] }> = {\n // Display metadata\n Field: { argTypes: [\"object\"] },\n\n // Grouping\n Group: { argTypes: [\"string\"] },\n\n // Conditional display\n ShowWhen: { argTypes: [\"object\"] },\n\n // Enum options\n EnumOptions: { argTypes: [\"array\"] },\n\n // Numeric constraints\n Minimum: { argTypes: [\"number\"] },\n Maximum: { argTypes: [\"number\"] },\n ExclusiveMinimum: { argTypes: [\"number\"] },\n ExclusiveMaximum: { argTypes: [\"number\"] },\n\n // String constraints\n MinLength: { argTypes: [\"number\"] },\n MaxLength: { argTypes: [\"number\"] },\n Pattern: { argTypes: [\"string\"] },\n} as const;\n\n/**\n * Checks if a file path belongs to the @formspec/decorators package.\n *\n * Matches both installed node_modules paths and local monorepo paths.\n */\nfunction isFormSpecDecoratorsPath(fileName: string): boolean {\n // Normalize separators for cross-platform matching\n const normalized = fileName.replace(/\\\\/g, \"/\");\n return (\n normalized.includes(\"node_modules/@formspec/decorators\") ||\n normalized.includes(\"/packages/decorators/\")\n );\n}\n\n/**\n * Resolves a decorator via the TypeScript type checker to determine\n * if it is a FormSpec decorator (built-in, extended, or custom).\n *\n * This enables detection of:\n * 1. Direct imports of built-in decorators from `@formspec/decorators`\n * 2. Extended decorators created via `extendDecorator(...).as(...)`\n * 3. Custom decorators created via `customDecorator(...).as(...)` or `.marker(...)`\n *\n * @param decorator - The decorator AST node\n * @param checker - TypeScript type checker\n * @returns Resolved decorator information, or null if not resolvable\n */\nexport function resolveDecorator(\n decorator: ts.Decorator,\n checker: ts.TypeChecker\n): ResolvedDecorator | null {\n const expr = decorator.expression;\n\n // Get the identifier to resolve\n let targetNode: ts.Node;\n let name: string;\n\n if (ts.isIdentifier(expr)) {\n // Simple marker decorator: @Decorator\n targetNode = expr;\n name = expr.text;\n } else if (ts.isCallExpression(expr)) {\n // Parameterized decorator: @Decorator(args)\n if (ts.isIdentifier(expr.expression)) {\n targetNode = expr.expression;\n name = expr.expression.text;\n } else {\n return null;\n }\n } else {\n return null;\n }\n\n // Check if it's a known built-in by name\n if (name in FORMSPEC_DECORATORS) {\n // Verify it actually comes from @formspec/decorators by checking the symbol\n const symbol = checker.getSymbolAtLocation(targetNode);\n if (symbol) {\n const declarations = symbol.declarations;\n if (declarations && declarations.length > 0) {\n const decl = declarations[0];\n if (decl) {\n const sourceFile = decl.getSourceFile();\n const fileName = sourceFile.fileName;\n if (isFormSpecDecoratorsPath(fileName)) {\n return {\n name,\n isFormSpec: true,\n isMarker: !ts.isCallExpression(expr),\n };\n }\n }\n }\n }\n }\n\n // Try to resolve branded types for custom/extended decorators\n const resolvedSymbol = checker.getSymbolAtLocation(targetNode);\n if (!resolvedSymbol) return null;\n\n const type = checker.getTypeOfSymbol(resolvedSymbol);\n const props = type.getProperties();\n\n let extendsBuiltin: string | undefined;\n let extensionName: string | undefined;\n let isMarker = false;\n\n for (const prop of props) {\n // __String is a branded string type; cast is safe for read-only string operations\n const escapedName = prop.getEscapedName() as string;\n\n // TypeScript represents unique symbol properties as __@<name>@<uniqueId>\n // in escaped names. The <name> portion may be either the Symbol description\n // (e.g., \"formspec.extends\") or the const variable name (e.g., \"FORMSPEC_EXTENDS\"),\n // depending on how the symbol is declared and resolved by the type checker.\n // We check for both patterns to handle all cases.\n if (\n escapedName.startsWith(\"__@\") &&\n (escapedName.includes(\"formspec.extends\") || escapedName.includes(\"FORMSPEC_EXTENDS\"))\n ) {\n const propType = checker.getTypeOfSymbol(prop);\n if (propType.isStringLiteral()) {\n extendsBuiltin = propType.value;\n }\n }\n\n if (\n escapedName.startsWith(\"__@\") &&\n (escapedName.includes(\"formspec.extension\") || escapedName.includes(\"FORMSPEC_EXTENSION\"))\n ) {\n const propType = checker.getTypeOfSymbol(prop);\n if (propType.isStringLiteral()) {\n extensionName = propType.value;\n }\n }\n\n if (\n escapedName.startsWith(\"__@\") &&\n (escapedName.includes(\"formspec.marker\") || escapedName.includes(\"FORMSPEC_MARKER\"))\n ) {\n isMarker = true;\n }\n }\n\n if (extendsBuiltin) {\n return {\n name,\n extendsBuiltin,\n isFormSpec: true,\n isMarker: false,\n };\n }\n\n if (extensionName) {\n return {\n name,\n extensionName,\n isFormSpec: true,\n isMarker,\n };\n }\n\n if (isMarker) {\n return {\n name,\n isFormSpec: true,\n isMarker: true,\n };\n }\n\n return null;\n}\n","/**\n * JSDoc constraint tag extractor.\n *\n * Extracts constraint tags from JSDoc comments on class fields and returns\n * synthetic {@link DecoratorInfo} objects that integrate seamlessly with\n * the existing decorator-based constraint pipeline.\n *\n * Supported tags correspond to keys in {@link CONSTRAINT_TAG_DEFINITIONS}\n * from `@formspec/core` (e.g., `@Minimum`, `@Maximum`, `@Pattern`).\n */\n\nimport * as ts from \"typescript\";\nimport { CONSTRAINT_TAG_DEFINITIONS, type ConstraintTagName } from \"@formspec/core\";\nimport type { DecoratorArg, DecoratorInfo } from \"./decorator-extractor.js\";\n\n/**\n * Extracts JSDoc constraint tags from a TypeScript AST node and returns\n * synthetic {@link DecoratorInfo} objects.\n *\n * For each recognised tag (case-sensitive PascalCase match against\n * {@link CONSTRAINT_TAG_DEFINITIONS}), the comment text is parsed\n * according to the tag's declared value type:\n * - `\"number\"` tags: parsed via `Number()` — skipped when NaN\n * - `\"string\"` tags (`Pattern`): used as-is (trimmed)\n *\n * @param node - The AST node to inspect for JSDoc tags\n * @returns Synthetic decorator info objects for each valid constraint tag\n */\nexport function extractJSDocConstraints(node: ts.Node): DecoratorInfo[] {\n const results: DecoratorInfo[] = [];\n const jsDocTags = ts.getJSDocTags(node);\n\n for (const tag of jsDocTags) {\n const tagName = tag.tagName.text;\n\n // Case-sensitive check against known constraint tags\n if (!(tagName in CONSTRAINT_TAG_DEFINITIONS)) {\n continue;\n }\n\n const constraintName = tagName as ConstraintTagName;\n const expectedType = CONSTRAINT_TAG_DEFINITIONS[constraintName];\n\n // Extract comment text — can be string, NodeArray<JSDocComment>, or undefined\n const commentText = getTagCommentText(tag);\n if (commentText === undefined || commentText === \"\") {\n continue;\n }\n\n const trimmed = commentText.trim();\n if (trimmed === \"\") {\n continue;\n }\n\n if (expectedType === \"number\") {\n const value = Number(trimmed);\n if (Number.isNaN(value)) {\n continue;\n }\n results.push(createSyntheticDecorator(constraintName, value));\n } else if (expectedType === \"json\") {\n // JSON type (EnumOptions) — parse inline JSON array only.\n // Downstream UI schema generation expects an array of options.\n try {\n const parsed: unknown = JSON.parse(trimmed);\n if (!Array.isArray(parsed)) {\n continue;\n }\n results.push(createSyntheticDecorator(constraintName, parsed as DecoratorArg));\n } catch {\n // Skip malformed JSON\n continue;\n }\n } else {\n // \"string\" type (Pattern)\n results.push(createSyntheticDecorator(constraintName, trimmed));\n }\n }\n\n return results;\n}\n\n/**\n * Extracts `@Field_displayName` and `@Field_description` TSDoc tags from\n * a node and returns a synthetic `Field` {@link DecoratorInfo} if either\n * is present.\n *\n * This enables interface properties to carry display metadata via TSDoc\n * tags instead of the `@Field` decorator (which requires a class):\n *\n * ```typescript\n * interface Config {\n * // @Field_displayName Program Name\n * // @Field_description Internal identifier\n * programName: string;\n * }\n * ```\n *\n * @param node - The AST node to inspect for display metadata tags\n * @returns A synthetic `Field` decorator info, or null if no tags found\n */\nexport function extractJSDocFieldMetadata(node: ts.Node): DecoratorInfo | null {\n const jsDocTags = ts.getJSDocTags(node);\n\n let displayName: string | undefined;\n let description: string | undefined;\n\n for (const tag of jsDocTags) {\n const tagName = tag.tagName.text;\n const commentText = getTagCommentText(tag);\n if (commentText === undefined || commentText.trim() === \"\") {\n continue;\n }\n\n const trimmed = commentText.trim();\n\n if (tagName === \"Field_displayName\") {\n displayName = trimmed;\n } else if (tagName === \"Field_description\") {\n description = trimmed;\n }\n }\n\n if (displayName === undefined && description === undefined) {\n return null;\n }\n\n // Build the FieldOptions-shaped arg object\n const fieldOpts: Record<string, DecoratorArg> = {\n ...(displayName !== undefined ? { displayName } : {}),\n ...(description !== undefined ? { description } : {}),\n };\n\n return createSyntheticDecorator(\"Field\", fieldOpts);\n}\n\n/**\n * Extracts the text content from a JSDoc tag's comment.\n *\n * The `tag.comment` property can be a plain string, an array of\n * `JSDocComment` nodes, or undefined. This helper normalises all\n * three cases to a single `string | undefined`.\n */\nfunction getTagCommentText(tag: ts.JSDocTag): string | undefined {\n if (tag.comment === undefined) {\n return undefined;\n }\n if (typeof tag.comment === \"string\") {\n return tag.comment;\n }\n // NodeArray<JSDocComment> — concatenate text spans\n return ts.getTextOfJSDocComment(tag.comment);\n}\n\n/**\n * Creates a synthetic {@link DecoratorInfo} for a JSDoc constraint tag.\n *\n * The `node` field is `undefined` because JSDoc constraints have no\n * decorator AST node. Downstream constraint processing only uses\n * the `name` and `args` fields.\n */\nfunction createSyntheticDecorator(name: string, value: DecoratorArg): DecoratorInfo {\n return {\n name,\n args: [value],\n node: undefined,\n };\n}\n","/**\n * Type converter for transforming TypeScript types to JSON Schema and FormSpec.\n *\n * Converts TypeScript types (extracted via type checker) to:\n * - JSON Schema definitions\n * - FormSpec field definitions\n */\n\nimport * as ts from \"typescript\";\nimport type { DecoratorInfo } from \"./decorator-extractor.js\";\nimport { analyzeField, analyzeInterfaceProperty, type FieldInfo } from \"./class-analyzer.js\";\nimport { setSchemaExtension, type ExtendedJSONSchema7 } from \"../json-schema/types.js\";\n\n/**\n * FormSpec field definition (simplified for output).\n */\nexport interface FormSpecField {\n _field: string;\n id: string;\n label?: string;\n placeholder?: string;\n description?: string;\n required?: boolean;\n min?: number;\n max?: number;\n step?: number;\n minLength?: number;\n maxLength?: number;\n minItems?: number;\n maxItems?: number;\n pattern?: string;\n options?: (string | { id: string; label: string })[];\n showWhen?: object;\n group?: string;\n fields?: FormSpecField[]; // Nested fields for object types\n}\n\n/**\n * Result of converting a TypeScript type.\n */\nexport interface TypeConversionResult {\n /** JSON Schema representation */\n jsonSchema: ExtendedJSONSchema7;\n /** FormSpec field type */\n formSpecFieldType: string;\n}\n\n/**\n * Given a ts.Type for a named type (class, interface, or type alias with\n * a type literal body), navigates to its declaration and returns a Map\n * from property name to its fully analyzed FieldInfo.\n *\n * - **Classes**: uses `analyzeField` to extract decorators + JSDoc constraints\n * - **Interfaces**: extracts `@Field_displayName`, `@Field_description`, and constraint tags\n * - **Type aliases** (object literals): same as interfaces\n *\n * Returns null for unnamed types (inline objects, mapped types, etc.),\n * preserving existing structural-only behavior for those cases.\n */\nfunction getNamedTypeFieldInfoMap(\n type: ts.Type,\n checker: ts.TypeChecker\n): Map<string, FieldInfo> | null {\n // Check both direct symbol and alias symbol — type aliases resolve to\n // an anonymous __type symbol, with the original alias on type.aliasSymbol.\n const symbols = [type.getSymbol(), type.aliasSymbol].filter(\n (s): s is ts.Symbol => s?.declarations != null && s.declarations.length > 0\n );\n\n for (const symbol of symbols) {\n const declarations = symbol.declarations;\n if (!declarations) continue;\n\n // Try class declaration\n const classDecl = declarations.find(ts.isClassDeclaration);\n if (classDecl) {\n const map = new Map<string, FieldInfo>();\n for (const member of classDecl.members) {\n if (ts.isPropertyDeclaration(member) && ts.isIdentifier(member.name)) {\n const fieldInfo = analyzeField(member, checker);\n if (fieldInfo) map.set(fieldInfo.name, fieldInfo);\n }\n }\n return map;\n }\n\n // Try interface declaration\n const interfaceDecl = declarations.find(ts.isInterfaceDeclaration);\n if (interfaceDecl) {\n return buildFieldInfoMapFromSignatures(interfaceDecl.members, checker);\n }\n\n // Try type alias with type literal body: type X = { ... }\n const typeAliasDecl = declarations.find(ts.isTypeAliasDeclaration);\n if (typeAliasDecl && ts.isTypeLiteralNode(typeAliasDecl.type)) {\n return buildFieldInfoMapFromSignatures(typeAliasDecl.type.members, checker);\n }\n }\n\n return null;\n}\n\n/**\n * Builds a FieldInfo map from interface/type-literal property signatures,\n * delegating to {@link analyzeInterfaceProperty} for JSDoc extraction.\n */\nfunction buildFieldInfoMapFromSignatures(\n members: ts.NodeArray<ts.TypeElement>,\n checker: ts.TypeChecker\n): Map<string, FieldInfo> {\n const map = new Map<string, FieldInfo>();\n for (const member of members) {\n if (ts.isPropertySignature(member)) {\n const fieldInfo = analyzeInterfaceProperty(member, checker);\n if (fieldInfo) {\n map.set(fieldInfo.name, fieldInfo);\n }\n }\n }\n return map;\n}\n\n/**\n * Resolved information about a single property of an object type.\n *\n * Computed once by `getObjectPropertyInfos` and consumed by both the\n * JSON Schema path (`convertObjectType`) and the UI Schema path\n * (`createFormSpecField`), eliminating duplicated iteration logic.\n */\ninterface ObjectPropertyInfo {\n /** Property name */\n name: string;\n /** Resolved TypeScript type for the property */\n type: ts.Type;\n /** Whether the property is optional */\n optional: boolean;\n /** FieldInfo from the class declaration, if this is a class-typed object */\n fieldInfo: FieldInfo | undefined;\n}\n\n/**\n * Iterates the properties of an object type and resolves each property's\n * type, optionality, and class-level field info (decorators/JSDoc).\n *\n * This is the single source of truth for nested property analysis, used\n * by both the JSON Schema and FormSpec field generation paths.\n */\nfunction getObjectPropertyInfos(\n type: ts.ObjectType,\n checker: ts.TypeChecker\n): ObjectPropertyInfo[] {\n const fieldInfoMap = getNamedTypeFieldInfoMap(type, checker);\n const result: ObjectPropertyInfo[] = [];\n\n for (const prop of type.getProperties()) {\n const declaration = prop.valueDeclaration ?? prop.declarations?.[0];\n if (!declaration) continue;\n\n const propType = checker.getTypeOfSymbolAtLocation(prop, declaration);\n const optional = !!(prop.flags & ts.SymbolFlags.Optional);\n const fieldInfo = fieldInfoMap?.get(prop.name) ?? undefined;\n\n result.push({ name: prop.name, type: propType, optional, fieldInfo });\n }\n\n return result;\n}\n\n/**\n * Converts a TypeScript type to JSON Schema and FormSpec field type.\n *\n * @param type - The TypeScript type to convert\n * @param checker - TypeScript type checker\n * @returns Conversion result with JSON Schema and FormSpec type\n */\nexport function convertType(type: ts.Type, checker: ts.TypeChecker): TypeConversionResult {\n return convertTypeInternal(type, checker, new Set());\n}\n\nfunction convertTypeInternal(\n type: ts.Type,\n checker: ts.TypeChecker,\n visiting: Set<ts.Type>\n): TypeConversionResult {\n // Handle primitive types\n if (type.flags & ts.TypeFlags.String) {\n return { jsonSchema: { type: \"string\" }, formSpecFieldType: \"text\" };\n }\n\n if (type.flags & ts.TypeFlags.Number) {\n return { jsonSchema: { type: \"number\" }, formSpecFieldType: \"number\" };\n }\n\n if (type.flags & ts.TypeFlags.Boolean) {\n return { jsonSchema: { type: \"boolean\" }, formSpecFieldType: \"boolean\" };\n }\n\n if (type.flags & ts.TypeFlags.Null) {\n return { jsonSchema: { type: \"null\" }, formSpecFieldType: \"null\" };\n }\n\n if (type.flags & ts.TypeFlags.Undefined) {\n return { jsonSchema: {}, formSpecFieldType: \"undefined\" };\n }\n\n // Handle literal types\n if (type.isStringLiteral()) {\n return {\n jsonSchema: { const: type.value },\n formSpecFieldType: \"enum\",\n };\n }\n\n if (type.isNumberLiteral()) {\n return {\n jsonSchema: { const: type.value },\n formSpecFieldType: \"number\",\n };\n }\n\n // Handle union types (including string literal unions for enums)\n if (type.isUnion()) {\n return convertUnionType(type, checker, visiting);\n }\n\n // Handle array types\n if (checker.isArrayType(type)) {\n return convertArrayType(type, checker, visiting);\n }\n\n // Handle object types\n if (type.flags & ts.TypeFlags.Object) {\n return convertObjectType(type as ts.ObjectType, checker, visiting);\n }\n\n // Fallback\n return { jsonSchema: {}, formSpecFieldType: \"unknown\" };\n}\n\n/**\n * Converts a union type to JSON Schema.\n */\nfunction convertUnionType(\n type: ts.UnionType,\n checker: ts.TypeChecker,\n visiting: Set<ts.Type>\n): TypeConversionResult {\n const types = type.types;\n\n // Filter out null and undefined for analysis\n // Note: undefined is filtered out since JSON Schema doesn't have an undefined type\n // Optional fields are handled via the 'required' array, not the type\n const nonNullTypes = types.filter(\n (t) => !(t.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined))\n );\n const hasNull = types.some((t) => t.flags & ts.TypeFlags.Null);\n\n // Check if this is a boolean type (true | false in TypeScript)\n // TypeScript represents `boolean` as a union of `true | false` literal types\n const isBooleanUnion =\n nonNullTypes.length === 2 && nonNullTypes.every((t) => t.flags & ts.TypeFlags.BooleanLiteral);\n\n if (isBooleanUnion) {\n const result: TypeConversionResult = {\n jsonSchema: { type: \"boolean\" },\n formSpecFieldType: \"boolean\",\n };\n if (hasNull) {\n result.jsonSchema = { oneOf: [{ type: \"boolean\" }, { type: \"null\" }] };\n }\n return result;\n }\n\n // Check if all types are string literals (enum pattern)\n const allStringLiterals = nonNullTypes.every((t) => t.isStringLiteral());\n if (allStringLiterals && nonNullTypes.length > 0) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- TypeScript doesn't narrow array types from `every` predicate\n const enumValues = nonNullTypes.map((t) => (t as ts.StringLiteralType).value);\n const result: TypeConversionResult = {\n jsonSchema: { enum: enumValues },\n formSpecFieldType: \"enum\",\n };\n if (hasNull) {\n result.jsonSchema = { oneOf: [{ enum: enumValues }, { type: \"null\" }] };\n }\n return result;\n }\n\n // Check if all types are number literals\n const allNumberLiterals = nonNullTypes.every((t) => t.isNumberLiteral());\n if (allNumberLiterals && nonNullTypes.length > 0) {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- TypeScript doesn't narrow array types from `every` predicate\n const enumValues = nonNullTypes.map((t) => (t as ts.NumberLiteralType).value);\n const result: TypeConversionResult = {\n jsonSchema: { enum: enumValues },\n formSpecFieldType: \"enum\",\n };\n if (hasNull) {\n result.jsonSchema = { oneOf: [{ enum: enumValues }, { type: \"null\" }] };\n }\n return result;\n }\n\n // Handle nullable types (T | null or T | undefined) with single non-null type\n if (nonNullTypes.length === 1 && nonNullTypes[0]) {\n const result = convertTypeInternal(nonNullTypes[0], checker, visiting);\n // Make it nullable in JSON Schema\n if (hasNull) {\n result.jsonSchema = { oneOf: [result.jsonSchema, { type: \"null\" }] };\n }\n return result;\n }\n\n // General union - use oneOf (filter out undefined which isn't valid in JSON Schema)\n const schemas = nonNullTypes.map((t) => convertTypeInternal(t, checker, visiting).jsonSchema);\n if (hasNull) {\n schemas.push({ type: \"null\" });\n }\n return {\n jsonSchema: { oneOf: schemas },\n formSpecFieldType: \"union\",\n };\n}\n\n/**\n * Converts an array type to JSON Schema.\n */\nfunction convertArrayType(\n type: ts.Type,\n checker: ts.TypeChecker,\n visiting: Set<ts.Type>\n): TypeConversionResult {\n const typeArgs = (type as ts.TypeReference).typeArguments;\n const elementType = typeArgs?.[0];\n\n const itemSchema = elementType\n ? convertTypeInternal(elementType, checker, visiting).jsonSchema\n : {};\n\n return {\n jsonSchema: {\n type: \"array\",\n items: itemSchema,\n },\n formSpecFieldType: \"array\",\n };\n}\n\n/**\n * Converts an object type to JSON Schema.\n */\nfunction convertObjectType(\n type: ts.ObjectType,\n checker: ts.TypeChecker,\n visiting: Set<ts.Type>\n): TypeConversionResult {\n // Circular reference guard\n if (visiting.has(type)) {\n return { jsonSchema: { type: \"object\" }, formSpecFieldType: \"object\" };\n }\n visiting.add(type);\n\n const properties: Record<string, ExtendedJSONSchema7> = {};\n const required: string[] = [];\n\n for (const propInfo of getObjectPropertyInfos(type, checker)) {\n const propSchema = convertTypeInternal(propInfo.type, checker, visiting).jsonSchema;\n\n // Apply decorator/JSDoc constraints from the class declaration if available\n properties[propInfo.name] = propInfo.fieldInfo\n ? applyDecoratorsToSchema(propSchema, propInfo.fieldInfo.decorators, propInfo.fieldInfo)\n : propSchema;\n\n if (!propInfo.optional) {\n required.push(propInfo.name);\n }\n }\n\n visiting.delete(type);\n\n return {\n jsonSchema: {\n type: \"object\",\n properties,\n ...(required.length > 0 ? { required } : {}),\n },\n formSpecFieldType: \"object\",\n };\n}\n\n/**\n * Creates a FormSpec field definition from a field's type and decorators.\n *\n * @param fieldName - The field name\n * @param type - The TypeScript type\n * @param decorators - Decorators applied to the field\n * @param optional - Whether the field is optional\n * @param checker - TypeScript type checker\n * @returns FormSpec field definition\n */\nexport function createFormSpecField(\n fieldName: string,\n type: ts.Type,\n decorators: DecoratorInfo[],\n optional: boolean,\n checker: ts.TypeChecker,\n visitedTypes = new Set<ts.Type>()\n): FormSpecField {\n const { formSpecFieldType } = convertType(type, checker);\n\n const field: FormSpecField = {\n _field: formSpecFieldType,\n id: fieldName,\n };\n\n // Apply optionality\n if (!optional) {\n field.required = true;\n }\n\n // For object types, recursively add nested fields.\n // Note: visitedTypes guards against circular references independently from\n // the `visiting` set in convertTypeInternal — they protect different recursion\n // paths (FormSpec field generation vs JSON Schema generation).\n if (formSpecFieldType === \"object\" && type.flags & ts.TypeFlags.Object) {\n if (!visitedTypes.has(type)) {\n visitedTypes.add(type);\n\n const nestedFields: FormSpecField[] = [];\n for (const propInfo of getObjectPropertyInfos(type as ts.ObjectType, checker)) {\n nestedFields.push(\n createFormSpecField(\n propInfo.name,\n propInfo.type,\n propInfo.fieldInfo?.decorators ?? [],\n propInfo.optional,\n checker,\n visitedTypes\n )\n );\n }\n\n visitedTypes.delete(type);\n\n if (nestedFields.length > 0) {\n field.fields = nestedFields;\n }\n }\n }\n\n // Apply decorator values\n for (const dec of decorators) {\n applyDecoratorToField(field, dec);\n }\n\n return field;\n}\n\n/**\n * Applies a decorator's values to a FormSpec field.\n *\n * Note: Custom decorator extensions (x-formspec-*) are only emitted in JSON Schema\n * via `applyDecoratorsToSchema`, not here. The FormSpecField interface does not\n * carry extension data — extensions are a schema-level concern.\n *\n * @param field - The FormSpec field to modify\n * @param decorator - The decorator information to apply\n */\nfunction applyDecoratorToField(field: FormSpecField, decorator: DecoratorInfo): void {\n const { args } = decorator;\n const resolved = decorator.resolved;\n\n // If this is an extended decorator, map it to the built-in it extends\n const effectiveName = resolved?.extendsBuiltin ?? decorator.name;\n\n switch (effectiveName) {\n case \"Field\": {\n // Field takes an object with displayName, description, placeholder\n const opts = args[0];\n if (typeof opts === \"object\" && opts !== null && !Array.isArray(opts)) {\n if (typeof opts[\"displayName\"] === \"string\") {\n field.label = opts[\"displayName\"];\n }\n if (typeof opts[\"description\"] === \"string\") {\n field.description = opts[\"description\"];\n }\n if (typeof opts[\"placeholder\"] === \"string\") {\n field.placeholder = opts[\"placeholder\"];\n }\n }\n break;\n }\n\n case \"Minimum\":\n if (typeof args[0] === \"number\") {\n field.min = args[0];\n }\n break;\n\n case \"Maximum\":\n if (typeof args[0] === \"number\") {\n field.max = args[0];\n }\n break;\n\n case \"MinLength\":\n if (typeof args[0] === \"number\") {\n field.minLength = args[0];\n }\n break;\n\n case \"MaxLength\":\n if (typeof args[0] === \"number\") {\n field.maxLength = args[0];\n }\n break;\n\n case \"Pattern\":\n if (typeof args[0] === \"string\") {\n field.pattern = args[0];\n }\n break;\n\n case \"EnumOptions\":\n if (Array.isArray(args[0])) {\n field.options = args[0] as (string | { id: string; label: string })[];\n }\n break;\n\n case \"ShowWhen\":\n if (typeof args[0] === \"object\" && args[0] !== null) {\n field.showWhen = args[0] as object;\n }\n break;\n\n case \"Group\":\n if (typeof args[0] === \"string\") {\n field.group = args[0];\n }\n break;\n }\n}\n\n/**\n * Applies decorator constraints to a JSON Schema.\n *\n * @param schema - The base JSON Schema\n * @param decorators - Decorators to apply\n * @param fieldInfo - Optional field info for deprecated/default values\n * @returns Modified JSON Schema with constraints\n */\nexport function applyDecoratorsToSchema(\n schema: ExtendedJSONSchema7,\n decorators: DecoratorInfo[],\n fieldInfo?: FieldInfo\n): ExtendedJSONSchema7 {\n const result = { ...schema };\n\n for (const dec of decorators) {\n const { args } = dec;\n const resolved = dec.resolved;\n\n // If this is an extended decorator, map it to the built-in it extends\n const effectiveName = resolved?.extendsBuiltin ?? dec.name;\n\n switch (effectiveName) {\n case \"Field\": {\n // Field takes an object: { displayName, description?, placeholder? }\n const opts = args[0];\n if (typeof opts === \"object\" && opts !== null && !Array.isArray(opts)) {\n if (typeof opts[\"displayName\"] === \"string\") {\n result.title = opts[\"displayName\"];\n }\n if (typeof opts[\"description\"] === \"string\") {\n result.description = opts[\"description\"];\n }\n }\n break;\n }\n\n case \"Minimum\":\n if (typeof args[0] === \"number\") {\n result.minimum = args[0];\n }\n break;\n\n case \"Maximum\":\n if (typeof args[0] === \"number\") {\n result.maximum = args[0];\n }\n break;\n\n case \"ExclusiveMinimum\":\n if (typeof args[0] === \"number\") {\n result.exclusiveMinimum = args[0];\n }\n break;\n\n case \"ExclusiveMaximum\":\n if (typeof args[0] === \"number\") {\n result.exclusiveMaximum = args[0];\n }\n break;\n\n case \"MinLength\":\n if (typeof args[0] === \"number\") {\n result.minLength = args[0];\n }\n break;\n\n case \"MaxLength\":\n if (typeof args[0] === \"number\") {\n result.maxLength = args[0];\n }\n break;\n\n case \"Pattern\":\n if (typeof args[0] === \"string\") {\n result.pattern = args[0];\n }\n break;\n }\n\n // Emit x-formspec-* for custom decorators with a valid extensionName.\n // Extension names must be lowercase alphanumeric with hyphens (e.g., \"title-field\", \"priority\").\n if (resolved?.extensionName && /^[a-z][a-z0-9-]*$/.test(resolved.extensionName)) {\n const key = `x-formspec-${resolved.extensionName}` as const;\n if (resolved.isMarker) {\n setSchemaExtension(result, key, true);\n } else {\n // Parameterized: use first argument as value\n setSchemaExtension(result, key, args[0] ?? true);\n }\n }\n }\n\n // Apply deprecated and default from FieldInfo\n if (fieldInfo) {\n // eslint-disable-next-line @typescript-eslint/no-deprecated -- `deprecated` is a FieldInfo flag tracking @deprecated JSDoc, not itself deprecated\n if (fieldInfo.deprecated) {\n result.deprecated = true;\n }\n if (fieldInfo.defaultValue !== undefined) {\n result.default = fieldInfo.defaultValue;\n }\n }\n\n return result;\n}\n","/**\n * JSON Schema Draft-07 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 */\nexport type JSONSchemaType =\n | \"string\"\n | \"number\"\n | \"integer\"\n | \"boolean\"\n | \"object\"\n | \"array\"\n | \"null\";\n\n/**\n * A JSON Schema definition (draft-07 subset).\n */\nexport interface JSONSchema7 {\n $schema?: string;\n $id?: string;\n $ref?: string;\n\n // Metadata\n title?: string;\n description?: string;\n deprecated?: boolean;\n\n // Type\n type?: JSONSchemaType | JSONSchemaType[];\n\n // String validation\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n\n // Number validation\n minimum?: number;\n maximum?: number;\n exclusiveMinimum?: number;\n exclusiveMaximum?: number;\n\n // Enum\n enum?: readonly (string | number | boolean | null)[];\n const?: string | number | boolean | null;\n\n // Object\n properties?: Record<string, JSONSchema7>;\n required?: string[];\n additionalProperties?: boolean | JSONSchema7;\n\n // Array\n items?: JSONSchema7 | JSONSchema7[];\n minItems?: number;\n maxItems?: number;\n\n // Composition\n allOf?: JSONSchema7[];\n anyOf?: JSONSchema7[];\n oneOf?: JSONSchema7[];\n not?: JSONSchema7;\n\n // Conditional\n if?: JSONSchema7;\n then?: JSONSchema7;\n else?: JSONSchema7;\n\n // Format\n format?: string;\n\n // Default\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/** Extension properties for custom FormSpec decorators. */\nexport type FormSpecSchemaExtensions = Record<`x-formspec-${string}`, unknown>;\n\n/** JSON Schema with FormSpec extension properties for arbitrary x-formspec-* keys. */\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 */\nexport function setSchemaExtension(\n schema: JSONSchema7,\n key: `x-formspec-${string}`,\n value: unknown\n): void {\n (schema as ExtendedJSONSchema7)[key] = value;\n}\n\n/**\n * Reads a FormSpec extension property from a JSON Schema node.\n *\n * Use this to safely read `x-formspec-*` properties from any schema,\n * including nested schemas typed as `JSONSchema7`.\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 */\nexport function getSchemaExtension(schema: JSONSchema7, key: `x-formspec-${string}`): unknown {\n return (schema as ExtendedJSONSchema7)[key];\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\";\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 */\nexport const ruleEffectSchema = z.enum([\"SHOW\", \"HIDE\", \"ENABLE\", \"DISABLE\"]);\n\n/**\n * Rule effect types for conditional visibility.\n */\nexport type RuleEffect = z.infer<typeof ruleEffectSchema>;\n\n/**\n * Zod schema for UI Schema element type strings.\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 */\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 */\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// Build the Zod schema referencing the pre-declared interface.\n// We use z.ZodType<RuleConditionSchema> so the recursive reference works.\n// The interface uses `?` (exact optional), and z.ZodType checks output only,\n// so the optional fields (which Zod infers as `T | undefined`) are compatible\n// because `T | undefined` is assignable to the optional field slot.\n//\n// @ts-expect-error -- exactOptionalPropertyTypes: the Zod output type for optional\n// fields is `T | undefined`, but our interface uses `?` (exact optional, key may\n// be absent). This is a known mismatch when using z.ZodType<T> with\n// exactOptionalPropertyTypes:true; the runtime behavior is correct.\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);\n\n// =============================================================================\n// Schema-Based Condition and Rule\n// =============================================================================\n\n/**\n * Zod schema for a schema-based rule condition.\n */\nexport const schemaBasedConditionSchema = z\n .object({\n scope: jsonPointerSchema,\n schema: ruleConditionSchema,\n })\n .strict();\n\n/**\n * Condition for a rule.\n */\nexport type SchemaBasedCondition = z.infer<typeof schemaBasedConditionSchema>;\n\n/**\n * Zod schema for a UI Schema rule.\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 */\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 */\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.\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 */\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 */\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 */\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\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 */\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\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 */\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\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 */\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\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 */\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\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 */\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 */\nexport type LabelElement = z.infer<typeof labelElementSchema>;\n\n// =============================================================================\n// Root UISchema\n// =============================================================================\n\n/**\n * Root UI Schema (always a layout — not a Control, Category, or Label).\n */\nexport type UISchema = VerticalLayout | HorizontalLayout | GroupLayout | Categorization;\n\n/**\n * Zod schema for the root UI Schema (layout types only).\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 for FormSpec forms.\n */\n\nimport type { FormElement, FormSpec, Group, Conditional } from \"@formspec/core\";\nimport type { UISchemaElement, UISchema, ControlElement, GroupLayout, Rule } from \"./types.js\";\nimport { uiSchema as uiSchemaValidator } from \"./schema.js\";\nimport type { FormSpecField } from \"../analyzer/type-converter.js\";\nimport { z } from \"zod\";\n\n/**\n * Parses a value through a Zod schema, converting validation errors to a 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.\n */\nfunction fieldToScope(fieldName: string): string {\n return `#/properties/${fieldName}`;\n}\n\n/**\n * Creates a rule for conditional visibility.\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 rules into one using allOf.\n *\n * When elements are nested inside multiple conditionals, all conditions\n * must be met for the element to be visible.\n */\nfunction combineRules(parentRule: Rule, childRule: Rule): Rule {\n // Both rules should have the same effect (SHOW)\n // Combine conditions using allOf\n const parentCondition = parentRule.condition;\n const childCondition = childRule.condition;\n\n return {\n effect: \"SHOW\",\n condition: {\n scope: \"#\",\n schema: {\n allOf: [\n {\n properties: {\n [parentCondition.scope.replace(\"#/properties/\", \"\")]: parentCondition.schema,\n },\n },\n {\n properties: {\n [childCondition.scope.replace(\"#/properties/\", \"\")]: childCondition.schema,\n },\n },\n ],\n },\n },\n };\n}\n\n/**\n * Converts form elements to UI Schema elements.\n *\n * @param elements - The form elements to convert\n * @param parentRule - Optional rule inherited from parent conditional\n * @returns Array of UI Schema elements\n */\nfunction elementsToUiSchema(\n elements: readonly FormElement[],\n parentRule?: Rule\n): UISchemaElement[] {\n const result: UISchemaElement[] = [];\n\n for (const element of elements) {\n switch (element._type) {\n case \"field\": {\n const control: ControlElement = {\n type: \"Control\",\n scope: fieldToScope(element.name),\n ...(element.label !== undefined && { label: element.label }),\n ...(parentRule !== undefined && { rule: parentRule }),\n };\n result.push(control);\n break;\n }\n\n case \"group\": {\n const groupElement = element as Group<readonly FormElement[]>;\n const group: GroupLayout = {\n type: \"Group\",\n label: groupElement.label,\n elements: elementsToUiSchema(groupElement.elements, parentRule),\n ...(parentRule !== undefined && { rule: parentRule }),\n };\n result.push(group);\n break;\n }\n\n case \"conditional\": {\n const conditionalElement = element as Conditional<string, unknown, readonly FormElement[]>;\n // Create a rule for this conditional\n const newRule = createShowRule(conditionalElement.field, conditionalElement.value);\n // Combine with parent rule if present (for nested conditionals)\n const combinedRule = parentRule !== undefined ? combineRules(parentRule, newRule) : newRule;\n // Apply the combined rule to all children\n const childElements = elementsToUiSchema(conditionalElement.elements, combinedRule);\n result.push(...childElements);\n break;\n }\n }\n }\n\n return result;\n}\n\n/**\n * Converts a single FormSpecField to a ControlElement, resolving showWhen into a rule.\n *\n * @param field - The FormSpecField to convert\n * @param scopePrefix - The JSON Pointer prefix for the field's scope\n * @returns A ControlElement\n */\nfunction formSpecFieldToElement(\n field: FormSpecField,\n scopePrefix = \"#/properties\"\n): ControlElement {\n const control: ControlElement = {\n type: \"Control\",\n scope: `${scopePrefix}/${field.id}`,\n };\n\n if (field.label !== undefined) {\n control.label = field.label;\n }\n\n if (\n field.showWhen !== undefined &&\n typeof field.showWhen === \"object\" &&\n \"field\" in field.showWhen &&\n \"value\" in field.showWhen\n ) {\n const sw = field.showWhen as { field: string; value: unknown };\n control.rule = {\n effect: \"SHOW\",\n condition: {\n scope: `#/properties/${sw.field}`,\n schema: { const: sw.value },\n },\n };\n }\n\n return control;\n}\n\n/**\n * Converts FormSpecField[] (from decorator/interface/type analysis) to a JSON Forms UISchema.\n *\n * Mapping:\n * - Each field → `{ type: \"Control\", scope: \"#/properties/{id}\", label? }`\n * - `showWhen: { field, value }` → rule with SHOW effect\n * - `group` property → Groups fields by group name, preserving insertion order\n * - `fields` (nested object) → single Control pointing to the object property\n * - Root wrapper → `{ type: \"VerticalLayout\", elements }`\n *\n * @param fields - The FormSpecField array to convert\n * @returns A JSON Forms UISchema\n */\nexport function generateUiSchemaFromFields(fields: FormSpecField[]): UISchema {\n // Collect elements, grouping by the `group` property.\n // Map preserves insertion order — first occurrence of a group name determines its position.\n const groupMap = new Map<string, ControlElement[]>();\n const orderedKeys: (string | null)[] = []; // null = ungrouped slot\n const ungrouped: ControlElement[] = [];\n\n for (const field of fields) {\n const element = formSpecFieldToElement(field);\n\n if (field.group !== undefined) {\n if (!groupMap.has(field.group)) {\n groupMap.set(field.group, []);\n orderedKeys.push(field.group);\n }\n // We know the key exists since we just set it above.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n groupMap.get(field.group)!.push(element);\n } else {\n // Track position for ungrouped fields relative to grouped fields.\n // Use a sentinel to mark the slot for ungrouped elements inline.\n orderedKeys.push(null);\n ungrouped.push(element);\n }\n }\n\n // Build the flat elements list respecting insertion order.\n const elements: UISchemaElement[] = [];\n let ungroupedIndex = 0;\n\n for (const key of orderedKeys) {\n if (key === null) {\n // Ungrouped field — emit directly.\n const el = ungrouped[ungroupedIndex++];\n if (el !== undefined) {\n elements.push(el);\n }\n } else {\n // Each group key appears in orderedKeys exactly once (guarded by\n // `!groupMap.has()` above), so we emit the Group element directly.\n const groupElements = groupMap.get(key) ?? [];\n const groupLayout: GroupLayout = {\n type: \"Group\",\n label: key,\n elements: groupElements,\n };\n elements.push(groupLayout);\n }\n }\n\n const result: UISchema = {\n type: \"VerticalLayout\",\n elements,\n };\n\n return parseOrThrow(uiSchemaValidator, result, \"UI Schema\");\n}\n\n/**\n * Generates a JSON Forms UI Schema from a FormSpec.\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 */\nexport function generateUiSchema<E extends readonly FormElement[]>(form: FormSpec<E>): UISchema {\n const result: UISchema = {\n type: \"VerticalLayout\",\n elements: elementsToUiSchema(form.elements),\n };\n\n return parseOrThrow(uiSchemaValidator, result, \"UI Schema\");\n}\n","/**\n * Class schema generator.\n *\n * Generates JSON Schema and FormSpec/UI Schema from statically analyzed\n * class fields and decorators.\n */\n\nimport type * as ts from \"typescript\";\nimport type { ClassAnalysis, FieldInfo } from \"../analyzer/class-analyzer.js\";\nimport {\n convertType,\n applyDecoratorsToSchema,\n createFormSpecField,\n type FormSpecField,\n} from \"../analyzer/type-converter.js\";\nimport type { ExtendedJSONSchema7 } from \"../json-schema/types.js\";\nimport type { UISchema } from \"../ui-schema/types.js\";\nimport { generateUiSchemaFromFields } from \"../ui-schema/generator.js\";\nimport {\n createProgramContext,\n findClassByName,\n findInterfaceByName,\n findTypeAliasByName,\n} from \"../analyzer/program.js\";\nimport { analyzeClass, analyzeInterface, analyzeTypeAlias } from \"../analyzer/class-analyzer.js\";\n\n/**\n * Generated schemas for a class.\n */\nexport interface ClassSchemas {\n /** JSON Schema for validation */\n jsonSchema: ExtendedJSONSchema7;\n /** JSON Forms UI Schema for rendering */\n uiSchema: UISchema;\n}\n\n/**\n * Generates JSON Schema and FormSpec from a class analysis.\n *\n * Uses static type information and decorator metadata to build\n * complete schema definitions for a class's fields.\n *\n * @param analysis - The class analysis result\n * @param checker - TypeScript type checker\n * @returns Generated JSON Schema and FormSpec\n */\nexport function generateClassSchemas(\n analysis: ClassAnalysis,\n checker: ts.TypeChecker\n): ClassSchemas {\n const properties: Record<string, ExtendedJSONSchema7> = {};\n const required: string[] = [];\n const uiElements: FormSpecField[] = [];\n\n for (const field of analysis.fields) {\n // Generate JSON Schema for field\n const { jsonSchema: baseSchema } = convertType(field.type, checker);\n const fieldSchema = applyDecoratorsToSchema(baseSchema, field.decorators, field);\n properties[field.name] = fieldSchema;\n\n // Track required fields\n if (!field.optional) {\n required.push(field.name);\n }\n\n // Generate FormSpec field\n const formSpecField = createFormSpecField(\n field.name,\n field.type,\n field.decorators,\n field.optional,\n checker\n );\n uiElements.push(formSpecField);\n }\n\n // Build complete JSON Schema\n const jsonSchema: ExtendedJSONSchema7 = {\n type: \"object\",\n properties,\n ...(required.length > 0 ? { required } : {}),\n };\n\n // Convert FormSpecField[] to JSON Forms UISchema\n const uiSchema = generateUiSchemaFromFields(uiElements);\n\n return { jsonSchema, uiSchema };\n}\n\n/**\n * Generates JSON Schema for a single field.\n *\n * Useful for generating schemas for method return types\n * or individual field extraction.\n *\n * @param field - The field information\n * @param checker - TypeScript type checker\n * @returns JSON Schema for the field's type\n */\nexport function generateFieldSchema(\n field: FieldInfo,\n checker: ts.TypeChecker\n): ExtendedJSONSchema7 {\n const { jsonSchema: baseSchema } = convertType(field.type, checker);\n return applyDecoratorsToSchema(baseSchema, field.decorators, field);\n}\n\n/**\n * Options for generating schemas from a decorated class.\n */\nexport interface GenerateFromClassOptions {\n /** Path to the TypeScript source file */\n filePath: string;\n /** Class name to analyze */\n className: string;\n}\n\n/**\n * Result of generating schemas from a decorated class.\n */\nexport interface GenerateFromClassResult {\n /** JSON Schema for validation */\n jsonSchema: ExtendedJSONSchema7;\n /** JSON Forms UI Schema for rendering */\n uiSchema: UISchema;\n}\n\n/**\n * Generates JSON Schema and FormSpec/UI Schema from a decorated TypeScript class.\n *\n * This is a high-level entry point that handles the entire pipeline:\n * creating a TypeScript program, finding the class, analyzing it,\n * and generating schemas — all in one call.\n *\n * @example\n * ```typescript\n * const result = generateSchemasFromClass({\n * filePath: \"./src/forms.ts\",\n * className: \"UserForm\",\n * });\n * console.log(result.jsonSchema);\n * ```\n *\n * @param options - File path, class name, and optional compiler options\n * @returns Generated JSON Schema and FormSpec/UI Schema\n */\nexport function generateSchemasFromClass(\n options: GenerateFromClassOptions\n): GenerateFromClassResult {\n const ctx = createProgramContext(options.filePath);\n const classDecl = findClassByName(ctx.sourceFile, options.className);\n\n if (!classDecl) {\n throw new Error(`Class \"${options.className}\" not found in ${options.filePath}`);\n }\n\n const analysis = analyzeClass(classDecl, ctx.checker);\n return generateClassSchemas(analysis, ctx.checker);\n}\n\n/**\n * Options for generating schemas from a named type (class, interface, or type alias).\n */\nexport interface GenerateSchemasOptions {\n /** Path to the TypeScript source file */\n filePath: string;\n /** Name of the exported class, interface, or type alias to analyze */\n typeName: string;\n}\n\n/**\n * Generates JSON Schema and FormSpec/UI Schema from a named TypeScript\n * type — a decorated class, an interface with TSDoc tags, or a type alias.\n *\n * This is the recommended entry point. It automatically detects whether\n * the name resolves to a class, interface, or type alias and uses the\n * appropriate analysis pipeline:\n *\n * - **Classes**: extracts decorators and JSDoc constraints\n * - **Interfaces**: extracts TSDoc tags (`@Field_displayName`, `@Minimum`, etc.)\n * - **Type aliases**: object literal bodies analyzed like interfaces\n *\n * @example\n * ```typescript\n * // Works with both classes and interfaces — caller doesn't need to know\n * const result = generateSchemas({\n * filePath: \"./src/config.ts\",\n * typeName: \"DiscountConfig\",\n * });\n * ```\n *\n * @param options - File path and type name\n * @returns Generated JSON Schema and FormSpec/UI Schema\n */\nexport function generateSchemas(options: GenerateSchemasOptions): GenerateFromClassResult {\n const ctx = createProgramContext(options.filePath);\n\n // Try class first\n const classDecl = findClassByName(ctx.sourceFile, options.typeName);\n if (classDecl) {\n const analysis = analyzeClass(classDecl, ctx.checker);\n return generateClassSchemas(analysis, ctx.checker);\n }\n\n // Try interface\n const interfaceDecl = findInterfaceByName(ctx.sourceFile, options.typeName);\n if (interfaceDecl) {\n const analysis = analyzeInterface(interfaceDecl, ctx.checker);\n return generateClassSchemas(analysis, ctx.checker);\n }\n\n // Try type alias\n const typeAlias = findTypeAliasByName(ctx.sourceFile, options.typeName);\n if (typeAlias) {\n const result = analyzeTypeAlias(typeAlias, ctx.checker);\n if (result.ok) {\n return generateClassSchemas(result.analysis, ctx.checker);\n }\n throw new Error(result.error);\n }\n\n throw new Error(\n `Type \"${options.typeName}\" not found as a class, interface, or type alias in ${options.filePath}`\n );\n}\n","/**\n * Method schema generator.\n *\n * Generates schemas for method parameters and return types:\n * - Parameters using FormSpec (InferSchema<typeof X>) -> runtime generation\n * - Parameters with regular types -> static type conversion\n * - Return types -> static type conversion\n */\n\nimport type * as ts from \"typescript\";\nimport type { MethodInfo, ParameterInfo } from \"../analyzer/class-analyzer.js\";\nimport { convertType } from \"../analyzer/type-converter.js\";\nimport type { ExtendedJSONSchema7 } from \"../json-schema/types.js\";\n\n/**\n * Runtime-loaded FormSpec schemas, compatible with the CLI's FormSpecSchemas type.\n */\nexport interface LoadedFormSpecSchemas {\n /** The FormSpec export name */\n name: string;\n /** Generated JSON Schema */\n jsonSchema: unknown;\n /** Generated UI Schema (FormSpec/JSON Forms) */\n uiSchema: unknown;\n}\n\n/**\n * Generated schemas for a method.\n */\nexport interface MethodSchemas {\n /** Method name */\n name: string;\n /** Parameter schemas (from FormSpec or static analysis) */\n params: MethodParamsSchemas | null;\n /** Return type schema */\n returnType: ExtendedJSONSchema7;\n}\n\n/**\n * Parameter schemas for a method.\n */\nexport interface MethodParamsSchemas {\n /** JSON Schema for parameters */\n jsonSchema: ExtendedJSONSchema7;\n /** UI Schema / FormSpec for parameters (if available) */\n uiSchema: object | null;\n /** Name of the FormSpec export used (if any) */\n formSpecExport: string | null;\n}\n\n/**\n * Generates schemas for a method's parameters and return type.\n *\n * If a parameter references a FormSpec via `InferSchema<typeof X>`,\n * the schemas are taken from the loaded FormSpec at runtime.\n * Otherwise, schemas are generated from static type analysis.\n *\n * @param method - The method information from static analysis\n * @param checker - TypeScript type checker\n * @param loadedFormSpecs - Map of FormSpec export names to their schemas\n * @returns Generated method schemas\n */\nexport function generateMethodSchemas(\n method: MethodInfo,\n checker: ts.TypeChecker,\n loadedFormSpecs: Map<string, LoadedFormSpecSchemas>\n): MethodSchemas {\n // Generate return type schema from static analysis\n const returnType = convertType(method.returnType, checker).jsonSchema;\n\n // Handle parameters\n const params = generateParamsSchemas(method.parameters, checker, loadedFormSpecs);\n\n return {\n name: method.name,\n params,\n returnType,\n };\n}\n\n/**\n * Generates schemas for method parameters.\n */\nfunction generateParamsSchemas(\n parameters: ParameterInfo[],\n checker: ts.TypeChecker,\n loadedFormSpecs: Map<string, LoadedFormSpecSchemas>\n): MethodParamsSchemas | null {\n if (parameters.length === 0) {\n return null;\n }\n\n // Check if any parameter uses InferSchema<typeof X>\n for (const param of parameters) {\n if (param.formSpecExportName) {\n const formSpec = loadedFormSpecs.get(param.formSpecExportName);\n if (formSpec) {\n // Use runtime-generated schemas from FormSpec\n // Cast to our ExtendedJSONSchema7 type (structurally compatible)\n return {\n jsonSchema: formSpec.jsonSchema as ExtendedJSONSchema7,\n uiSchema: formSpec.uiSchema as object | null,\n formSpecExport: param.formSpecExportName,\n };\n }\n\n // FormSpec not found - fall back to static analysis\n console.warn(\n `Warning: FormSpec export \"${param.formSpecExportName}\" not found, using static analysis`\n );\n }\n }\n\n // Generate from static type analysis\n if (parameters.length === 1 && parameters[0]) {\n // Single parameter - use its type directly\n const param = parameters[0];\n const jsonSchema = convertType(param.type, checker).jsonSchema;\n return {\n jsonSchema,\n uiSchema: null,\n formSpecExport: null,\n };\n }\n\n // Multiple parameters - create object schema\n const properties: Record<string, ExtendedJSONSchema7> = {};\n const required: string[] = [];\n\n for (const param of parameters) {\n const paramSchema = convertType(param.type, checker).jsonSchema;\n properties[param.name] = paramSchema;\n // Only non-optional parameters should be marked as required\n if (!param.optional) {\n required.push(param.name);\n }\n }\n\n return {\n jsonSchema: {\n type: \"object\",\n properties,\n ...(required.length > 0 ? { required } : {}),\n },\n uiSchema: null,\n formSpecExport: null,\n };\n}\n\n/**\n * Collects all FormSpec export names referenced by methods.\n *\n * Use this to determine which exports to load at runtime.\n *\n * @param methods - Array of method infos\n * @returns Set of FormSpec export names\n */\nexport function collectFormSpecReferences(methods: MethodInfo[]): Set<string> {\n const references = new Set<string>();\n\n for (const method of methods) {\n for (const param of method.parameters) {\n if (param.formSpecExportName) {\n references.add(param.formSpecExportName);\n }\n }\n }\n\n return references;\n}\n"],"mappings":"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","names":["ts","ts","ts","ts","z","uiSchema"]}
@@ -1 +1 @@
1
- {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/json-schema/generator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,EAMT,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA2J9C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,SAAS,WAAW,EAAE,EACjE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,GAChB,WAAW,CAgBb"}
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/json-schema/generator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,EAMT,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA6K9C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,SAAS,WAAW,EAAE,EACjE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,GAChB,WAAW,CAkBb"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Zod schemas for JSON Schema draft-07 output validation.
3
+ *
4
+ * These schemas cover the subset of JSON Schema draft-07 that FormSpec generates,
5
+ * plus the FormSpec-specific `x-formspec-*` extension properties.
6
+ *
7
+ * @see https://json-schema.org/draft-07/schema
8
+ */
9
+ import { z } from "zod";
10
+ import type { JSONSchema7 } from "./types.js";
11
+ /**
12
+ * Zod schema for JSON Schema primitive type strings.
13
+ */
14
+ export declare const jsonSchemaTypeSchema: z.ZodEnum<["string", "number", "integer", "boolean", "object", "array", "null"]>;
15
+ export declare const jsonSchema7Schema: z.ZodType<JSONSchema7>;
16
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/json-schema/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAM9C;;GAEG;AACH,eAAO,MAAM,oBAAoB,kFAQ/B,CAAC;AAeH,eAAO,MAAM,iBAAiB,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAoEpD,CAAC"}
@@ -3,6 +3,21 @@
3
3
  */
4
4
  import type { FormElement, FormSpec } from "@formspec/core";
5
5
  import type { UISchema } from "./types.js";
6
+ import type { FormSpecField } from "../analyzer/type-converter.js";
7
+ /**
8
+ * Converts FormSpecField[] (from decorator/interface/type analysis) to a JSON Forms UISchema.
9
+ *
10
+ * Mapping:
11
+ * - Each field → `{ type: "Control", scope: "#/properties/{id}", label? }`
12
+ * - `showWhen: { field, value }` → rule with SHOW effect
13
+ * - `group` property → Groups fields by group name, preserving insertion order
14
+ * - `fields` (nested object) → single Control pointing to the object property
15
+ * - Root wrapper → `{ type: "VerticalLayout", elements }`
16
+ *
17
+ * @param fields - The FormSpecField array to convert
18
+ * @returns A JSON Forms UISchema
19
+ */
20
+ export declare function generateUiSchemaFromFields(fields: FormSpecField[]): UISchema;
6
21
  /**
7
22
  * Generates a JSON Forms UI Schema from a FormSpec.
8
23
  *
@@ -1 +1 @@
1
- {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/ui-schema/generator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAsB,MAAM,gBAAgB,CAAC;AAChF,OAAO,KAAK,EAAmB,QAAQ,EAAqC,MAAM,YAAY,CAAC;AA+G/F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,SAAS,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,CAK9F"}
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/ui-schema/generator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAsB,MAAM,gBAAgB,CAAC;AAChF,OAAO,KAAK,EAAmB,QAAQ,EAAqC,MAAM,YAAY,CAAC;AAE/F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAuKnE;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,QAAQ,CAwD5E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,SAAS,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,CAO9F"}