@formspec/cli 0.1.0-alpha.10
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 +480 -0
- package/dist/__tests__/analyzer.test.d.ts +8 -0
- package/dist/__tests__/analyzer.test.d.ts.map +1 -0
- package/dist/__tests__/analyzer.test.js +70 -0
- package/dist/__tests__/analyzer.test.js.map +1 -0
- package/dist/__tests__/codegen.test.d.ts +8 -0
- package/dist/__tests__/codegen.test.d.ts.map +1 -0
- package/dist/__tests__/codegen.test.js +51 -0
- package/dist/__tests__/codegen.test.js.map +1 -0
- package/dist/__tests__/edge-cases.test.d.ts +12 -0
- package/dist/__tests__/edge-cases.test.d.ts.map +1 -0
- package/dist/__tests__/edge-cases.test.js +169 -0
- package/dist/__tests__/edge-cases.test.js.map +1 -0
- package/dist/__tests__/fixtures/edge-cases.d.ts +110 -0
- package/dist/__tests__/fixtures/edge-cases.d.ts.map +1 -0
- package/dist/__tests__/fixtures/edge-cases.js +137 -0
- package/dist/__tests__/fixtures/edge-cases.js.map +1 -0
- package/dist/__tests__/fixtures/sample-forms.d.ts +55 -0
- package/dist/__tests__/fixtures/sample-forms.d.ts.map +1 -0
- package/dist/__tests__/fixtures/sample-forms.js +78 -0
- package/dist/__tests__/fixtures/sample-forms.js.map +1 -0
- package/dist/__tests__/integration.test.d.ts +5 -0
- package/dist/__tests__/integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration.test.js +186 -0
- package/dist/__tests__/integration.test.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +374 -0
- package/dist/index.js.map +1 -0
- package/dist/output/writer.d.ts +82 -0
- package/dist/output/writer.d.ts.map +1 -0
- package/dist/output/writer.js +152 -0
- package/dist/output/writer.js.map +1 -0
- package/dist/runtime/formspec-loader.d.ts +80 -0
- package/dist/runtime/formspec-loader.d.ts.map +1 -0
- package/dist/runtime/formspec-loader.js +152 -0
- package/dist/runtime/formspec-loader.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests for the CLI workflow.
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, expect, beforeAll, afterAll } from "vitest";
|
|
5
|
+
import * as fs from "node:fs";
|
|
6
|
+
import * as path from "node:path";
|
|
7
|
+
import { createProgramContext, findClassByName, analyzeClass, generateClassSchemas, generateMethodSchemas, collectFormSpecReferences, } from "@formspec/build/internals";
|
|
8
|
+
import { loadFormSpecs, isFormSpec } from "../runtime/formspec-loader.js";
|
|
9
|
+
import { writeClassSchemas, writeFormSpecSchemas } from "../output/writer.js";
|
|
10
|
+
const fixturesDir = path.join(__dirname, "fixtures");
|
|
11
|
+
const sampleFormsPath = path.join(fixturesDir, "sample-forms.ts");
|
|
12
|
+
const compiledPath = path.join(fixturesDir, "sample-forms.js");
|
|
13
|
+
const testOutputDir = path.join(__dirname, "__test_output__");
|
|
14
|
+
// Check if compiled fixture exists (may need to be built)
|
|
15
|
+
const hasCompiledFixture = fs.existsSync(compiledPath);
|
|
16
|
+
/**
|
|
17
|
+
* Converts FormSpecSchemas from loader to LoadedFormSpecSchemas for build API.
|
|
18
|
+
*/
|
|
19
|
+
function toLoadedSchemas(formSpecs) {
|
|
20
|
+
const result = new Map();
|
|
21
|
+
for (const [name, schemas] of formSpecs) {
|
|
22
|
+
result.set(name, {
|
|
23
|
+
name: schemas.name,
|
|
24
|
+
jsonSchema: schemas.jsonSchema,
|
|
25
|
+
uiSchema: schemas.uiSchema,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
describe("generators", () => {
|
|
31
|
+
it("generates class schemas from static analysis", () => {
|
|
32
|
+
const ctx = createProgramContext(sampleFormsPath);
|
|
33
|
+
const classDecl = findClassByName(ctx.sourceFile, "SimpleProduct");
|
|
34
|
+
if (!classDecl)
|
|
35
|
+
throw new Error("SimpleProduct class not found");
|
|
36
|
+
const analysis = analyzeClass(classDecl, ctx.checker);
|
|
37
|
+
const schemas = generateClassSchemas(analysis, ctx.checker);
|
|
38
|
+
// JSON Schema
|
|
39
|
+
expect(schemas.jsonSchema.type).toBe("object");
|
|
40
|
+
expect(schemas.jsonSchema.properties).toBeDefined();
|
|
41
|
+
expect(schemas.jsonSchema.properties?.["name"]).toBeDefined();
|
|
42
|
+
expect(schemas.jsonSchema.properties?.["price"]).toBeDefined();
|
|
43
|
+
expect(schemas.jsonSchema.required).toContain("name");
|
|
44
|
+
expect(schemas.jsonSchema.required).toContain("active");
|
|
45
|
+
expect(schemas.jsonSchema.required).not.toContain("price");
|
|
46
|
+
// UI Schema
|
|
47
|
+
expect(schemas.uiSchema.elements).toHaveLength(4);
|
|
48
|
+
const nameElement = schemas.uiSchema.elements.find((e) => e.id === "name");
|
|
49
|
+
expect(nameElement?._field).toBe("text");
|
|
50
|
+
expect(nameElement?.required).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
it("collects FormSpec references from methods", () => {
|
|
53
|
+
const ctx = createProgramContext(sampleFormsPath);
|
|
54
|
+
const classDecl = findClassByName(ctx.sourceFile, "InstallmentPlan");
|
|
55
|
+
if (!classDecl)
|
|
56
|
+
throw new Error("InstallmentPlan class not found");
|
|
57
|
+
const analysis = analyzeClass(classDecl, ctx.checker);
|
|
58
|
+
const refs = collectFormSpecReferences([
|
|
59
|
+
...analysis.instanceMethods,
|
|
60
|
+
...analysis.staticMethods,
|
|
61
|
+
]);
|
|
62
|
+
expect(refs.size).toBe(2);
|
|
63
|
+
expect(refs.has("ActivateParams")).toBe(true);
|
|
64
|
+
expect(refs.has("CancelParams")).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
it("generates method schemas without FormSpec (static only)", () => {
|
|
67
|
+
const ctx = createProgramContext(sampleFormsPath);
|
|
68
|
+
const classDecl = findClassByName(ctx.sourceFile, "SimpleProduct");
|
|
69
|
+
if (!classDecl)
|
|
70
|
+
throw new Error("SimpleProduct class not found");
|
|
71
|
+
const analysis = analyzeClass(classDecl, ctx.checker);
|
|
72
|
+
const updateMethod = analysis.instanceMethods[0];
|
|
73
|
+
if (!updateMethod)
|
|
74
|
+
throw new Error("updateMethod not found");
|
|
75
|
+
const methodSchemas = generateMethodSchemas(updateMethod, ctx.checker, new Map());
|
|
76
|
+
expect(methodSchemas.name).toBe("update");
|
|
77
|
+
expect(methodSchemas.params).not.toBeNull();
|
|
78
|
+
expect(methodSchemas.params?.jsonSchema.type).toBe("object");
|
|
79
|
+
expect(methodSchemas.params?.uiSchema).toBeNull();
|
|
80
|
+
expect(methodSchemas.returnType.type).toBe("boolean");
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
describe("isFormSpec", () => {
|
|
84
|
+
it("detects valid FormSpec-like objects", () => {
|
|
85
|
+
const validFormSpec = {
|
|
86
|
+
elements: [{ _type: "field", _field: "text", name: "test" }],
|
|
87
|
+
};
|
|
88
|
+
expect(isFormSpec(validFormSpec)).toBe(true);
|
|
89
|
+
});
|
|
90
|
+
it("rejects invalid objects", () => {
|
|
91
|
+
expect(isFormSpec(null)).toBe(false);
|
|
92
|
+
expect(isFormSpec(undefined)).toBe(false);
|
|
93
|
+
expect(isFormSpec({})).toBe(false);
|
|
94
|
+
expect(isFormSpec({ elements: "not-array" })).toBe(false);
|
|
95
|
+
expect(isFormSpec({ elements: [{ noType: true }] })).toBe(false);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe.skipIf(!hasCompiledFixture)("runtime loading", () => {
|
|
99
|
+
it("loads FormSpec exports from compiled module", async () => {
|
|
100
|
+
const { formSpecs, module } = await loadFormSpecs(compiledPath);
|
|
101
|
+
// Should find our exported FormSpecs
|
|
102
|
+
expect(formSpecs.size).toBeGreaterThan(0);
|
|
103
|
+
expect(formSpecs.has("UserRegistrationForm")).toBe(true);
|
|
104
|
+
expect(formSpecs.has("ProductConfigForm")).toBe(true);
|
|
105
|
+
expect(formSpecs.has("ActivateParams")).toBe(true);
|
|
106
|
+
expect(formSpecs.has("CancelParams")).toBe(true);
|
|
107
|
+
// Check generated schemas
|
|
108
|
+
const userForm = formSpecs.get("UserRegistrationForm");
|
|
109
|
+
if (!userForm)
|
|
110
|
+
throw new Error("UserRegistrationForm not found");
|
|
111
|
+
expect(userForm.jsonSchema).toBeDefined();
|
|
112
|
+
expect(userForm.uiSchema).toBeDefined();
|
|
113
|
+
// Module should have the class exports too
|
|
114
|
+
expect(module["InstallmentPlan"]).toBeDefined();
|
|
115
|
+
});
|
|
116
|
+
it("generates method schemas with FormSpec params", async () => {
|
|
117
|
+
const ctx = createProgramContext(sampleFormsPath);
|
|
118
|
+
const classDecl = findClassByName(ctx.sourceFile, "InstallmentPlan");
|
|
119
|
+
if (!classDecl)
|
|
120
|
+
throw new Error("InstallmentPlan class not found");
|
|
121
|
+
const analysis = analyzeClass(classDecl, ctx.checker);
|
|
122
|
+
// Load FormSpecs at runtime
|
|
123
|
+
const { formSpecs } = await loadFormSpecs(compiledPath);
|
|
124
|
+
const loadedSchemas = toLoadedSchemas(formSpecs);
|
|
125
|
+
// Generate method schemas
|
|
126
|
+
const activateMethod = analysis.instanceMethods.find((m) => m.name === "activate");
|
|
127
|
+
if (!activateMethod)
|
|
128
|
+
throw new Error("activate method not found");
|
|
129
|
+
const methodSchemas = generateMethodSchemas(activateMethod, ctx.checker, loadedSchemas);
|
|
130
|
+
expect(methodSchemas.name).toBe("activate");
|
|
131
|
+
expect(methodSchemas.params).not.toBeNull();
|
|
132
|
+
expect(methodSchemas.params?.formSpecExport).toBe("ActivateParams");
|
|
133
|
+
// Should have UI Schema from the FormSpec
|
|
134
|
+
expect(methodSchemas.params?.uiSchema).not.toBeNull();
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
describe.skipIf(!hasCompiledFixture)("output writer", () => {
|
|
138
|
+
beforeAll(() => {
|
|
139
|
+
// Clean up test output directory
|
|
140
|
+
if (fs.existsSync(testOutputDir)) {
|
|
141
|
+
fs.rmSync(testOutputDir, { recursive: true });
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
afterAll(() => {
|
|
145
|
+
// Clean up test output directory
|
|
146
|
+
if (fs.existsSync(testOutputDir)) {
|
|
147
|
+
fs.rmSync(testOutputDir, { recursive: true });
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
it("writes class schemas to output directory", async () => {
|
|
151
|
+
const ctx = createProgramContext(sampleFormsPath);
|
|
152
|
+
const classDecl = findClassByName(ctx.sourceFile, "InstallmentPlan");
|
|
153
|
+
if (!classDecl)
|
|
154
|
+
throw new Error("InstallmentPlan class not found");
|
|
155
|
+
const analysis = analyzeClass(classDecl, ctx.checker);
|
|
156
|
+
// Load FormSpecs
|
|
157
|
+
const { formSpecs } = await loadFormSpecs(compiledPath);
|
|
158
|
+
const loadedSchemas = toLoadedSchemas(formSpecs);
|
|
159
|
+
// Generate schemas
|
|
160
|
+
const classSchemas = generateClassSchemas(analysis, ctx.checker);
|
|
161
|
+
const instanceMethodSchemas = analysis.instanceMethods.map((m) => generateMethodSchemas(m, ctx.checker, loadedSchemas));
|
|
162
|
+
const staticMethodSchemas = analysis.staticMethods.map((m) => generateMethodSchemas(m, ctx.checker, loadedSchemas));
|
|
163
|
+
// Write output
|
|
164
|
+
const result = writeClassSchemas(analysis.name, classSchemas, instanceMethodSchemas, staticMethodSchemas, { outDir: testOutputDir });
|
|
165
|
+
// Verify directory structure
|
|
166
|
+
expect(fs.existsSync(result.dir)).toBe(true);
|
|
167
|
+
expect(fs.existsSync(path.join(result.dir, "schema.json"))).toBe(true);
|
|
168
|
+
expect(fs.existsSync(path.join(result.dir, "ui_schema.json"))).toBe(true);
|
|
169
|
+
expect(fs.existsSync(path.join(result.dir, "instance_methods", "activate", "params.schema.json"))).toBe(true);
|
|
170
|
+
expect(fs.existsSync(path.join(result.dir, "instance_methods", "activate", "params.ui_schema.json"))).toBe(true);
|
|
171
|
+
expect(fs.existsSync(path.join(result.dir, "static_methods", "createStandard", "return_type.schema.json"))).toBe(true);
|
|
172
|
+
// Verify JSON content
|
|
173
|
+
const schemaContent = JSON.parse(fs.readFileSync(path.join(result.dir, "schema.json"), "utf-8"));
|
|
174
|
+
expect(schemaContent.type).toBe("object");
|
|
175
|
+
expect(schemaContent.properties).toBeDefined();
|
|
176
|
+
});
|
|
177
|
+
it("writes FormSpec schemas to output directory", async () => {
|
|
178
|
+
const { formSpecs } = await loadFormSpecs(compiledPath);
|
|
179
|
+
const result = writeFormSpecSchemas(formSpecs, { outDir: testOutputDir });
|
|
180
|
+
expect(fs.existsSync(result.dir)).toBe(true);
|
|
181
|
+
expect(fs.existsSync(path.join(result.dir, "UserRegistrationForm", "schema.json"))).toBe(true);
|
|
182
|
+
expect(fs.existsSync(path.join(result.dir, "UserRegistrationForm", "ui_schema.json"))).toBe(true);
|
|
183
|
+
expect(fs.existsSync(path.join(result.dir, "ProductConfigForm", "schema.json"))).toBe(true);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
//# sourceMappingURL=integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration.test.js","sourceRoot":"","sources":["../../src/__tests__/integration.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* FormSpec CLI - Generate JSON Schema and FormSpec from TypeScript
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* formspec generate <file> [className] [-o <outDir>]
|
|
7
|
+
*
|
|
8
|
+
* Examples:
|
|
9
|
+
* # Generate schemas from a class with decorators
|
|
10
|
+
* formspec generate ./src/forms.ts InstallmentPlan -o ./generated
|
|
11
|
+
*
|
|
12
|
+
* # Generate schemas from all FormSpec exports in a file (chain DSL)
|
|
13
|
+
* formspec generate ./src/forms.ts -o ./generated
|
|
14
|
+
*
|
|
15
|
+
* # Generate schemas from both classes and FormSpec exports
|
|
16
|
+
* formspec generate ./src/forms.ts MyClass -o ./generated
|
|
17
|
+
*/
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;GAeG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* FormSpec CLI - Generate JSON Schema and FormSpec from TypeScript
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* formspec generate <file> [className] [-o <outDir>]
|
|
7
|
+
*
|
|
8
|
+
* Examples:
|
|
9
|
+
* # Generate schemas from a class with decorators
|
|
10
|
+
* formspec generate ./src/forms.ts InstallmentPlan -o ./generated
|
|
11
|
+
*
|
|
12
|
+
* # Generate schemas from all FormSpec exports in a file (chain DSL)
|
|
13
|
+
* formspec generate ./src/forms.ts -o ./generated
|
|
14
|
+
*
|
|
15
|
+
* # Generate schemas from both classes and FormSpec exports
|
|
16
|
+
* formspec generate ./src/forms.ts MyClass -o ./generated
|
|
17
|
+
*/
|
|
18
|
+
import { runCodegen } from "@formspec/build";
|
|
19
|
+
import { createProgramContext, findClassByName, analyzeClass, generateClassSchemas, generateMethodSchemas, collectFormSpecReferences, } from "@formspec/build/internals";
|
|
20
|
+
import { loadFormSpecs, loadNamedFormSpecs, resolveCompiledPath, } from "./runtime/formspec-loader.js";
|
|
21
|
+
import { writeClassSchemas, writeFormSpecSchemas } from "./output/writer.js";
|
|
22
|
+
/**
|
|
23
|
+
* Parses codegen command arguments.
|
|
24
|
+
*/
|
|
25
|
+
function parseCodegenArgs(args) {
|
|
26
|
+
const files = [];
|
|
27
|
+
let output = "./__formspec_types__.ts";
|
|
28
|
+
for (let i = 0; i < args.length; i++) {
|
|
29
|
+
const arg = args[i];
|
|
30
|
+
if (!arg)
|
|
31
|
+
continue;
|
|
32
|
+
if (arg === "-o" || arg === "--output") {
|
|
33
|
+
const nextArg = args[++i];
|
|
34
|
+
if (nextArg)
|
|
35
|
+
output = nextArg;
|
|
36
|
+
}
|
|
37
|
+
else if (arg.startsWith("-")) {
|
|
38
|
+
console.error(`Unknown option: ${arg}`);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
files.push(arg);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (files.length === 0) {
|
|
46
|
+
console.error("Error: No source files provided");
|
|
47
|
+
console.error("Usage: formspec codegen <files...> [-o <output>]");
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
return { command: "codegen", files, output };
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Parses command line arguments.
|
|
54
|
+
*/
|
|
55
|
+
function parseArgs(args) {
|
|
56
|
+
const [command, ...rest] = args;
|
|
57
|
+
if (!command || command === "--help" || command === "-h") {
|
|
58
|
+
printHelp();
|
|
59
|
+
process.exit(0);
|
|
60
|
+
}
|
|
61
|
+
// Handle codegen command
|
|
62
|
+
if (command === "codegen") {
|
|
63
|
+
// Check for --help on subcommand
|
|
64
|
+
if (rest.includes("--help") || rest.includes("-h")) {
|
|
65
|
+
printCodegenHelp();
|
|
66
|
+
process.exit(0);
|
|
67
|
+
}
|
|
68
|
+
return parseCodegenArgs(rest);
|
|
69
|
+
}
|
|
70
|
+
// Accept both "generate" (primary) and "analyze" (alias for backwards compatibility)
|
|
71
|
+
if (command !== "generate" && command !== "analyze") {
|
|
72
|
+
console.error(`Unknown command: ${command}`);
|
|
73
|
+
console.error('Use "formspec generate" or "formspec codegen"');
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
// Check for --help on subcommand
|
|
77
|
+
if (rest.includes("--help") || rest.includes("-h")) {
|
|
78
|
+
printGenerateHelp();
|
|
79
|
+
process.exit(0);
|
|
80
|
+
}
|
|
81
|
+
let filePath;
|
|
82
|
+
let className;
|
|
83
|
+
let outDir = "./generated";
|
|
84
|
+
let compiledPath;
|
|
85
|
+
for (let i = 0; i < rest.length; i++) {
|
|
86
|
+
const arg = rest[i];
|
|
87
|
+
if (!arg)
|
|
88
|
+
continue;
|
|
89
|
+
if (arg === "-o" || arg === "--output") {
|
|
90
|
+
const nextArg = rest[++i];
|
|
91
|
+
if (nextArg)
|
|
92
|
+
outDir = nextArg;
|
|
93
|
+
}
|
|
94
|
+
else if (arg === "--compiled" || arg === "-c") {
|
|
95
|
+
const nextArg = rest[++i];
|
|
96
|
+
if (nextArg)
|
|
97
|
+
compiledPath = nextArg;
|
|
98
|
+
}
|
|
99
|
+
else if (arg.startsWith("-")) {
|
|
100
|
+
console.error(`Unknown option: ${arg}`);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
else if (!filePath) {
|
|
104
|
+
filePath = arg;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
className ??= arg;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (!filePath) {
|
|
111
|
+
console.error("Error: No file path provided");
|
|
112
|
+
console.error("Usage: formspec generate <file> [className] [-o <outDir>]");
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
command,
|
|
117
|
+
filePath,
|
|
118
|
+
className,
|
|
119
|
+
outDir,
|
|
120
|
+
compiledPath,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Prints help message.
|
|
125
|
+
*/
|
|
126
|
+
function printHelp() {
|
|
127
|
+
console.log(`
|
|
128
|
+
FormSpec CLI - Generate JSON Schema and FormSpec from TypeScript
|
|
129
|
+
|
|
130
|
+
COMMANDS:
|
|
131
|
+
generate Generate JSON Schema and UI Schema files from TypeScript
|
|
132
|
+
codegen Generate type metadata file for runtime schema generation
|
|
133
|
+
|
|
134
|
+
USAGE:
|
|
135
|
+
formspec generate <file> [className] [options]
|
|
136
|
+
formspec codegen <files...> [-o <output>]
|
|
137
|
+
|
|
138
|
+
Use 'formspec <command> --help' for more information about a command.
|
|
139
|
+
`);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Prints help for the generate command.
|
|
143
|
+
*/
|
|
144
|
+
function printGenerateHelp() {
|
|
145
|
+
console.log(`
|
|
146
|
+
formspec generate - Generate JSON Schema and UI Schema files from TypeScript
|
|
147
|
+
|
|
148
|
+
USAGE:
|
|
149
|
+
formspec generate <file> [className] [options]
|
|
150
|
+
|
|
151
|
+
ARGUMENTS:
|
|
152
|
+
<file> Path to TypeScript source file (.ts)
|
|
153
|
+
[className] Optional class name to analyze
|
|
154
|
+
|
|
155
|
+
OPTIONS:
|
|
156
|
+
-o, --output <dir> Output directory (default: ./generated)
|
|
157
|
+
-c, --compiled <path> Path to compiled JS file (auto-detected if omitted)
|
|
158
|
+
-h, --help Show this help message
|
|
159
|
+
|
|
160
|
+
EXAMPLES:
|
|
161
|
+
# Generate from a decorated class (static analysis only)
|
|
162
|
+
formspec generate ./src/forms.ts UserForm -o ./generated
|
|
163
|
+
|
|
164
|
+
# Generate from FormSpec exports (requires compiled JS)
|
|
165
|
+
# First compile using your build tool (tsc, esbuild, swc, etc.)
|
|
166
|
+
formspec generate ./src/forms.ts -o ./generated
|
|
167
|
+
|
|
168
|
+
HOW IT WORKS:
|
|
169
|
+
The CLI performs static analysis of TypeScript source files using the
|
|
170
|
+
TypeScript Compiler API. It reads decorator metadata and type information
|
|
171
|
+
directly from the AST - no compiled output needed for class analysis.
|
|
172
|
+
|
|
173
|
+
For FormSpec chain DSL exports (formspec(...)), the CLI needs to import
|
|
174
|
+
the compiled JavaScript to generate schemas at runtime. Compile your
|
|
175
|
+
TypeScript using your project's build process, or use the --compiled
|
|
176
|
+
flag to specify the JS path explicitly.
|
|
177
|
+
`);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Prints help for the codegen command.
|
|
181
|
+
*/
|
|
182
|
+
function printCodegenHelp() {
|
|
183
|
+
console.log(`
|
|
184
|
+
formspec codegen - Generate type metadata for runtime schema generation
|
|
185
|
+
|
|
186
|
+
USAGE:
|
|
187
|
+
formspec codegen <files...> [options]
|
|
188
|
+
|
|
189
|
+
ARGUMENTS:
|
|
190
|
+
<files...> TypeScript source files to analyze
|
|
191
|
+
|
|
192
|
+
OPTIONS:
|
|
193
|
+
-o, --output <file> Output file (default: ./__formspec_types__.ts)
|
|
194
|
+
-h, --help Show this help message
|
|
195
|
+
|
|
196
|
+
EXAMPLES:
|
|
197
|
+
formspec codegen ./src/forms.ts -o ./src/__formspec_types__.ts
|
|
198
|
+
formspec codegen ./src/**/*.ts -o ./src/__formspec_types__.ts
|
|
199
|
+
|
|
200
|
+
USAGE IN CODE:
|
|
201
|
+
After generating the type metadata file:
|
|
202
|
+
|
|
203
|
+
// Import once at application entry point
|
|
204
|
+
import './__formspec_types__';
|
|
205
|
+
|
|
206
|
+
// Then use the generated accessor functions
|
|
207
|
+
import { getUserFormFormSpec } from './__formspec_types__';
|
|
208
|
+
|
|
209
|
+
const spec = getUserFormFormSpec();
|
|
210
|
+
// Use \`spec\` with your preferred schema builder or form renderer.
|
|
211
|
+
|
|
212
|
+
Alternatively, use generateSchemasFromClass() for static analysis
|
|
213
|
+
without codegen:
|
|
214
|
+
|
|
215
|
+
import { generateSchemasFromClass } from '@formspec/build';
|
|
216
|
+
|
|
217
|
+
const { jsonSchema, uiSchema } = generateSchemasFromClass({
|
|
218
|
+
filePath: './src/forms.ts',
|
|
219
|
+
className: 'UserForm',
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
HOW IT WORKS:
|
|
223
|
+
TypeScript erases type information at runtime. This command extracts
|
|
224
|
+
type metadata (field types, enum values, optional/nullable flags) from
|
|
225
|
+
your decorated classes and generates a file that patches them with
|
|
226
|
+
a __formspec_types__ property and accessor functions.
|
|
227
|
+
|
|
228
|
+
Without codegen, use generateSchemasFromClass() from @formspec/build
|
|
229
|
+
for purely static analysis (no runtime metadata needed).
|
|
230
|
+
`);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Converts FormSpecSchemas to LoadedFormSpecSchemas for the build package API.
|
|
234
|
+
*/
|
|
235
|
+
function toLoadedSchemas(formSpecs) {
|
|
236
|
+
const result = new Map();
|
|
237
|
+
for (const [name, schemas] of formSpecs) {
|
|
238
|
+
result.set(name, {
|
|
239
|
+
name: schemas.name,
|
|
240
|
+
jsonSchema: schemas.jsonSchema,
|
|
241
|
+
uiSchema: schemas.uiSchema,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
return result;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Main CLI entry point.
|
|
248
|
+
*/
|
|
249
|
+
async function main() {
|
|
250
|
+
const args = process.argv.slice(2);
|
|
251
|
+
const options = parseArgs(args);
|
|
252
|
+
// Handle codegen command
|
|
253
|
+
if (options.command === "codegen") {
|
|
254
|
+
const codegenOptions = options;
|
|
255
|
+
runCodegen({
|
|
256
|
+
files: codegenOptions.files,
|
|
257
|
+
output: codegenOptions.output,
|
|
258
|
+
});
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
// Handle generate command
|
|
262
|
+
const generateOptions = options;
|
|
263
|
+
console.log(`Generating schemas from: ${generateOptions.filePath}`);
|
|
264
|
+
if (generateOptions.className) {
|
|
265
|
+
console.log(`Class: ${generateOptions.className}`);
|
|
266
|
+
}
|
|
267
|
+
console.log(`Output: ${generateOptions.outDir}`);
|
|
268
|
+
console.log();
|
|
269
|
+
try {
|
|
270
|
+
// Step 1: Static analysis with TypeScript
|
|
271
|
+
const ctx = createProgramContext(generateOptions.filePath);
|
|
272
|
+
console.log("✓ Created TypeScript program");
|
|
273
|
+
// Step 2: Resolve compiled JS path for runtime loading
|
|
274
|
+
const compiledPath = generateOptions.compiledPath ?? resolveCompiledPath(generateOptions.filePath);
|
|
275
|
+
// Step 3: Load all FormSpec exports from compiled module
|
|
276
|
+
let loadedFormSpecs = new Map();
|
|
277
|
+
let loadError;
|
|
278
|
+
try {
|
|
279
|
+
const { formSpecs } = await loadFormSpecs(compiledPath);
|
|
280
|
+
loadedFormSpecs = formSpecs;
|
|
281
|
+
console.log(`✓ Loaded ${String(formSpecs.size)} FormSpec export(s) from module`);
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
// Track load errors for better messaging later
|
|
285
|
+
// Runtime loading is only needed for chain DSL exports and method parameters
|
|
286
|
+
if (error instanceof Error && error.message.includes("Cannot find module")) {
|
|
287
|
+
loadError = `Compiled file not found at: ${compiledPath}`;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
// Step 4: If className specified, analyze the class
|
|
291
|
+
if (!generateOptions.className && loadedFormSpecs.size === 0) {
|
|
292
|
+
// No class name and no FormSpec exports - provide context-aware error
|
|
293
|
+
console.warn("⚠️ No class name specified and no FormSpec exports found.");
|
|
294
|
+
console.warn();
|
|
295
|
+
if (loadError) {
|
|
296
|
+
// Compiled file doesn't exist - suggest building first
|
|
297
|
+
console.warn(" For chain DSL forms, compile your TypeScript first:");
|
|
298
|
+
console.warn(` ${loadError}`);
|
|
299
|
+
console.warn();
|
|
300
|
+
console.warn(" Run your build tool (tsc, esbuild, swc, etc.) then try again.");
|
|
301
|
+
console.warn(" Or use -c/--compiled to specify the JS path explicitly:");
|
|
302
|
+
console.warn(` npx formspec generate ${generateOptions.filePath} -c ./dist/forms.js -o ${generateOptions.outDir}`);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
// Compiled file exists but no FormSpec exports found
|
|
306
|
+
console.warn(" For decorated classes, specify the class name:");
|
|
307
|
+
console.warn(` npx formspec generate ${generateOptions.filePath} <ClassName> -o ${generateOptions.outDir}`);
|
|
308
|
+
console.warn();
|
|
309
|
+
console.warn(" For chain DSL, export a FormSpec from your file:");
|
|
310
|
+
console.warn(" export const MyForm = formspec(...);");
|
|
311
|
+
}
|
|
312
|
+
console.warn();
|
|
313
|
+
process.exit(1);
|
|
314
|
+
}
|
|
315
|
+
if (generateOptions.className) {
|
|
316
|
+
const classDecl = findClassByName(ctx.sourceFile, generateOptions.className);
|
|
317
|
+
if (!classDecl) {
|
|
318
|
+
console.error(`Error: Class "${generateOptions.className}" not found in ${generateOptions.filePath}`);
|
|
319
|
+
process.exit(1);
|
|
320
|
+
}
|
|
321
|
+
// Analyze class
|
|
322
|
+
const analysis = analyzeClass(classDecl, ctx.checker);
|
|
323
|
+
console.log(`✓ Analyzed class "${analysis.name}" with ${String(analysis.fields.length)} field(s)`);
|
|
324
|
+
console.log(` Instance methods: ${String(analysis.instanceMethods.length)}`);
|
|
325
|
+
console.log(` Static methods: ${String(analysis.staticMethods.length)}`);
|
|
326
|
+
// Collect FormSpec references from methods
|
|
327
|
+
const allMethods = [...analysis.instanceMethods, ...analysis.staticMethods];
|
|
328
|
+
const formSpecRefs = collectFormSpecReferences(allMethods);
|
|
329
|
+
if (formSpecRefs.size > 0) {
|
|
330
|
+
console.log(` FormSpec refs: ${Array.from(formSpecRefs).join(", ")}`);
|
|
331
|
+
// Load specific FormSpecs if not already loaded
|
|
332
|
+
const missing = Array.from(formSpecRefs).filter((name) => !loadedFormSpecs.has(name));
|
|
333
|
+
if (missing.length > 0) {
|
|
334
|
+
try {
|
|
335
|
+
const namedFormSpecs = await loadNamedFormSpecs(compiledPath, missing);
|
|
336
|
+
for (const [name, schemas] of namedFormSpecs) {
|
|
337
|
+
loadedFormSpecs.set(name, schemas);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
catch {
|
|
341
|
+
// Already warned about module loading
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
// Generate class schemas
|
|
346
|
+
const classSchemas = generateClassSchemas(analysis, ctx.checker);
|
|
347
|
+
// Generate method schemas
|
|
348
|
+
const loadedSchemasMap = toLoadedSchemas(loadedFormSpecs);
|
|
349
|
+
const instanceMethodSchemas = analysis.instanceMethods.map((m) => generateMethodSchemas(m, ctx.checker, loadedSchemasMap));
|
|
350
|
+
const staticMethodSchemas = analysis.staticMethods.map((m) => generateMethodSchemas(m, ctx.checker, loadedSchemasMap));
|
|
351
|
+
// Write class output
|
|
352
|
+
const classResult = writeClassSchemas(analysis.name, classSchemas, instanceMethodSchemas, staticMethodSchemas, { outDir: generateOptions.outDir });
|
|
353
|
+
console.log(`✓ Wrote ${String(classResult.files.length)} file(s) to ${classResult.dir}`);
|
|
354
|
+
}
|
|
355
|
+
// Step 5: Write standalone FormSpec exports (chain DSL)
|
|
356
|
+
if (loadedFormSpecs.size > 0) {
|
|
357
|
+
const formSpecResult = writeFormSpecSchemas(loadedFormSpecs, {
|
|
358
|
+
outDir: generateOptions.outDir,
|
|
359
|
+
});
|
|
360
|
+
if (formSpecResult.files.length > 0) {
|
|
361
|
+
console.log(`✓ Wrote ${String(formSpecResult.files.length)} FormSpec file(s) to ${formSpecResult.dir}`);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
console.log();
|
|
365
|
+
console.log("Done!");
|
|
366
|
+
}
|
|
367
|
+
catch (error) {
|
|
368
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
369
|
+
process.exit(1);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
// Run CLI
|
|
373
|
+
void main();
|
|
374
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|