@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.
- package/README.md +51 -15
- package/dist/__tests__/chain-dsl-canonicalizer.test.d.ts +2 -0
- package/dist/__tests__/chain-dsl-canonicalizer.test.d.ts.map +1 -0
- package/dist/__tests__/constraint-validator.test.d.ts +2 -0
- package/dist/__tests__/constraint-validator.test.d.ts.map +1 -0
- package/dist/__tests__/extension-api.test.d.ts +2 -0
- package/dist/__tests__/extension-api.test.d.ts.map +1 -0
- package/dist/__tests__/fixtures/example-a-builtins.d.ts +18 -0
- package/dist/__tests__/fixtures/example-a-builtins.d.ts.map +1 -1
- package/dist/__tests__/ir-analyzer.test.d.ts +11 -0
- package/dist/__tests__/ir-analyzer.test.d.ts.map +1 -0
- package/dist/__tests__/ir-jsdoc-constraints.test.d.ts +12 -0
- package/dist/__tests__/ir-jsdoc-constraints.test.d.ts.map +1 -0
- package/dist/__tests__/ir-json-schema-generator.test.d.ts +11 -0
- package/dist/__tests__/ir-json-schema-generator.test.d.ts.map +1 -0
- package/dist/__tests__/ir-ui-schema-generator.test.d.ts +2 -0
- package/dist/__tests__/ir-ui-schema-generator.test.d.ts.map +1 -0
- package/dist/__tests__/jsdoc-constraints.test.d.ts +4 -4
- package/dist/__tests__/parity/fixtures/address/chain-dsl.d.ts +9 -0
- package/dist/__tests__/parity/fixtures/address/chain-dsl.d.ts.map +1 -0
- package/dist/__tests__/parity/fixtures/address/expected-ir.d.ts +9 -0
- package/dist/__tests__/parity/fixtures/address/expected-ir.d.ts.map +1 -0
- package/dist/__tests__/parity/fixtures/address/tsdoc.d.ts +19 -0
- package/dist/__tests__/parity/fixtures/address/tsdoc.d.ts.map +1 -0
- package/dist/__tests__/parity/fixtures/product-config/chain-dsl.d.ts +13 -0
- package/dist/__tests__/parity/fixtures/product-config/chain-dsl.d.ts.map +1 -0
- package/dist/__tests__/parity/fixtures/product-config/expected-ir.d.ts +9 -0
- package/dist/__tests__/parity/fixtures/product-config/expected-ir.d.ts.map +1 -0
- package/dist/__tests__/parity/fixtures/product-config/tsdoc.d.ts +28 -0
- package/dist/__tests__/parity/fixtures/product-config/tsdoc.d.ts.map +1 -0
- package/dist/__tests__/parity/fixtures/user-registration/chain-dsl.d.ts +12 -0
- package/dist/__tests__/parity/fixtures/user-registration/chain-dsl.d.ts.map +1 -0
- package/dist/__tests__/parity/fixtures/user-registration/expected-ir.d.ts +9 -0
- package/dist/__tests__/parity/fixtures/user-registration/expected-ir.d.ts.map +1 -0
- package/dist/__tests__/parity/fixtures/user-registration/tsdoc.d.ts +19 -0
- package/dist/__tests__/parity/fixtures/user-registration/tsdoc.d.ts.map +1 -0
- package/dist/__tests__/parity/parity.test.d.ts +14 -0
- package/dist/__tests__/parity/parity.test.d.ts.map +1 -0
- package/dist/__tests__/parity/utils.d.ts +139 -0
- package/dist/__tests__/parity/utils.d.ts.map +1 -0
- package/dist/analyzer/class-analyzer.d.ts +54 -99
- package/dist/analyzer/class-analyzer.d.ts.map +1 -1
- package/dist/analyzer/jsdoc-constraints.d.ts +78 -30
- package/dist/analyzer/jsdoc-constraints.d.ts.map +1 -1
- package/dist/analyzer/tsdoc-parser.d.ts +61 -0
- package/dist/analyzer/tsdoc-parser.d.ts.map +1 -0
- package/dist/browser.cjs +1200 -0
- package/dist/browser.cjs.map +1 -0
- package/dist/browser.d.ts +12 -6
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +1147 -44
- package/dist/browser.js.map +1 -1
- package/dist/build.d.ts +385 -160
- package/dist/canonicalize/chain-dsl-canonicalizer.d.ts +18 -0
- package/dist/canonicalize/chain-dsl-canonicalizer.d.ts.map +1 -0
- package/dist/canonicalize/index.d.ts +8 -0
- package/dist/canonicalize/index.d.ts.map +1 -0
- package/dist/canonicalize/tsdoc-canonicalizer.d.ts +34 -0
- package/dist/canonicalize/tsdoc-canonicalizer.d.ts.map +1 -0
- package/dist/cli.cjs +2028 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.js +1978 -101
- package/dist/cli.js.map +1 -1
- package/dist/extensions/index.d.ts +8 -0
- package/dist/extensions/index.d.ts.map +1 -0
- package/dist/extensions/registry.d.ts +55 -0
- package/dist/extensions/registry.d.ts.map +1 -0
- package/dist/generators/class-schema.d.ts +28 -47
- package/dist/generators/class-schema.d.ts.map +1 -1
- package/dist/generators/method-schema.d.ts +6 -8
- package/dist/generators/method-schema.d.ts.map +1 -1
- package/dist/index.cjs +1832 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +8 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1779 -114
- package/dist/index.js.map +1 -1
- package/dist/internals.cjs +2125 -0
- package/dist/internals.cjs.map +1 -0
- package/dist/internals.d.ts +12 -2
- package/dist/internals.d.ts.map +1 -1
- package/dist/internals.js +2084 -21
- package/dist/internals.js.map +1 -1
- package/dist/json-schema/generator.d.ts +10 -5
- package/dist/json-schema/generator.d.ts.map +1 -1
- package/dist/json-schema/ir-generator.d.ts +84 -0
- package/dist/json-schema/ir-generator.d.ts.map +1 -0
- package/dist/json-schema/schema.d.ts +16 -0
- package/dist/json-schema/schema.d.ts.map +1 -0
- package/dist/json-schema/types.d.ts +5 -6
- package/dist/json-schema/types.d.ts.map +1 -1
- package/dist/ui-schema/generator.d.ts +5 -0
- package/dist/ui-schema/generator.d.ts.map +1 -1
- package/dist/ui-schema/ir-generator.d.ts +53 -0
- package/dist/ui-schema/ir-generator.d.ts.map +1 -0
- package/dist/ui-schema/schema.d.ts +357 -0
- package/dist/ui-schema/schema.d.ts.map +1 -0
- package/dist/ui-schema/types.d.ts +8 -73
- package/dist/ui-schema/types.d.ts.map +1 -1
- package/dist/validate/constraint-validator.d.ts +66 -0
- package/dist/validate/constraint-validator.d.ts.map +1 -0
- package/dist/validate/index.d.ts +9 -0
- package/dist/validate/index.d.ts.map +1 -0
- package/package.json +15 -9
- package/dist/__tests__/analyzer-edge-cases.test.d.ts +0 -13
- package/dist/__tests__/analyzer-edge-cases.test.d.ts.map +0 -1
- package/dist/__tests__/analyzer-edge-cases.test.js +0 -376
- package/dist/__tests__/analyzer-edge-cases.test.js.map +0 -1
- package/dist/__tests__/analyzer.test.d.ts +0 -5
- package/dist/__tests__/analyzer.test.d.ts.map +0 -1
- package/dist/__tests__/analyzer.test.js +0 -190
- package/dist/__tests__/analyzer.test.js.map +0 -1
- package/dist/__tests__/cli.test.js +0 -178
- package/dist/__tests__/cli.test.js.map +0 -1
- package/dist/__tests__/codegen.test.d.ts +0 -5
- package/dist/__tests__/codegen.test.d.ts.map +0 -1
- package/dist/__tests__/codegen.test.js +0 -506
- package/dist/__tests__/codegen.test.js.map +0 -1
- package/dist/__tests__/decorator-pipeline.test.d.ts +0 -11
- package/dist/__tests__/decorator-pipeline.test.d.ts.map +0 -1
- package/dist/__tests__/decorator-pipeline.test.js +0 -460
- package/dist/__tests__/decorator-pipeline.test.js.map +0 -1
- package/dist/__tests__/edge-cases.test.js +0 -215
- package/dist/__tests__/edge-cases.test.js.map +0 -1
- package/dist/__tests__/fixtures/edge-cases.js +0 -137
- package/dist/__tests__/fixtures/edge-cases.js.map +0 -1
- package/dist/__tests__/fixtures/example-a-builtins.js +0 -100
- package/dist/__tests__/fixtures/example-a-builtins.js.map +0 -1
- package/dist/__tests__/fixtures/example-b-decorators.d.ts +0 -5
- package/dist/__tests__/fixtures/example-b-decorators.d.ts.map +0 -1
- package/dist/__tests__/fixtures/example-b-decorators.js +0 -5
- package/dist/__tests__/fixtures/example-b-decorators.js.map +0 -1
- package/dist/__tests__/fixtures/example-b-extended.d.ts +0 -5
- package/dist/__tests__/fixtures/example-b-extended.d.ts.map +0 -1
- package/dist/__tests__/fixtures/example-b-extended.js +0 -60
- package/dist/__tests__/fixtures/example-b-extended.js.map +0 -1
- package/dist/__tests__/fixtures/example-c-custom.d.ts +0 -5
- package/dist/__tests__/fixtures/example-c-custom.d.ts.map +0 -1
- package/dist/__tests__/fixtures/example-c-custom.js +0 -61
- package/dist/__tests__/fixtures/example-c-custom.js.map +0 -1
- package/dist/__tests__/fixtures/example-c-decorators.d.ts +0 -5
- package/dist/__tests__/fixtures/example-c-decorators.d.ts.map +0 -1
- package/dist/__tests__/fixtures/example-c-decorators.js +0 -4
- package/dist/__tests__/fixtures/example-c-decorators.js.map +0 -1
- package/dist/__tests__/fixtures/example-d-mixed-decorators.d.ts +0 -6
- package/dist/__tests__/fixtures/example-d-mixed-decorators.d.ts.map +0 -1
- package/dist/__tests__/fixtures/example-d-mixed-decorators.js +0 -75
- package/dist/__tests__/fixtures/example-d-mixed-decorators.js.map +0 -1
- package/dist/__tests__/fixtures/example-e-decorators.d.ts +0 -11
- package/dist/__tests__/fixtures/example-e-decorators.d.ts.map +0 -1
- package/dist/__tests__/fixtures/example-e-decorators.js +0 -10
- package/dist/__tests__/fixtures/example-e-decorators.js.map +0 -1
- package/dist/__tests__/fixtures/example-e-no-namespace.d.ts +0 -5
- package/dist/__tests__/fixtures/example-e-no-namespace.d.ts.map +0 -1
- package/dist/__tests__/fixtures/example-e-no-namespace.js +0 -61
- package/dist/__tests__/fixtures/example-e-no-namespace.js.map +0 -1
- package/dist/__tests__/fixtures/example-interface-types.js +0 -8
- package/dist/__tests__/fixtures/example-interface-types.js.map +0 -1
- package/dist/__tests__/fixtures/example-jsdoc-constraints.d.ts +0 -16
- package/dist/__tests__/fixtures/example-jsdoc-constraints.d.ts.map +0 -1
- package/dist/__tests__/fixtures/example-jsdoc-constraints.js +0 -98
- package/dist/__tests__/fixtures/example-jsdoc-constraints.js.map +0 -1
- package/dist/__tests__/fixtures/example-nested-class.d.ts +0 -45
- package/dist/__tests__/fixtures/example-nested-class.d.ts.map +0 -1
- package/dist/__tests__/fixtures/example-nested-class.js +0 -248
- package/dist/__tests__/fixtures/example-nested-class.js.map +0 -1
- package/dist/__tests__/fixtures/sample-forms.js +0 -78
- package/dist/__tests__/fixtures/sample-forms.js.map +0 -1
- package/dist/__tests__/generator.test.js +0 -234
- package/dist/__tests__/generator.test.js.map +0 -1
- package/dist/__tests__/integration.test.js +0 -161
- package/dist/__tests__/integration.test.js.map +0 -1
- package/dist/__tests__/interface-types.test.d.ts +0 -11
- package/dist/__tests__/interface-types.test.d.ts.map +0 -1
- package/dist/__tests__/interface-types.test.js +0 -404
- package/dist/__tests__/interface-types.test.js.map +0 -1
- package/dist/__tests__/jsdoc-constraints.test.js +0 -465
- package/dist/__tests__/jsdoc-constraints.test.js.map +0 -1
- package/dist/__tests__/write-schemas.test.js +0 -198
- package/dist/__tests__/write-schemas.test.js.map +0 -1
- package/dist/analyzer/class-analyzer.js +0 -377
- package/dist/analyzer/class-analyzer.js.map +0 -1
- package/dist/analyzer/decorator-extractor.d.ts +0 -78
- package/dist/analyzer/decorator-extractor.d.ts.map +0 -1
- package/dist/analyzer/decorator-extractor.js +0 -336
- package/dist/analyzer/decorator-extractor.js.map +0 -1
- package/dist/analyzer/jsdoc-constraints.js +0 -153
- package/dist/analyzer/jsdoc-constraints.js.map +0 -1
- package/dist/analyzer/program.js +0 -114
- package/dist/analyzer/program.js.map +0 -1
- package/dist/analyzer/type-converter.d.ts +0 -75
- package/dist/analyzer/type-converter.d.ts.map +0 -1
- package/dist/analyzer/type-converter.js +0 -474
- package/dist/analyzer/type-converter.js.map +0 -1
- package/dist/codegen/index.d.ts +0 -75
- package/dist/codegen/index.d.ts.map +0 -1
- package/dist/codegen/index.js +0 -597
- package/dist/codegen/index.js.map +0 -1
- package/dist/generators/class-schema.js +0 -140
- package/dist/generators/class-schema.js.map +0 -1
- package/dist/generators/method-schema.js +0 -108
- package/dist/generators/method-schema.js.map +0 -1
- package/dist/json-schema/generator.js +0 -166
- package/dist/json-schema/generator.js.map +0 -1
- package/dist/json-schema/types.js +0 -33
- package/dist/json-schema/types.js.map +0 -1
- package/dist/ui-schema/generator.js +0 -148
- package/dist/ui-schema/generator.js.map +0 -1
- package/dist/ui-schema/types.js +0 -8
- 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
|