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

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 (210) hide show
  1. package/README.md +51 -15
  2. package/dist/__tests__/chain-dsl-canonicalizer.test.d.ts +2 -0
  3. package/dist/__tests__/chain-dsl-canonicalizer.test.d.ts.map +1 -0
  4. package/dist/__tests__/constraint-validator.test.d.ts +2 -0
  5. package/dist/__tests__/constraint-validator.test.d.ts.map +1 -0
  6. package/dist/__tests__/extension-api.test.d.ts +2 -0
  7. package/dist/__tests__/extension-api.test.d.ts.map +1 -0
  8. package/dist/__tests__/fixtures/example-a-builtins.d.ts +18 -0
  9. package/dist/__tests__/fixtures/example-a-builtins.d.ts.map +1 -1
  10. package/dist/__tests__/ir-analyzer.test.d.ts +11 -0
  11. package/dist/__tests__/ir-analyzer.test.d.ts.map +1 -0
  12. package/dist/__tests__/ir-jsdoc-constraints.test.d.ts +12 -0
  13. package/dist/__tests__/ir-jsdoc-constraints.test.d.ts.map +1 -0
  14. package/dist/__tests__/ir-json-schema-generator.test.d.ts +11 -0
  15. package/dist/__tests__/ir-json-schema-generator.test.d.ts.map +1 -0
  16. package/dist/__tests__/ir-ui-schema-generator.test.d.ts +2 -0
  17. package/dist/__tests__/ir-ui-schema-generator.test.d.ts.map +1 -0
  18. package/dist/__tests__/jsdoc-constraints.test.d.ts +4 -4
  19. package/dist/__tests__/parity/fixtures/address/chain-dsl.d.ts +9 -0
  20. package/dist/__tests__/parity/fixtures/address/chain-dsl.d.ts.map +1 -0
  21. package/dist/__tests__/parity/fixtures/address/expected-ir.d.ts +9 -0
  22. package/dist/__tests__/parity/fixtures/address/expected-ir.d.ts.map +1 -0
  23. package/dist/__tests__/parity/fixtures/address/tsdoc.d.ts +19 -0
  24. package/dist/__tests__/parity/fixtures/address/tsdoc.d.ts.map +1 -0
  25. package/dist/__tests__/parity/fixtures/product-config/chain-dsl.d.ts +13 -0
  26. package/dist/__tests__/parity/fixtures/product-config/chain-dsl.d.ts.map +1 -0
  27. package/dist/__tests__/parity/fixtures/product-config/expected-ir.d.ts +9 -0
  28. package/dist/__tests__/parity/fixtures/product-config/expected-ir.d.ts.map +1 -0
  29. package/dist/__tests__/parity/fixtures/product-config/tsdoc.d.ts +28 -0
  30. package/dist/__tests__/parity/fixtures/product-config/tsdoc.d.ts.map +1 -0
  31. package/dist/__tests__/parity/fixtures/user-registration/chain-dsl.d.ts +12 -0
  32. package/dist/__tests__/parity/fixtures/user-registration/chain-dsl.d.ts.map +1 -0
  33. package/dist/__tests__/parity/fixtures/user-registration/expected-ir.d.ts +9 -0
  34. package/dist/__tests__/parity/fixtures/user-registration/expected-ir.d.ts.map +1 -0
  35. package/dist/__tests__/parity/fixtures/user-registration/tsdoc.d.ts +19 -0
  36. package/dist/__tests__/parity/fixtures/user-registration/tsdoc.d.ts.map +1 -0
  37. package/dist/__tests__/parity/parity.test.d.ts +14 -0
  38. package/dist/__tests__/parity/parity.test.d.ts.map +1 -0
  39. package/dist/__tests__/parity/utils.d.ts +139 -0
  40. package/dist/__tests__/parity/utils.d.ts.map +1 -0
  41. package/dist/analyzer/class-analyzer.d.ts +54 -99
  42. package/dist/analyzer/class-analyzer.d.ts.map +1 -1
  43. package/dist/analyzer/jsdoc-constraints.d.ts +78 -30
  44. package/dist/analyzer/jsdoc-constraints.d.ts.map +1 -1
  45. package/dist/analyzer/tsdoc-parser.d.ts +61 -0
  46. package/dist/analyzer/tsdoc-parser.d.ts.map +1 -0
  47. package/dist/browser.cjs +1200 -0
  48. package/dist/browser.cjs.map +1 -0
  49. package/dist/browser.d.ts +12 -6
  50. package/dist/browser.d.ts.map +1 -1
  51. package/dist/browser.js +1147 -44
  52. package/dist/browser.js.map +1 -1
  53. package/dist/build.d.ts +385 -160
  54. package/dist/canonicalize/chain-dsl-canonicalizer.d.ts +18 -0
  55. package/dist/canonicalize/chain-dsl-canonicalizer.d.ts.map +1 -0
  56. package/dist/canonicalize/index.d.ts +8 -0
  57. package/dist/canonicalize/index.d.ts.map +1 -0
  58. package/dist/canonicalize/tsdoc-canonicalizer.d.ts +34 -0
  59. package/dist/canonicalize/tsdoc-canonicalizer.d.ts.map +1 -0
  60. package/dist/cli.cjs +2028 -0
  61. package/dist/cli.cjs.map +1 -0
  62. package/dist/cli.js +1978 -101
  63. package/dist/cli.js.map +1 -1
  64. package/dist/extensions/index.d.ts +8 -0
  65. package/dist/extensions/index.d.ts.map +1 -0
  66. package/dist/extensions/registry.d.ts +55 -0
  67. package/dist/extensions/registry.d.ts.map +1 -0
  68. package/dist/generators/class-schema.d.ts +28 -47
  69. package/dist/generators/class-schema.d.ts.map +1 -1
  70. package/dist/generators/method-schema.d.ts +6 -8
  71. package/dist/generators/method-schema.d.ts.map +1 -1
  72. package/dist/index.cjs +1832 -0
  73. package/dist/index.cjs.map +1 -0
  74. package/dist/index.d.ts +8 -8
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +1779 -114
  77. package/dist/index.js.map +1 -1
  78. package/dist/internals.cjs +2125 -0
  79. package/dist/internals.cjs.map +1 -0
  80. package/dist/internals.d.ts +12 -2
  81. package/dist/internals.d.ts.map +1 -1
  82. package/dist/internals.js +2084 -21
  83. package/dist/internals.js.map +1 -1
  84. package/dist/json-schema/generator.d.ts +10 -5
  85. package/dist/json-schema/generator.d.ts.map +1 -1
  86. package/dist/json-schema/ir-generator.d.ts +84 -0
  87. package/dist/json-schema/ir-generator.d.ts.map +1 -0
  88. package/dist/json-schema/schema.d.ts +16 -0
  89. package/dist/json-schema/schema.d.ts.map +1 -0
  90. package/dist/json-schema/types.d.ts +5 -6
  91. package/dist/json-schema/types.d.ts.map +1 -1
  92. package/dist/ui-schema/generator.d.ts +5 -0
  93. package/dist/ui-schema/generator.d.ts.map +1 -1
  94. package/dist/ui-schema/ir-generator.d.ts +53 -0
  95. package/dist/ui-schema/ir-generator.d.ts.map +1 -0
  96. package/dist/ui-schema/schema.d.ts +357 -0
  97. package/dist/ui-schema/schema.d.ts.map +1 -0
  98. package/dist/ui-schema/types.d.ts +8 -73
  99. package/dist/ui-schema/types.d.ts.map +1 -1
  100. package/dist/validate/constraint-validator.d.ts +66 -0
  101. package/dist/validate/constraint-validator.d.ts.map +1 -0
  102. package/dist/validate/index.d.ts +9 -0
  103. package/dist/validate/index.d.ts.map +1 -0
  104. package/package.json +15 -9
  105. package/dist/__tests__/analyzer-edge-cases.test.d.ts +0 -13
  106. package/dist/__tests__/analyzer-edge-cases.test.d.ts.map +0 -1
  107. package/dist/__tests__/analyzer-edge-cases.test.js +0 -376
  108. package/dist/__tests__/analyzer-edge-cases.test.js.map +0 -1
  109. package/dist/__tests__/analyzer.test.d.ts +0 -5
  110. package/dist/__tests__/analyzer.test.d.ts.map +0 -1
  111. package/dist/__tests__/analyzer.test.js +0 -190
  112. package/dist/__tests__/analyzer.test.js.map +0 -1
  113. package/dist/__tests__/cli.test.js +0 -178
  114. package/dist/__tests__/cli.test.js.map +0 -1
  115. package/dist/__tests__/codegen.test.d.ts +0 -5
  116. package/dist/__tests__/codegen.test.d.ts.map +0 -1
  117. package/dist/__tests__/codegen.test.js +0 -506
  118. package/dist/__tests__/codegen.test.js.map +0 -1
  119. package/dist/__tests__/decorator-pipeline.test.d.ts +0 -11
  120. package/dist/__tests__/decorator-pipeline.test.d.ts.map +0 -1
  121. package/dist/__tests__/decorator-pipeline.test.js +0 -460
  122. package/dist/__tests__/decorator-pipeline.test.js.map +0 -1
  123. package/dist/__tests__/edge-cases.test.js +0 -215
  124. package/dist/__tests__/edge-cases.test.js.map +0 -1
  125. package/dist/__tests__/fixtures/edge-cases.js +0 -137
  126. package/dist/__tests__/fixtures/edge-cases.js.map +0 -1
  127. package/dist/__tests__/fixtures/example-a-builtins.js +0 -100
  128. package/dist/__tests__/fixtures/example-a-builtins.js.map +0 -1
  129. package/dist/__tests__/fixtures/example-b-decorators.d.ts +0 -5
  130. package/dist/__tests__/fixtures/example-b-decorators.d.ts.map +0 -1
  131. package/dist/__tests__/fixtures/example-b-decorators.js +0 -5
  132. package/dist/__tests__/fixtures/example-b-decorators.js.map +0 -1
  133. package/dist/__tests__/fixtures/example-b-extended.d.ts +0 -5
  134. package/dist/__tests__/fixtures/example-b-extended.d.ts.map +0 -1
  135. package/dist/__tests__/fixtures/example-b-extended.js +0 -60
  136. package/dist/__tests__/fixtures/example-b-extended.js.map +0 -1
  137. package/dist/__tests__/fixtures/example-c-custom.d.ts +0 -5
  138. package/dist/__tests__/fixtures/example-c-custom.d.ts.map +0 -1
  139. package/dist/__tests__/fixtures/example-c-custom.js +0 -61
  140. package/dist/__tests__/fixtures/example-c-custom.js.map +0 -1
  141. package/dist/__tests__/fixtures/example-c-decorators.d.ts +0 -5
  142. package/dist/__tests__/fixtures/example-c-decorators.d.ts.map +0 -1
  143. package/dist/__tests__/fixtures/example-c-decorators.js +0 -4
  144. package/dist/__tests__/fixtures/example-c-decorators.js.map +0 -1
  145. package/dist/__tests__/fixtures/example-d-mixed-decorators.d.ts +0 -6
  146. package/dist/__tests__/fixtures/example-d-mixed-decorators.d.ts.map +0 -1
  147. package/dist/__tests__/fixtures/example-d-mixed-decorators.js +0 -75
  148. package/dist/__tests__/fixtures/example-d-mixed-decorators.js.map +0 -1
  149. package/dist/__tests__/fixtures/example-e-decorators.d.ts +0 -11
  150. package/dist/__tests__/fixtures/example-e-decorators.d.ts.map +0 -1
  151. package/dist/__tests__/fixtures/example-e-decorators.js +0 -10
  152. package/dist/__tests__/fixtures/example-e-decorators.js.map +0 -1
  153. package/dist/__tests__/fixtures/example-e-no-namespace.d.ts +0 -5
  154. package/dist/__tests__/fixtures/example-e-no-namespace.d.ts.map +0 -1
  155. package/dist/__tests__/fixtures/example-e-no-namespace.js +0 -61
  156. package/dist/__tests__/fixtures/example-e-no-namespace.js.map +0 -1
  157. package/dist/__tests__/fixtures/example-interface-types.js +0 -8
  158. package/dist/__tests__/fixtures/example-interface-types.js.map +0 -1
  159. package/dist/__tests__/fixtures/example-jsdoc-constraints.d.ts +0 -16
  160. package/dist/__tests__/fixtures/example-jsdoc-constraints.d.ts.map +0 -1
  161. package/dist/__tests__/fixtures/example-jsdoc-constraints.js +0 -98
  162. package/dist/__tests__/fixtures/example-jsdoc-constraints.js.map +0 -1
  163. package/dist/__tests__/fixtures/example-nested-class.d.ts +0 -45
  164. package/dist/__tests__/fixtures/example-nested-class.d.ts.map +0 -1
  165. package/dist/__tests__/fixtures/example-nested-class.js +0 -248
  166. package/dist/__tests__/fixtures/example-nested-class.js.map +0 -1
  167. package/dist/__tests__/fixtures/sample-forms.js +0 -78
  168. package/dist/__tests__/fixtures/sample-forms.js.map +0 -1
  169. package/dist/__tests__/generator.test.js +0 -234
  170. package/dist/__tests__/generator.test.js.map +0 -1
  171. package/dist/__tests__/integration.test.js +0 -161
  172. package/dist/__tests__/integration.test.js.map +0 -1
  173. package/dist/__tests__/interface-types.test.d.ts +0 -11
  174. package/dist/__tests__/interface-types.test.d.ts.map +0 -1
  175. package/dist/__tests__/interface-types.test.js +0 -404
  176. package/dist/__tests__/interface-types.test.js.map +0 -1
  177. package/dist/__tests__/jsdoc-constraints.test.js +0 -465
  178. package/dist/__tests__/jsdoc-constraints.test.js.map +0 -1
  179. package/dist/__tests__/write-schemas.test.js +0 -198
  180. package/dist/__tests__/write-schemas.test.js.map +0 -1
  181. package/dist/analyzer/class-analyzer.js +0 -377
  182. package/dist/analyzer/class-analyzer.js.map +0 -1
  183. package/dist/analyzer/decorator-extractor.d.ts +0 -78
  184. package/dist/analyzer/decorator-extractor.d.ts.map +0 -1
  185. package/dist/analyzer/decorator-extractor.js +0 -336
  186. package/dist/analyzer/decorator-extractor.js.map +0 -1
  187. package/dist/analyzer/jsdoc-constraints.js +0 -153
  188. package/dist/analyzer/jsdoc-constraints.js.map +0 -1
  189. package/dist/analyzer/program.js +0 -114
  190. package/dist/analyzer/program.js.map +0 -1
  191. package/dist/analyzer/type-converter.d.ts +0 -75
  192. package/dist/analyzer/type-converter.d.ts.map +0 -1
  193. package/dist/analyzer/type-converter.js +0 -474
  194. package/dist/analyzer/type-converter.js.map +0 -1
  195. package/dist/codegen/index.d.ts +0 -75
  196. package/dist/codegen/index.d.ts.map +0 -1
  197. package/dist/codegen/index.js +0 -597
  198. package/dist/codegen/index.js.map +0 -1
  199. package/dist/generators/class-schema.js +0 -140
  200. package/dist/generators/class-schema.js.map +0 -1
  201. package/dist/generators/method-schema.js +0 -108
  202. package/dist/generators/method-schema.js.map +0 -1
  203. package/dist/json-schema/generator.js +0 -166
  204. package/dist/json-schema/generator.js.map +0 -1
  205. package/dist/json-schema/types.js +0 -33
  206. package/dist/json-schema/types.js.map +0 -1
  207. package/dist/ui-schema/generator.js +0 -148
  208. package/dist/ui-schema/generator.js.map +0 -1
  209. package/dist/ui-schema/types.js +0 -8
  210. package/dist/ui-schema/types.js.map +0 -1
package/dist/cli.js CHANGED
@@ -1,22 +1,1905 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * FormSpec CLI - Generate JSON Schema and UI Schema from form definitions
4
- *
5
- * Usage:
6
- * formspec-build <input-file> [options]
7
- *
8
- * Options:
9
- * -o, --out-dir <dir> Output directory (default: ./generated)
10
- * -n, --name <name> Base name for output files (default: derived from input)
11
- * -h, --help Show help
12
- *
13
- * Example:
14
- * formspec-build src/forms/product.ts -o ./schemas -n product
15
- */
16
- import * as path from "node:path";
17
- import { pathToFileURL } from "node:url";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
+ };
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+
12
+ // src/canonicalize/chain-dsl-canonicalizer.ts
13
+ import { IR_VERSION } from "@formspec/core";
14
+ function isGroup(el) {
15
+ return el._type === "group";
16
+ }
17
+ function isConditional(el) {
18
+ return el._type === "conditional";
19
+ }
20
+ function isField(el) {
21
+ return el._type === "field";
22
+ }
23
+ function canonicalizeChainDSL(form) {
24
+ return {
25
+ kind: "form-ir",
26
+ irVersion: IR_VERSION,
27
+ elements: canonicalizeElements(form.elements),
28
+ typeRegistry: {},
29
+ provenance: CHAIN_DSL_PROVENANCE
30
+ };
31
+ }
32
+ function canonicalizeElements(elements) {
33
+ return elements.map(canonicalizeElement);
34
+ }
35
+ function canonicalizeElement(element) {
36
+ if (isField(element)) {
37
+ return canonicalizeField(element);
38
+ }
39
+ if (isGroup(element)) {
40
+ return canonicalizeGroup(element);
41
+ }
42
+ if (isConditional(element)) {
43
+ return canonicalizeConditional(element);
44
+ }
45
+ const _exhaustive = element;
46
+ throw new Error(`Unknown element type: ${JSON.stringify(_exhaustive)}`);
47
+ }
48
+ function canonicalizeField(field) {
49
+ switch (field._field) {
50
+ case "text":
51
+ return canonicalizeTextField(field);
52
+ case "number":
53
+ return canonicalizeNumberField(field);
54
+ case "boolean":
55
+ return canonicalizeBooleanField(field);
56
+ case "enum":
57
+ return canonicalizeStaticEnumField(field);
58
+ case "dynamic_enum":
59
+ return canonicalizeDynamicEnumField(field);
60
+ case "dynamic_schema":
61
+ return canonicalizeDynamicSchemaField(field);
62
+ case "array":
63
+ return canonicalizeArrayField(field);
64
+ case "object":
65
+ return canonicalizeObjectField(field);
66
+ default: {
67
+ const _exhaustive = field;
68
+ throw new Error(`Unknown field type: ${JSON.stringify(_exhaustive)}`);
69
+ }
70
+ }
71
+ }
72
+ function canonicalizeTextField(field) {
73
+ const type = { kind: "primitive", primitiveKind: "string" };
74
+ return buildFieldNode(
75
+ field.name,
76
+ type,
77
+ field.required,
78
+ buildAnnotations(field.label, field.placeholder)
79
+ );
80
+ }
81
+ function canonicalizeNumberField(field) {
82
+ const type = { kind: "primitive", primitiveKind: "number" };
83
+ const constraints = [];
84
+ if (field.min !== void 0) {
85
+ const c = {
86
+ kind: "constraint",
87
+ constraintKind: "minimum",
88
+ value: field.min,
89
+ provenance: CHAIN_DSL_PROVENANCE
90
+ };
91
+ constraints.push(c);
92
+ }
93
+ if (field.max !== void 0) {
94
+ const c = {
95
+ kind: "constraint",
96
+ constraintKind: "maximum",
97
+ value: field.max,
98
+ provenance: CHAIN_DSL_PROVENANCE
99
+ };
100
+ constraints.push(c);
101
+ }
102
+ return buildFieldNode(
103
+ field.name,
104
+ type,
105
+ field.required,
106
+ buildAnnotations(field.label),
107
+ constraints
108
+ );
109
+ }
110
+ function canonicalizeBooleanField(field) {
111
+ const type = { kind: "primitive", primitiveKind: "boolean" };
112
+ return buildFieldNode(field.name, type, field.required, buildAnnotations(field.label));
113
+ }
114
+ function canonicalizeStaticEnumField(field) {
115
+ const members = field.options.map((opt) => {
116
+ if (typeof opt === "string") {
117
+ return { value: opt };
118
+ }
119
+ return { value: opt.id, displayName: opt.label };
120
+ });
121
+ const type = { kind: "enum", members };
122
+ return buildFieldNode(field.name, type, field.required, buildAnnotations(field.label));
123
+ }
124
+ function canonicalizeDynamicEnumField(field) {
125
+ const type = {
126
+ kind: "dynamic",
127
+ dynamicKind: "enum",
128
+ sourceKey: field.source,
129
+ parameterFields: field.params ? [...field.params] : []
130
+ };
131
+ return buildFieldNode(field.name, type, field.required, buildAnnotations(field.label));
132
+ }
133
+ function canonicalizeDynamicSchemaField(field) {
134
+ const type = {
135
+ kind: "dynamic",
136
+ dynamicKind: "schema",
137
+ sourceKey: field.schemaSource,
138
+ parameterFields: []
139
+ };
140
+ return buildFieldNode(field.name, type, field.required, buildAnnotations(field.label));
141
+ }
142
+ function canonicalizeArrayField(field) {
143
+ const itemProperties = buildObjectProperties(field.items);
144
+ const itemsType = {
145
+ kind: "object",
146
+ properties: itemProperties,
147
+ additionalProperties: false
148
+ };
149
+ const type = { kind: "array", items: itemsType };
150
+ const constraints = [];
151
+ if (field.minItems !== void 0) {
152
+ const c = {
153
+ kind: "constraint",
154
+ constraintKind: "minItems",
155
+ value: field.minItems,
156
+ provenance: CHAIN_DSL_PROVENANCE
157
+ };
158
+ constraints.push(c);
159
+ }
160
+ if (field.maxItems !== void 0) {
161
+ const c = {
162
+ kind: "constraint",
163
+ constraintKind: "maxItems",
164
+ value: field.maxItems,
165
+ provenance: CHAIN_DSL_PROVENANCE
166
+ };
167
+ constraints.push(c);
168
+ }
169
+ return buildFieldNode(
170
+ field.name,
171
+ type,
172
+ field.required,
173
+ buildAnnotations(field.label),
174
+ constraints
175
+ );
176
+ }
177
+ function canonicalizeObjectField(field) {
178
+ const properties = buildObjectProperties(field.properties);
179
+ const type = {
180
+ kind: "object",
181
+ properties,
182
+ additionalProperties: false
183
+ };
184
+ return buildFieldNode(field.name, type, field.required, buildAnnotations(field.label));
185
+ }
186
+ function canonicalizeGroup(g) {
187
+ return {
188
+ kind: "group",
189
+ label: g.label,
190
+ elements: canonicalizeElements(g.elements),
191
+ provenance: CHAIN_DSL_PROVENANCE
192
+ };
193
+ }
194
+ function canonicalizeConditional(c) {
195
+ return {
196
+ kind: "conditional",
197
+ fieldName: c.field,
198
+ // Conditional values from the chain DSL are JSON-serializable primitives
199
+ // (strings, numbers, booleans) produced by the `is()` predicate helper.
200
+ value: assertJsonValue(c.value),
201
+ elements: canonicalizeElements(c.elements),
202
+ provenance: CHAIN_DSL_PROVENANCE
203
+ };
204
+ }
205
+ function assertJsonValue(v) {
206
+ if (v === null || typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
207
+ return v;
208
+ }
209
+ if (Array.isArray(v)) {
210
+ return v.map(assertJsonValue);
211
+ }
212
+ if (typeof v === "object") {
213
+ const result = {};
214
+ for (const [key, val] of Object.entries(v)) {
215
+ result[key] = assertJsonValue(val);
216
+ }
217
+ return result;
218
+ }
219
+ throw new TypeError(`Conditional value is not a valid JsonValue: ${typeof v}`);
220
+ }
221
+ function buildFieldNode(name, type, required, annotations, constraints = []) {
222
+ return {
223
+ kind: "field",
224
+ name,
225
+ type,
226
+ required: required === true,
227
+ constraints,
228
+ annotations,
229
+ provenance: CHAIN_DSL_PROVENANCE
230
+ };
231
+ }
232
+ function buildAnnotations(label, placeholder) {
233
+ const annotations = [];
234
+ if (label !== void 0) {
235
+ const a = {
236
+ kind: "annotation",
237
+ annotationKind: "displayName",
238
+ value: label,
239
+ provenance: CHAIN_DSL_PROVENANCE
240
+ };
241
+ annotations.push(a);
242
+ }
243
+ if (placeholder !== void 0) {
244
+ const a = {
245
+ kind: "annotation",
246
+ annotationKind: "placeholder",
247
+ value: placeholder,
248
+ provenance: CHAIN_DSL_PROVENANCE
249
+ };
250
+ annotations.push(a);
251
+ }
252
+ return annotations;
253
+ }
254
+ function buildObjectProperties(elements, insideConditional = false) {
255
+ const properties = [];
256
+ for (const el of elements) {
257
+ if (isField(el)) {
258
+ const fieldNode = canonicalizeField(el);
259
+ properties.push({
260
+ name: fieldNode.name,
261
+ type: fieldNode.type,
262
+ // Fields inside a conditional branch are always optional in the
263
+ // data schema, regardless of their `required` flag — the condition
264
+ // may not be met, so the field may be absent.
265
+ optional: insideConditional || !fieldNode.required,
266
+ constraints: fieldNode.constraints,
267
+ annotations: fieldNode.annotations,
268
+ provenance: CHAIN_DSL_PROVENANCE
269
+ });
270
+ } else if (isGroup(el)) {
271
+ properties.push(...buildObjectProperties(el.elements, insideConditional));
272
+ } else if (isConditional(el)) {
273
+ properties.push(...buildObjectProperties(el.elements, true));
274
+ }
275
+ }
276
+ return properties;
277
+ }
278
+ var CHAIN_DSL_PROVENANCE;
279
+ var init_chain_dsl_canonicalizer = __esm({
280
+ "src/canonicalize/chain-dsl-canonicalizer.ts"() {
281
+ "use strict";
282
+ CHAIN_DSL_PROVENANCE = {
283
+ surface: "chain-dsl",
284
+ file: "",
285
+ line: 0,
286
+ column: 0
287
+ };
288
+ }
289
+ });
290
+
291
+ // src/canonicalize/tsdoc-canonicalizer.ts
292
+ import { IR_VERSION as IR_VERSION2 } from "@formspec/core";
293
+ function canonicalizeTSDoc(analysis, source) {
294
+ const file = source?.file ?? "";
295
+ const provenance = {
296
+ surface: "tsdoc",
297
+ file,
298
+ line: 1,
299
+ column: 0
300
+ };
301
+ const elements = assembleElements(analysis.fields, analysis.fieldLayouts, provenance);
302
+ return {
303
+ kind: "form-ir",
304
+ irVersion: IR_VERSION2,
305
+ elements,
306
+ typeRegistry: analysis.typeRegistry,
307
+ provenance
308
+ };
309
+ }
310
+ function assembleElements(fields, layouts, provenance) {
311
+ const elements = [];
312
+ const groupMap = /* @__PURE__ */ new Map();
313
+ const topLevelOrder = [];
314
+ for (let i = 0; i < fields.length; i++) {
315
+ const field = fields[i];
316
+ const layout = layouts[i];
317
+ if (!field || !layout) continue;
318
+ const element = wrapInConditional(field, layout, provenance);
319
+ if (layout.groupLabel !== void 0) {
320
+ const label = layout.groupLabel;
321
+ let groupElements = groupMap.get(label);
322
+ if (!groupElements) {
323
+ groupElements = [];
324
+ groupMap.set(label, groupElements);
325
+ topLevelOrder.push({ type: "group", label });
326
+ }
327
+ groupElements.push(element);
328
+ } else {
329
+ topLevelOrder.push({ type: "element", element });
330
+ }
331
+ }
332
+ for (const entry of topLevelOrder) {
333
+ if (entry.type === "group") {
334
+ const groupElements = groupMap.get(entry.label);
335
+ if (groupElements) {
336
+ const groupNode = {
337
+ kind: "group",
338
+ label: entry.label,
339
+ elements: groupElements,
340
+ provenance
341
+ };
342
+ elements.push(groupNode);
343
+ groupMap.delete(entry.label);
344
+ }
345
+ } else {
346
+ elements.push(entry.element);
347
+ }
348
+ }
349
+ return elements;
350
+ }
351
+ function wrapInConditional(field, layout, provenance) {
352
+ if (layout.showWhen === void 0) {
353
+ return field;
354
+ }
355
+ const conditional = {
356
+ kind: "conditional",
357
+ fieldName: layout.showWhen.field,
358
+ value: layout.showWhen.value,
359
+ elements: [field],
360
+ provenance
361
+ };
362
+ return conditional;
363
+ }
364
+ var init_tsdoc_canonicalizer = __esm({
365
+ "src/canonicalize/tsdoc-canonicalizer.ts"() {
366
+ "use strict";
367
+ }
368
+ });
369
+
370
+ // src/canonicalize/index.ts
371
+ var init_canonicalize = __esm({
372
+ "src/canonicalize/index.ts"() {
373
+ "use strict";
374
+ init_chain_dsl_canonicalizer();
375
+ init_tsdoc_canonicalizer();
376
+ }
377
+ });
378
+
379
+ // src/json-schema/ir-generator.ts
380
+ function makeContext() {
381
+ return { defs: {} };
382
+ }
383
+ function generateJsonSchemaFromIR(ir) {
384
+ const ctx = makeContext();
385
+ for (const [name, typeDef] of Object.entries(ir.typeRegistry)) {
386
+ ctx.defs[name] = generateTypeNode(typeDef.type, ctx);
387
+ }
388
+ const properties = {};
389
+ const required = [];
390
+ collectFields(ir.elements, properties, required, ctx);
391
+ const uniqueRequired = [...new Set(required)];
392
+ const result = {
393
+ $schema: "https://json-schema.org/draft/2020-12/schema",
394
+ type: "object",
395
+ properties,
396
+ ...uniqueRequired.length > 0 && { required: uniqueRequired }
397
+ };
398
+ if (Object.keys(ctx.defs).length > 0) {
399
+ result.$defs = ctx.defs;
400
+ }
401
+ return result;
402
+ }
403
+ function collectFields(elements, properties, required, ctx) {
404
+ for (const element of elements) {
405
+ switch (element.kind) {
406
+ case "field":
407
+ properties[element.name] = generateFieldSchema(element, ctx);
408
+ if (element.required) {
409
+ required.push(element.name);
410
+ }
411
+ break;
412
+ case "group":
413
+ collectFields(element.elements, properties, required, ctx);
414
+ break;
415
+ case "conditional":
416
+ collectFields(element.elements, properties, required, ctx);
417
+ break;
418
+ default: {
419
+ const _exhaustive = element;
420
+ void _exhaustive;
421
+ }
422
+ }
423
+ }
424
+ }
425
+ function generateFieldSchema(field, ctx) {
426
+ const schema = generateTypeNode(field.type, ctx);
427
+ applyConstraints(schema, field.constraints);
428
+ applyAnnotations(schema, field.annotations);
429
+ return schema;
430
+ }
431
+ function generateTypeNode(type, ctx) {
432
+ switch (type.kind) {
433
+ case "primitive":
434
+ return generatePrimitiveType(type);
435
+ case "enum":
436
+ return generateEnumType(type);
437
+ case "array":
438
+ return generateArrayType(type, ctx);
439
+ case "object":
440
+ return generateObjectType(type, ctx);
441
+ case "union":
442
+ return generateUnionType(type, ctx);
443
+ case "reference":
444
+ return generateReferenceType(type);
445
+ case "dynamic":
446
+ return generateDynamicType(type);
447
+ case "custom":
448
+ return generateCustomType(type);
449
+ default: {
450
+ const _exhaustive = type;
451
+ return _exhaustive;
452
+ }
453
+ }
454
+ }
455
+ function generatePrimitiveType(type) {
456
+ return { type: type.primitiveKind };
457
+ }
458
+ function generateEnumType(type) {
459
+ const hasDisplayNames = type.members.some((m) => m.displayName !== void 0);
460
+ if (hasDisplayNames) {
461
+ return {
462
+ oneOf: type.members.map((m) => {
463
+ const entry = { const: m.value };
464
+ if (m.displayName !== void 0) {
465
+ entry.title = m.displayName;
466
+ }
467
+ return entry;
468
+ })
469
+ };
470
+ }
471
+ return { enum: type.members.map((m) => m.value) };
472
+ }
473
+ function generateArrayType(type, ctx) {
474
+ return {
475
+ type: "array",
476
+ items: generateTypeNode(type.items, ctx)
477
+ };
478
+ }
479
+ function generateObjectType(type, ctx) {
480
+ const properties = {};
481
+ const required = [];
482
+ for (const prop of type.properties) {
483
+ properties[prop.name] = generatePropertySchema(prop, ctx);
484
+ if (!prop.optional) {
485
+ required.push(prop.name);
486
+ }
487
+ }
488
+ const schema = { type: "object", properties };
489
+ if (required.length > 0) {
490
+ schema.required = required;
491
+ }
492
+ if (!type.additionalProperties) {
493
+ schema.additionalProperties = false;
494
+ }
495
+ return schema;
496
+ }
497
+ function generatePropertySchema(prop, ctx) {
498
+ const schema = generateTypeNode(prop.type, ctx);
499
+ applyConstraints(schema, prop.constraints);
500
+ applyAnnotations(schema, prop.annotations);
501
+ return schema;
502
+ }
503
+ function generateUnionType(type, ctx) {
504
+ if (isBooleanUnion(type)) {
505
+ return { type: "boolean" };
506
+ }
507
+ return {
508
+ anyOf: type.members.map((m) => generateTypeNode(m, ctx))
509
+ };
510
+ }
511
+ function isBooleanUnion(type) {
512
+ if (type.members.length !== 2) return false;
513
+ const kinds = type.members.map((m) => m.kind);
514
+ return kinds.every((k) => k === "primitive") && type.members.every((m) => m.kind === "primitive" && m.primitiveKind === "boolean");
515
+ }
516
+ function generateReferenceType(type) {
517
+ return { $ref: `#/$defs/${type.name}` };
518
+ }
519
+ function generateDynamicType(type) {
520
+ if (type.dynamicKind === "enum") {
521
+ const schema = {
522
+ type: "string",
523
+ "x-formspec-source": type.sourceKey
524
+ };
525
+ if (type.parameterFields.length > 0) {
526
+ schema["x-formspec-params"] = [...type.parameterFields];
527
+ }
528
+ return schema;
529
+ }
530
+ return {
531
+ type: "object",
532
+ additionalProperties: true,
533
+ "x-formspec-schemaSource": type.sourceKey
534
+ };
535
+ }
536
+ function generateCustomType(_type) {
537
+ return { type: "object" };
538
+ }
539
+ function applyConstraints(schema, constraints) {
540
+ for (const constraint of constraints) {
541
+ switch (constraint.constraintKind) {
542
+ case "minimum":
543
+ schema.minimum = constraint.value;
544
+ break;
545
+ case "maximum":
546
+ schema.maximum = constraint.value;
547
+ break;
548
+ case "exclusiveMinimum":
549
+ schema.exclusiveMinimum = constraint.value;
550
+ break;
551
+ case "exclusiveMaximum":
552
+ schema.exclusiveMaximum = constraint.value;
553
+ break;
554
+ case "multipleOf": {
555
+ const { value } = constraint;
556
+ if (value === 1 && schema.type === "number") {
557
+ schema.type = "integer";
558
+ } else {
559
+ schema.multipleOf = value;
560
+ }
561
+ break;
562
+ }
563
+ case "minLength":
564
+ schema.minLength = constraint.value;
565
+ break;
566
+ case "maxLength":
567
+ schema.maxLength = constraint.value;
568
+ break;
569
+ case "minItems":
570
+ schema.minItems = constraint.value;
571
+ break;
572
+ case "maxItems":
573
+ schema.maxItems = constraint.value;
574
+ break;
575
+ case "pattern":
576
+ schema.pattern = constraint.pattern;
577
+ break;
578
+ case "uniqueItems":
579
+ schema.uniqueItems = constraint.value;
580
+ break;
581
+ case "allowedMembers":
582
+ break;
583
+ case "custom":
584
+ break;
585
+ default: {
586
+ const _exhaustive = constraint;
587
+ void _exhaustive;
588
+ }
589
+ }
590
+ }
591
+ }
592
+ function applyAnnotations(schema, annotations) {
593
+ for (const annotation of annotations) {
594
+ switch (annotation.annotationKind) {
595
+ case "displayName":
596
+ schema.title = annotation.value;
597
+ break;
598
+ case "description":
599
+ schema.description = annotation.value;
600
+ break;
601
+ case "defaultValue":
602
+ schema.default = annotation.value;
603
+ break;
604
+ case "deprecated":
605
+ schema.deprecated = true;
606
+ break;
607
+ case "placeholder":
608
+ break;
609
+ case "formatHint":
610
+ break;
611
+ case "custom":
612
+ break;
613
+ default: {
614
+ const _exhaustive = annotation;
615
+ void _exhaustive;
616
+ }
617
+ }
618
+ }
619
+ }
620
+ var init_ir_generator = __esm({
621
+ "src/json-schema/ir-generator.ts"() {
622
+ "use strict";
623
+ }
624
+ });
625
+
626
+ // src/json-schema/generator.ts
627
+ function generateJsonSchema(form) {
628
+ const ir = canonicalizeChainDSL(form);
629
+ return generateJsonSchemaFromIR(ir);
630
+ }
631
+ var init_generator = __esm({
632
+ "src/json-schema/generator.ts"() {
633
+ "use strict";
634
+ init_canonicalize();
635
+ init_ir_generator();
636
+ }
637
+ });
638
+
639
+ // src/ui-schema/schema.ts
640
+ import { z } from "zod";
641
+ var jsonPointerSchema, ruleEffectSchema, uiSchemaElementTypeSchema, ruleConditionSchema, schemaBasedConditionSchema, ruleSchema, uiSchemaElementSchema, controlSchema, verticalLayoutSchema, horizontalLayoutSchema, groupLayoutSchema, categorySchema, categorizationSchema, labelElementSchema, uiSchema;
642
+ var init_schema = __esm({
643
+ "src/ui-schema/schema.ts"() {
644
+ "use strict";
645
+ jsonPointerSchema = z.string();
646
+ ruleEffectSchema = z.enum(["SHOW", "HIDE", "ENABLE", "DISABLE"]);
647
+ uiSchemaElementTypeSchema = z.enum([
648
+ "Control",
649
+ "VerticalLayout",
650
+ "HorizontalLayout",
651
+ "Group",
652
+ "Categorization",
653
+ "Category",
654
+ "Label"
655
+ ]);
656
+ ruleConditionSchema = z.lazy(
657
+ () => z.object({
658
+ const: z.unknown().optional(),
659
+ enum: z.array(z.unknown()).readonly().optional(),
660
+ type: z.string().optional(),
661
+ not: ruleConditionSchema.optional(),
662
+ minimum: z.number().optional(),
663
+ maximum: z.number().optional(),
664
+ exclusiveMinimum: z.number().optional(),
665
+ exclusiveMaximum: z.number().optional(),
666
+ minLength: z.number().optional(),
667
+ properties: z.record(z.string(), ruleConditionSchema).optional(),
668
+ required: z.array(z.string()).optional(),
669
+ allOf: z.array(ruleConditionSchema).optional()
670
+ }).strict()
671
+ );
672
+ schemaBasedConditionSchema = z.object({
673
+ scope: jsonPointerSchema,
674
+ schema: ruleConditionSchema
675
+ }).strict();
676
+ ruleSchema = z.object({
677
+ effect: ruleEffectSchema,
678
+ condition: schemaBasedConditionSchema
679
+ }).strict();
680
+ uiSchemaElementSchema = z.lazy(
681
+ () => z.union([
682
+ controlSchema,
683
+ verticalLayoutSchema,
684
+ horizontalLayoutSchema,
685
+ groupLayoutSchema,
686
+ categorizationSchema,
687
+ categorySchema,
688
+ labelElementSchema
689
+ ])
690
+ );
691
+ controlSchema = z.object({
692
+ type: z.literal("Control"),
693
+ scope: jsonPointerSchema,
694
+ label: z.union([z.string(), z.literal(false)]).optional(),
695
+ rule: ruleSchema.optional(),
696
+ options: z.record(z.string(), z.unknown()).optional()
697
+ }).passthrough();
698
+ verticalLayoutSchema = z.lazy(
699
+ () => z.object({
700
+ type: z.literal("VerticalLayout"),
701
+ elements: z.array(uiSchemaElementSchema),
702
+ rule: ruleSchema.optional(),
703
+ options: z.record(z.string(), z.unknown()).optional()
704
+ }).passthrough()
705
+ );
706
+ horizontalLayoutSchema = z.lazy(
707
+ () => z.object({
708
+ type: z.literal("HorizontalLayout"),
709
+ elements: z.array(uiSchemaElementSchema),
710
+ rule: ruleSchema.optional(),
711
+ options: z.record(z.string(), z.unknown()).optional()
712
+ }).passthrough()
713
+ );
714
+ groupLayoutSchema = z.lazy(
715
+ () => z.object({
716
+ type: z.literal("Group"),
717
+ label: z.string(),
718
+ elements: z.array(uiSchemaElementSchema),
719
+ rule: ruleSchema.optional(),
720
+ options: z.record(z.string(), z.unknown()).optional()
721
+ }).passthrough()
722
+ );
723
+ categorySchema = z.lazy(
724
+ () => z.object({
725
+ type: z.literal("Category"),
726
+ label: z.string(),
727
+ elements: z.array(uiSchemaElementSchema),
728
+ rule: ruleSchema.optional(),
729
+ options: z.record(z.string(), z.unknown()).optional()
730
+ }).passthrough()
731
+ );
732
+ categorizationSchema = z.lazy(
733
+ () => z.object({
734
+ type: z.literal("Categorization"),
735
+ elements: z.array(categorySchema),
736
+ label: z.string().optional(),
737
+ rule: ruleSchema.optional(),
738
+ options: z.record(z.string(), z.unknown()).optional()
739
+ }).passthrough()
740
+ );
741
+ labelElementSchema = z.object({
742
+ type: z.literal("Label"),
743
+ text: z.string(),
744
+ rule: ruleSchema.optional(),
745
+ options: z.record(z.string(), z.unknown()).optional()
746
+ }).passthrough();
747
+ uiSchema = z.lazy(
748
+ () => z.union([verticalLayoutSchema, horizontalLayoutSchema, groupLayoutSchema, categorizationSchema])
749
+ );
750
+ }
751
+ });
752
+
753
+ // src/ui-schema/ir-generator.ts
754
+ import { z as z2 } from "zod";
755
+ function parseOrThrow(schema, value, label) {
756
+ try {
757
+ return schema.parse(value);
758
+ } catch (error) {
759
+ if (error instanceof z2.ZodError) {
760
+ throw new Error(
761
+ `Generated ${label} failed validation:
762
+ ${error.issues.map((i) => ` ${i.path.join(".")}: ${i.message}`).join("\n")}`
763
+ );
764
+ }
765
+ throw error;
766
+ }
767
+ }
768
+ function fieldToScope(fieldName) {
769
+ return `#/properties/${fieldName}`;
770
+ }
771
+ function createShowRule(fieldName, value) {
772
+ return {
773
+ effect: "SHOW",
774
+ condition: {
775
+ scope: fieldToScope(fieldName),
776
+ schema: { const: value }
777
+ }
778
+ };
779
+ }
780
+ function combineRules(parentRule, childRule) {
781
+ const parentCondition = parentRule.condition;
782
+ const childCondition = childRule.condition;
783
+ return {
784
+ effect: "SHOW",
785
+ condition: {
786
+ scope: "#",
787
+ schema: {
788
+ allOf: [
789
+ {
790
+ properties: {
791
+ [parentCondition.scope.replace("#/properties/", "")]: parentCondition.schema
792
+ }
793
+ },
794
+ {
795
+ properties: {
796
+ [childCondition.scope.replace("#/properties/", "")]: childCondition.schema
797
+ }
798
+ }
799
+ ]
800
+ }
801
+ }
802
+ };
803
+ }
804
+ function fieldNodeToControl(field, parentRule) {
805
+ const displayNameAnnotation = field.annotations.find((a) => a.annotationKind === "displayName");
806
+ const control = {
807
+ type: "Control",
808
+ scope: fieldToScope(field.name),
809
+ ...displayNameAnnotation !== void 0 && { label: displayNameAnnotation.value },
810
+ ...parentRule !== void 0 && { rule: parentRule }
811
+ };
812
+ return control;
813
+ }
814
+ function groupNodeToLayout(group, parentRule) {
815
+ return {
816
+ type: "Group",
817
+ label: group.label,
818
+ elements: irElementsToUiSchema(group.elements, parentRule),
819
+ ...parentRule !== void 0 && { rule: parentRule }
820
+ };
821
+ }
822
+ function irElementsToUiSchema(elements, parentRule) {
823
+ const result = [];
824
+ for (const element of elements) {
825
+ switch (element.kind) {
826
+ case "field": {
827
+ result.push(fieldNodeToControl(element, parentRule));
828
+ break;
829
+ }
830
+ case "group": {
831
+ result.push(groupNodeToLayout(element, parentRule));
832
+ break;
833
+ }
834
+ case "conditional": {
835
+ const newRule = createShowRule(element.fieldName, element.value);
836
+ const combinedRule = parentRule !== void 0 ? combineRules(parentRule, newRule) : newRule;
837
+ const childElements = irElementsToUiSchema(element.elements, combinedRule);
838
+ result.push(...childElements);
839
+ break;
840
+ }
841
+ default: {
842
+ const _exhaustive = element;
843
+ void _exhaustive;
844
+ throw new Error("Unhandled IR element kind");
845
+ }
846
+ }
847
+ }
848
+ return result;
849
+ }
850
+ function generateUiSchemaFromIR(ir) {
851
+ const result = {
852
+ type: "VerticalLayout",
853
+ elements: irElementsToUiSchema(ir.elements)
854
+ };
855
+ return parseOrThrow(uiSchema, result, "UI Schema");
856
+ }
857
+ var init_ir_generator2 = __esm({
858
+ "src/ui-schema/ir-generator.ts"() {
859
+ "use strict";
860
+ init_schema();
861
+ }
862
+ });
863
+
864
+ // src/ui-schema/generator.ts
865
+ function generateUiSchema(form) {
866
+ const ir = canonicalizeChainDSL(form);
867
+ return generateUiSchemaFromIR(ir);
868
+ }
869
+ var init_generator2 = __esm({
870
+ "src/ui-schema/generator.ts"() {
871
+ "use strict";
872
+ init_canonicalize();
873
+ init_ir_generator2();
874
+ }
875
+ });
876
+
877
+ // src/json-schema/types.ts
878
+ function setSchemaExtension(schema, key, value) {
879
+ schema[key] = value;
880
+ }
881
+ function getSchemaExtension(schema, key) {
882
+ return schema[key];
883
+ }
884
+ var init_types = __esm({
885
+ "src/json-schema/types.ts"() {
886
+ "use strict";
887
+ }
888
+ });
889
+
890
+ // src/json-schema/schema.ts
891
+ import { z as z3 } from "zod";
892
+ var jsonSchemaTypeSchema, jsonSchema7Schema;
893
+ var init_schema2 = __esm({
894
+ "src/json-schema/schema.ts"() {
895
+ "use strict";
896
+ jsonSchemaTypeSchema = z3.enum([
897
+ "string",
898
+ "number",
899
+ "integer",
900
+ "boolean",
901
+ "object",
902
+ "array",
903
+ "null"
904
+ ]);
905
+ jsonSchema7Schema = z3.lazy(
906
+ () => z3.object({
907
+ $schema: z3.string().optional(),
908
+ $id: z3.string().optional(),
909
+ $ref: z3.string().optional(),
910
+ // Metadata
911
+ title: z3.string().optional(),
912
+ description: z3.string().optional(),
913
+ deprecated: z3.boolean().optional(),
914
+ // Type
915
+ type: z3.union([jsonSchemaTypeSchema, z3.array(jsonSchemaTypeSchema)]).optional(),
916
+ // String validation
917
+ minLength: z3.number().optional(),
918
+ maxLength: z3.number().optional(),
919
+ pattern: z3.string().optional(),
920
+ // Number validation
921
+ minimum: z3.number().optional(),
922
+ maximum: z3.number().optional(),
923
+ exclusiveMinimum: z3.number().optional(),
924
+ exclusiveMaximum: z3.number().optional(),
925
+ // Enum
926
+ enum: z3.array(z3.union([z3.string(), z3.number(), z3.boolean(), z3.null()])).readonly().optional(),
927
+ const: z3.union([z3.string(), z3.number(), z3.boolean(), z3.null()]).optional(),
928
+ // Object
929
+ properties: z3.record(z3.string(), jsonSchema7Schema).optional(),
930
+ required: z3.array(z3.string()).optional(),
931
+ additionalProperties: z3.union([z3.boolean(), jsonSchema7Schema]).optional(),
932
+ // Array
933
+ items: z3.union([jsonSchema7Schema, z3.array(jsonSchema7Schema)]).optional(),
934
+ minItems: z3.number().optional(),
935
+ maxItems: z3.number().optional(),
936
+ // Composition
937
+ allOf: z3.array(jsonSchema7Schema).optional(),
938
+ anyOf: z3.array(jsonSchema7Schema).optional(),
939
+ oneOf: z3.array(jsonSchema7Schema).optional(),
940
+ not: jsonSchema7Schema.optional(),
941
+ // Conditional
942
+ if: jsonSchema7Schema.optional(),
943
+ then: jsonSchema7Schema.optional(),
944
+ else: jsonSchema7Schema.optional(),
945
+ // Format
946
+ format: z3.string().optional(),
947
+ // Default
948
+ default: z3.unknown().optional(),
949
+ // FormSpec extensions
950
+ "x-formspec-source": z3.string().optional(),
951
+ "x-formspec-params": z3.array(z3.string()).readonly().optional(),
952
+ "x-formspec-schemaSource": z3.string().optional()
953
+ }).passthrough()
954
+ );
955
+ }
956
+ });
957
+
958
+ // src/analyzer/program.ts
959
+ import * as ts from "typescript";
960
+ import * as path from "path";
961
+ function createProgramContext(filePath) {
962
+ const absolutePath = path.resolve(filePath);
963
+ const fileDir = path.dirname(absolutePath);
964
+ const configPath = ts.findConfigFile(fileDir, ts.sys.fileExists.bind(ts.sys), "tsconfig.json");
965
+ let compilerOptions;
966
+ let fileNames;
967
+ if (configPath) {
968
+ const configFile = ts.readConfigFile(configPath, ts.sys.readFile.bind(ts.sys));
969
+ if (configFile.error) {
970
+ throw new Error(
971
+ `Error reading tsconfig.json: ${ts.flattenDiagnosticMessageText(configFile.error.messageText, "\n")}`
972
+ );
973
+ }
974
+ const parsed = ts.parseJsonConfigFileContent(
975
+ configFile.config,
976
+ ts.sys,
977
+ path.dirname(configPath)
978
+ );
979
+ if (parsed.errors.length > 0) {
980
+ const errorMessages = parsed.errors.map((e) => ts.flattenDiagnosticMessageText(e.messageText, "\n")).join("\n");
981
+ throw new Error(`Error parsing tsconfig.json: ${errorMessages}`);
982
+ }
983
+ compilerOptions = parsed.options;
984
+ fileNames = parsed.fileNames.includes(absolutePath) ? parsed.fileNames : [...parsed.fileNames, absolutePath];
985
+ } else {
986
+ compilerOptions = {
987
+ target: ts.ScriptTarget.ES2022,
988
+ module: ts.ModuleKind.NodeNext,
989
+ moduleResolution: ts.ModuleResolutionKind.NodeNext,
990
+ strict: true,
991
+ skipLibCheck: true,
992
+ declaration: true
993
+ };
994
+ fileNames = [absolutePath];
995
+ }
996
+ const program = ts.createProgram(fileNames, compilerOptions);
997
+ const sourceFile = program.getSourceFile(absolutePath);
998
+ if (!sourceFile) {
999
+ throw new Error(`Could not find source file: ${absolutePath}`);
1000
+ }
1001
+ return {
1002
+ program,
1003
+ checker: program.getTypeChecker(),
1004
+ sourceFile
1005
+ };
1006
+ }
1007
+ function findNodeByName(sourceFile, name, predicate, getName) {
1008
+ let result = null;
1009
+ function visit(node) {
1010
+ if (result) return;
1011
+ if (predicate(node) && getName(node) === name) {
1012
+ result = node;
1013
+ return;
1014
+ }
1015
+ ts.forEachChild(node, visit);
1016
+ }
1017
+ visit(sourceFile);
1018
+ return result;
1019
+ }
1020
+ function findClassByName(sourceFile, className) {
1021
+ return findNodeByName(sourceFile, className, ts.isClassDeclaration, (n) => n.name?.text);
1022
+ }
1023
+ function findInterfaceByName(sourceFile, interfaceName) {
1024
+ return findNodeByName(sourceFile, interfaceName, ts.isInterfaceDeclaration, (n) => n.name.text);
1025
+ }
1026
+ function findTypeAliasByName(sourceFile, aliasName) {
1027
+ return findNodeByName(sourceFile, aliasName, ts.isTypeAliasDeclaration, (n) => n.name.text);
1028
+ }
1029
+ var init_program = __esm({
1030
+ "src/analyzer/program.ts"() {
1031
+ "use strict";
1032
+ }
1033
+ });
1034
+
1035
+ // src/analyzer/tsdoc-parser.ts
1036
+ import * as ts2 from "typescript";
1037
+ import {
1038
+ TSDocParser,
1039
+ TSDocConfiguration,
1040
+ TSDocTagDefinition,
1041
+ TSDocTagSyntaxKind,
1042
+ DocPlainText,
1043
+ DocSoftBreak,
1044
+ TextRange
1045
+ } from "@microsoft/tsdoc";
1046
+ import {
1047
+ BUILTIN_CONSTRAINT_DEFINITIONS
1048
+ } from "@formspec/core";
1049
+ function isBuiltinConstraintName(tagName) {
1050
+ return tagName in BUILTIN_CONSTRAINT_DEFINITIONS;
1051
+ }
1052
+ function createFormSpecTSDocConfig() {
1053
+ const config = new TSDocConfiguration();
1054
+ for (const tagName of Object.keys(BUILTIN_CONSTRAINT_DEFINITIONS)) {
1055
+ config.addTagDefinition(
1056
+ new TSDocTagDefinition({
1057
+ tagName: "@" + tagName,
1058
+ syntaxKind: TSDocTagSyntaxKind.BlockTag,
1059
+ allowMultiple: true
1060
+ })
1061
+ );
1062
+ }
1063
+ return config;
1064
+ }
1065
+ function getParser() {
1066
+ sharedParser ??= new TSDocParser(createFormSpecTSDocConfig());
1067
+ return sharedParser;
1068
+ }
1069
+ function parseTSDocTags(node, file = "") {
1070
+ const constraints = [];
1071
+ const annotations = [];
1072
+ const sourceFile = node.getSourceFile();
1073
+ const sourceText = sourceFile.getFullText();
1074
+ const commentRanges = ts2.getLeadingCommentRanges(sourceText, node.getFullStart());
1075
+ if (commentRanges) {
1076
+ for (const range of commentRanges) {
1077
+ if (range.kind !== ts2.SyntaxKind.MultiLineCommentTrivia) {
1078
+ continue;
1079
+ }
1080
+ const commentText = sourceText.substring(range.pos, range.end);
1081
+ if (!commentText.startsWith("/**")) {
1082
+ continue;
1083
+ }
1084
+ const parser = getParser();
1085
+ const parserContext = parser.parseRange(
1086
+ TextRange.fromStringRange(sourceText, range.pos, range.end)
1087
+ );
1088
+ const docComment = parserContext.docComment;
1089
+ for (const block of docComment.customBlocks) {
1090
+ const tagName = block.blockTag.tagName.substring(1);
1091
+ if (TAGS_REQUIRING_RAW_TEXT.has(tagName)) continue;
1092
+ const text = extractBlockText(block).trim();
1093
+ if (text === "") continue;
1094
+ const provenance = provenanceForComment(range, sourceFile, file, tagName);
1095
+ const constraintNode = parseConstraintValue(tagName, text, provenance);
1096
+ if (constraintNode) {
1097
+ constraints.push(constraintNode);
1098
+ }
1099
+ }
1100
+ if (docComment.deprecatedBlock !== void 0) {
1101
+ annotations.push({
1102
+ kind: "annotation",
1103
+ annotationKind: "deprecated",
1104
+ provenance: provenanceForComment(range, sourceFile, file, "deprecated")
1105
+ });
1106
+ }
1107
+ }
1108
+ }
1109
+ const jsDocTagsAll = ts2.getJSDocTags(node);
1110
+ for (const tag of jsDocTagsAll) {
1111
+ const tagName = tag.tagName.text;
1112
+ if (!TAGS_REQUIRING_RAW_TEXT.has(tagName)) continue;
1113
+ const commentText = getTagCommentText(tag);
1114
+ if (commentText === void 0 || commentText.trim() === "") continue;
1115
+ const text = commentText.trim();
1116
+ const provenance = provenanceForJSDocTag(tag, file);
1117
+ const constraintNode = parseConstraintValue(tagName, text, provenance);
1118
+ if (constraintNode) {
1119
+ constraints.push(constraintNode);
1120
+ }
1121
+ }
1122
+ let displayName;
1123
+ let description;
1124
+ let displayNameTag;
1125
+ let descriptionTag;
1126
+ for (const tag of jsDocTagsAll) {
1127
+ const tagName = tag.tagName.text;
1128
+ const commentText = getTagCommentText(tag);
1129
+ if (commentText === void 0 || commentText.trim() === "") {
1130
+ continue;
1131
+ }
1132
+ const trimmed = commentText.trim();
1133
+ if (tagName === "Field_displayName") {
1134
+ displayName = trimmed;
1135
+ displayNameTag = tag;
1136
+ } else if (tagName === "Field_description") {
1137
+ description = trimmed;
1138
+ descriptionTag = tag;
1139
+ }
1140
+ }
1141
+ if (displayName !== void 0 && displayNameTag) {
1142
+ annotations.push({
1143
+ kind: "annotation",
1144
+ annotationKind: "displayName",
1145
+ value: displayName,
1146
+ provenance: provenanceForJSDocTag(displayNameTag, file)
1147
+ });
1148
+ }
1149
+ if (description !== void 0 && descriptionTag) {
1150
+ annotations.push({
1151
+ kind: "annotation",
1152
+ annotationKind: "description",
1153
+ value: description,
1154
+ provenance: provenanceForJSDocTag(descriptionTag, file)
1155
+ });
1156
+ }
1157
+ return { constraints, annotations };
1158
+ }
1159
+ function extractBlockText(block) {
1160
+ return extractPlainText(block.content);
1161
+ }
1162
+ function extractPlainText(node) {
1163
+ let result = "";
1164
+ if (node instanceof DocPlainText) {
1165
+ return node.text;
1166
+ }
1167
+ if (node instanceof DocSoftBreak) {
1168
+ return " ";
1169
+ }
1170
+ if (typeof node.getChildNodes === "function") {
1171
+ for (const child of node.getChildNodes()) {
1172
+ result += extractPlainText(child);
1173
+ }
1174
+ }
1175
+ return result;
1176
+ }
1177
+ function parseConstraintValue(tagName, text, provenance) {
1178
+ if (!isBuiltinConstraintName(tagName)) {
1179
+ return null;
1180
+ }
1181
+ const expectedType = BUILTIN_CONSTRAINT_DEFINITIONS[tagName];
1182
+ if (expectedType === "number") {
1183
+ const value = Number(text);
1184
+ if (Number.isNaN(value)) {
1185
+ return null;
1186
+ }
1187
+ const numericKind = NUMERIC_CONSTRAINT_MAP[tagName];
1188
+ if (numericKind) {
1189
+ return {
1190
+ kind: "constraint",
1191
+ constraintKind: numericKind,
1192
+ value,
1193
+ provenance
1194
+ };
1195
+ }
1196
+ const lengthKind = LENGTH_CONSTRAINT_MAP[tagName];
1197
+ if (lengthKind) {
1198
+ return {
1199
+ kind: "constraint",
1200
+ constraintKind: lengthKind,
1201
+ value,
1202
+ provenance
1203
+ };
1204
+ }
1205
+ return null;
1206
+ }
1207
+ if (expectedType === "json") {
1208
+ try {
1209
+ const parsed = JSON.parse(text);
1210
+ if (!Array.isArray(parsed)) {
1211
+ return null;
1212
+ }
1213
+ const members = [];
1214
+ for (const item of parsed) {
1215
+ if (typeof item === "string" || typeof item === "number") {
1216
+ members.push(item);
1217
+ } else if (typeof item === "object" && item !== null && "id" in item) {
1218
+ const id = item["id"];
1219
+ if (typeof id === "string" || typeof id === "number") {
1220
+ members.push(id);
1221
+ }
1222
+ }
1223
+ }
1224
+ return {
1225
+ kind: "constraint",
1226
+ constraintKind: "allowedMembers",
1227
+ members,
1228
+ provenance
1229
+ };
1230
+ } catch {
1231
+ return null;
1232
+ }
1233
+ }
1234
+ return {
1235
+ kind: "constraint",
1236
+ constraintKind: "pattern",
1237
+ pattern: text,
1238
+ provenance
1239
+ };
1240
+ }
1241
+ function provenanceForComment(range, sourceFile, file, tagName) {
1242
+ const { line, character } = sourceFile.getLineAndCharacterOfPosition(range.pos);
1243
+ return {
1244
+ surface: "tsdoc",
1245
+ file,
1246
+ line: line + 1,
1247
+ column: character,
1248
+ tagName: "@" + tagName
1249
+ };
1250
+ }
1251
+ function provenanceForJSDocTag(tag, file) {
1252
+ const sourceFile = tag.getSourceFile();
1253
+ const { line, character } = sourceFile.getLineAndCharacterOfPosition(tag.getStart());
1254
+ return {
1255
+ surface: "tsdoc",
1256
+ file,
1257
+ line: line + 1,
1258
+ column: character,
1259
+ tagName: "@" + tag.tagName.text
1260
+ };
1261
+ }
1262
+ function getTagCommentText(tag) {
1263
+ if (tag.comment === void 0) {
1264
+ return void 0;
1265
+ }
1266
+ if (typeof tag.comment === "string") {
1267
+ return tag.comment;
1268
+ }
1269
+ return ts2.getTextOfJSDocComment(tag.comment);
1270
+ }
1271
+ var NUMERIC_CONSTRAINT_MAP, LENGTH_CONSTRAINT_MAP, TAGS_REQUIRING_RAW_TEXT, sharedParser;
1272
+ var init_tsdoc_parser = __esm({
1273
+ "src/analyzer/tsdoc-parser.ts"() {
1274
+ "use strict";
1275
+ NUMERIC_CONSTRAINT_MAP = {
1276
+ Minimum: "minimum",
1277
+ Maximum: "maximum",
1278
+ ExclusiveMinimum: "exclusiveMinimum",
1279
+ ExclusiveMaximum: "exclusiveMaximum"
1280
+ };
1281
+ LENGTH_CONSTRAINT_MAP = {
1282
+ MinLength: "minLength",
1283
+ MaxLength: "maxLength"
1284
+ };
1285
+ TAGS_REQUIRING_RAW_TEXT = /* @__PURE__ */ new Set(["Pattern", "EnumOptions"]);
1286
+ }
1287
+ });
1288
+
1289
+ // src/analyzer/jsdoc-constraints.ts
1290
+ import * as ts3 from "typescript";
1291
+ import {
1292
+ BUILTIN_CONSTRAINT_DEFINITIONS as BUILTIN_CONSTRAINT_DEFINITIONS2
1293
+ } from "@formspec/core";
1294
+ function extractJSDocConstraintNodes(node, file = "") {
1295
+ const result = parseTSDocTags(node, file);
1296
+ return [...result.constraints];
1297
+ }
1298
+ function extractJSDocAnnotationNodes(node, file = "") {
1299
+ const result = parseTSDocTags(node, file);
1300
+ return [...result.annotations];
1301
+ }
1302
+ function extractDefaultValueAnnotation(initializer, file = "") {
1303
+ if (!initializer) return null;
1304
+ let value;
1305
+ if (ts3.isStringLiteral(initializer)) {
1306
+ value = initializer.text;
1307
+ } else if (ts3.isNumericLiteral(initializer)) {
1308
+ value = Number(initializer.text);
1309
+ } else if (initializer.kind === ts3.SyntaxKind.TrueKeyword) {
1310
+ value = true;
1311
+ } else if (initializer.kind === ts3.SyntaxKind.FalseKeyword) {
1312
+ value = false;
1313
+ } else if (initializer.kind === ts3.SyntaxKind.NullKeyword) {
1314
+ value = null;
1315
+ } else if (ts3.isPrefixUnaryExpression(initializer)) {
1316
+ if (initializer.operator === ts3.SyntaxKind.MinusToken && ts3.isNumericLiteral(initializer.operand)) {
1317
+ value = -Number(initializer.operand.text);
1318
+ }
1319
+ }
1320
+ if (value === void 0) return null;
1321
+ const sourceFile = initializer.getSourceFile();
1322
+ const { line, character } = sourceFile.getLineAndCharacterOfPosition(initializer.getStart());
1323
+ return {
1324
+ kind: "annotation",
1325
+ annotationKind: "defaultValue",
1326
+ value,
1327
+ provenance: {
1328
+ surface: "tsdoc",
1329
+ file,
1330
+ line: line + 1,
1331
+ column: character
1332
+ }
1333
+ };
1334
+ }
1335
+ var init_jsdoc_constraints = __esm({
1336
+ "src/analyzer/jsdoc-constraints.ts"() {
1337
+ "use strict";
1338
+ init_tsdoc_parser();
1339
+ }
1340
+ });
1341
+
1342
+ // src/analyzer/class-analyzer.ts
1343
+ import * as ts4 from "typescript";
1344
+ function isObjectType(type) {
1345
+ return !!(type.flags & ts4.TypeFlags.Object);
1346
+ }
1347
+ function isTypeReference(type) {
1348
+ return !!(type.flags & ts4.TypeFlags.Object) && !!(type.objectFlags & ts4.ObjectFlags.Reference);
1349
+ }
1350
+ function analyzeClassToIR(classDecl, checker, file = "") {
1351
+ const name = classDecl.name?.text ?? "AnonymousClass";
1352
+ const fields = [];
1353
+ const fieldLayouts = [];
1354
+ const typeRegistry = {};
1355
+ const visiting = /* @__PURE__ */ new Set();
1356
+ const instanceMethods = [];
1357
+ const staticMethods = [];
1358
+ for (const member of classDecl.members) {
1359
+ if (ts4.isPropertyDeclaration(member)) {
1360
+ const fieldNode = analyzeFieldToIR(member, checker, file, typeRegistry, visiting);
1361
+ if (fieldNode) {
1362
+ fields.push(fieldNode);
1363
+ fieldLayouts.push({});
1364
+ }
1365
+ } else if (ts4.isMethodDeclaration(member)) {
1366
+ const methodInfo = analyzeMethod(member, checker);
1367
+ if (methodInfo) {
1368
+ const isStatic = member.modifiers?.some((m) => m.kind === ts4.SyntaxKind.StaticKeyword);
1369
+ if (isStatic) {
1370
+ staticMethods.push(methodInfo);
1371
+ } else {
1372
+ instanceMethods.push(methodInfo);
1373
+ }
1374
+ }
1375
+ }
1376
+ }
1377
+ return { name, fields, fieldLayouts, typeRegistry, instanceMethods, staticMethods };
1378
+ }
1379
+ function analyzeInterfaceToIR(interfaceDecl, checker, file = "") {
1380
+ const name = interfaceDecl.name.text;
1381
+ const fields = [];
1382
+ const typeRegistry = {};
1383
+ const visiting = /* @__PURE__ */ new Set();
1384
+ for (const member of interfaceDecl.members) {
1385
+ if (ts4.isPropertySignature(member)) {
1386
+ const fieldNode = analyzeInterfacePropertyToIR(member, checker, file, typeRegistry, visiting);
1387
+ if (fieldNode) {
1388
+ fields.push(fieldNode);
1389
+ }
1390
+ }
1391
+ }
1392
+ const fieldLayouts = fields.map(() => ({}));
1393
+ return { name, fields, fieldLayouts, typeRegistry, instanceMethods: [], staticMethods: [] };
1394
+ }
1395
+ function analyzeTypeAliasToIR(typeAlias, checker, file = "") {
1396
+ if (!ts4.isTypeLiteralNode(typeAlias.type)) {
1397
+ const sourceFile = typeAlias.getSourceFile();
1398
+ const { line } = sourceFile.getLineAndCharacterOfPosition(typeAlias.getStart());
1399
+ const kindDesc = ts4.SyntaxKind[typeAlias.type.kind] ?? "unknown";
1400
+ return {
1401
+ ok: false,
1402
+ error: `Type alias "${typeAlias.name.text}" at line ${String(line + 1)} is not an object type literal (found ${kindDesc})`
1403
+ };
1404
+ }
1405
+ const name = typeAlias.name.text;
1406
+ const fields = [];
1407
+ const typeRegistry = {};
1408
+ const visiting = /* @__PURE__ */ new Set();
1409
+ for (const member of typeAlias.type.members) {
1410
+ if (ts4.isPropertySignature(member)) {
1411
+ const fieldNode = analyzeInterfacePropertyToIR(member, checker, file, typeRegistry, visiting);
1412
+ if (fieldNode) {
1413
+ fields.push(fieldNode);
1414
+ }
1415
+ }
1416
+ }
1417
+ return {
1418
+ ok: true,
1419
+ analysis: {
1420
+ name,
1421
+ fields,
1422
+ fieldLayouts: fields.map(() => ({})),
1423
+ typeRegistry,
1424
+ instanceMethods: [],
1425
+ staticMethods: []
1426
+ }
1427
+ };
1428
+ }
1429
+ function analyzeFieldToIR(prop, checker, file, typeRegistry, visiting) {
1430
+ if (!ts4.isIdentifier(prop.name)) {
1431
+ return null;
1432
+ }
1433
+ const name = prop.name.text;
1434
+ const tsType = checker.getTypeAtLocation(prop);
1435
+ const optional = prop.questionToken !== void 0;
1436
+ const provenance = provenanceForNode(prop, file);
1437
+ const type = resolveTypeNode(tsType, checker, file, typeRegistry, visiting);
1438
+ const constraints = [];
1439
+ if (prop.type) {
1440
+ constraints.push(...extractTypeAliasConstraintNodes(prop.type, checker, file));
1441
+ }
1442
+ constraints.push(...extractJSDocConstraintNodes(prop, file));
1443
+ const annotations = [];
1444
+ annotations.push(...extractJSDocAnnotationNodes(prop, file));
1445
+ const defaultAnnotation = extractDefaultValueAnnotation(prop.initializer, file);
1446
+ if (defaultAnnotation) {
1447
+ annotations.push(defaultAnnotation);
1448
+ }
1449
+ return {
1450
+ kind: "field",
1451
+ name,
1452
+ type,
1453
+ required: !optional,
1454
+ constraints,
1455
+ annotations,
1456
+ provenance
1457
+ };
1458
+ }
1459
+ function analyzeInterfacePropertyToIR(prop, checker, file, typeRegistry, visiting) {
1460
+ if (!ts4.isIdentifier(prop.name)) {
1461
+ return null;
1462
+ }
1463
+ const name = prop.name.text;
1464
+ const tsType = checker.getTypeAtLocation(prop);
1465
+ const optional = prop.questionToken !== void 0;
1466
+ const provenance = provenanceForNode(prop, file);
1467
+ const type = resolveTypeNode(tsType, checker, file, typeRegistry, visiting);
1468
+ const constraints = [];
1469
+ if (prop.type) {
1470
+ constraints.push(...extractTypeAliasConstraintNodes(prop.type, checker, file));
1471
+ }
1472
+ constraints.push(...extractJSDocConstraintNodes(prop, file));
1473
+ const annotations = [];
1474
+ annotations.push(...extractJSDocAnnotationNodes(prop, file));
1475
+ return {
1476
+ kind: "field",
1477
+ name,
1478
+ type,
1479
+ required: !optional,
1480
+ constraints,
1481
+ annotations,
1482
+ provenance
1483
+ };
1484
+ }
1485
+ function resolveTypeNode(type, checker, file, typeRegistry, visiting) {
1486
+ if (type.flags & ts4.TypeFlags.String) {
1487
+ return { kind: "primitive", primitiveKind: "string" };
1488
+ }
1489
+ if (type.flags & ts4.TypeFlags.Number) {
1490
+ return { kind: "primitive", primitiveKind: "number" };
1491
+ }
1492
+ if (type.flags & ts4.TypeFlags.Boolean) {
1493
+ return { kind: "primitive", primitiveKind: "boolean" };
1494
+ }
1495
+ if (type.flags & ts4.TypeFlags.Null) {
1496
+ return { kind: "primitive", primitiveKind: "null" };
1497
+ }
1498
+ if (type.flags & ts4.TypeFlags.Undefined) {
1499
+ return { kind: "primitive", primitiveKind: "null" };
1500
+ }
1501
+ if (type.isStringLiteral()) {
1502
+ return {
1503
+ kind: "enum",
1504
+ members: [{ value: type.value }]
1505
+ };
1506
+ }
1507
+ if (type.isNumberLiteral()) {
1508
+ return {
1509
+ kind: "enum",
1510
+ members: [{ value: type.value }]
1511
+ };
1512
+ }
1513
+ if (type.isUnion()) {
1514
+ return resolveUnionType(type, checker, file, typeRegistry, visiting);
1515
+ }
1516
+ if (checker.isArrayType(type)) {
1517
+ return resolveArrayType(type, checker, file, typeRegistry, visiting);
1518
+ }
1519
+ if (isObjectType(type)) {
1520
+ return resolveObjectType(type, checker, file, typeRegistry, visiting);
1521
+ }
1522
+ return { kind: "primitive", primitiveKind: "string" };
1523
+ }
1524
+ function resolveUnionType(type, checker, file, typeRegistry, visiting) {
1525
+ const allTypes = type.types;
1526
+ const nonNullTypes = allTypes.filter(
1527
+ (t) => !(t.flags & (ts4.TypeFlags.Null | ts4.TypeFlags.Undefined))
1528
+ );
1529
+ const hasNull = allTypes.some((t) => t.flags & ts4.TypeFlags.Null);
1530
+ const isBooleanUnion2 = nonNullTypes.length === 2 && nonNullTypes.every((t) => t.flags & ts4.TypeFlags.BooleanLiteral);
1531
+ if (isBooleanUnion2) {
1532
+ const boolNode = { kind: "primitive", primitiveKind: "boolean" };
1533
+ if (hasNull) {
1534
+ return {
1535
+ kind: "union",
1536
+ members: [boolNode, { kind: "primitive", primitiveKind: "null" }]
1537
+ };
1538
+ }
1539
+ return boolNode;
1540
+ }
1541
+ const allStringLiterals = nonNullTypes.every((t) => t.isStringLiteral());
1542
+ if (allStringLiterals && nonNullTypes.length > 0) {
1543
+ const stringTypes = nonNullTypes.filter((t) => t.isStringLiteral());
1544
+ const enumNode = {
1545
+ kind: "enum",
1546
+ members: stringTypes.map((t) => ({ value: t.value }))
1547
+ };
1548
+ if (hasNull) {
1549
+ return {
1550
+ kind: "union",
1551
+ members: [enumNode, { kind: "primitive", primitiveKind: "null" }]
1552
+ };
1553
+ }
1554
+ return enumNode;
1555
+ }
1556
+ const allNumberLiterals = nonNullTypes.every((t) => t.isNumberLiteral());
1557
+ if (allNumberLiterals && nonNullTypes.length > 0) {
1558
+ const numberTypes = nonNullTypes.filter((t) => t.isNumberLiteral());
1559
+ const enumNode = {
1560
+ kind: "enum",
1561
+ members: numberTypes.map((t) => ({ value: t.value }))
1562
+ };
1563
+ if (hasNull) {
1564
+ return {
1565
+ kind: "union",
1566
+ members: [enumNode, { kind: "primitive", primitiveKind: "null" }]
1567
+ };
1568
+ }
1569
+ return enumNode;
1570
+ }
1571
+ if (nonNullTypes.length === 1 && nonNullTypes[0]) {
1572
+ const inner = resolveTypeNode(nonNullTypes[0], checker, file, typeRegistry, visiting);
1573
+ if (hasNull) {
1574
+ return {
1575
+ kind: "union",
1576
+ members: [inner, { kind: "primitive", primitiveKind: "null" }]
1577
+ };
1578
+ }
1579
+ return inner;
1580
+ }
1581
+ const members = nonNullTypes.map(
1582
+ (t) => resolveTypeNode(t, checker, file, typeRegistry, visiting)
1583
+ );
1584
+ if (hasNull) {
1585
+ members.push({ kind: "primitive", primitiveKind: "null" });
1586
+ }
1587
+ return { kind: "union", members };
1588
+ }
1589
+ function resolveArrayType(type, checker, file, typeRegistry, visiting) {
1590
+ const typeArgs = isTypeReference(type) ? type.typeArguments : void 0;
1591
+ const elementType = typeArgs?.[0];
1592
+ const items = elementType ? resolveTypeNode(elementType, checker, file, typeRegistry, visiting) : { kind: "primitive", primitiveKind: "string" };
1593
+ return { kind: "array", items };
1594
+ }
1595
+ function resolveObjectType(type, checker, file, typeRegistry, visiting) {
1596
+ if (visiting.has(type)) {
1597
+ return { kind: "object", properties: [], additionalProperties: false };
1598
+ }
1599
+ visiting.add(type);
1600
+ const typeName = getNamedTypeName(type);
1601
+ if (typeName && typeName in typeRegistry) {
1602
+ visiting.delete(type);
1603
+ return { kind: "reference", name: typeName, typeArguments: [] };
1604
+ }
1605
+ const properties = [];
1606
+ const fieldInfoMap = getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visiting);
1607
+ for (const prop of type.getProperties()) {
1608
+ const declaration = prop.valueDeclaration ?? prop.declarations?.[0];
1609
+ if (!declaration) continue;
1610
+ const propType = checker.getTypeOfSymbolAtLocation(prop, declaration);
1611
+ const optional = !!(prop.flags & ts4.SymbolFlags.Optional);
1612
+ const propTypeNode = resolveTypeNode(propType, checker, file, typeRegistry, visiting);
1613
+ const fieldNodeInfo = fieldInfoMap?.get(prop.name);
1614
+ properties.push({
1615
+ name: prop.name,
1616
+ type: propTypeNode,
1617
+ optional,
1618
+ constraints: fieldNodeInfo?.constraints ?? [],
1619
+ annotations: fieldNodeInfo?.annotations ?? [],
1620
+ provenance: fieldNodeInfo?.provenance ?? provenanceForFile(file)
1621
+ });
1622
+ }
1623
+ visiting.delete(type);
1624
+ const objectNode = {
1625
+ kind: "object",
1626
+ properties,
1627
+ additionalProperties: false
1628
+ };
1629
+ if (typeName) {
1630
+ typeRegistry[typeName] = {
1631
+ name: typeName,
1632
+ type: objectNode,
1633
+ provenance: provenanceForFile(file)
1634
+ };
1635
+ return { kind: "reference", name: typeName, typeArguments: [] };
1636
+ }
1637
+ return objectNode;
1638
+ }
1639
+ function getNamedTypeFieldNodeInfoMap(type, checker, file, typeRegistry, visiting) {
1640
+ const symbols = [type.getSymbol(), type.aliasSymbol].filter(
1641
+ (s) => s?.declarations != null && s.declarations.length > 0
1642
+ );
1643
+ for (const symbol of symbols) {
1644
+ const declarations = symbol.declarations;
1645
+ if (!declarations) continue;
1646
+ const classDecl = declarations.find(ts4.isClassDeclaration);
1647
+ if (classDecl) {
1648
+ const map = /* @__PURE__ */ new Map();
1649
+ for (const member of classDecl.members) {
1650
+ if (ts4.isPropertyDeclaration(member) && ts4.isIdentifier(member.name)) {
1651
+ const fieldNode = analyzeFieldToIR(member, checker, file, typeRegistry, visiting);
1652
+ if (fieldNode) {
1653
+ map.set(fieldNode.name, {
1654
+ constraints: [...fieldNode.constraints],
1655
+ annotations: [...fieldNode.annotations],
1656
+ provenance: fieldNode.provenance
1657
+ });
1658
+ }
1659
+ }
1660
+ }
1661
+ return map;
1662
+ }
1663
+ const interfaceDecl = declarations.find(ts4.isInterfaceDeclaration);
1664
+ if (interfaceDecl) {
1665
+ return buildFieldNodeInfoMap(interfaceDecl.members, checker, file, typeRegistry, visiting);
1666
+ }
1667
+ const typeAliasDecl = declarations.find(ts4.isTypeAliasDeclaration);
1668
+ if (typeAliasDecl && ts4.isTypeLiteralNode(typeAliasDecl.type)) {
1669
+ return buildFieldNodeInfoMap(
1670
+ typeAliasDecl.type.members,
1671
+ checker,
1672
+ file,
1673
+ typeRegistry,
1674
+ visiting
1675
+ );
1676
+ }
1677
+ }
1678
+ return null;
1679
+ }
1680
+ function buildFieldNodeInfoMap(members, checker, file, typeRegistry, visiting) {
1681
+ const map = /* @__PURE__ */ new Map();
1682
+ for (const member of members) {
1683
+ if (ts4.isPropertySignature(member)) {
1684
+ const fieldNode = analyzeInterfacePropertyToIR(member, checker, file, typeRegistry, visiting);
1685
+ if (fieldNode) {
1686
+ map.set(fieldNode.name, {
1687
+ constraints: [...fieldNode.constraints],
1688
+ annotations: [...fieldNode.annotations],
1689
+ provenance: fieldNode.provenance
1690
+ });
1691
+ }
1692
+ }
1693
+ }
1694
+ return map;
1695
+ }
1696
+ function extractTypeAliasConstraintNodes(typeNode, checker, file) {
1697
+ if (!ts4.isTypeReferenceNode(typeNode)) return [];
1698
+ const symbol = checker.getSymbolAtLocation(typeNode.typeName);
1699
+ if (!symbol?.declarations) return [];
1700
+ const aliasDecl = symbol.declarations.find(ts4.isTypeAliasDeclaration);
1701
+ if (!aliasDecl) return [];
1702
+ if (ts4.isTypeLiteralNode(aliasDecl.type)) return [];
1703
+ return extractJSDocConstraintNodes(aliasDecl, file);
1704
+ }
1705
+ function provenanceForNode(node, file) {
1706
+ const sourceFile = node.getSourceFile();
1707
+ const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
1708
+ return {
1709
+ surface: "tsdoc",
1710
+ file,
1711
+ line: line + 1,
1712
+ column: character
1713
+ };
1714
+ }
1715
+ function provenanceForFile(file) {
1716
+ return { surface: "tsdoc", file, line: 0, column: 0 };
1717
+ }
1718
+ function getNamedTypeName(type) {
1719
+ const symbol = type.getSymbol();
1720
+ if (symbol?.declarations) {
1721
+ const decl = symbol.declarations[0];
1722
+ if (decl && (ts4.isClassDeclaration(decl) || ts4.isInterfaceDeclaration(decl) || ts4.isTypeAliasDeclaration(decl))) {
1723
+ const name = ts4.isClassDeclaration(decl) ? decl.name?.text : decl.name.text;
1724
+ if (name) return name;
1725
+ }
1726
+ }
1727
+ const aliasSymbol = type.aliasSymbol;
1728
+ if (aliasSymbol?.declarations) {
1729
+ const aliasDecl = aliasSymbol.declarations.find(ts4.isTypeAliasDeclaration);
1730
+ if (aliasDecl) {
1731
+ return aliasDecl.name.text;
1732
+ }
1733
+ }
1734
+ return null;
1735
+ }
1736
+ function analyzeMethod(method, checker) {
1737
+ if (!ts4.isIdentifier(method.name)) {
1738
+ return null;
1739
+ }
1740
+ const name = method.name.text;
1741
+ const parameters = [];
1742
+ for (const param of method.parameters) {
1743
+ if (ts4.isIdentifier(param.name)) {
1744
+ const paramInfo = analyzeParameter(param, checker);
1745
+ parameters.push(paramInfo);
1746
+ }
1747
+ }
1748
+ const returnTypeNode = method.type;
1749
+ const signature = checker.getSignatureFromDeclaration(method);
1750
+ const returnType = signature ? checker.getReturnTypeOfSignature(signature) : checker.getTypeAtLocation(method);
1751
+ return { name, parameters, returnTypeNode, returnType };
1752
+ }
1753
+ function analyzeParameter(param, checker) {
1754
+ const name = ts4.isIdentifier(param.name) ? param.name.text : "param";
1755
+ const typeNode = param.type;
1756
+ const type = checker.getTypeAtLocation(param);
1757
+ const formSpecExportName = detectFormSpecReference(typeNode);
1758
+ const optional = param.questionToken !== void 0 || param.initializer !== void 0;
1759
+ return { name, typeNode, type, formSpecExportName, optional };
1760
+ }
1761
+ function detectFormSpecReference(typeNode) {
1762
+ if (!typeNode) return null;
1763
+ if (!ts4.isTypeReferenceNode(typeNode)) return null;
1764
+ const typeName = ts4.isIdentifier(typeNode.typeName) ? typeNode.typeName.text : ts4.isQualifiedName(typeNode.typeName) ? typeNode.typeName.right.text : null;
1765
+ if (typeName !== "InferSchema" && typeName !== "InferFormSchema") return null;
1766
+ const typeArg = typeNode.typeArguments?.[0];
1767
+ if (!typeArg || !ts4.isTypeQueryNode(typeArg)) return null;
1768
+ if (ts4.isIdentifier(typeArg.exprName)) {
1769
+ return typeArg.exprName.text;
1770
+ }
1771
+ if (ts4.isQualifiedName(typeArg.exprName)) {
1772
+ return typeArg.exprName.right.text;
1773
+ }
1774
+ return null;
1775
+ }
1776
+ var init_class_analyzer = __esm({
1777
+ "src/analyzer/class-analyzer.ts"() {
1778
+ "use strict";
1779
+ init_jsdoc_constraints();
1780
+ }
1781
+ });
1782
+
1783
+ // src/generators/class-schema.ts
1784
+ function generateClassSchemas(analysis, source) {
1785
+ const ir = canonicalizeTSDoc(analysis, source);
1786
+ return {
1787
+ jsonSchema: generateJsonSchemaFromIR(ir),
1788
+ uiSchema: generateUiSchemaFromIR(ir)
1789
+ };
1790
+ }
1791
+ function generateSchemasFromClass(options) {
1792
+ const ctx = createProgramContext(options.filePath);
1793
+ const classDecl = findClassByName(ctx.sourceFile, options.className);
1794
+ if (!classDecl) {
1795
+ throw new Error(`Class "${options.className}" not found in ${options.filePath}`);
1796
+ }
1797
+ const analysis = analyzeClassToIR(classDecl, ctx.checker, options.filePath);
1798
+ return generateClassSchemas(analysis, { file: options.filePath });
1799
+ }
1800
+ function generateSchemas(options) {
1801
+ const ctx = createProgramContext(options.filePath);
1802
+ const source = { file: options.filePath };
1803
+ const classDecl = findClassByName(ctx.sourceFile, options.typeName);
1804
+ if (classDecl) {
1805
+ const analysis = analyzeClassToIR(classDecl, ctx.checker, options.filePath);
1806
+ return generateClassSchemas(analysis, source);
1807
+ }
1808
+ const interfaceDecl = findInterfaceByName(ctx.sourceFile, options.typeName);
1809
+ if (interfaceDecl) {
1810
+ const analysis = analyzeInterfaceToIR(interfaceDecl, ctx.checker, options.filePath);
1811
+ return generateClassSchemas(analysis, source);
1812
+ }
1813
+ const typeAlias = findTypeAliasByName(ctx.sourceFile, options.typeName);
1814
+ if (typeAlias) {
1815
+ const result = analyzeTypeAliasToIR(typeAlias, ctx.checker, options.filePath);
1816
+ if (result.ok) {
1817
+ return generateClassSchemas(result.analysis, source);
1818
+ }
1819
+ throw new Error(result.error);
1820
+ }
1821
+ throw new Error(
1822
+ `Type "${options.typeName}" not found as a class, interface, or type alias in ${options.filePath}`
1823
+ );
1824
+ }
1825
+ var init_class_schema = __esm({
1826
+ "src/generators/class-schema.ts"() {
1827
+ "use strict";
1828
+ init_program();
1829
+ init_class_analyzer();
1830
+ init_canonicalize();
1831
+ init_ir_generator();
1832
+ init_ir_generator2();
1833
+ }
1834
+ });
1835
+
1836
+ // src/index.ts
1837
+ var index_exports = {};
1838
+ __export(index_exports, {
1839
+ buildFormSchemas: () => buildFormSchemas,
1840
+ categorizationSchema: () => categorizationSchema,
1841
+ categorySchema: () => categorySchema,
1842
+ controlSchema: () => controlSchema,
1843
+ generateJsonSchema: () => generateJsonSchema,
1844
+ generateSchemas: () => generateSchemas,
1845
+ generateSchemasFromClass: () => generateSchemasFromClass,
1846
+ generateUiSchema: () => generateUiSchema,
1847
+ getSchemaExtension: () => getSchemaExtension,
1848
+ groupLayoutSchema: () => groupLayoutSchema,
1849
+ horizontalLayoutSchema: () => horizontalLayoutSchema,
1850
+ jsonSchema7Schema: () => jsonSchema7Schema,
1851
+ jsonSchemaTypeSchema: () => jsonSchemaTypeSchema,
1852
+ labelElementSchema: () => labelElementSchema,
1853
+ ruleConditionSchema: () => ruleConditionSchema,
1854
+ ruleEffectSchema: () => ruleEffectSchema,
1855
+ ruleSchema: () => ruleSchema,
1856
+ schemaBasedConditionSchema: () => schemaBasedConditionSchema,
1857
+ setSchemaExtension: () => setSchemaExtension,
1858
+ uiSchemaElementSchema: () => uiSchemaElementSchema,
1859
+ uiSchemaElementTypeSchema: () => uiSchemaElementTypeSchema,
1860
+ uiSchemaSchema: () => uiSchema,
1861
+ verticalLayoutSchema: () => verticalLayoutSchema,
1862
+ writeSchemas: () => writeSchemas
1863
+ });
1864
+ import * as fs from "fs";
1865
+ import * as path2 from "path";
1866
+ function buildFormSchemas(form) {
1867
+ return {
1868
+ jsonSchema: generateJsonSchema(form),
1869
+ uiSchema: generateUiSchema(form)
1870
+ };
1871
+ }
1872
+ function writeSchemas(form, options) {
1873
+ const { outDir, name = "schema", indent = 2 } = options;
1874
+ const { jsonSchema, uiSchema: uiSchema2 } = buildFormSchemas(form);
1875
+ if (!fs.existsSync(outDir)) {
1876
+ fs.mkdirSync(outDir, { recursive: true });
1877
+ }
1878
+ const jsonSchemaPath = path2.join(outDir, `${name}-schema.json`);
1879
+ const uiSchemaPath = path2.join(outDir, `${name}-uischema.json`);
1880
+ fs.writeFileSync(jsonSchemaPath, JSON.stringify(jsonSchema, null, indent));
1881
+ fs.writeFileSync(uiSchemaPath, JSON.stringify(uiSchema2, null, indent));
1882
+ return { jsonSchemaPath, uiSchemaPath };
1883
+ }
1884
+ var init_index = __esm({
1885
+ "src/index.ts"() {
1886
+ "use strict";
1887
+ init_generator();
1888
+ init_generator2();
1889
+ init_types();
1890
+ init_schema();
1891
+ init_schema2();
1892
+ init_generator();
1893
+ init_generator2();
1894
+ init_class_schema();
1895
+ }
1896
+ });
1897
+
1898
+ // src/cli.ts
1899
+ import * as path3 from "path";
1900
+ import { pathToFileURL } from "url";
18
1901
  function printHelp() {
19
- console.log(`
1902
+ console.log(`
20
1903
  FormSpec Build CLI - Generate JSON Schema and UI Schema
21
1904
 
22
1905
  Usage:
@@ -38,99 +1921,93 @@ The input file should export a FormSpec as its default export or as 'form':
38
1921
  `);
39
1922
  }
40
1923
  function parseArgs(args) {
41
- const positional = [];
42
- let outDir = "./generated";
43
- let name = "";
44
- for (let i = 0; i < args.length; i++) {
45
- const arg = args[i];
46
- if (arg === undefined)
47
- continue;
48
- if (arg === "-h" || arg === "--help") {
49
- printHelp();
50
- process.exit(0);
51
- }
52
- if (arg === "-o" || arg === "--out-dir") {
53
- const nextArg = args[i + 1];
54
- if (!nextArg) {
55
- console.error("Error: --out-dir requires a value");
56
- return null;
57
- }
58
- outDir = nextArg;
59
- i++;
60
- continue;
61
- }
62
- if (arg === "-n" || arg === "--name") {
63
- const nextArg = args[i + 1];
64
- if (!nextArg) {
65
- console.error("Error: --name requires a value");
66
- return null;
67
- }
68
- name = nextArg;
69
- i++;
70
- continue;
71
- }
72
- if (arg.startsWith("-")) {
73
- console.error(`Error: Unknown option: ${arg}`);
74
- return null;
75
- }
76
- positional.push(arg);
1924
+ const positional = [];
1925
+ let outDir = "./generated";
1926
+ let name = "";
1927
+ for (let i = 0; i < args.length; i++) {
1928
+ const arg = args[i];
1929
+ if (arg === void 0) continue;
1930
+ if (arg === "-h" || arg === "--help") {
1931
+ printHelp();
1932
+ process.exit(0);
77
1933
  }
78
- if (positional.length === 0) {
79
- console.error("Error: No input file specified");
80
- printHelp();
1934
+ if (arg === "-o" || arg === "--out-dir") {
1935
+ const nextArg = args[i + 1];
1936
+ if (!nextArg) {
1937
+ console.error("Error: --out-dir requires a value");
81
1938
  return null;
1939
+ }
1940
+ outDir = nextArg;
1941
+ i++;
1942
+ continue;
82
1943
  }
83
- const inputFile = positional[0];
84
- if (!inputFile) {
85
- console.error("Error: No input file specified");
1944
+ if (arg === "-n" || arg === "--name") {
1945
+ const nextArg = args[i + 1];
1946
+ if (!nextArg) {
1947
+ console.error("Error: --name requires a value");
86
1948
  return null;
1949
+ }
1950
+ name = nextArg;
1951
+ i++;
1952
+ continue;
87
1953
  }
88
- // Default name from input file
89
- if (!name) {
90
- name = path.basename(inputFile, path.extname(inputFile));
1954
+ if (arg.startsWith("-")) {
1955
+ console.error(`Error: Unknown option: ${arg}`);
1956
+ return null;
91
1957
  }
92
- return { inputFile, outDir, name };
1958
+ positional.push(arg);
1959
+ }
1960
+ if (positional.length === 0) {
1961
+ console.error("Error: No input file specified");
1962
+ printHelp();
1963
+ return null;
1964
+ }
1965
+ const inputFile = positional[0];
1966
+ if (!inputFile) {
1967
+ console.error("Error: No input file specified");
1968
+ return null;
1969
+ }
1970
+ if (!name) {
1971
+ name = path3.basename(inputFile, path3.extname(inputFile));
1972
+ }
1973
+ return { inputFile, outDir, name };
93
1974
  }
94
1975
  async function main() {
95
- const args = process.argv.slice(2);
96
- const options = parseArgs(args);
97
- if (!options) {
98
- process.exit(1);
99
- }
100
- const { inputFile, outDir, name } = options;
101
- // Resolve input file path
102
- const absoluteInput = path.resolve(process.cwd(), inputFile);
103
- try {
104
- // Dynamically import the input file
105
- // Use file URL for cross-platform compatibility (Windows paths need file:// URLs)
106
- const fileUrl = pathToFileURL(absoluteInput).href;
107
- const module = (await import(fileUrl));
108
- // Look for the form export
109
- const form = module["default"] ?? module["form"];
110
- if (!form || typeof form !== "object" || !("elements" in form)) {
111
- console.error("Error: Input file must export a FormSpec as default export or as 'form'");
112
- console.error("Example:");
113
- console.error(' export default formspec(field.text("name"));');
114
- console.error(" // or");
115
- console.error(' export const form = formspec(field.text("name"));');
116
- process.exit(1);
117
- }
118
- // Import writeSchemas dynamically to avoid circular deps
119
- const { writeSchemas } = await import("./index.js");
120
- const { jsonSchemaPath, uiSchemaPath } = writeSchemas(form, { outDir, name });
121
- console.log("Generated:");
122
- console.log(` ${jsonSchemaPath}`);
123
- console.log(` ${uiSchemaPath}`);
124
- }
125
- catch (error) {
126
- if (error instanceof Error) {
127
- console.error(`Error: ${error.message}`);
128
- }
129
- else {
130
- console.error("Error:", error);
131
- }
132
- process.exit(1);
1976
+ const args = process.argv.slice(2);
1977
+ const options = parseArgs(args);
1978
+ if (!options) {
1979
+ process.exit(1);
1980
+ }
1981
+ const { inputFile, outDir, name } = options;
1982
+ const absoluteInput = path3.resolve(process.cwd(), inputFile);
1983
+ try {
1984
+ const fileUrl = pathToFileURL(absoluteInput).href;
1985
+ const module = await import(fileUrl);
1986
+ const form = module["default"] ?? module["form"];
1987
+ if (!form || typeof form !== "object" || !("elements" in form)) {
1988
+ console.error("Error: Input file must export a FormSpec as default export or as 'form'");
1989
+ console.error("Example:");
1990
+ console.error(' export default formspec(field.text("name"));');
1991
+ console.error(" // or");
1992
+ console.error(' export const form = formspec(field.text("name"));');
1993
+ process.exit(1);
1994
+ }
1995
+ const { writeSchemas: writeSchemas2 } = await Promise.resolve().then(() => (init_index(), index_exports));
1996
+ const { jsonSchemaPath, uiSchemaPath } = writeSchemas2(
1997
+ form,
1998
+ { outDir, name }
1999
+ );
2000
+ console.log("Generated:");
2001
+ console.log(` ${jsonSchemaPath}`);
2002
+ console.log(` ${uiSchemaPath}`);
2003
+ } catch (error) {
2004
+ if (error instanceof Error) {
2005
+ console.error(`Error: ${error.message}`);
2006
+ } else {
2007
+ console.error("Error:", error);
133
2008
  }
2009
+ process.exit(1);
2010
+ }
134
2011
  }
135
2012
  void main();
136
2013
  //# sourceMappingURL=cli.js.map