@formspec/cli 0.1.0-alpha.3
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 +314 -0
- package/dist/__tests__/analyzer.test.d.ts +5 -0
- package/dist/__tests__/analyzer.test.d.ts.map +1 -0
- package/dist/__tests__/analyzer.test.js +141 -0
- package/dist/__tests__/analyzer.test.js.map +1 -0
- package/dist/__tests__/codegen.test.d.ts +5 -0
- package/dist/__tests__/codegen.test.d.ts.map +1 -0
- package/dist/__tests__/codegen.test.js +482 -0
- package/dist/__tests__/codegen.test.js.map +1 -0
- package/dist/__tests__/edge-cases.test.d.ts +14 -0
- package/dist/__tests__/edge-cases.test.d.ts.map +1 -0
- package/dist/__tests__/edge-cases.test.js +432 -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 +135 -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 +159 -0
- package/dist/__tests__/integration.test.js.map +1 -0
- package/dist/analyzer/class-analyzer.d.ts +75 -0
- package/dist/analyzer/class-analyzer.d.ts.map +1 -0
- package/dist/analyzer/class-analyzer.js +151 -0
- package/dist/analyzer/class-analyzer.js.map +1 -0
- package/dist/analyzer/decorator-extractor.d.ts +87 -0
- package/dist/analyzer/decorator-extractor.d.ts.map +1 -0
- package/dist/analyzer/decorator-extractor.js +193 -0
- package/dist/analyzer/decorator-extractor.js.map +1 -0
- package/dist/analyzer/program.d.ts +37 -0
- package/dist/analyzer/program.d.ts.map +1 -0
- package/dist/analyzer/program.js +89 -0
- package/dist/analyzer/program.js.map +1 -0
- package/dist/analyzer/type-converter.d.ts +97 -0
- package/dist/analyzer/type-converter.d.ts.map +1 -0
- package/dist/analyzer/type-converter.js +353 -0
- package/dist/analyzer/type-converter.js.map +1 -0
- package/dist/codegen/index.d.ts +74 -0
- package/dist/codegen/index.d.ts.map +1 -0
- package/dist/codegen/index.js +501 -0
- package/dist/codegen/index.js.map +1 -0
- package/dist/generators/class-schema.d.ts +43 -0
- package/dist/generators/class-schema.d.ts.map +1 -0
- package/dist/generators/class-schema.js +61 -0
- package/dist/generators/class-schema.js.map +1 -0
- package/dist/generators/method-schema.d.ts +57 -0
- package/dist/generators/method-schema.d.ts.map +1 -0
- package/dist/generators/method-schema.js +108 -0
- package/dist/generators/method-schema.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +282 -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 +154 -0
- package/dist/runtime/formspec-loader.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output writer for creating the schema folder structure.
|
|
3
|
+
*
|
|
4
|
+
* Creates directories and writes JSON files for:
|
|
5
|
+
* - Class schema and UI Schema
|
|
6
|
+
* - Instance method schemas
|
|
7
|
+
* - Static method schemas
|
|
8
|
+
* - Standalone FormSpec exports (chain DSL)
|
|
9
|
+
*/
|
|
10
|
+
import * as fs from "node:fs";
|
|
11
|
+
import * as path from "node:path";
|
|
12
|
+
/**
|
|
13
|
+
* Writes all schemas for a class to the output directory.
|
|
14
|
+
*
|
|
15
|
+
* Creates the following structure:
|
|
16
|
+
* ```
|
|
17
|
+
* {outDir}/{className}/
|
|
18
|
+
* ├── schema.json
|
|
19
|
+
* ├── ux_spec.json
|
|
20
|
+
* ├── instance_methods/
|
|
21
|
+
* │ └── {methodName}/
|
|
22
|
+
* │ ├── params.schema.json
|
|
23
|
+
* │ ├── params.ux_spec.json (if FormSpec-based)
|
|
24
|
+
* │ └── return_type.schema.json
|
|
25
|
+
* └── static_methods/
|
|
26
|
+
* └── {methodName}/
|
|
27
|
+
* └── ...
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @param className - Name of the class
|
|
31
|
+
* @param classSchemas - Generated class schemas
|
|
32
|
+
* @param instanceMethods - Instance method schemas
|
|
33
|
+
* @param staticMethods - Static method schemas
|
|
34
|
+
* @param options - Write options
|
|
35
|
+
* @returns Write result with paths
|
|
36
|
+
*/
|
|
37
|
+
export function writeClassSchemas(className, classSchemas, instanceMethods, staticMethods, options) {
|
|
38
|
+
const { outDir, indent = 2 } = options;
|
|
39
|
+
const classDir = path.join(outDir, className);
|
|
40
|
+
const files = [];
|
|
41
|
+
// Ensure class directory exists
|
|
42
|
+
ensureDir(classDir);
|
|
43
|
+
// Write class schema
|
|
44
|
+
const schemaPath = path.join(classDir, "schema.json");
|
|
45
|
+
writeJson(schemaPath, classSchemas.jsonSchema, indent);
|
|
46
|
+
files.push(schemaPath);
|
|
47
|
+
// Write class UI Schema
|
|
48
|
+
const uxSpecPath = path.join(classDir, "ux_spec.json");
|
|
49
|
+
writeJson(uxSpecPath, classSchemas.uxSpec, indent);
|
|
50
|
+
files.push(uxSpecPath);
|
|
51
|
+
// Write instance methods
|
|
52
|
+
if (instanceMethods.length > 0) {
|
|
53
|
+
const instanceDir = path.join(classDir, "instance_methods");
|
|
54
|
+
ensureDir(instanceDir);
|
|
55
|
+
for (const method of instanceMethods) {
|
|
56
|
+
const methodFiles = writeMethodSchemas(method, instanceDir, indent);
|
|
57
|
+
files.push(...methodFiles);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Write static methods
|
|
61
|
+
if (staticMethods.length > 0) {
|
|
62
|
+
const staticDir = path.join(classDir, "static_methods");
|
|
63
|
+
ensureDir(staticDir);
|
|
64
|
+
for (const method of staticMethods) {
|
|
65
|
+
const methodFiles = writeMethodSchemas(method, staticDir, indent);
|
|
66
|
+
files.push(...methodFiles);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return { dir: classDir, files };
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Writes schemas for a single method.
|
|
73
|
+
*
|
|
74
|
+
* @param method - Method schemas
|
|
75
|
+
* @param parentDir - Parent directory (instance_methods or static_methods)
|
|
76
|
+
* @param indent - JSON indentation
|
|
77
|
+
* @returns Array of written file paths
|
|
78
|
+
*/
|
|
79
|
+
function writeMethodSchemas(method, parentDir, indent) {
|
|
80
|
+
const methodDir = path.join(parentDir, method.name);
|
|
81
|
+
ensureDir(methodDir);
|
|
82
|
+
const files = [];
|
|
83
|
+
// Write params schema
|
|
84
|
+
if (method.params) {
|
|
85
|
+
const paramsSchemaPath = path.join(methodDir, "params.schema.json");
|
|
86
|
+
writeJson(paramsSchemaPath, method.params.jsonSchema, indent);
|
|
87
|
+
files.push(paramsSchemaPath);
|
|
88
|
+
// Write params UI Schema if available (from FormSpec)
|
|
89
|
+
if (method.params.uxSpec) {
|
|
90
|
+
const paramsUxPath = path.join(methodDir, "params.ux_spec.json");
|
|
91
|
+
writeJson(paramsUxPath, method.params.uxSpec, indent);
|
|
92
|
+
files.push(paramsUxPath);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Write return type schema
|
|
96
|
+
const returnPath = path.join(methodDir, "return_type.schema.json");
|
|
97
|
+
writeJson(returnPath, method.returnType, indent);
|
|
98
|
+
files.push(returnPath);
|
|
99
|
+
return files;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Writes standalone FormSpec schemas (chain DSL exports).
|
|
103
|
+
*
|
|
104
|
+
* Creates the following structure:
|
|
105
|
+
* ```
|
|
106
|
+
* {outDir}/formspecs/
|
|
107
|
+
* └── {exportName}/
|
|
108
|
+
* ├── schema.json
|
|
109
|
+
* └── ux_spec.json
|
|
110
|
+
* ```
|
|
111
|
+
*
|
|
112
|
+
* @param formSpecs - Map of FormSpec export names to their schemas
|
|
113
|
+
* @param options - Write options
|
|
114
|
+
* @returns Write result with paths
|
|
115
|
+
*/
|
|
116
|
+
export function writeFormSpecSchemas(formSpecs, options) {
|
|
117
|
+
const { outDir, indent = 2 } = options;
|
|
118
|
+
const formspecsDir = path.join(outDir, "formspecs");
|
|
119
|
+
const files = [];
|
|
120
|
+
if (formSpecs.size === 0) {
|
|
121
|
+
return { dir: formspecsDir, files };
|
|
122
|
+
}
|
|
123
|
+
ensureDir(formspecsDir);
|
|
124
|
+
for (const [name, schemas] of formSpecs) {
|
|
125
|
+
const exportDir = path.join(formspecsDir, name);
|
|
126
|
+
ensureDir(exportDir);
|
|
127
|
+
// Write JSON Schema
|
|
128
|
+
const schemaPath = path.join(exportDir, "schema.json");
|
|
129
|
+
writeJson(schemaPath, schemas.jsonSchema, indent);
|
|
130
|
+
files.push(schemaPath);
|
|
131
|
+
// Write UI Schema
|
|
132
|
+
const uxSpecPath = path.join(exportDir, "ux_spec.json");
|
|
133
|
+
writeJson(uxSpecPath, schemas.uiSchema, indent);
|
|
134
|
+
files.push(uxSpecPath);
|
|
135
|
+
}
|
|
136
|
+
return { dir: formspecsDir, files };
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Ensures a directory exists, creating it if necessary.
|
|
140
|
+
*/
|
|
141
|
+
function ensureDir(dir) {
|
|
142
|
+
if (!fs.existsSync(dir)) {
|
|
143
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Writes a JSON object to a file.
|
|
148
|
+
*/
|
|
149
|
+
function writeJson(filePath, data, indent) {
|
|
150
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, indent) + "\n");
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/output/writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAmClC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,iBAAiB,CAC/B,SAAiB,EACjB,YAA0B,EAC1B,eAAgC,EAChC,aAA8B,EAC9B,OAAqB;IAErB,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,gCAAgC;IAChC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAEpB,qBAAqB;IACrB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;IACtD,SAAS,CAAC,UAAU,EAAE,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IACvD,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAEvB,wBAAwB;IACxB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;IACvD,SAAS,CAAC,UAAU,EAAE,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnD,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAEvB,yBAAyB;IACzB,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;QAC5D,SAAS,CAAC,WAAW,CAAC,CAAC;QAEvB,KAAK,MAAM,MAAM,IAAI,eAAe,EAAE,CAAC;YACrC,MAAM,WAAW,GAAG,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;YACpE,KAAK,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,uBAAuB;IACvB,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;QACxD,SAAS,CAAC,SAAS,CAAC,CAAC;QAErB,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE,CAAC;YACnC,MAAM,WAAW,GAAG,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;YAClE,KAAK,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AAClC,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,kBAAkB,CACzB,MAAqB,EACrB,SAAiB,EACjB,MAAc;IAEd,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IACpD,SAAS,CAAC,SAAS,CAAC,CAAC;IACrB,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,sBAAsB;IACtB,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;QACpE,SAAS,CAAC,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAC9D,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAE7B,sDAAsD;QACtD,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACzB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,qBAAqB,CAAC,CAAC;YACjE,SAAS,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACtD,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,2BAA2B;IAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,yBAAyB,CAAC,CAAC;IACnE,SAAS,CAAC,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IACjD,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAEvB,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,oBAAoB,CAClC,SAAuC,EACvC,OAAqB;IAErB,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC;IACvC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpD,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;IACtC,CAAC;IAED,SAAS,CAAC,YAAY,CAAC,CAAC;IAExB,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,SAAS,EAAE,CAAC;QACxC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QAChD,SAAS,CAAC,SAAS,CAAC,CAAC;QAErB,oBAAoB;QACpB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QACvD,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAClD,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAEvB,kBAAkB;QAClB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QACxD,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAChD,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACzB,CAAC;IAED,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,SAAS,SAAS,CAAC,GAAW;IAC5B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,SAAS,CAAC,QAAgB,EAAE,IAAa,EAAE,MAAc;IAChE,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACxE,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FormSpec loader for dynamic import and runtime access.
|
|
3
|
+
*
|
|
4
|
+
* Loads compiled TypeScript modules and extracts:
|
|
5
|
+
* - Exported FormSpec constants (chain DSL)
|
|
6
|
+
* - Specific exports by name (for method parameters)
|
|
7
|
+
*
|
|
8
|
+
* Uses the @formspec/build package to generate schemas from FormSpec objects.
|
|
9
|
+
*/
|
|
10
|
+
import type { JSONSchema7, UISchema } from "@formspec/build";
|
|
11
|
+
/**
|
|
12
|
+
* A FormSpec object (duck-typed for runtime detection).
|
|
13
|
+
*/
|
|
14
|
+
interface FormSpecLike {
|
|
15
|
+
elements: unknown[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Result of loading and generating schemas from a FormSpec.
|
|
19
|
+
*/
|
|
20
|
+
export interface FormSpecSchemas {
|
|
21
|
+
/** The FormSpec export name */
|
|
22
|
+
name: string;
|
|
23
|
+
/** Generated JSON Schema */
|
|
24
|
+
jsonSchema: JSONSchema7;
|
|
25
|
+
/** Generated UI Schema (FormSpec/JSON Forms) */
|
|
26
|
+
uiSchema: UISchema;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Result of loading all FormSpecs from a module.
|
|
30
|
+
*/
|
|
31
|
+
export interface ModuleFormSpecs {
|
|
32
|
+
/** All FormSpec exports found in the module */
|
|
33
|
+
formSpecs: Map<string, FormSpecSchemas>;
|
|
34
|
+
/** The raw module for accessing other exports */
|
|
35
|
+
module: Record<string, unknown>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Checks if a value is a FormSpec object.
|
|
39
|
+
*
|
|
40
|
+
* Uses duck typing since the actual FormSpec type may come from
|
|
41
|
+
* different package versions.
|
|
42
|
+
*/
|
|
43
|
+
export declare function isFormSpec(value: unknown): value is FormSpecLike;
|
|
44
|
+
/**
|
|
45
|
+
* Loads a module and extracts all FormSpec exports.
|
|
46
|
+
*
|
|
47
|
+
* This handles both:
|
|
48
|
+
* - Chain DSL: `export const MyForm = formspec(...)`
|
|
49
|
+
* - Method parameters: exports referenced by `InferSchema<typeof X>`
|
|
50
|
+
*
|
|
51
|
+
* @param filePath - Path to the compiled JavaScript file
|
|
52
|
+
* @returns Map of export names to their generated schemas
|
|
53
|
+
*/
|
|
54
|
+
export declare function loadFormSpecs(filePath: string): Promise<ModuleFormSpecs>;
|
|
55
|
+
/**
|
|
56
|
+
* Loads specific FormSpec exports by name.
|
|
57
|
+
*
|
|
58
|
+
* Use this when you know which exports to load (e.g., from static analysis
|
|
59
|
+
* of `InferSchema<typeof X>` patterns in method parameters).
|
|
60
|
+
*
|
|
61
|
+
* @param filePath - Path to the compiled JavaScript file
|
|
62
|
+
* @param exportNames - Names of exports to load
|
|
63
|
+
* @returns Map of found FormSpecs with their schemas
|
|
64
|
+
*/
|
|
65
|
+
export declare function loadNamedFormSpecs(filePath: string, exportNames: string[]): Promise<Map<string, FormSpecSchemas>>;
|
|
66
|
+
/**
|
|
67
|
+
* Resolves the compiled JS path from a TS source path.
|
|
68
|
+
*
|
|
69
|
+
* This handles common TypeScript output patterns:
|
|
70
|
+
* - ./src/*.ts → ./dist/*.js
|
|
71
|
+
* - ./src/*.ts → ./build/*.js
|
|
72
|
+
* - ./src/*.ts → ./src/*.js (in-place compilation)
|
|
73
|
+
*
|
|
74
|
+
* @param tsPath - Path to the TypeScript source file
|
|
75
|
+
* @param outDir - Optional explicit output directory
|
|
76
|
+
* @returns Path to the expected compiled JS file
|
|
77
|
+
*/
|
|
78
|
+
export declare function resolveCompiledPath(tsPath: string, outDir?: string): string;
|
|
79
|
+
export {};
|
|
80
|
+
//# sourceMappingURL=formspec-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formspec-loader.d.ts","sourceRoot":"","sources":["../../src/runtime/formspec-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAI7D;;GAEG;AACH,UAAU,YAAY;IACpB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,UAAU,EAAE,WAAW,CAAC;IACxB,gDAAgD;IAChD,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,+CAA+C;IAC/C,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACxC,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,YAAY,CAoBhE;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAoC9E;AAED;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EAAE,GACpB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAmCvC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAiC3E"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FormSpec loader for dynamic import and runtime access.
|
|
3
|
+
*
|
|
4
|
+
* Loads compiled TypeScript modules and extracts:
|
|
5
|
+
* - Exported FormSpec constants (chain DSL)
|
|
6
|
+
* - Specific exports by name (for method parameters)
|
|
7
|
+
*
|
|
8
|
+
* Uses the @formspec/build package to generate schemas from FormSpec objects.
|
|
9
|
+
*/
|
|
10
|
+
import { generateJsonSchema, generateUiSchema } from "@formspec/build";
|
|
11
|
+
import * as path from "node:path";
|
|
12
|
+
import { pathToFileURL } from "node:url";
|
|
13
|
+
/**
|
|
14
|
+
* Checks if a value is a FormSpec object.
|
|
15
|
+
*
|
|
16
|
+
* Uses duck typing since the actual FormSpec type may come from
|
|
17
|
+
* different package versions.
|
|
18
|
+
*/
|
|
19
|
+
export function isFormSpec(value) {
|
|
20
|
+
if (value === null || typeof value !== "object") {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
const obj = value;
|
|
24
|
+
// FormSpec objects have an 'elements' array property
|
|
25
|
+
const elements = obj["elements"];
|
|
26
|
+
if (!Array.isArray(elements)) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
// Each element should have a _type property with a string value
|
|
30
|
+
return elements.every((el) => el !== null &&
|
|
31
|
+
typeof el === "object" &&
|
|
32
|
+
typeof el._type === "string");
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Loads a module and extracts all FormSpec exports.
|
|
36
|
+
*
|
|
37
|
+
* This handles both:
|
|
38
|
+
* - Chain DSL: `export const MyForm = formspec(...)`
|
|
39
|
+
* - Method parameters: exports referenced by `InferSchema<typeof X>`
|
|
40
|
+
*
|
|
41
|
+
* @param filePath - Path to the compiled JavaScript file
|
|
42
|
+
* @returns Map of export names to their generated schemas
|
|
43
|
+
*/
|
|
44
|
+
export async function loadFormSpecs(filePath) {
|
|
45
|
+
const absolutePath = path.resolve(filePath);
|
|
46
|
+
// Convert to file URL for ESM import
|
|
47
|
+
const fileUrl = pathToFileURL(absolutePath).href;
|
|
48
|
+
// Dynamic import
|
|
49
|
+
const module = (await import(fileUrl));
|
|
50
|
+
const formSpecs = new Map();
|
|
51
|
+
// Find all FormSpec exports
|
|
52
|
+
for (const [name, value] of Object.entries(module)) {
|
|
53
|
+
if (isFormSpec(value)) {
|
|
54
|
+
try {
|
|
55
|
+
// Use @formspec/build generators
|
|
56
|
+
// The types expect FormSpec<readonly FormElement[]>
|
|
57
|
+
// but we're duck-typing at runtime
|
|
58
|
+
const jsonSchema = generateJsonSchema(value);
|
|
59
|
+
const uiSchema = generateUiSchema(value);
|
|
60
|
+
formSpecs.set(name, {
|
|
61
|
+
name,
|
|
62
|
+
jsonSchema,
|
|
63
|
+
uiSchema,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
console.warn(`Warning: Failed to generate schemas for export "${name}":`, error instanceof Error ? error.message : error);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return { formSpecs, module };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Loads specific FormSpec exports by name.
|
|
75
|
+
*
|
|
76
|
+
* Use this when you know which exports to load (e.g., from static analysis
|
|
77
|
+
* of `InferSchema<typeof X>` patterns in method parameters).
|
|
78
|
+
*
|
|
79
|
+
* @param filePath - Path to the compiled JavaScript file
|
|
80
|
+
* @param exportNames - Names of exports to load
|
|
81
|
+
* @returns Map of found FormSpecs with their schemas
|
|
82
|
+
*/
|
|
83
|
+
export async function loadNamedFormSpecs(filePath, exportNames) {
|
|
84
|
+
const { formSpecs, module } = await loadFormSpecs(filePath);
|
|
85
|
+
const result = new Map();
|
|
86
|
+
for (const name of exportNames) {
|
|
87
|
+
// Check if we already have it from the full scan
|
|
88
|
+
const existing = formSpecs.get(name);
|
|
89
|
+
if (existing) {
|
|
90
|
+
result.set(name, existing);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
// Try to access it directly from the module
|
|
94
|
+
const value = module[name];
|
|
95
|
+
if (value && isFormSpec(value)) {
|
|
96
|
+
try {
|
|
97
|
+
const jsonSchema = generateJsonSchema(value);
|
|
98
|
+
const uiSchema = generateUiSchema(value);
|
|
99
|
+
result.set(name, { name, jsonSchema, uiSchema });
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
console.warn(`Warning: Failed to generate schemas for "${name}":`, error instanceof Error ? error.message : error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else if (value) {
|
|
106
|
+
console.warn(`Warning: Export "${name}" exists but is not a valid FormSpec object`);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
console.warn(`Warning: Export "${name}" not found in module`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Resolves the compiled JS path from a TS source path.
|
|
116
|
+
*
|
|
117
|
+
* This handles common TypeScript output patterns:
|
|
118
|
+
* - ./src/*.ts → ./dist/*.js
|
|
119
|
+
* - ./src/*.ts → ./build/*.js
|
|
120
|
+
* - ./src/*.ts → ./src/*.js (in-place compilation)
|
|
121
|
+
*
|
|
122
|
+
* @param tsPath - Path to the TypeScript source file
|
|
123
|
+
* @param outDir - Optional explicit output directory
|
|
124
|
+
* @returns Path to the expected compiled JS file
|
|
125
|
+
*/
|
|
126
|
+
export function resolveCompiledPath(tsPath, outDir) {
|
|
127
|
+
const absolutePath = path.resolve(tsPath);
|
|
128
|
+
const ext = path.extname(absolutePath);
|
|
129
|
+
// Already a JS file
|
|
130
|
+
if (ext === ".js" || ext === ".mjs" || ext === ".cjs") {
|
|
131
|
+
return absolutePath;
|
|
132
|
+
}
|
|
133
|
+
// Replace .ts/.tsx/.mts extension with .js
|
|
134
|
+
const basePath = absolutePath.replace(/\.(ts|tsx|mts)$/, ".js");
|
|
135
|
+
if (outDir) {
|
|
136
|
+
// If outDir is specified, replace src dir with outDir
|
|
137
|
+
const fileName = path.basename(basePath);
|
|
138
|
+
const dirName = path.dirname(absolutePath);
|
|
139
|
+
// Try to find 'src' in the path and replace with outDir
|
|
140
|
+
const srcPattern = path.sep + "src";
|
|
141
|
+
const srcIndex = dirName.lastIndexOf(srcPattern);
|
|
142
|
+
if (srcIndex !== -1) {
|
|
143
|
+
const baseDir = dirName.substring(0, srcIndex);
|
|
144
|
+
const subPath = dirName.substring(srcIndex + srcPattern.length);
|
|
145
|
+
return path.join(baseDir, outDir, subPath, fileName);
|
|
146
|
+
}
|
|
147
|
+
// Fallback: just use outDir relative to file's directory
|
|
148
|
+
return path.join(path.dirname(absolutePath), outDir, fileName);
|
|
149
|
+
}
|
|
150
|
+
// Return basePath (actual existence check happens at import time)
|
|
151
|
+
// Future enhancement: could check fs.existsSync for common patterns
|
|
152
|
+
return basePath;
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=formspec-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formspec-loader.js","sourceRoot":"","sources":["../../src/runtime/formspec-loader.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@formspec/cli",
|
|
3
|
+
"version": "0.1.0-alpha.3",
|
|
4
|
+
"description": "CLI tool for generating JSON Schema and FormSpec from TypeScript classes",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"formspec": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"typescript": "^5.0.0",
|
|
22
|
+
"@formspec/build": "0.1.0-alpha.2"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"vitest": "^3.0.0",
|
|
26
|
+
"@formspec/core": "0.1.0-alpha.2",
|
|
27
|
+
"@formspec/dsl": "0.1.0-alpha.2"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"license": "UNLICENSED",
|
|
33
|
+
"keywords": [
|
|
34
|
+
"formspec",
|
|
35
|
+
"cli",
|
|
36
|
+
"typescript",
|
|
37
|
+
"json-schema",
|
|
38
|
+
"code-generation"
|
|
39
|
+
],
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsc",
|
|
42
|
+
"clean": "rm -rf dist",
|
|
43
|
+
"typecheck": "tsc --noEmit",
|
|
44
|
+
"test": "vitest run"
|
|
45
|
+
}
|
|
46
|
+
}
|