@formspec/build 0.1.0-alpha.1 → 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 (108) hide show
  1. package/README.md +138 -0
  2. package/dist/__tests__/analyzer-edge-cases.test.d.ts +13 -0
  3. package/dist/__tests__/analyzer-edge-cases.test.d.ts.map +1 -0
  4. package/dist/__tests__/analyzer.test.d.ts +5 -0
  5. package/dist/__tests__/analyzer.test.d.ts.map +1 -0
  6. package/dist/__tests__/codegen.test.d.ts +5 -0
  7. package/dist/__tests__/codegen.test.d.ts.map +1 -0
  8. package/dist/__tests__/decorator-pipeline.test.d.ts +11 -0
  9. package/dist/__tests__/decorator-pipeline.test.d.ts.map +1 -0
  10. package/dist/__tests__/fixtures/edge-cases.d.ts +110 -0
  11. package/dist/__tests__/fixtures/edge-cases.d.ts.map +1 -0
  12. package/dist/__tests__/fixtures/example-a-builtins.d.ts +12 -0
  13. package/dist/__tests__/fixtures/example-a-builtins.d.ts.map +1 -0
  14. package/dist/__tests__/fixtures/example-b-decorators.d.ts +5 -0
  15. package/dist/__tests__/fixtures/example-b-decorators.d.ts.map +1 -0
  16. package/dist/__tests__/fixtures/example-b-extended.d.ts +5 -0
  17. package/dist/__tests__/fixtures/example-b-extended.d.ts.map +1 -0
  18. package/dist/__tests__/fixtures/example-c-custom.d.ts +5 -0
  19. package/dist/__tests__/fixtures/example-c-custom.d.ts.map +1 -0
  20. package/dist/__tests__/fixtures/example-c-decorators.d.ts +5 -0
  21. package/dist/__tests__/fixtures/example-c-decorators.d.ts.map +1 -0
  22. package/dist/__tests__/fixtures/example-d-mixed-decorators.d.ts +6 -0
  23. package/dist/__tests__/fixtures/example-d-mixed-decorators.d.ts.map +1 -0
  24. package/dist/__tests__/fixtures/example-e-decorators.d.ts +11 -0
  25. package/dist/__tests__/fixtures/example-e-decorators.d.ts.map +1 -0
  26. package/dist/__tests__/fixtures/example-e-no-namespace.d.ts +5 -0
  27. package/dist/__tests__/fixtures/example-e-no-namespace.d.ts.map +1 -0
  28. package/dist/__tests__/fixtures/example-interface-types.d.ts +102 -0
  29. package/dist/__tests__/fixtures/example-interface-types.d.ts.map +1 -0
  30. package/dist/__tests__/fixtures/example-jsdoc-constraints.d.ts +16 -0
  31. package/dist/__tests__/fixtures/example-jsdoc-constraints.d.ts.map +1 -0
  32. package/dist/__tests__/fixtures/example-nested-class.d.ts +45 -0
  33. package/dist/__tests__/fixtures/example-nested-class.d.ts.map +1 -0
  34. package/dist/__tests__/fixtures/sample-forms.d.ts +55 -0
  35. package/dist/__tests__/fixtures/sample-forms.d.ts.map +1 -0
  36. package/dist/__tests__/interface-types.test.d.ts +11 -0
  37. package/dist/__tests__/interface-types.test.d.ts.map +1 -0
  38. package/dist/__tests__/jsdoc-constraints.test.d.ts +10 -0
  39. package/dist/__tests__/jsdoc-constraints.test.d.ts.map +1 -0
  40. package/dist/analyzer/class-analyzer.d.ts +139 -0
  41. package/dist/analyzer/class-analyzer.d.ts.map +1 -0
  42. package/dist/analyzer/decorator-extractor.d.ts +78 -0
  43. package/dist/analyzer/decorator-extractor.d.ts.map +1 -0
  44. package/dist/analyzer/jsdoc-constraints.d.ts +47 -0
  45. package/dist/analyzer/jsdoc-constraints.d.ts.map +1 -0
  46. package/dist/analyzer/program.d.ts +53 -0
  47. package/dist/analyzer/program.d.ts.map +1 -0
  48. package/dist/analyzer/type-converter.d.ts +75 -0
  49. package/dist/analyzer/type-converter.d.ts.map +1 -0
  50. package/dist/browser.cjs +549 -0
  51. package/dist/browser.cjs.map +1 -0
  52. package/dist/browser.d.ts +56 -0
  53. package/dist/browser.d.ts.map +1 -0
  54. package/dist/browser.js +501 -0
  55. package/dist/browser.js.map +1 -0
  56. package/dist/build.d.ts +890 -0
  57. package/dist/cli.cjs +2267 -0
  58. package/dist/cli.cjs.map +1 -0
  59. package/dist/cli.js +2204 -103
  60. package/dist/cli.js.map +1 -1
  61. package/dist/codegen/index.d.ts +75 -0
  62. package/dist/codegen/index.d.ts.map +1 -0
  63. package/dist/generators/class-schema.d.ts +114 -0
  64. package/dist/generators/class-schema.d.ts.map +1 -0
  65. package/dist/generators/method-schema.d.ts +67 -0
  66. package/dist/generators/method-schema.d.ts.map +1 -0
  67. package/dist/index.cjs +2093 -0
  68. package/dist/index.cjs.map +1 -0
  69. package/dist/index.d.ts +11 -3
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +2024 -104
  72. package/dist/index.js.map +1 -1
  73. package/dist/internals.cjs +1345 -0
  74. package/dist/internals.cjs.map +1 -0
  75. package/dist/internals.d.ts +21 -0
  76. package/dist/internals.d.ts.map +1 -0
  77. package/dist/internals.js +1298 -0
  78. package/dist/internals.js.map +1 -0
  79. package/dist/json-schema/generator.d.ts.map +1 -1
  80. package/dist/json-schema/schema.d.ts +16 -0
  81. package/dist/json-schema/schema.d.ts.map +1 -0
  82. package/dist/json-schema/types.d.ts +28 -0
  83. package/dist/json-schema/types.d.ts.map +1 -1
  84. package/dist/ui-schema/generator.d.ts +15 -0
  85. package/dist/ui-schema/generator.d.ts.map +1 -1
  86. package/dist/ui-schema/schema.d.ts +357 -0
  87. package/dist/ui-schema/schema.d.ts.map +1 -0
  88. package/dist/ui-schema/types.d.ts +8 -73
  89. package/dist/ui-schema/types.d.ts.map +1 -1
  90. package/package.json +25 -7
  91. package/dist/__tests__/cli.test.js +0 -178
  92. package/dist/__tests__/cli.test.js.map +0 -1
  93. package/dist/__tests__/edge-cases.test.js +0 -209
  94. package/dist/__tests__/edge-cases.test.js.map +0 -1
  95. package/dist/__tests__/generator.test.js +0 -208
  96. package/dist/__tests__/generator.test.js.map +0 -1
  97. package/dist/__tests__/integration.test.js +0 -163
  98. package/dist/__tests__/integration.test.js.map +0 -1
  99. package/dist/__tests__/write-schemas.test.js +0 -196
  100. package/dist/__tests__/write-schemas.test.js.map +0 -1
  101. package/dist/json-schema/generator.js +0 -146
  102. package/dist/json-schema/generator.js.map +0 -1
  103. package/dist/json-schema/types.js +0 -7
  104. package/dist/json-schema/types.js.map +0 -1
  105. package/dist/ui-schema/generator.js +0 -150
  106. package/dist/ui-schema/generator.js.map +0 -1
  107. package/dist/ui-schema/types.js +0 -8
  108. package/dist/ui-schema/types.js.map +0 -1
@@ -0,0 +1,1345 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/internals.ts
31
+ var internals_exports = {};
32
+ __export(internals_exports, {
33
+ analyzeClass: () => analyzeClass,
34
+ analyzeInterface: () => analyzeInterface,
35
+ analyzeTypeAlias: () => analyzeTypeAlias,
36
+ collectFormSpecReferences: () => collectFormSpecReferences,
37
+ createProgramContext: () => createProgramContext,
38
+ findClassByName: () => findClassByName,
39
+ findInterfaceByName: () => findInterfaceByName,
40
+ findTypeAliasByName: () => findTypeAliasByName,
41
+ generateClassSchemas: () => generateClassSchemas,
42
+ generateMethodSchemas: () => generateMethodSchemas,
43
+ generateUiSchemaFromFields: () => generateUiSchemaFromFields
44
+ });
45
+ module.exports = __toCommonJS(internals_exports);
46
+
47
+ // src/analyzer/program.ts
48
+ var ts = __toESM(require("typescript"), 1);
49
+ var path = __toESM(require("path"), 1);
50
+ function createProgramContext(filePath) {
51
+ const absolutePath = path.resolve(filePath);
52
+ const fileDir = path.dirname(absolutePath);
53
+ const configPath = ts.findConfigFile(fileDir, ts.sys.fileExists.bind(ts.sys), "tsconfig.json");
54
+ let compilerOptions;
55
+ let fileNames;
56
+ if (configPath) {
57
+ const configFile = ts.readConfigFile(configPath, ts.sys.readFile.bind(ts.sys));
58
+ if (configFile.error) {
59
+ throw new Error(
60
+ `Error reading tsconfig.json: ${ts.flattenDiagnosticMessageText(configFile.error.messageText, "\n")}`
61
+ );
62
+ }
63
+ const parsed = ts.parseJsonConfigFileContent(
64
+ configFile.config,
65
+ ts.sys,
66
+ path.dirname(configPath)
67
+ );
68
+ if (parsed.errors.length > 0) {
69
+ const errorMessages = parsed.errors.map((e) => ts.flattenDiagnosticMessageText(e.messageText, "\n")).join("\n");
70
+ throw new Error(`Error parsing tsconfig.json: ${errorMessages}`);
71
+ }
72
+ compilerOptions = parsed.options;
73
+ fileNames = parsed.fileNames.includes(absolutePath) ? parsed.fileNames : [...parsed.fileNames, absolutePath];
74
+ } else {
75
+ compilerOptions = {
76
+ target: ts.ScriptTarget.ES2022,
77
+ module: ts.ModuleKind.NodeNext,
78
+ moduleResolution: ts.ModuleResolutionKind.NodeNext,
79
+ strict: true,
80
+ skipLibCheck: true,
81
+ declaration: true
82
+ };
83
+ fileNames = [absolutePath];
84
+ }
85
+ const program = ts.createProgram(fileNames, compilerOptions);
86
+ const sourceFile = program.getSourceFile(absolutePath);
87
+ if (!sourceFile) {
88
+ throw new Error(`Could not find source file: ${absolutePath}`);
89
+ }
90
+ return {
91
+ program,
92
+ checker: program.getTypeChecker(),
93
+ sourceFile
94
+ };
95
+ }
96
+ function findNodeByName(sourceFile, name, predicate, getName) {
97
+ let result = null;
98
+ function visit(node) {
99
+ if (result) return;
100
+ if (predicate(node) && getName(node) === name) {
101
+ result = node;
102
+ return;
103
+ }
104
+ ts.forEachChild(node, visit);
105
+ }
106
+ visit(sourceFile);
107
+ return result;
108
+ }
109
+ function findClassByName(sourceFile, className) {
110
+ return findNodeByName(sourceFile, className, ts.isClassDeclaration, (n) => n.name?.text);
111
+ }
112
+ function findInterfaceByName(sourceFile, interfaceName) {
113
+ return findNodeByName(sourceFile, interfaceName, ts.isInterfaceDeclaration, (n) => n.name.text);
114
+ }
115
+ function findTypeAliasByName(sourceFile, aliasName) {
116
+ return findNodeByName(sourceFile, aliasName, ts.isTypeAliasDeclaration, (n) => n.name.text);
117
+ }
118
+
119
+ // src/analyzer/class-analyzer.ts
120
+ var ts4 = __toESM(require("typescript"), 1);
121
+
122
+ // src/analyzer/decorator-extractor.ts
123
+ var ts2 = __toESM(require("typescript"), 1);
124
+ var import_core = require("@formspec/core");
125
+ function extractDecorators(member) {
126
+ const decorators = [];
127
+ const modifiers = ts2.canHaveDecorators(member) ? ts2.getDecorators(member) : void 0;
128
+ if (!modifiers) return decorators;
129
+ for (const decorator of modifiers) {
130
+ const info = parseDecorator(decorator);
131
+ if (info) {
132
+ decorators.push(info);
133
+ }
134
+ }
135
+ return decorators;
136
+ }
137
+ function parseDecorator(decorator) {
138
+ const expr = decorator.expression;
139
+ if (ts2.isIdentifier(expr)) {
140
+ return {
141
+ name: expr.text,
142
+ args: [],
143
+ node: decorator
144
+ };
145
+ }
146
+ if (ts2.isCallExpression(expr)) {
147
+ const callee = expr.expression;
148
+ let name = null;
149
+ if (ts2.isIdentifier(callee)) {
150
+ name = callee.text;
151
+ } else if (ts2.isPropertyAccessExpression(callee)) {
152
+ name = callee.name.text;
153
+ }
154
+ if (!name) return null;
155
+ const args = expr.arguments.map(extractArgValue);
156
+ return {
157
+ name,
158
+ args,
159
+ node: decorator
160
+ };
161
+ }
162
+ return null;
163
+ }
164
+ function extractArgValue(node) {
165
+ if (ts2.isStringLiteral(node)) {
166
+ return node.text;
167
+ }
168
+ if (ts2.isNumericLiteral(node)) {
169
+ return Number(node.text);
170
+ }
171
+ if (node.kind === ts2.SyntaxKind.TrueKeyword) {
172
+ return true;
173
+ }
174
+ if (node.kind === ts2.SyntaxKind.FalseKeyword) {
175
+ return false;
176
+ }
177
+ if (node.kind === ts2.SyntaxKind.NullKeyword) {
178
+ return null;
179
+ }
180
+ if (ts2.isPrefixUnaryExpression(node)) {
181
+ if (node.operator === ts2.SyntaxKind.MinusToken && ts2.isNumericLiteral(node.operand)) {
182
+ return -Number(node.operand.text);
183
+ }
184
+ if (node.operator === ts2.SyntaxKind.PlusToken && ts2.isNumericLiteral(node.operand)) {
185
+ return Number(node.operand.text);
186
+ }
187
+ }
188
+ if (ts2.isArrayLiteralExpression(node)) {
189
+ return node.elements.map((el) => {
190
+ if (ts2.isSpreadElement(el)) {
191
+ return null;
192
+ }
193
+ return extractArgValue(el);
194
+ });
195
+ }
196
+ if (ts2.isObjectLiteralExpression(node)) {
197
+ const obj = {};
198
+ for (const prop of node.properties) {
199
+ if (ts2.isPropertyAssignment(prop)) {
200
+ const key = getPropertyName(prop.name);
201
+ if (key) {
202
+ obj[key] = extractArgValue(prop.initializer);
203
+ }
204
+ } else if (ts2.isShorthandPropertyAssignment(prop)) {
205
+ const key = prop.name.text;
206
+ obj[key] = null;
207
+ }
208
+ }
209
+ return obj;
210
+ }
211
+ if (ts2.isNoSubstitutionTemplateLiteral(node)) {
212
+ return node.text;
213
+ }
214
+ if (ts2.isRegularExpressionLiteral(node)) {
215
+ const regexText = node.text;
216
+ const lastSlash = regexText.lastIndexOf("/");
217
+ if (lastSlash > 0) {
218
+ return regexText.substring(1, lastSlash);
219
+ }
220
+ return regexText;
221
+ }
222
+ if (ts2.isNewExpression(node)) {
223
+ if (ts2.isIdentifier(node.expression) && node.expression.text === "RegExp" && node.arguments && node.arguments.length > 0) {
224
+ const firstArg = node.arguments[0];
225
+ if (firstArg && ts2.isStringLiteral(firstArg)) {
226
+ return firstArg.text;
227
+ }
228
+ }
229
+ }
230
+ if (ts2.isIdentifier(node)) {
231
+ return null;
232
+ }
233
+ return null;
234
+ }
235
+ function getPropertyName(name) {
236
+ if (ts2.isIdentifier(name)) {
237
+ return name.text;
238
+ }
239
+ if (ts2.isStringLiteral(name)) {
240
+ return name.text;
241
+ }
242
+ if (ts2.isNumericLiteral(name)) {
243
+ return name.text;
244
+ }
245
+ return null;
246
+ }
247
+ var FORMSPEC_DECORATORS = {
248
+ // Display metadata
249
+ Field: { argTypes: ["object"] },
250
+ // Grouping
251
+ Group: { argTypes: ["string"] },
252
+ // Conditional display
253
+ ShowWhen: { argTypes: ["object"] },
254
+ // Enum options
255
+ EnumOptions: { argTypes: ["array"] },
256
+ // Numeric constraints
257
+ Minimum: { argTypes: ["number"] },
258
+ Maximum: { argTypes: ["number"] },
259
+ ExclusiveMinimum: { argTypes: ["number"] },
260
+ ExclusiveMaximum: { argTypes: ["number"] },
261
+ // String constraints
262
+ MinLength: { argTypes: ["number"] },
263
+ MaxLength: { argTypes: ["number"] },
264
+ Pattern: { argTypes: ["string"] }
265
+ };
266
+ function isFormSpecDecoratorsPath(fileName) {
267
+ const normalized = fileName.replace(/\\/g, "/");
268
+ return normalized.includes("node_modules/@formspec/decorators") || normalized.includes("/packages/decorators/");
269
+ }
270
+ function resolveDecorator(decorator, checker) {
271
+ const expr = decorator.expression;
272
+ let targetNode;
273
+ let name;
274
+ if (ts2.isIdentifier(expr)) {
275
+ targetNode = expr;
276
+ name = expr.text;
277
+ } else if (ts2.isCallExpression(expr)) {
278
+ if (ts2.isIdentifier(expr.expression)) {
279
+ targetNode = expr.expression;
280
+ name = expr.expression.text;
281
+ } else {
282
+ return null;
283
+ }
284
+ } else {
285
+ return null;
286
+ }
287
+ if (name in FORMSPEC_DECORATORS) {
288
+ const symbol = checker.getSymbolAtLocation(targetNode);
289
+ if (symbol) {
290
+ const declarations = symbol.declarations;
291
+ if (declarations && declarations.length > 0) {
292
+ const decl = declarations[0];
293
+ if (decl) {
294
+ const sourceFile = decl.getSourceFile();
295
+ const fileName = sourceFile.fileName;
296
+ if (isFormSpecDecoratorsPath(fileName)) {
297
+ return {
298
+ name,
299
+ isFormSpec: true,
300
+ isMarker: !ts2.isCallExpression(expr)
301
+ };
302
+ }
303
+ }
304
+ }
305
+ }
306
+ }
307
+ const resolvedSymbol = checker.getSymbolAtLocation(targetNode);
308
+ if (!resolvedSymbol) return null;
309
+ const type = checker.getTypeOfSymbol(resolvedSymbol);
310
+ const props = type.getProperties();
311
+ let extendsBuiltin;
312
+ let extensionName;
313
+ let isMarker = false;
314
+ for (const prop of props) {
315
+ const escapedName = prop.getEscapedName();
316
+ if (escapedName.startsWith("__@") && (escapedName.includes("formspec.extends") || escapedName.includes("FORMSPEC_EXTENDS"))) {
317
+ const propType = checker.getTypeOfSymbol(prop);
318
+ if (propType.isStringLiteral()) {
319
+ extendsBuiltin = propType.value;
320
+ }
321
+ }
322
+ if (escapedName.startsWith("__@") && (escapedName.includes("formspec.extension") || escapedName.includes("FORMSPEC_EXTENSION"))) {
323
+ const propType = checker.getTypeOfSymbol(prop);
324
+ if (propType.isStringLiteral()) {
325
+ extensionName = propType.value;
326
+ }
327
+ }
328
+ if (escapedName.startsWith("__@") && (escapedName.includes("formspec.marker") || escapedName.includes("FORMSPEC_MARKER"))) {
329
+ isMarker = true;
330
+ }
331
+ }
332
+ if (extendsBuiltin) {
333
+ return {
334
+ name,
335
+ extendsBuiltin,
336
+ isFormSpec: true,
337
+ isMarker: false
338
+ };
339
+ }
340
+ if (extensionName) {
341
+ return {
342
+ name,
343
+ extensionName,
344
+ isFormSpec: true,
345
+ isMarker
346
+ };
347
+ }
348
+ if (isMarker) {
349
+ return {
350
+ name,
351
+ isFormSpec: true,
352
+ isMarker: true
353
+ };
354
+ }
355
+ return null;
356
+ }
357
+
358
+ // src/analyzer/jsdoc-constraints.ts
359
+ var ts3 = __toESM(require("typescript"), 1);
360
+ var import_core2 = require("@formspec/core");
361
+ function extractJSDocConstraints(node) {
362
+ const results = [];
363
+ const jsDocTags = ts3.getJSDocTags(node);
364
+ for (const tag of jsDocTags) {
365
+ const tagName = tag.tagName.text;
366
+ if (!(tagName in import_core2.CONSTRAINT_TAG_DEFINITIONS)) {
367
+ continue;
368
+ }
369
+ const constraintName = tagName;
370
+ const expectedType = import_core2.CONSTRAINT_TAG_DEFINITIONS[constraintName];
371
+ const commentText = getTagCommentText(tag);
372
+ if (commentText === void 0 || commentText === "") {
373
+ continue;
374
+ }
375
+ const trimmed = commentText.trim();
376
+ if (trimmed === "") {
377
+ continue;
378
+ }
379
+ if (expectedType === "number") {
380
+ const value = Number(trimmed);
381
+ if (Number.isNaN(value)) {
382
+ continue;
383
+ }
384
+ results.push(createSyntheticDecorator(constraintName, value));
385
+ } else if (expectedType === "json") {
386
+ try {
387
+ const parsed = JSON.parse(trimmed);
388
+ if (!Array.isArray(parsed)) {
389
+ continue;
390
+ }
391
+ results.push(createSyntheticDecorator(constraintName, parsed));
392
+ } catch {
393
+ continue;
394
+ }
395
+ } else {
396
+ results.push(createSyntheticDecorator(constraintName, trimmed));
397
+ }
398
+ }
399
+ return results;
400
+ }
401
+ function extractJSDocFieldMetadata(node) {
402
+ const jsDocTags = ts3.getJSDocTags(node);
403
+ let displayName;
404
+ let description;
405
+ for (const tag of jsDocTags) {
406
+ const tagName = tag.tagName.text;
407
+ const commentText = getTagCommentText(tag);
408
+ if (commentText === void 0 || commentText.trim() === "") {
409
+ continue;
410
+ }
411
+ const trimmed = commentText.trim();
412
+ if (tagName === "Field_displayName") {
413
+ displayName = trimmed;
414
+ } else if (tagName === "Field_description") {
415
+ description = trimmed;
416
+ }
417
+ }
418
+ if (displayName === void 0 && description === void 0) {
419
+ return null;
420
+ }
421
+ const fieldOpts = {
422
+ ...displayName !== void 0 ? { displayName } : {},
423
+ ...description !== void 0 ? { description } : {}
424
+ };
425
+ return createSyntheticDecorator("Field", fieldOpts);
426
+ }
427
+ function getTagCommentText(tag) {
428
+ if (tag.comment === void 0) {
429
+ return void 0;
430
+ }
431
+ if (typeof tag.comment === "string") {
432
+ return tag.comment;
433
+ }
434
+ return ts3.getTextOfJSDocComment(tag.comment);
435
+ }
436
+ function createSyntheticDecorator(name, value) {
437
+ return {
438
+ name,
439
+ args: [value],
440
+ node: void 0
441
+ };
442
+ }
443
+
444
+ // src/analyzer/class-analyzer.ts
445
+ function analyzeClass(classDecl, checker) {
446
+ const name = classDecl.name?.text ?? "AnonymousClass";
447
+ const fields = [];
448
+ const instanceMethods = [];
449
+ const staticMethods = [];
450
+ for (const member of classDecl.members) {
451
+ if (ts4.isPropertyDeclaration(member)) {
452
+ const fieldInfo = analyzeField(member, checker);
453
+ if (fieldInfo) {
454
+ fields.push(fieldInfo);
455
+ }
456
+ } else if (ts4.isMethodDeclaration(member)) {
457
+ const methodInfo = analyzeMethod(member, checker);
458
+ if (methodInfo) {
459
+ const isStatic = member.modifiers?.some((m) => m.kind === ts4.SyntaxKind.StaticKeyword);
460
+ if (isStatic) {
461
+ staticMethods.push(methodInfo);
462
+ } else {
463
+ instanceMethods.push(methodInfo);
464
+ }
465
+ }
466
+ }
467
+ }
468
+ return {
469
+ name,
470
+ fields,
471
+ instanceMethods,
472
+ staticMethods
473
+ };
474
+ }
475
+ function analyzeField(prop, checker) {
476
+ if (!ts4.isIdentifier(prop.name)) {
477
+ return null;
478
+ }
479
+ const name = prop.name.text;
480
+ const typeNode = prop.type;
481
+ const type = checker.getTypeAtLocation(prop);
482
+ const optional = prop.questionToken !== void 0;
483
+ const decorators = extractDecorators(prop);
484
+ for (const dec of decorators) {
485
+ if (dec.node) {
486
+ const resolved = resolveDecorator(dec.node, checker);
487
+ if (resolved) {
488
+ dec.resolved = resolved;
489
+ }
490
+ }
491
+ }
492
+ if (prop.type) {
493
+ const aliasConstraints = extractTypeAliasConstraints(prop.type, checker);
494
+ decorators.push(...aliasConstraints);
495
+ }
496
+ const jsdocConstraints = extractJSDocConstraints(prop);
497
+ decorators.push(...jsdocConstraints);
498
+ const deprecated = hasDeprecatedTag(prop);
499
+ const defaultValue = extractDefaultValue(prop.initializer);
500
+ return {
501
+ name,
502
+ typeNode,
503
+ type,
504
+ optional,
505
+ decorators,
506
+ deprecated,
507
+ defaultValue
508
+ };
509
+ }
510
+ function extractTypeAliasConstraints(typeNode, checker) {
511
+ if (!ts4.isTypeReferenceNode(typeNode)) return [];
512
+ const symbol = checker.getSymbolAtLocation(typeNode.typeName);
513
+ if (!symbol?.declarations) return [];
514
+ const aliasDecl = symbol.declarations.find(ts4.isTypeAliasDeclaration);
515
+ if (!aliasDecl) return [];
516
+ if (ts4.isTypeLiteralNode(aliasDecl.type)) return [];
517
+ return extractJSDocConstraints(aliasDecl);
518
+ }
519
+ function hasDeprecatedTag(node) {
520
+ const jsDocTags = ts4.getJSDocTags(node);
521
+ return jsDocTags.some((tag) => tag.tagName.text === "deprecated");
522
+ }
523
+ function extractDefaultValue(initializer) {
524
+ if (!initializer) return void 0;
525
+ if (ts4.isStringLiteral(initializer)) {
526
+ return initializer.text;
527
+ }
528
+ if (ts4.isNumericLiteral(initializer)) {
529
+ return Number(initializer.text);
530
+ }
531
+ if (initializer.kind === ts4.SyntaxKind.TrueKeyword) {
532
+ return true;
533
+ }
534
+ if (initializer.kind === ts4.SyntaxKind.FalseKeyword) {
535
+ return false;
536
+ }
537
+ if (initializer.kind === ts4.SyntaxKind.NullKeyword) {
538
+ return null;
539
+ }
540
+ if (ts4.isPrefixUnaryExpression(initializer)) {
541
+ if (initializer.operator === ts4.SyntaxKind.MinusToken && ts4.isNumericLiteral(initializer.operand)) {
542
+ return -Number(initializer.operand.text);
543
+ }
544
+ }
545
+ return void 0;
546
+ }
547
+ function analyzeMethod(method, checker) {
548
+ if (!ts4.isIdentifier(method.name)) {
549
+ return null;
550
+ }
551
+ const name = method.name.text;
552
+ const parameters = [];
553
+ for (const param of method.parameters) {
554
+ if (ts4.isIdentifier(param.name)) {
555
+ const paramInfo = analyzeParameter(param, checker);
556
+ parameters.push(paramInfo);
557
+ }
558
+ }
559
+ const returnTypeNode = method.type;
560
+ const signature = checker.getSignatureFromDeclaration(method);
561
+ const returnType = signature ? checker.getReturnTypeOfSignature(signature) : checker.getTypeAtLocation(method);
562
+ return {
563
+ name,
564
+ parameters,
565
+ returnTypeNode,
566
+ returnType
567
+ };
568
+ }
569
+ function analyzeParameter(param, checker) {
570
+ const name = ts4.isIdentifier(param.name) ? param.name.text : "param";
571
+ const typeNode = param.type;
572
+ const type = checker.getTypeAtLocation(param);
573
+ const formSpecExportName = detectFormSpecReference(typeNode);
574
+ const optional = param.questionToken !== void 0 || param.initializer !== void 0;
575
+ return {
576
+ name,
577
+ typeNode,
578
+ type,
579
+ formSpecExportName,
580
+ optional
581
+ };
582
+ }
583
+ function detectFormSpecReference(typeNode) {
584
+ if (!typeNode) return null;
585
+ if (!ts4.isTypeReferenceNode(typeNode)) return null;
586
+ const typeName = ts4.isIdentifier(typeNode.typeName) ? typeNode.typeName.text : ts4.isQualifiedName(typeNode.typeName) ? typeNode.typeName.right.text : null;
587
+ if (typeName !== "InferSchema" && typeName !== "InferFormSchema") return null;
588
+ const typeArg = typeNode.typeArguments?.[0];
589
+ if (!typeArg || !ts4.isTypeQueryNode(typeArg)) return null;
590
+ if (ts4.isIdentifier(typeArg.exprName)) {
591
+ return typeArg.exprName.text;
592
+ }
593
+ if (ts4.isQualifiedName(typeArg.exprName)) {
594
+ return typeArg.exprName.right.text;
595
+ }
596
+ return null;
597
+ }
598
+ function analyzeInterface(interfaceDecl, checker) {
599
+ const name = interfaceDecl.name.text;
600
+ const fields = [];
601
+ for (const member of interfaceDecl.members) {
602
+ if (ts4.isPropertySignature(member)) {
603
+ const fieldInfo = analyzeInterfaceProperty(member, checker);
604
+ if (fieldInfo) {
605
+ fields.push(fieldInfo);
606
+ }
607
+ }
608
+ }
609
+ return {
610
+ name,
611
+ fields,
612
+ instanceMethods: [],
613
+ staticMethods: []
614
+ };
615
+ }
616
+ function analyzeTypeAlias(typeAlias, checker) {
617
+ if (!ts4.isTypeLiteralNode(typeAlias.type)) {
618
+ const sourceFile = typeAlias.getSourceFile();
619
+ const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
620
+ const kindDesc = ts4.SyntaxKind[typeAlias.type.kind] ?? "unknown";
621
+ return {
622
+ ok: false,
623
+ error: `Type alias "${typeAlias.name.text}" at line ${String(line + 1)} is not an object type literal (found ${kindDesc})`
624
+ };
625
+ }
626
+ const name = typeAlias.name.text;
627
+ const fields = [];
628
+ for (const member of typeAlias.type.members) {
629
+ if (ts4.isPropertySignature(member)) {
630
+ const fieldInfo = analyzeInterfaceProperty(member, checker);
631
+ if (fieldInfo) {
632
+ fields.push(fieldInfo);
633
+ }
634
+ }
635
+ }
636
+ return {
637
+ ok: true,
638
+ analysis: {
639
+ name,
640
+ fields,
641
+ instanceMethods: [],
642
+ staticMethods: []
643
+ }
644
+ };
645
+ }
646
+ function analyzeInterfaceProperty(prop, checker) {
647
+ if (!ts4.isIdentifier(prop.name)) {
648
+ return null;
649
+ }
650
+ const name = prop.name.text;
651
+ const typeNode = prop.type;
652
+ const type = checker.getTypeAtLocation(prop);
653
+ const optional = prop.questionToken !== void 0;
654
+ const decorators = [];
655
+ if (typeNode) {
656
+ const aliasConstraints = extractTypeAliasConstraints(typeNode, checker);
657
+ decorators.push(...aliasConstraints);
658
+ }
659
+ const fieldMetadata = extractJSDocFieldMetadata(prop);
660
+ if (fieldMetadata) {
661
+ decorators.push(fieldMetadata);
662
+ }
663
+ const jsdocConstraints = extractJSDocConstraints(prop);
664
+ decorators.push(...jsdocConstraints);
665
+ const deprecated = hasDeprecatedTag(prop);
666
+ return {
667
+ name,
668
+ typeNode,
669
+ type,
670
+ optional,
671
+ decorators,
672
+ deprecated,
673
+ defaultValue: void 0
674
+ };
675
+ }
676
+
677
+ // src/analyzer/type-converter.ts
678
+ var ts5 = __toESM(require("typescript"), 1);
679
+
680
+ // src/json-schema/types.ts
681
+ function setSchemaExtension(schema, key, value) {
682
+ schema[key] = value;
683
+ }
684
+
685
+ // src/analyzer/type-converter.ts
686
+ function getNamedTypeFieldInfoMap(type, checker) {
687
+ const symbols = [type.getSymbol(), type.aliasSymbol].filter(
688
+ (s) => s?.declarations != null && s.declarations.length > 0
689
+ );
690
+ for (const symbol of symbols) {
691
+ const declarations = symbol.declarations;
692
+ if (!declarations) continue;
693
+ const classDecl = declarations.find(ts5.isClassDeclaration);
694
+ if (classDecl) {
695
+ const map = /* @__PURE__ */ new Map();
696
+ for (const member of classDecl.members) {
697
+ if (ts5.isPropertyDeclaration(member) && ts5.isIdentifier(member.name)) {
698
+ const fieldInfo = analyzeField(member, checker);
699
+ if (fieldInfo) map.set(fieldInfo.name, fieldInfo);
700
+ }
701
+ }
702
+ return map;
703
+ }
704
+ const interfaceDecl = declarations.find(ts5.isInterfaceDeclaration);
705
+ if (interfaceDecl) {
706
+ return buildFieldInfoMapFromSignatures(interfaceDecl.members, checker);
707
+ }
708
+ const typeAliasDecl = declarations.find(ts5.isTypeAliasDeclaration);
709
+ if (typeAliasDecl && ts5.isTypeLiteralNode(typeAliasDecl.type)) {
710
+ return buildFieldInfoMapFromSignatures(typeAliasDecl.type.members, checker);
711
+ }
712
+ }
713
+ return null;
714
+ }
715
+ function buildFieldInfoMapFromSignatures(members, checker) {
716
+ const map = /* @__PURE__ */ new Map();
717
+ for (const member of members) {
718
+ if (ts5.isPropertySignature(member)) {
719
+ const fieldInfo = analyzeInterfaceProperty(member, checker);
720
+ if (fieldInfo) {
721
+ map.set(fieldInfo.name, fieldInfo);
722
+ }
723
+ }
724
+ }
725
+ return map;
726
+ }
727
+ function getObjectPropertyInfos(type, checker) {
728
+ const fieldInfoMap = getNamedTypeFieldInfoMap(type, checker);
729
+ const result = [];
730
+ for (const prop of type.getProperties()) {
731
+ const declaration = prop.valueDeclaration ?? prop.declarations?.[0];
732
+ if (!declaration) continue;
733
+ const propType = checker.getTypeOfSymbolAtLocation(prop, declaration);
734
+ const optional = !!(prop.flags & ts5.SymbolFlags.Optional);
735
+ const fieldInfo = fieldInfoMap?.get(prop.name) ?? void 0;
736
+ result.push({ name: prop.name, type: propType, optional, fieldInfo });
737
+ }
738
+ return result;
739
+ }
740
+ function convertType(type, checker) {
741
+ return convertTypeInternal(type, checker, /* @__PURE__ */ new Set());
742
+ }
743
+ function convertTypeInternal(type, checker, visiting) {
744
+ if (type.flags & ts5.TypeFlags.String) {
745
+ return { jsonSchema: { type: "string" }, formSpecFieldType: "text" };
746
+ }
747
+ if (type.flags & ts5.TypeFlags.Number) {
748
+ return { jsonSchema: { type: "number" }, formSpecFieldType: "number" };
749
+ }
750
+ if (type.flags & ts5.TypeFlags.Boolean) {
751
+ return { jsonSchema: { type: "boolean" }, formSpecFieldType: "boolean" };
752
+ }
753
+ if (type.flags & ts5.TypeFlags.Null) {
754
+ return { jsonSchema: { type: "null" }, formSpecFieldType: "null" };
755
+ }
756
+ if (type.flags & ts5.TypeFlags.Undefined) {
757
+ return { jsonSchema: {}, formSpecFieldType: "undefined" };
758
+ }
759
+ if (type.isStringLiteral()) {
760
+ return {
761
+ jsonSchema: { const: type.value },
762
+ formSpecFieldType: "enum"
763
+ };
764
+ }
765
+ if (type.isNumberLiteral()) {
766
+ return {
767
+ jsonSchema: { const: type.value },
768
+ formSpecFieldType: "number"
769
+ };
770
+ }
771
+ if (type.isUnion()) {
772
+ return convertUnionType(type, checker, visiting);
773
+ }
774
+ if (checker.isArrayType(type)) {
775
+ return convertArrayType(type, checker, visiting);
776
+ }
777
+ if (type.flags & ts5.TypeFlags.Object) {
778
+ return convertObjectType(type, checker, visiting);
779
+ }
780
+ return { jsonSchema: {}, formSpecFieldType: "unknown" };
781
+ }
782
+ function convertUnionType(type, checker, visiting) {
783
+ const types = type.types;
784
+ const nonNullTypes = types.filter(
785
+ (t) => !(t.flags & (ts5.TypeFlags.Null | ts5.TypeFlags.Undefined))
786
+ );
787
+ const hasNull = types.some((t) => t.flags & ts5.TypeFlags.Null);
788
+ const isBooleanUnion = nonNullTypes.length === 2 && nonNullTypes.every((t) => t.flags & ts5.TypeFlags.BooleanLiteral);
789
+ if (isBooleanUnion) {
790
+ const result = {
791
+ jsonSchema: { type: "boolean" },
792
+ formSpecFieldType: "boolean"
793
+ };
794
+ if (hasNull) {
795
+ result.jsonSchema = { oneOf: [{ type: "boolean" }, { type: "null" }] };
796
+ }
797
+ return result;
798
+ }
799
+ const allStringLiterals = nonNullTypes.every((t) => t.isStringLiteral());
800
+ if (allStringLiterals && nonNullTypes.length > 0) {
801
+ const enumValues = nonNullTypes.map((t) => t.value);
802
+ const result = {
803
+ jsonSchema: { enum: enumValues },
804
+ formSpecFieldType: "enum"
805
+ };
806
+ if (hasNull) {
807
+ result.jsonSchema = { oneOf: [{ enum: enumValues }, { type: "null" }] };
808
+ }
809
+ return result;
810
+ }
811
+ const allNumberLiterals = nonNullTypes.every((t) => t.isNumberLiteral());
812
+ if (allNumberLiterals && nonNullTypes.length > 0) {
813
+ const enumValues = nonNullTypes.map((t) => t.value);
814
+ const result = {
815
+ jsonSchema: { enum: enumValues },
816
+ formSpecFieldType: "enum"
817
+ };
818
+ if (hasNull) {
819
+ result.jsonSchema = { oneOf: [{ enum: enumValues }, { type: "null" }] };
820
+ }
821
+ return result;
822
+ }
823
+ if (nonNullTypes.length === 1 && nonNullTypes[0]) {
824
+ const result = convertTypeInternal(nonNullTypes[0], checker, visiting);
825
+ if (hasNull) {
826
+ result.jsonSchema = { oneOf: [result.jsonSchema, { type: "null" }] };
827
+ }
828
+ return result;
829
+ }
830
+ const schemas = nonNullTypes.map((t) => convertTypeInternal(t, checker, visiting).jsonSchema);
831
+ if (hasNull) {
832
+ schemas.push({ type: "null" });
833
+ }
834
+ return {
835
+ jsonSchema: { oneOf: schemas },
836
+ formSpecFieldType: "union"
837
+ };
838
+ }
839
+ function convertArrayType(type, checker, visiting) {
840
+ const typeArgs = type.typeArguments;
841
+ const elementType = typeArgs?.[0];
842
+ const itemSchema = elementType ? convertTypeInternal(elementType, checker, visiting).jsonSchema : {};
843
+ return {
844
+ jsonSchema: {
845
+ type: "array",
846
+ items: itemSchema
847
+ },
848
+ formSpecFieldType: "array"
849
+ };
850
+ }
851
+ function convertObjectType(type, checker, visiting) {
852
+ if (visiting.has(type)) {
853
+ return { jsonSchema: { type: "object" }, formSpecFieldType: "object" };
854
+ }
855
+ visiting.add(type);
856
+ const properties = {};
857
+ const required = [];
858
+ for (const propInfo of getObjectPropertyInfos(type, checker)) {
859
+ const propSchema = convertTypeInternal(propInfo.type, checker, visiting).jsonSchema;
860
+ properties[propInfo.name] = propInfo.fieldInfo ? applyDecoratorsToSchema(propSchema, propInfo.fieldInfo.decorators, propInfo.fieldInfo) : propSchema;
861
+ if (!propInfo.optional) {
862
+ required.push(propInfo.name);
863
+ }
864
+ }
865
+ visiting.delete(type);
866
+ return {
867
+ jsonSchema: {
868
+ type: "object",
869
+ properties,
870
+ ...required.length > 0 ? { required } : {}
871
+ },
872
+ formSpecFieldType: "object"
873
+ };
874
+ }
875
+ function createFormSpecField(fieldName, type, decorators, optional, checker, visitedTypes = /* @__PURE__ */ new Set()) {
876
+ const { formSpecFieldType } = convertType(type, checker);
877
+ const field = {
878
+ _field: formSpecFieldType,
879
+ id: fieldName
880
+ };
881
+ if (!optional) {
882
+ field.required = true;
883
+ }
884
+ if (formSpecFieldType === "object" && type.flags & ts5.TypeFlags.Object) {
885
+ if (!visitedTypes.has(type)) {
886
+ visitedTypes.add(type);
887
+ const nestedFields = [];
888
+ for (const propInfo of getObjectPropertyInfos(type, checker)) {
889
+ nestedFields.push(
890
+ createFormSpecField(
891
+ propInfo.name,
892
+ propInfo.type,
893
+ propInfo.fieldInfo?.decorators ?? [],
894
+ propInfo.optional,
895
+ checker,
896
+ visitedTypes
897
+ )
898
+ );
899
+ }
900
+ visitedTypes.delete(type);
901
+ if (nestedFields.length > 0) {
902
+ field.fields = nestedFields;
903
+ }
904
+ }
905
+ }
906
+ for (const dec of decorators) {
907
+ applyDecoratorToField(field, dec);
908
+ }
909
+ return field;
910
+ }
911
+ function applyDecoratorToField(field, decorator) {
912
+ const { args } = decorator;
913
+ const resolved = decorator.resolved;
914
+ const effectiveName = resolved?.extendsBuiltin ?? decorator.name;
915
+ switch (effectiveName) {
916
+ case "Field": {
917
+ const opts = args[0];
918
+ if (typeof opts === "object" && opts !== null && !Array.isArray(opts)) {
919
+ if (typeof opts["displayName"] === "string") {
920
+ field.label = opts["displayName"];
921
+ }
922
+ if (typeof opts["description"] === "string") {
923
+ field.description = opts["description"];
924
+ }
925
+ if (typeof opts["placeholder"] === "string") {
926
+ field.placeholder = opts["placeholder"];
927
+ }
928
+ }
929
+ break;
930
+ }
931
+ case "Minimum":
932
+ if (typeof args[0] === "number") {
933
+ field.min = args[0];
934
+ }
935
+ break;
936
+ case "Maximum":
937
+ if (typeof args[0] === "number") {
938
+ field.max = args[0];
939
+ }
940
+ break;
941
+ case "MinLength":
942
+ if (typeof args[0] === "number") {
943
+ field.minLength = args[0];
944
+ }
945
+ break;
946
+ case "MaxLength":
947
+ if (typeof args[0] === "number") {
948
+ field.maxLength = args[0];
949
+ }
950
+ break;
951
+ case "Pattern":
952
+ if (typeof args[0] === "string") {
953
+ field.pattern = args[0];
954
+ }
955
+ break;
956
+ case "EnumOptions":
957
+ if (Array.isArray(args[0])) {
958
+ field.options = args[0];
959
+ }
960
+ break;
961
+ case "ShowWhen":
962
+ if (typeof args[0] === "object" && args[0] !== null) {
963
+ field.showWhen = args[0];
964
+ }
965
+ break;
966
+ case "Group":
967
+ if (typeof args[0] === "string") {
968
+ field.group = args[0];
969
+ }
970
+ break;
971
+ }
972
+ }
973
+ function applyDecoratorsToSchema(schema, decorators, fieldInfo) {
974
+ const result = { ...schema };
975
+ for (const dec of decorators) {
976
+ const { args } = dec;
977
+ const resolved = dec.resolved;
978
+ const effectiveName = resolved?.extendsBuiltin ?? dec.name;
979
+ switch (effectiveName) {
980
+ case "Field": {
981
+ const opts = args[0];
982
+ if (typeof opts === "object" && opts !== null && !Array.isArray(opts)) {
983
+ if (typeof opts["displayName"] === "string") {
984
+ result.title = opts["displayName"];
985
+ }
986
+ if (typeof opts["description"] === "string") {
987
+ result.description = opts["description"];
988
+ }
989
+ }
990
+ break;
991
+ }
992
+ case "Minimum":
993
+ if (typeof args[0] === "number") {
994
+ result.minimum = args[0];
995
+ }
996
+ break;
997
+ case "Maximum":
998
+ if (typeof args[0] === "number") {
999
+ result.maximum = args[0];
1000
+ }
1001
+ break;
1002
+ case "ExclusiveMinimum":
1003
+ if (typeof args[0] === "number") {
1004
+ result.exclusiveMinimum = args[0];
1005
+ }
1006
+ break;
1007
+ case "ExclusiveMaximum":
1008
+ if (typeof args[0] === "number") {
1009
+ result.exclusiveMaximum = args[0];
1010
+ }
1011
+ break;
1012
+ case "MinLength":
1013
+ if (typeof args[0] === "number") {
1014
+ result.minLength = args[0];
1015
+ }
1016
+ break;
1017
+ case "MaxLength":
1018
+ if (typeof args[0] === "number") {
1019
+ result.maxLength = args[0];
1020
+ }
1021
+ break;
1022
+ case "Pattern":
1023
+ if (typeof args[0] === "string") {
1024
+ result.pattern = args[0];
1025
+ }
1026
+ break;
1027
+ }
1028
+ if (resolved?.extensionName && /^[a-z][a-z0-9-]*$/.test(resolved.extensionName)) {
1029
+ const key = `x-formspec-${resolved.extensionName}`;
1030
+ if (resolved.isMarker) {
1031
+ setSchemaExtension(result, key, true);
1032
+ } else {
1033
+ setSchemaExtension(result, key, args[0] ?? true);
1034
+ }
1035
+ }
1036
+ }
1037
+ if (fieldInfo) {
1038
+ if (fieldInfo.deprecated) {
1039
+ result.deprecated = true;
1040
+ }
1041
+ if (fieldInfo.defaultValue !== void 0) {
1042
+ result.default = fieldInfo.defaultValue;
1043
+ }
1044
+ }
1045
+ return result;
1046
+ }
1047
+
1048
+ // src/ui-schema/schema.ts
1049
+ var import_zod = require("zod");
1050
+ var jsonPointerSchema = import_zod.z.string();
1051
+ var ruleEffectSchema = import_zod.z.enum(["SHOW", "HIDE", "ENABLE", "DISABLE"]);
1052
+ var uiSchemaElementTypeSchema = import_zod.z.enum([
1053
+ "Control",
1054
+ "VerticalLayout",
1055
+ "HorizontalLayout",
1056
+ "Group",
1057
+ "Categorization",
1058
+ "Category",
1059
+ "Label"
1060
+ ]);
1061
+ var ruleConditionSchema = import_zod.z.lazy(
1062
+ () => import_zod.z.object({
1063
+ const: import_zod.z.unknown().optional(),
1064
+ enum: import_zod.z.array(import_zod.z.unknown()).readonly().optional(),
1065
+ type: import_zod.z.string().optional(),
1066
+ not: ruleConditionSchema.optional(),
1067
+ minimum: import_zod.z.number().optional(),
1068
+ maximum: import_zod.z.number().optional(),
1069
+ exclusiveMinimum: import_zod.z.number().optional(),
1070
+ exclusiveMaximum: import_zod.z.number().optional(),
1071
+ minLength: import_zod.z.number().optional(),
1072
+ properties: import_zod.z.record(import_zod.z.string(), ruleConditionSchema).optional(),
1073
+ required: import_zod.z.array(import_zod.z.string()).optional(),
1074
+ allOf: import_zod.z.array(ruleConditionSchema).optional()
1075
+ }).strict()
1076
+ );
1077
+ var schemaBasedConditionSchema = import_zod.z.object({
1078
+ scope: jsonPointerSchema,
1079
+ schema: ruleConditionSchema
1080
+ }).strict();
1081
+ var ruleSchema = import_zod.z.object({
1082
+ effect: ruleEffectSchema,
1083
+ condition: schemaBasedConditionSchema
1084
+ }).strict();
1085
+ var uiSchemaElementSchema = import_zod.z.lazy(
1086
+ () => import_zod.z.union([
1087
+ controlSchema,
1088
+ verticalLayoutSchema,
1089
+ horizontalLayoutSchema,
1090
+ groupLayoutSchema,
1091
+ categorizationSchema,
1092
+ categorySchema,
1093
+ labelElementSchema
1094
+ ])
1095
+ );
1096
+ var controlSchema = import_zod.z.object({
1097
+ type: import_zod.z.literal("Control"),
1098
+ scope: jsonPointerSchema,
1099
+ label: import_zod.z.union([import_zod.z.string(), import_zod.z.literal(false)]).optional(),
1100
+ rule: ruleSchema.optional(),
1101
+ options: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
1102
+ }).passthrough();
1103
+ var verticalLayoutSchema = import_zod.z.lazy(
1104
+ () => import_zod.z.object({
1105
+ type: import_zod.z.literal("VerticalLayout"),
1106
+ elements: import_zod.z.array(uiSchemaElementSchema),
1107
+ rule: ruleSchema.optional(),
1108
+ options: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
1109
+ }).passthrough()
1110
+ );
1111
+ var horizontalLayoutSchema = import_zod.z.lazy(
1112
+ () => import_zod.z.object({
1113
+ type: import_zod.z.literal("HorizontalLayout"),
1114
+ elements: import_zod.z.array(uiSchemaElementSchema),
1115
+ rule: ruleSchema.optional(),
1116
+ options: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
1117
+ }).passthrough()
1118
+ );
1119
+ var groupLayoutSchema = import_zod.z.lazy(
1120
+ () => import_zod.z.object({
1121
+ type: import_zod.z.literal("Group"),
1122
+ label: import_zod.z.string(),
1123
+ elements: import_zod.z.array(uiSchemaElementSchema),
1124
+ rule: ruleSchema.optional(),
1125
+ options: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
1126
+ }).passthrough()
1127
+ );
1128
+ var categorySchema = import_zod.z.lazy(
1129
+ () => import_zod.z.object({
1130
+ type: import_zod.z.literal("Category"),
1131
+ label: import_zod.z.string(),
1132
+ elements: import_zod.z.array(uiSchemaElementSchema),
1133
+ rule: ruleSchema.optional(),
1134
+ options: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
1135
+ }).passthrough()
1136
+ );
1137
+ var categorizationSchema = import_zod.z.lazy(
1138
+ () => import_zod.z.object({
1139
+ type: import_zod.z.literal("Categorization"),
1140
+ elements: import_zod.z.array(categorySchema),
1141
+ label: import_zod.z.string().optional(),
1142
+ rule: ruleSchema.optional(),
1143
+ options: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
1144
+ }).passthrough()
1145
+ );
1146
+ var labelElementSchema = import_zod.z.object({
1147
+ type: import_zod.z.literal("Label"),
1148
+ text: import_zod.z.string(),
1149
+ rule: ruleSchema.optional(),
1150
+ options: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
1151
+ }).passthrough();
1152
+ var uiSchema = import_zod.z.lazy(
1153
+ () => import_zod.z.union([verticalLayoutSchema, horizontalLayoutSchema, groupLayoutSchema, categorizationSchema])
1154
+ );
1155
+
1156
+ // src/ui-schema/generator.ts
1157
+ var import_zod2 = require("zod");
1158
+ function parseOrThrow(schema, value, label) {
1159
+ try {
1160
+ return schema.parse(value);
1161
+ } catch (error) {
1162
+ if (error instanceof import_zod2.z.ZodError) {
1163
+ throw new Error(
1164
+ `Generated ${label} failed validation:
1165
+ ${error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).join("\n")}`
1166
+ );
1167
+ }
1168
+ throw error;
1169
+ }
1170
+ }
1171
+ function formSpecFieldToElement(field, scopePrefix = "#/properties") {
1172
+ const control = {
1173
+ type: "Control",
1174
+ scope: `${scopePrefix}/${field.id}`
1175
+ };
1176
+ if (field.label !== void 0) {
1177
+ control.label = field.label;
1178
+ }
1179
+ if (field.showWhen !== void 0 && typeof field.showWhen === "object" && "field" in field.showWhen && "value" in field.showWhen) {
1180
+ const sw = field.showWhen;
1181
+ control.rule = {
1182
+ effect: "SHOW",
1183
+ condition: {
1184
+ scope: `#/properties/${sw.field}`,
1185
+ schema: { const: sw.value }
1186
+ }
1187
+ };
1188
+ }
1189
+ return control;
1190
+ }
1191
+ function generateUiSchemaFromFields(fields) {
1192
+ const groupMap = /* @__PURE__ */ new Map();
1193
+ const orderedKeys = [];
1194
+ const ungrouped = [];
1195
+ for (const field of fields) {
1196
+ const element = formSpecFieldToElement(field);
1197
+ if (field.group !== void 0) {
1198
+ if (!groupMap.has(field.group)) {
1199
+ groupMap.set(field.group, []);
1200
+ orderedKeys.push(field.group);
1201
+ }
1202
+ groupMap.get(field.group).push(element);
1203
+ } else {
1204
+ orderedKeys.push(null);
1205
+ ungrouped.push(element);
1206
+ }
1207
+ }
1208
+ const elements = [];
1209
+ let ungroupedIndex = 0;
1210
+ for (const key of orderedKeys) {
1211
+ if (key === null) {
1212
+ const el = ungrouped[ungroupedIndex++];
1213
+ if (el !== void 0) {
1214
+ elements.push(el);
1215
+ }
1216
+ } else {
1217
+ const groupElements = groupMap.get(key) ?? [];
1218
+ const groupLayout = {
1219
+ type: "Group",
1220
+ label: key,
1221
+ elements: groupElements
1222
+ };
1223
+ elements.push(groupLayout);
1224
+ }
1225
+ }
1226
+ const result = {
1227
+ type: "VerticalLayout",
1228
+ elements
1229
+ };
1230
+ return parseOrThrow(uiSchema, result, "UI Schema");
1231
+ }
1232
+
1233
+ // src/generators/class-schema.ts
1234
+ function generateClassSchemas(analysis, checker) {
1235
+ const properties = {};
1236
+ const required = [];
1237
+ const uiElements = [];
1238
+ for (const field of analysis.fields) {
1239
+ const { jsonSchema: baseSchema } = convertType(field.type, checker);
1240
+ const fieldSchema = applyDecoratorsToSchema(baseSchema, field.decorators, field);
1241
+ properties[field.name] = fieldSchema;
1242
+ if (!field.optional) {
1243
+ required.push(field.name);
1244
+ }
1245
+ const formSpecField = createFormSpecField(
1246
+ field.name,
1247
+ field.type,
1248
+ field.decorators,
1249
+ field.optional,
1250
+ checker
1251
+ );
1252
+ uiElements.push(formSpecField);
1253
+ }
1254
+ const jsonSchema = {
1255
+ type: "object",
1256
+ properties,
1257
+ ...required.length > 0 ? { required } : {}
1258
+ };
1259
+ const uiSchema2 = generateUiSchemaFromFields(uiElements);
1260
+ return { jsonSchema, uiSchema: uiSchema2 };
1261
+ }
1262
+
1263
+ // src/generators/method-schema.ts
1264
+ function generateMethodSchemas(method, checker, loadedFormSpecs) {
1265
+ const returnType = convertType(method.returnType, checker).jsonSchema;
1266
+ const params = generateParamsSchemas(method.parameters, checker, loadedFormSpecs);
1267
+ return {
1268
+ name: method.name,
1269
+ params,
1270
+ returnType
1271
+ };
1272
+ }
1273
+ function generateParamsSchemas(parameters, checker, loadedFormSpecs) {
1274
+ if (parameters.length === 0) {
1275
+ return null;
1276
+ }
1277
+ for (const param of parameters) {
1278
+ if (param.formSpecExportName) {
1279
+ const formSpec = loadedFormSpecs.get(param.formSpecExportName);
1280
+ if (formSpec) {
1281
+ return {
1282
+ jsonSchema: formSpec.jsonSchema,
1283
+ uiSchema: formSpec.uiSchema,
1284
+ formSpecExport: param.formSpecExportName
1285
+ };
1286
+ }
1287
+ console.warn(
1288
+ `Warning: FormSpec export "${param.formSpecExportName}" not found, using static analysis`
1289
+ );
1290
+ }
1291
+ }
1292
+ if (parameters.length === 1 && parameters[0]) {
1293
+ const param = parameters[0];
1294
+ const jsonSchema = convertType(param.type, checker).jsonSchema;
1295
+ return {
1296
+ jsonSchema,
1297
+ uiSchema: null,
1298
+ formSpecExport: null
1299
+ };
1300
+ }
1301
+ const properties = {};
1302
+ const required = [];
1303
+ for (const param of parameters) {
1304
+ const paramSchema = convertType(param.type, checker).jsonSchema;
1305
+ properties[param.name] = paramSchema;
1306
+ if (!param.optional) {
1307
+ required.push(param.name);
1308
+ }
1309
+ }
1310
+ return {
1311
+ jsonSchema: {
1312
+ type: "object",
1313
+ properties,
1314
+ ...required.length > 0 ? { required } : {}
1315
+ },
1316
+ uiSchema: null,
1317
+ formSpecExport: null
1318
+ };
1319
+ }
1320
+ function collectFormSpecReferences(methods) {
1321
+ const references = /* @__PURE__ */ new Set();
1322
+ for (const method of methods) {
1323
+ for (const param of method.parameters) {
1324
+ if (param.formSpecExportName) {
1325
+ references.add(param.formSpecExportName);
1326
+ }
1327
+ }
1328
+ }
1329
+ return references;
1330
+ }
1331
+ // Annotate the CommonJS export names for ESM import in node:
1332
+ 0 && (module.exports = {
1333
+ analyzeClass,
1334
+ analyzeInterface,
1335
+ analyzeTypeAlias,
1336
+ collectFormSpecReferences,
1337
+ createProgramContext,
1338
+ findClassByName,
1339
+ findInterfaceByName,
1340
+ findTypeAliasByName,
1341
+ generateClassSchemas,
1342
+ generateMethodSchemas,
1343
+ generateUiSchemaFromFields
1344
+ });
1345
+ //# sourceMappingURL=internals.cjs.map