@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,465 +0,0 @@
1
- /**
2
- * Unit tests for JSDoc constraint tag extraction.
3
- *
4
- * Verifies that {@link extractJSDocConstraints} correctly parses TSDoc
5
- * constraint tags into synthetic DecoratorInfo objects.
6
- *
7
- * @see packages/core/src/types/decorators.ts for CONSTRAINT_TAG_DEFINITIONS
8
- */
9
- import { describe, it, expect } from "vitest";
10
- import * as ts from "typescript";
11
- import { extractJSDocConstraints, extractJSDocFieldMetadata, } from "../analyzer/jsdoc-constraints.js";
12
- /**
13
- * Helper: creates an in-memory TypeScript source file and returns the
14
- * first property declaration found in the first class.
15
- */
16
- function getPropertyFromSource(source) {
17
- const sourceFile = ts.createSourceFile("test.ts", source, ts.ScriptTarget.Latest, true);
18
- for (const stmt of sourceFile.statements) {
19
- if (ts.isClassDeclaration(stmt)) {
20
- for (const member of stmt.members) {
21
- if (ts.isPropertyDeclaration(member)) {
22
- return member;
23
- }
24
- }
25
- }
26
- }
27
- throw new Error("No property declaration found in source");
28
- }
29
- /**
30
- * Helper: creates an in-memory TypeScript source file and returns the
31
- * first property signature found in the first interface.
32
- */
33
- function getInterfacePropertyFromSource(source) {
34
- const sourceFile = ts.createSourceFile("test.ts", source, ts.ScriptTarget.Latest, true);
35
- for (const stmt of sourceFile.statements) {
36
- if (ts.isInterfaceDeclaration(stmt)) {
37
- for (const member of stmt.members) {
38
- if (ts.isPropertySignature(member)) {
39
- return member;
40
- }
41
- }
42
- }
43
- }
44
- throw new Error("No property signature found in source");
45
- }
46
- describe("extractJSDocConstraints", () => {
47
- it("parses @Minimum with an integer value", () => {
48
- const prop = getPropertyFromSource(`
49
- class Foo {
50
- /** @Minimum 34 */
51
- x!: number;
52
- }
53
- `);
54
- const result = extractJSDocConstraints(prop);
55
- expect(result).toHaveLength(1);
56
- expect(result[0]).toMatchObject({ name: "Minimum", args: [34] });
57
- });
58
- it("parses @Maximum with an integer value", () => {
59
- const prop = getPropertyFromSource(`
60
- class Foo {
61
- /** @Maximum 100 */
62
- x!: number;
63
- }
64
- `);
65
- const result = extractJSDocConstraints(prop);
66
- expect(result).toHaveLength(1);
67
- expect(result[0]).toMatchObject({ name: "Maximum", args: [100] });
68
- });
69
- it("parses @Pattern as a string value", () => {
70
- const prop = getPropertyFromSource(`
71
- class Foo {
72
- /** @Pattern ^[a-z]+$ */
73
- x!: string;
74
- }
75
- `);
76
- const result = extractJSDocConstraints(prop);
77
- expect(result).toHaveLength(1);
78
- expect(result[0]).toMatchObject({ name: "Pattern", args: ["^[a-z]+$"] });
79
- });
80
- it("handles negative numbers", () => {
81
- const prop = getPropertyFromSource(`
82
- class Foo {
83
- /** @Minimum -10 */
84
- x!: number;
85
- }
86
- `);
87
- const result = extractJSDocConstraints(prop);
88
- expect(result).toHaveLength(1);
89
- expect(result[0]).toMatchObject({ name: "Minimum", args: [-10] });
90
- });
91
- it("handles decimal numbers", () => {
92
- const prop = getPropertyFromSource(`
93
- class Foo {
94
- /** @Maximum 3.14 */
95
- x!: number;
96
- }
97
- `);
98
- const result = extractJSDocConstraints(prop);
99
- expect(result).toHaveLength(1);
100
- expect(result[0]).toMatchObject({ name: "Maximum", args: [3.14] });
101
- });
102
- it("handles negative decimal numbers", () => {
103
- const prop = getPropertyFromSource(`
104
- class Foo {
105
- /** @Minimum -273.15 */
106
- x!: number;
107
- }
108
- `);
109
- const result = extractJSDocConstraints(prop);
110
- expect(result).toHaveLength(1);
111
- expect(result[0]).toMatchObject({ name: "Minimum", args: [-273.15] });
112
- });
113
- it("ignores non-constraint tags like @deprecated and @param", () => {
114
- const prop = getPropertyFromSource(`
115
- class Foo {
116
- /** @deprecated Use something else @param foo */
117
- x!: number;
118
- }
119
- `);
120
- const result = extractJSDocConstraints(prop);
121
- expect(result).toHaveLength(0);
122
- });
123
- it("skips tags with malformed numeric values", () => {
124
- const prop = getPropertyFromSource(`
125
- class Foo {
126
- /** @Minimum abc */
127
- x!: number;
128
- }
129
- `);
130
- const result = extractJSDocConstraints(prop);
131
- expect(result).toHaveLength(0);
132
- });
133
- it("skips tags with empty values", () => {
134
- const prop = getPropertyFromSource(`
135
- class Foo {
136
- /** @Minimum */
137
- x!: number;
138
- }
139
- `);
140
- const result = extractJSDocConstraints(prop);
141
- expect(result).toHaveLength(0);
142
- });
143
- it("extracts multiple constraint tags from one comment", () => {
144
- const prop = getPropertyFromSource(`
145
- class Foo {
146
- /** @Minimum 0 @Maximum 100 */
147
- x!: number;
148
- }
149
- `);
150
- const result = extractJSDocConstraints(prop);
151
- expect(result).toHaveLength(2);
152
- expect(result[0]).toMatchObject({ name: "Minimum", args: [0] });
153
- expect(result[1]).toMatchObject({ name: "Maximum", args: [100] });
154
- });
155
- it("is case-sensitive: ignores lowercase @minimum", () => {
156
- const prop = getPropertyFromSource(`
157
- class Foo {
158
- /** @minimum 5 */
159
- x!: number;
160
- }
161
- `);
162
- const result = extractJSDocConstraints(prop);
163
- expect(result).toHaveLength(0);
164
- });
165
- it("parses all supported numeric tags", () => {
166
- const prop = getPropertyFromSource(`
167
- class Foo {
168
- /** @Minimum 1 @Maximum 10 @ExclusiveMinimum 0 @ExclusiveMaximum 11 @MinLength 2 @MaxLength 8 */
169
- x!: number;
170
- }
171
- `);
172
- const result = extractJSDocConstraints(prop);
173
- expect(result).toHaveLength(6);
174
- expect(result.map((d) => d.name)).toEqual([
175
- "Minimum",
176
- "Maximum",
177
- "ExclusiveMinimum",
178
- "ExclusiveMaximum",
179
- "MinLength",
180
- "MaxLength",
181
- ]);
182
- });
183
- it("returns an empty array for a node with no JSDoc", () => {
184
- const prop = getPropertyFromSource(`
185
- class Foo {
186
- x!: number;
187
- }
188
- `);
189
- const result = extractJSDocConstraints(prop);
190
- expect(result).toHaveLength(0);
191
- });
192
- it("sets node to undefined (cast) on synthetic decorators", () => {
193
- const prop = getPropertyFromSource(`
194
- class Foo {
195
- /** @Minimum 5 */
196
- x!: number;
197
- }
198
- `);
199
- const result = extractJSDocConstraints(prop);
200
- expect(result).toHaveLength(1);
201
- // The node field is undefined cast as ts.Decorator
202
- expect(result[0]?.node).toBeUndefined();
203
- });
204
- it("handles zero as a valid numeric value", () => {
205
- const prop = getPropertyFromSource(`
206
- class Foo {
207
- /** @Minimum 0 */
208
- x!: number;
209
- }
210
- `);
211
- const result = extractJSDocConstraints(prop);
212
- expect(result).toHaveLength(1);
213
- expect(result[0]).toMatchObject({ name: "Minimum", args: [0] });
214
- });
215
- });
216
- // ============================================================================
217
- // @EnumOptions JSON parsing
218
- // ============================================================================
219
- describe("@EnumOptions JSON parsing", () => {
220
- it("parses a valid JSON string array", () => {
221
- const prop = getPropertyFromSource(`
222
- class Foo {
223
- /** @EnumOptions ["a","b","c"] */
224
- x!: string;
225
- }
226
- `);
227
- const result = extractJSDocConstraints(prop);
228
- expect(result).toHaveLength(1);
229
- expect(result[0]).toMatchObject({ name: "EnumOptions", args: [["a", "b", "c"]] });
230
- });
231
- it("parses a valid JSON object array (labeled options)", () => {
232
- const prop = getPropertyFromSource(`
233
- class Foo {
234
- /** @EnumOptions [{"id":"low","label":"Low"},{"id":"high","label":"High"}] */
235
- x!: string;
236
- }
237
- `);
238
- const result = extractJSDocConstraints(prop);
239
- expect(result).toHaveLength(1);
240
- expect(result[0]).toMatchObject({
241
- name: "EnumOptions",
242
- args: [
243
- [
244
- { id: "low", label: "Low" },
245
- { id: "high", label: "High" },
246
- ],
247
- ],
248
- });
249
- });
250
- it("skips a JSON record (only arrays are accepted)", () => {
251
- const prop = getPropertyFromSource(`
252
- class Foo {
253
- /** @EnumOptions {"a":"Label A","b":"Label B"} */
254
- x!: string;
255
- }
256
- `);
257
- const result = extractJSDocConstraints(prop);
258
- expect(result).toHaveLength(0);
259
- });
260
- it("accepts an empty JSON array", () => {
261
- const prop = getPropertyFromSource(`
262
- class Foo {
263
- /** @EnumOptions [] */
264
- x!: string;
265
- }
266
- `);
267
- const result = extractJSDocConstraints(prop);
268
- expect(result).toHaveLength(1);
269
- expect(result[0]).toMatchObject({ name: "EnumOptions", args: [[]] });
270
- });
271
- it("skips an empty JSON object", () => {
272
- const prop = getPropertyFromSource(`
273
- class Foo {
274
- /** @EnumOptions {} */
275
- x!: string;
276
- }
277
- `);
278
- const result = extractJSDocConstraints(prop);
279
- expect(result).toHaveLength(0);
280
- });
281
- it("skips malformed JSON syntax", () => {
282
- const prop = getPropertyFromSource(`
283
- class Foo {
284
- /** @EnumOptions ["unclosed */
285
- x!: string;
286
- }
287
- `);
288
- const result = extractJSDocConstraints(prop);
289
- expect(result).toHaveLength(0);
290
- });
291
- it("skips JSON with trailing comma", () => {
292
- const prop = getPropertyFromSource(`
293
- class Foo {
294
- /** @EnumOptions ["a","b",] */
295
- x!: string;
296
- }
297
- `);
298
- // JSON.parse rejects trailing commas
299
- const result = extractJSDocConstraints(prop);
300
- expect(result).toHaveLength(0);
301
- });
302
- it("skips JSON string primitive", () => {
303
- const prop = getPropertyFromSource(`
304
- class Foo {
305
- /** @EnumOptions "not-an-array" */
306
- x!: string;
307
- }
308
- `);
309
- const result = extractJSDocConstraints(prop);
310
- expect(result).toHaveLength(0);
311
- });
312
- it("skips JSON number primitive", () => {
313
- const prop = getPropertyFromSource(`
314
- class Foo {
315
- /** @EnumOptions 42 */
316
- x!: string;
317
- }
318
- `);
319
- const result = extractJSDocConstraints(prop);
320
- expect(result).toHaveLength(0);
321
- });
322
- it("skips JSON boolean primitive", () => {
323
- const prop = getPropertyFromSource(`
324
- class Foo {
325
- /** @EnumOptions true */
326
- x!: string;
327
- }
328
- `);
329
- const result = extractJSDocConstraints(prop);
330
- expect(result).toHaveLength(0);
331
- });
332
- it("skips JSON null", () => {
333
- const prop = getPropertyFromSource(`
334
- class Foo {
335
- /** @EnumOptions null */
336
- x!: string;
337
- }
338
- `);
339
- const result = extractJSDocConstraints(prop);
340
- expect(result).toHaveLength(0);
341
- });
342
- it("coexists with other constraint tags", () => {
343
- const prop = getPropertyFromSource(`
344
- class Foo {
345
- /** @EnumOptions ["a","b"] @MinLength 1 */
346
- x!: string;
347
- }
348
- `);
349
- const result = extractJSDocConstraints(prop);
350
- expect(result).toHaveLength(2);
351
- expect(result.find((d) => d.name === "EnumOptions")).toMatchObject({
352
- args: [["a", "b"]],
353
- });
354
- expect(result.find((d) => d.name === "MinLength")).toMatchObject({
355
- args: [1],
356
- });
357
- });
358
- });
359
- // ============================================================================
360
- // extractJSDocFieldMetadata
361
- // ============================================================================
362
- describe("extractJSDocFieldMetadata", () => {
363
- it("extracts @Field_displayName", () => {
364
- const prop = getInterfacePropertyFromSource(`
365
- interface Foo {
366
- /** @Field_displayName Full Name */
367
- name: string;
368
- }
369
- `);
370
- const result = extractJSDocFieldMetadata(prop);
371
- expect(result).not.toBeNull();
372
- expect(result).toMatchObject({
373
- name: "Field",
374
- args: [{ displayName: "Full Name" }],
375
- });
376
- });
377
- it("extracts @Field_description", () => {
378
- const prop = getInterfacePropertyFromSource(`
379
- interface Foo {
380
- /** @Field_description Help text for this field */
381
- name: string;
382
- }
383
- `);
384
- const result = extractJSDocFieldMetadata(prop);
385
- expect(result).not.toBeNull();
386
- expect(result).toMatchObject({
387
- name: "Field",
388
- args: [{ description: "Help text for this field" }],
389
- });
390
- // Should not have displayName when only description is present
391
- const opts = result?.args[0];
392
- expect(opts["displayName"]).toBeUndefined();
393
- });
394
- it("extracts both @Field_displayName and @Field_description", () => {
395
- const prop = getInterfacePropertyFromSource(`
396
- interface Foo {
397
- /**
398
- * @Field_displayName Full Name
399
- * @Field_description The user's legal name
400
- */
401
- name: string;
402
- }
403
- `);
404
- const result = extractJSDocFieldMetadata(prop);
405
- expect(result).not.toBeNull();
406
- expect(result).toMatchObject({
407
- name: "Field",
408
- args: [{ displayName: "Full Name", description: "The user's legal name" }],
409
- });
410
- });
411
- it("returns null when no metadata tags are present", () => {
412
- const prop = getInterfacePropertyFromSource(`
413
- interface Foo {
414
- /** @Minimum 0 */
415
- x: number;
416
- }
417
- `);
418
- const result = extractJSDocFieldMetadata(prop);
419
- expect(result).toBeNull();
420
- });
421
- it("returns null when no JSDoc comment exists", () => {
422
- const prop = getInterfacePropertyFromSource(`
423
- interface Foo {
424
- name: string;
425
- }
426
- `);
427
- const result = extractJSDocFieldMetadata(prop);
428
- expect(result).toBeNull();
429
- });
430
- it("skips tags with empty values", () => {
431
- const prop = getInterfacePropertyFromSource(`
432
- interface Foo {
433
- /** @Field_displayName */
434
- name: string;
435
- }
436
- `);
437
- const result = extractJSDocFieldMetadata(prop);
438
- expect(result).toBeNull();
439
- });
440
- it("skips tags with whitespace-only values", () => {
441
- const prop = getInterfacePropertyFromSource(`
442
- interface Foo {
443
- /** @Field_displayName */
444
- name: string;
445
- }
446
- `);
447
- const result = extractJSDocFieldMetadata(prop);
448
- expect(result).toBeNull();
449
- });
450
- it("works on class properties too", () => {
451
- const prop = getPropertyFromSource(`
452
- class Foo {
453
- /** @Field_displayName Class Field */
454
- x!: string;
455
- }
456
- `);
457
- const result = extractJSDocFieldMetadata(prop);
458
- expect(result).not.toBeNull();
459
- expect(result).toMatchObject({
460
- name: "Field",
461
- args: [{ displayName: "Class Field" }],
462
- });
463
- });
464
- });
465
- //# sourceMappingURL=jsdoc-constraints.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"jsdoc-constraints.test.js","sourceRoot":"","sources":["../../src/__tests__/jsdoc-constraints.test.ts"],"names":[],"mappings":"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"}
@@ -1,198 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
- import * as fs from "node:fs";
3
- import * as path from "node:path";
4
- import * as os from "node:os";
5
- import { writeSchemas } from "../index.js";
6
- import { formspec, field, group } from "@formspec/dsl";
7
- describe("writeSchemas", () => {
8
- let tempDir;
9
- beforeEach(() => {
10
- tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "formspec-test-"));
11
- });
12
- afterEach(() => {
13
- // Clean up temp directory
14
- if (fs.existsSync(tempDir)) {
15
- fs.rmSync(tempDir, { recursive: true });
16
- }
17
- });
18
- // Positive tests
19
- describe("positive cases", () => {
20
- it("should write both schema files to specified directory", () => {
21
- const form = formspec(field.text("name", { required: true }), field.number("age"));
22
- const result = writeSchemas(form, {
23
- outDir: tempDir,
24
- name: "test",
25
- });
26
- expect(fs.existsSync(result.jsonSchemaPath)).toBe(true);
27
- expect(fs.existsSync(result.uiSchemaPath)).toBe(true);
28
- expect(result.jsonSchemaPath).toBe(path.join(tempDir, "test-schema.json"));
29
- expect(result.uiSchemaPath).toBe(path.join(tempDir, "test-uischema.json"));
30
- });
31
- it("should create output directory if it doesn't exist", () => {
32
- const form = formspec(field.text("name"));
33
- const nestedDir = path.join(tempDir, "nested", "deeply", "output");
34
- expect(fs.existsSync(nestedDir)).toBe(false);
35
- writeSchemas(form, {
36
- outDir: nestedDir,
37
- name: "test",
38
- });
39
- expect(fs.existsSync(nestedDir)).toBe(true);
40
- });
41
- it("should use 'schema' as default name when not provided", () => {
42
- const form = formspec(field.text("name"));
43
- const result = writeSchemas(form, {
44
- outDir: tempDir,
45
- });
46
- expect(result.jsonSchemaPath).toBe(path.join(tempDir, "schema-schema.json"));
47
- expect(result.uiSchemaPath).toBe(path.join(tempDir, "schema-uischema.json"));
48
- });
49
- it("should use custom indentation when provided", () => {
50
- const form = formspec(field.text("name"));
51
- writeSchemas(form, {
52
- outDir: tempDir,
53
- name: "test",
54
- indent: 4,
55
- });
56
- const content = fs.readFileSync(path.join(tempDir, "test-schema.json"), "utf-8");
57
- // With indent 4, we should see 4-space indentation
58
- expect(content).toContain(" "); // 4 spaces
59
- });
60
- it("should generate valid JSON files that can be parsed", () => {
61
- const form = formspec(field.text("name"), field.enum("status", ["draft", "active"]));
62
- const result = writeSchemas(form, {
63
- outDir: tempDir,
64
- name: "test",
65
- });
66
- const jsonSchema = JSON.parse(fs.readFileSync(result.jsonSchemaPath, "utf-8"));
67
- const uiSchema = JSON.parse(fs.readFileSync(result.uiSchemaPath, "utf-8"));
68
- expect(jsonSchema).toHaveProperty("type", "object");
69
- expect(jsonSchema).toHaveProperty("properties");
70
- expect(uiSchema).toHaveProperty("type");
71
- });
72
- it("should generate correct schema content matching buildFormSchemas output", () => {
73
- const form = formspec(group("Info", field.text("name", { label: "Name", required: true }), field.number("age", { label: "Age", min: 0 })));
74
- const result = writeSchemas(form, {
75
- outDir: tempDir,
76
- name: "test",
77
- });
78
- const jsonSchema = JSON.parse(fs.readFileSync(result.jsonSchemaPath, "utf-8"));
79
- expect(jsonSchema.properties).toHaveProperty("name");
80
- expect(jsonSchema.properties).toHaveProperty("age");
81
- expect(jsonSchema.required).toContain("name");
82
- expect(jsonSchema.properties?.["age"]).toHaveProperty("minimum", 0);
83
- });
84
- it("should handle forms with enum fields", () => {
85
- const form = formspec(field.enum("status", ["draft", "published", "archived"]));
86
- const result = writeSchemas(form, {
87
- outDir: tempDir,
88
- name: "test",
89
- });
90
- const jsonSchema = JSON.parse(fs.readFileSync(result.jsonSchemaPath, "utf-8"));
91
- const statusProperty = jsonSchema.properties?.["status"];
92
- expect(statusProperty).toHaveProperty("enum");
93
- expect(statusProperty?.enum).toEqual(["draft", "published", "archived"]);
94
- });
95
- it("should handle forms with nested objects", () => {
96
- const form = formspec(field.object("address", field.text("street"), field.text("city")));
97
- const result = writeSchemas(form, {
98
- outDir: tempDir,
99
- name: "test",
100
- });
101
- const jsonSchema = JSON.parse(fs.readFileSync(result.jsonSchemaPath, "utf-8"));
102
- const addressProperty = jsonSchema.properties?.["address"];
103
- expect(addressProperty).toHaveProperty("type", "object");
104
- expect(addressProperty?.properties).toHaveProperty("street");
105
- expect(addressProperty?.properties).toHaveProperty("city");
106
- });
107
- it("should handle forms with arrays", () => {
108
- const form = formspec(field.array("items", field.text("name"), field.number("quantity")));
109
- const result = writeSchemas(form, {
110
- outDir: tempDir,
111
- name: "test",
112
- });
113
- const jsonSchema = JSON.parse(fs.readFileSync(result.jsonSchemaPath, "utf-8"));
114
- expect(jsonSchema.properties?.["items"]).toHaveProperty("type", "array");
115
- expect(jsonSchema.properties?.["items"]).toHaveProperty("items");
116
- });
117
- });
118
- // Negative tests
119
- describe("negative cases", () => {
120
- it("should overwrite existing files", () => {
121
- const form1 = formspec(field.text("original"));
122
- const form2 = formspec(field.text("updated"));
123
- // Write first version
124
- writeSchemas(form1, {
125
- outDir: tempDir,
126
- name: "test",
127
- });
128
- // Write second version
129
- const result = writeSchemas(form2, {
130
- outDir: tempDir,
131
- name: "test",
132
- });
133
- const jsonSchema = JSON.parse(fs.readFileSync(result.jsonSchemaPath, "utf-8"));
134
- expect(jsonSchema.properties).toHaveProperty("updated");
135
- expect(jsonSchema.properties).not.toHaveProperty("original");
136
- });
137
- it("should handle empty forms", () => {
138
- const form = formspec();
139
- const result = writeSchemas(form, {
140
- outDir: tempDir,
141
- name: "empty",
142
- });
143
- expect(fs.existsSync(result.jsonSchemaPath)).toBe(true);
144
- const jsonSchema = JSON.parse(fs.readFileSync(result.jsonSchemaPath, "utf-8"));
145
- expect(jsonSchema).toHaveProperty("type", "object");
146
- });
147
- it("should handle forms with special characters in field names", () => {
148
- const form = formspec(field.text("field-with-dashes"), field.text("field_with_underscores"));
149
- const result = writeSchemas(form, {
150
- outDir: tempDir,
151
- name: "test",
152
- });
153
- const jsonSchema = JSON.parse(fs.readFileSync(result.jsonSchemaPath, "utf-8"));
154
- expect(jsonSchema.properties).toHaveProperty("field-with-dashes");
155
- expect(jsonSchema.properties).toHaveProperty("field_with_underscores");
156
- });
157
- it("should handle output directory with trailing slash", () => {
158
- const form = formspec(field.text("name"));
159
- const result = writeSchemas(form, {
160
- outDir: tempDir + "/",
161
- name: "test",
162
- });
163
- expect(fs.existsSync(result.jsonSchemaPath)).toBe(true);
164
- });
165
- });
166
- // Edge cases
167
- describe("edge cases", () => {
168
- it("should handle name with dots", () => {
169
- const form = formspec(field.text("name"));
170
- const result = writeSchemas(form, {
171
- outDir: tempDir,
172
- name: "my.form.v1",
173
- });
174
- expect(result.jsonSchemaPath).toBe(path.join(tempDir, "my.form.v1-schema.json"));
175
- });
176
- it("should return absolute paths", () => {
177
- const form = formspec(field.text("name"));
178
- const result = writeSchemas(form, {
179
- outDir: tempDir,
180
- name: "test",
181
- });
182
- expect(path.isAbsolute(result.jsonSchemaPath)).toBe(true);
183
- expect(path.isAbsolute(result.uiSchemaPath)).toBe(true);
184
- });
185
- it("should handle zero indent (compact JSON)", () => {
186
- const form = formspec(field.text("name"));
187
- writeSchemas(form, {
188
- outDir: tempDir,
189
- name: "test",
190
- indent: 0,
191
- });
192
- const content = fs.readFileSync(path.join(tempDir, "test-schema.json"), "utf-8");
193
- // With indent 0, JSON should be on one line (no newlines except at end)
194
- expect(content.split("\n").length).toBeLessThanOrEqual(2);
195
- });
196
- });
197
- });
198
- //# sourceMappingURL=write-schemas.test.js.map