@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
@@ -1,336 +0,0 @@
1
- /**
2
- * Decorator extractor for parsing decorator AST nodes.
3
- *
4
- * Extracts decorator names and arguments from class field decorators,
5
- * supporting the FormSpec decorator DSL (@Field, @Minimum, @Maximum, etc.).
6
- *
7
- * Also supports branded type resolution via the TypeScript type checker
8
- * to detect custom decorators created with `extendDecorator` and
9
- * `customDecorator` from `@formspec/decorators`.
10
- */
11
- import * as ts from "typescript";
12
- import {} from "@formspec/core";
13
- /**
14
- * Extracts decorators from a class member (property or method).
15
- *
16
- * @param member - The class member to extract decorators from
17
- * @returns Array of extracted decorator info
18
- */
19
- export function extractDecorators(member) {
20
- const decorators = [];
21
- // TC39 decorators are in the modifiers array
22
- const modifiers = ts.canHaveDecorators(member) ? ts.getDecorators(member) : undefined;
23
- if (!modifiers)
24
- return decorators;
25
- for (const decorator of modifiers) {
26
- const info = parseDecorator(decorator);
27
- if (info) {
28
- decorators.push(info);
29
- }
30
- }
31
- return decorators;
32
- }
33
- /**
34
- * Parses a single decorator node.
35
- */
36
- function parseDecorator(decorator) {
37
- const expr = decorator.expression;
38
- // Simple decorator: @Decorator
39
- if (ts.isIdentifier(expr)) {
40
- return {
41
- name: expr.text,
42
- args: [],
43
- node: decorator,
44
- };
45
- }
46
- // Call expression: @Decorator(args)
47
- if (ts.isCallExpression(expr)) {
48
- const callee = expr.expression;
49
- // Get decorator name
50
- let name = null;
51
- if (ts.isIdentifier(callee)) {
52
- name = callee.text;
53
- }
54
- else if (ts.isPropertyAccessExpression(callee)) {
55
- // For namespaced decorators like @formspec.Field()
56
- name = callee.name.text;
57
- }
58
- if (!name)
59
- return null;
60
- // Extract arguments
61
- const args = expr.arguments.map(extractArgValue);
62
- return {
63
- name,
64
- args,
65
- node: decorator,
66
- };
67
- }
68
- return null;
69
- }
70
- /**
71
- * Extracts the value from an expression node.
72
- * Supports literals, arrays, object literals, and RegExp.
73
- */
74
- function extractArgValue(node) {
75
- // String literal
76
- if (ts.isStringLiteral(node)) {
77
- return node.text;
78
- }
79
- // Numeric literal
80
- if (ts.isNumericLiteral(node)) {
81
- return Number(node.text);
82
- }
83
- // Boolean literals (true/false are identifiers in TS AST)
84
- if (node.kind === ts.SyntaxKind.TrueKeyword) {
85
- return true;
86
- }
87
- if (node.kind === ts.SyntaxKind.FalseKeyword) {
88
- return false;
89
- }
90
- // Null literal
91
- if (node.kind === ts.SyntaxKind.NullKeyword) {
92
- return null;
93
- }
94
- // Prefix unary expression (for negative numbers)
95
- if (ts.isPrefixUnaryExpression(node)) {
96
- if (node.operator === ts.SyntaxKind.MinusToken && ts.isNumericLiteral(node.operand)) {
97
- return -Number(node.operand.text);
98
- }
99
- if (node.operator === ts.SyntaxKind.PlusToken && ts.isNumericLiteral(node.operand)) {
100
- return Number(node.operand.text);
101
- }
102
- }
103
- // Array literal
104
- if (ts.isArrayLiteralExpression(node)) {
105
- return node.elements.map((el) => {
106
- if (ts.isSpreadElement(el)) {
107
- // Can't evaluate spread at compile time
108
- return null;
109
- }
110
- return extractArgValue(el);
111
- });
112
- }
113
- // Object literal
114
- if (ts.isObjectLiteralExpression(node)) {
115
- const obj = {};
116
- for (const prop of node.properties) {
117
- if (ts.isPropertyAssignment(prop)) {
118
- const key = getPropertyName(prop.name);
119
- if (key) {
120
- obj[key] = extractArgValue(prop.initializer);
121
- }
122
- }
123
- else if (ts.isShorthandPropertyAssignment(prop)) {
124
- // { foo } shorthand - we can't resolve the value
125
- const key = prop.name.text;
126
- obj[key] = null;
127
- }
128
- }
129
- return obj;
130
- }
131
- // Template literal (simple case)
132
- if (ts.isNoSubstitutionTemplateLiteral(node)) {
133
- return node.text;
134
- }
135
- // RegExp literal: extract the source pattern string
136
- if (ts.isRegularExpressionLiteral(node)) {
137
- const regexText = node.text;
138
- // RegExp literal format is /pattern/flags
139
- const lastSlash = regexText.lastIndexOf("/");
140
- if (lastSlash > 0) {
141
- return regexText.substring(1, lastSlash);
142
- }
143
- return regexText;
144
- }
145
- // new RegExp("pattern") — extract pattern from constructor call
146
- if (ts.isNewExpression(node)) {
147
- if (ts.isIdentifier(node.expression) &&
148
- node.expression.text === "RegExp" &&
149
- node.arguments &&
150
- node.arguments.length > 0) {
151
- const firstArg = node.arguments[0];
152
- if (firstArg && ts.isStringLiteral(firstArg)) {
153
- return firstArg.text;
154
- }
155
- }
156
- }
157
- // Identifier - could be an enum member or constant
158
- // We can't resolve it statically, return null
159
- if (ts.isIdentifier(node)) {
160
- return null;
161
- }
162
- // For other expressions, return null
163
- return null;
164
- }
165
- /**
166
- * Gets the property name from a property name node.
167
- */
168
- function getPropertyName(name) {
169
- if (ts.isIdentifier(name)) {
170
- return name.text;
171
- }
172
- if (ts.isStringLiteral(name)) {
173
- return name.text;
174
- }
175
- if (ts.isNumericLiteral(name)) {
176
- return name.text;
177
- }
178
- // Computed property names can't be resolved statically
179
- return null;
180
- }
181
- /**
182
- * Known FormSpec decorators and their expected argument types.
183
- *
184
- * This metadata object provides additional information about each decorator's
185
- * expected argument types. The keys are constrained to match FormSpecDecoratorName.
186
- */
187
- export const FORMSPEC_DECORATORS = {
188
- // Display metadata
189
- Field: { argTypes: ["object"] },
190
- // Grouping
191
- Group: { argTypes: ["string"] },
192
- // Conditional display
193
- ShowWhen: { argTypes: ["object"] },
194
- // Enum options
195
- EnumOptions: { argTypes: ["array"] },
196
- // Numeric constraints
197
- Minimum: { argTypes: ["number"] },
198
- Maximum: { argTypes: ["number"] },
199
- ExclusiveMinimum: { argTypes: ["number"] },
200
- ExclusiveMaximum: { argTypes: ["number"] },
201
- // String constraints
202
- MinLength: { argTypes: ["number"] },
203
- MaxLength: { argTypes: ["number"] },
204
- Pattern: { argTypes: ["string"] },
205
- };
206
- /**
207
- * Checks if a file path belongs to the @formspec/decorators package.
208
- *
209
- * Matches both installed node_modules paths and local monorepo paths.
210
- */
211
- function isFormSpecDecoratorsPath(fileName) {
212
- // Normalize separators for cross-platform matching
213
- const normalized = fileName.replace(/\\/g, "/");
214
- return (normalized.includes("node_modules/@formspec/decorators") ||
215
- normalized.includes("/packages/decorators/"));
216
- }
217
- /**
218
- * Resolves a decorator via the TypeScript type checker to determine
219
- * if it is a FormSpec decorator (built-in, extended, or custom).
220
- *
221
- * This enables detection of:
222
- * 1. Direct imports of built-in decorators from `@formspec/decorators`
223
- * 2. Extended decorators created via `extendDecorator(...).as(...)`
224
- * 3. Custom decorators created via `customDecorator(...).as(...)` or `.marker(...)`
225
- *
226
- * @param decorator - The decorator AST node
227
- * @param checker - TypeScript type checker
228
- * @returns Resolved decorator information, or null if not resolvable
229
- */
230
- export function resolveDecorator(decorator, checker) {
231
- const expr = decorator.expression;
232
- // Get the identifier to resolve
233
- let targetNode;
234
- let name;
235
- if (ts.isIdentifier(expr)) {
236
- // Simple marker decorator: @Decorator
237
- targetNode = expr;
238
- name = expr.text;
239
- }
240
- else if (ts.isCallExpression(expr)) {
241
- // Parameterized decorator: @Decorator(args)
242
- if (ts.isIdentifier(expr.expression)) {
243
- targetNode = expr.expression;
244
- name = expr.expression.text;
245
- }
246
- else {
247
- return null;
248
- }
249
- }
250
- else {
251
- return null;
252
- }
253
- // Check if it's a known built-in by name
254
- if (name in FORMSPEC_DECORATORS) {
255
- // Verify it actually comes from @formspec/decorators by checking the symbol
256
- const symbol = checker.getSymbolAtLocation(targetNode);
257
- if (symbol) {
258
- const declarations = symbol.declarations;
259
- if (declarations && declarations.length > 0) {
260
- const decl = declarations[0];
261
- if (decl) {
262
- const sourceFile = decl.getSourceFile();
263
- const fileName = sourceFile.fileName;
264
- if (isFormSpecDecoratorsPath(fileName)) {
265
- return {
266
- name,
267
- isFormSpec: true,
268
- isMarker: !ts.isCallExpression(expr),
269
- };
270
- }
271
- }
272
- }
273
- }
274
- }
275
- // Try to resolve branded types for custom/extended decorators
276
- const resolvedSymbol = checker.getSymbolAtLocation(targetNode);
277
- if (!resolvedSymbol)
278
- return null;
279
- const type = checker.getTypeOfSymbol(resolvedSymbol);
280
- const props = type.getProperties();
281
- let extendsBuiltin;
282
- let extensionName;
283
- let isMarker = false;
284
- for (const prop of props) {
285
- // __String is a branded string type; cast is safe for read-only string operations
286
- const escapedName = prop.getEscapedName();
287
- // TypeScript represents unique symbol properties as __@<name>@<uniqueId>
288
- // in escaped names. The <name> portion may be either the Symbol description
289
- // (e.g., "formspec.extends") or the const variable name (e.g., "FORMSPEC_EXTENDS"),
290
- // depending on how the symbol is declared and resolved by the type checker.
291
- // We check for both patterns to handle all cases.
292
- if (escapedName.startsWith("__@") &&
293
- (escapedName.includes("formspec.extends") || escapedName.includes("FORMSPEC_EXTENDS"))) {
294
- const propType = checker.getTypeOfSymbol(prop);
295
- if (propType.isStringLiteral()) {
296
- extendsBuiltin = propType.value;
297
- }
298
- }
299
- if (escapedName.startsWith("__@") &&
300
- (escapedName.includes("formspec.extension") || escapedName.includes("FORMSPEC_EXTENSION"))) {
301
- const propType = checker.getTypeOfSymbol(prop);
302
- if (propType.isStringLiteral()) {
303
- extensionName = propType.value;
304
- }
305
- }
306
- if (escapedName.startsWith("__@") &&
307
- (escapedName.includes("formspec.marker") || escapedName.includes("FORMSPEC_MARKER"))) {
308
- isMarker = true;
309
- }
310
- }
311
- if (extendsBuiltin) {
312
- return {
313
- name,
314
- extendsBuiltin,
315
- isFormSpec: true,
316
- isMarker: false,
317
- };
318
- }
319
- if (extensionName) {
320
- return {
321
- name,
322
- extensionName,
323
- isFormSpec: true,
324
- isMarker,
325
- };
326
- }
327
- if (isMarker) {
328
- return {
329
- name,
330
- isFormSpec: true,
331
- isMarker: true,
332
- };
333
- }
334
- return null;
335
- }
336
- //# sourceMappingURL=decorator-extractor.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"decorator-extractor.js","sourceRoot":"","sources":["../../src/analyzer/decorator-extractor.ts"],"names":[],"mappings":"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"}
@@ -1,153 +0,0 @@
1
- /**
2
- * JSDoc constraint tag extractor.
3
- *
4
- * Extracts constraint tags from JSDoc comments on class fields and returns
5
- * synthetic {@link DecoratorInfo} objects that integrate seamlessly with
6
- * the existing decorator-based constraint pipeline.
7
- *
8
- * Supported tags correspond to keys in {@link CONSTRAINT_TAG_DEFINITIONS}
9
- * from `@formspec/core` (e.g., `@Minimum`, `@Maximum`, `@Pattern`).
10
- */
11
- import * as ts from "typescript";
12
- import { CONSTRAINT_TAG_DEFINITIONS } from "@formspec/core";
13
- /**
14
- * Extracts JSDoc constraint tags from a TypeScript AST node and returns
15
- * synthetic {@link DecoratorInfo} objects.
16
- *
17
- * For each recognised tag (case-sensitive PascalCase match against
18
- * {@link CONSTRAINT_TAG_DEFINITIONS}), the comment text is parsed
19
- * according to the tag's declared value type:
20
- * - `"number"` tags: parsed via `Number()` — skipped when NaN
21
- * - `"string"` tags (`Pattern`): used as-is (trimmed)
22
- *
23
- * @param node - The AST node to inspect for JSDoc tags
24
- * @returns Synthetic decorator info objects for each valid constraint tag
25
- */
26
- export function extractJSDocConstraints(node) {
27
- const results = [];
28
- const jsDocTags = ts.getJSDocTags(node);
29
- for (const tag of jsDocTags) {
30
- const tagName = tag.tagName.text;
31
- // Case-sensitive check against known constraint tags
32
- if (!(tagName in CONSTRAINT_TAG_DEFINITIONS)) {
33
- continue;
34
- }
35
- const constraintName = tagName;
36
- const expectedType = CONSTRAINT_TAG_DEFINITIONS[constraintName];
37
- // Extract comment text — can be string, NodeArray<JSDocComment>, or undefined
38
- const commentText = getTagCommentText(tag);
39
- if (commentText === undefined || commentText === "") {
40
- continue;
41
- }
42
- const trimmed = commentText.trim();
43
- if (trimmed === "") {
44
- continue;
45
- }
46
- if (expectedType === "number") {
47
- const value = Number(trimmed);
48
- if (Number.isNaN(value)) {
49
- continue;
50
- }
51
- results.push(createSyntheticDecorator(constraintName, value));
52
- }
53
- else if (expectedType === "json") {
54
- // JSON type (EnumOptions) — parse inline JSON array only.
55
- // Downstream UI schema generation expects an array of options.
56
- try {
57
- const parsed = JSON.parse(trimmed);
58
- if (!Array.isArray(parsed)) {
59
- continue;
60
- }
61
- results.push(createSyntheticDecorator(constraintName, parsed));
62
- }
63
- catch {
64
- // Skip malformed JSON
65
- continue;
66
- }
67
- }
68
- else {
69
- // "string" type (Pattern)
70
- results.push(createSyntheticDecorator(constraintName, trimmed));
71
- }
72
- }
73
- return results;
74
- }
75
- /**
76
- * Extracts `@Field_displayName` and `@Field_description` TSDoc tags from
77
- * a node and returns a synthetic `Field` {@link DecoratorInfo} if either
78
- * is present.
79
- *
80
- * This enables interface properties to carry display metadata via TSDoc
81
- * tags instead of the `@Field` decorator (which requires a class):
82
- *
83
- * ```typescript
84
- * interface Config {
85
- * // @Field_displayName Program Name
86
- * // @Field_description Internal identifier
87
- * programName: string;
88
- * }
89
- * ```
90
- *
91
- * @param node - The AST node to inspect for display metadata tags
92
- * @returns A synthetic `Field` decorator info, or null if no tags found
93
- */
94
- export function extractJSDocFieldMetadata(node) {
95
- const jsDocTags = ts.getJSDocTags(node);
96
- let displayName;
97
- let description;
98
- for (const tag of jsDocTags) {
99
- const tagName = tag.tagName.text;
100
- const commentText = getTagCommentText(tag);
101
- if (commentText === undefined || commentText.trim() === "") {
102
- continue;
103
- }
104
- const trimmed = commentText.trim();
105
- if (tagName === "Field_displayName") {
106
- displayName = trimmed;
107
- }
108
- else if (tagName === "Field_description") {
109
- description = trimmed;
110
- }
111
- }
112
- if (displayName === undefined && description === undefined) {
113
- return null;
114
- }
115
- // Build the FieldOptions-shaped arg object
116
- const fieldOpts = {
117
- ...(displayName !== undefined ? { displayName } : {}),
118
- ...(description !== undefined ? { description } : {}),
119
- };
120
- return createSyntheticDecorator("Field", fieldOpts);
121
- }
122
- /**
123
- * Extracts the text content from a JSDoc tag's comment.
124
- *
125
- * The `tag.comment` property can be a plain string, an array of
126
- * `JSDocComment` nodes, or undefined. This helper normalises all
127
- * three cases to a single `string | undefined`.
128
- */
129
- function getTagCommentText(tag) {
130
- if (tag.comment === undefined) {
131
- return undefined;
132
- }
133
- if (typeof tag.comment === "string") {
134
- return tag.comment;
135
- }
136
- // NodeArray<JSDocComment> — concatenate text spans
137
- return ts.getTextOfJSDocComment(tag.comment);
138
- }
139
- /**
140
- * Creates a synthetic {@link DecoratorInfo} for a JSDoc constraint tag.
141
- *
142
- * The `node` field is `undefined` because JSDoc constraints have no
143
- * decorator AST node. Downstream constraint processing only uses
144
- * the `name` and `args` fields.
145
- */
146
- function createSyntheticDecorator(name, value) {
147
- return {
148
- name,
149
- args: [value],
150
- node: undefined,
151
- };
152
- }
153
- //# sourceMappingURL=jsdoc-constraints.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"jsdoc-constraints.js","sourceRoot":"","sources":["../../src/analyzer/jsdoc-constraints.ts"],"names":[],"mappings":"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"}
@@ -1,114 +0,0 @@
1
- /**
2
- * TypeScript program setup for static analysis.
3
- *
4
- * Creates a TypeScript program with type checker from a source file,
5
- * using the project's tsconfig.json for compiler options.
6
- */
7
- import * as ts from "typescript";
8
- import * as path from "node:path";
9
- /**
10
- * Creates a TypeScript program for analyzing a source file.
11
- *
12
- * Looks for tsconfig.json in the file's directory or parent directories.
13
- * Falls back to default compiler options if no config is found.
14
- *
15
- * @param filePath - Absolute path to the TypeScript source file
16
- * @returns Program context with checker and source file
17
- */
18
- export function createProgramContext(filePath) {
19
- const absolutePath = path.resolve(filePath);
20
- const fileDir = path.dirname(absolutePath);
21
- // Find tsconfig.json - using ts.sys.fileExists which has `this: void` requirement
22
- const configPath = ts.findConfigFile(fileDir, ts.sys.fileExists.bind(ts.sys), "tsconfig.json");
23
- let compilerOptions;
24
- let fileNames;
25
- if (configPath) {
26
- const configFile = ts.readConfigFile(configPath, ts.sys.readFile.bind(ts.sys));
27
- if (configFile.error) {
28
- throw new Error(`Error reading tsconfig.json: ${ts.flattenDiagnosticMessageText(configFile.error.messageText, "\n")}`);
29
- }
30
- const parsed = ts.parseJsonConfigFileContent(configFile.config, ts.sys, path.dirname(configPath));
31
- if (parsed.errors.length > 0) {
32
- const errorMessages = parsed.errors
33
- .map((e) => ts.flattenDiagnosticMessageText(e.messageText, "\n"))
34
- .join("\n");
35
- throw new Error(`Error parsing tsconfig.json: ${errorMessages}`);
36
- }
37
- compilerOptions = parsed.options;
38
- // Include the target file in the program
39
- fileNames = parsed.fileNames.includes(absolutePath)
40
- ? parsed.fileNames
41
- : [...parsed.fileNames, absolutePath];
42
- }
43
- else {
44
- // Fallback to default options
45
- compilerOptions = {
46
- target: ts.ScriptTarget.ES2022,
47
- module: ts.ModuleKind.NodeNext,
48
- moduleResolution: ts.ModuleResolutionKind.NodeNext,
49
- strict: true,
50
- skipLibCheck: true,
51
- declaration: true,
52
- };
53
- fileNames = [absolutePath];
54
- }
55
- const program = ts.createProgram(fileNames, compilerOptions);
56
- const sourceFile = program.getSourceFile(absolutePath);
57
- if (!sourceFile) {
58
- throw new Error(`Could not find source file: ${absolutePath}`);
59
- }
60
- return {
61
- program,
62
- checker: program.getTypeChecker(),
63
- sourceFile,
64
- };
65
- }
66
- /**
67
- * Generic AST node finder by name. Walks the source file tree and returns
68
- * the first node matching the predicate with the given name.
69
- */
70
- function findNodeByName(sourceFile, name, predicate, getName) {
71
- let result = null;
72
- function visit(node) {
73
- if (result)
74
- return;
75
- if (predicate(node) && getName(node) === name) {
76
- result = node;
77
- return;
78
- }
79
- ts.forEachChild(node, visit);
80
- }
81
- visit(sourceFile);
82
- return result;
83
- }
84
- /**
85
- * Finds a class declaration by name in a source file.
86
- *
87
- * @param sourceFile - The source file to search
88
- * @param className - Name of the class to find
89
- * @returns The class declaration node, or null if not found
90
- */
91
- export function findClassByName(sourceFile, className) {
92
- return findNodeByName(sourceFile, className, ts.isClassDeclaration, (n) => n.name?.text);
93
- }
94
- /**
95
- * Finds an interface declaration by name in a source file.
96
- *
97
- * @param sourceFile - The source file to search
98
- * @param interfaceName - Name of the interface to find
99
- * @returns The interface declaration node, or null if not found
100
- */
101
- export function findInterfaceByName(sourceFile, interfaceName) {
102
- return findNodeByName(sourceFile, interfaceName, ts.isInterfaceDeclaration, (n) => n.name.text);
103
- }
104
- /**
105
- * Finds a type alias declaration by name in a source file.
106
- *
107
- * @param sourceFile - The source file to search
108
- * @param aliasName - Name of the type alias to find
109
- * @returns The type alias declaration node, or null if not found
110
- */
111
- export function findTypeAliasByName(sourceFile, aliasName) {
112
- return findNodeByName(sourceFile, aliasName, ts.isTypeAliasDeclaration, (n) => n.name.text);
113
- }
114
- //# sourceMappingURL=program.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"program.js","sourceRoot":"","sources":["../../src/analyzer/program.ts"],"names":[],"mappings":"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"}