@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,501 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code generation for FormSpec type metadata.
|
|
3
|
+
*
|
|
4
|
+
* Generates a TypeScript file that patches decorated classes with
|
|
5
|
+
* their extracted type metadata, enabling runtime schema generation
|
|
6
|
+
* as an alternative to a TypeScript transformer.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* formspec codegen ./src/forms.ts -o ./src/__formspec_types__.ts
|
|
10
|
+
*
|
|
11
|
+
* Then in your code:
|
|
12
|
+
* import './__formspec_types__'; // Patches all decorated classes
|
|
13
|
+
* import { UserForm } from './forms';
|
|
14
|
+
* import { toFormSpec } from '@formspec/decorators';
|
|
15
|
+
* const spec = toFormSpec(UserForm);
|
|
16
|
+
*/
|
|
17
|
+
import * as ts from "typescript";
|
|
18
|
+
import * as path from "path";
|
|
19
|
+
import * as fs from "fs";
|
|
20
|
+
/**
|
|
21
|
+
* Finds all decorated classes in the given source files.
|
|
22
|
+
*/
|
|
23
|
+
export function findDecoratedClasses(files, baseDir) {
|
|
24
|
+
const program = ts.createProgram(files, {
|
|
25
|
+
target: ts.ScriptTarget.ESNext,
|
|
26
|
+
module: ts.ModuleKind.ESNext,
|
|
27
|
+
moduleResolution: ts.ModuleResolutionKind.NodeNext,
|
|
28
|
+
experimentalDecorators: true,
|
|
29
|
+
strict: true,
|
|
30
|
+
});
|
|
31
|
+
const checker = program.getTypeChecker();
|
|
32
|
+
const results = [];
|
|
33
|
+
for (const sourceFile of program.getSourceFiles()) {
|
|
34
|
+
if (sourceFile.isDeclarationFile)
|
|
35
|
+
continue;
|
|
36
|
+
if (!files.some((f) => path.resolve(f) === sourceFile.fileName))
|
|
37
|
+
continue;
|
|
38
|
+
ts.forEachChild(sourceFile, (node) => {
|
|
39
|
+
if (ts.isClassDeclaration(node) && hasDecoratedProperties(node)) {
|
|
40
|
+
const className = node.name?.text;
|
|
41
|
+
if (!className)
|
|
42
|
+
return;
|
|
43
|
+
const typeMetadata = extractTypeMetadata(node, checker);
|
|
44
|
+
const relativePath = path.relative(baseDir, sourceFile.fileName);
|
|
45
|
+
results.push({
|
|
46
|
+
name: className,
|
|
47
|
+
sourcePath: relativePath.replace(/\.tsx?$/, ""),
|
|
48
|
+
typeMetadata,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return results;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Checks if a class has any decorated properties.
|
|
57
|
+
*/
|
|
58
|
+
function hasDecoratedProperties(node) {
|
|
59
|
+
return node.members.some((member) => {
|
|
60
|
+
if (!ts.isPropertyDeclaration(member))
|
|
61
|
+
return false;
|
|
62
|
+
const decorators = ts.getDecorators(member);
|
|
63
|
+
return decorators !== undefined && decorators.length > 0;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Extracts type metadata for all properties in a class.
|
|
68
|
+
*/
|
|
69
|
+
function extractTypeMetadata(classNode, checker) {
|
|
70
|
+
const metadata = {};
|
|
71
|
+
for (const member of classNode.members) {
|
|
72
|
+
if (!ts.isPropertyDeclaration(member))
|
|
73
|
+
continue;
|
|
74
|
+
if (!member.name || !ts.isIdentifier(member.name))
|
|
75
|
+
continue;
|
|
76
|
+
const symbol = checker.getSymbolAtLocation(member.name);
|
|
77
|
+
if (!symbol)
|
|
78
|
+
continue;
|
|
79
|
+
const type = checker.getTypeOfSymbolAtLocation(symbol, member);
|
|
80
|
+
const fieldName = member.name.text;
|
|
81
|
+
const isOptional = !!(symbol.flags & ts.SymbolFlags.Optional);
|
|
82
|
+
const typeInfo = convertTypeToMetadata(type, checker);
|
|
83
|
+
if (isOptional) {
|
|
84
|
+
typeInfo.optional = true;
|
|
85
|
+
}
|
|
86
|
+
metadata[fieldName] = typeInfo;
|
|
87
|
+
}
|
|
88
|
+
return metadata;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Converts a TypeScript type to serializable metadata.
|
|
92
|
+
*/
|
|
93
|
+
function convertTypeToMetadata(type, checker, visited = new Set()) {
|
|
94
|
+
// Cycle detection for object types only
|
|
95
|
+
const isObjectType = (type.flags & ts.TypeFlags.Object) !== 0;
|
|
96
|
+
if (isObjectType) {
|
|
97
|
+
if (visited.has(type)) {
|
|
98
|
+
return { type: "unknown" };
|
|
99
|
+
}
|
|
100
|
+
visited.add(type);
|
|
101
|
+
}
|
|
102
|
+
// Handle union types
|
|
103
|
+
if (type.isUnion()) {
|
|
104
|
+
const types = type.types;
|
|
105
|
+
const nonNullTypes = types.filter((t) => !(t.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined)));
|
|
106
|
+
const hasNull = types.some((t) => t.flags & ts.TypeFlags.Null);
|
|
107
|
+
// Boolean union (true | false)
|
|
108
|
+
const isBooleanUnion = nonNullTypes.length === 2 &&
|
|
109
|
+
nonNullTypes.every((t) => t.flags & ts.TypeFlags.BooleanLiteral);
|
|
110
|
+
if (isBooleanUnion) {
|
|
111
|
+
const result = { type: "boolean" };
|
|
112
|
+
if (hasNull)
|
|
113
|
+
result.nullable = true;
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
// String literal union = enum
|
|
117
|
+
const allStringLiterals = nonNullTypes.every((t) => t.isStringLiteral());
|
|
118
|
+
if (allStringLiterals && nonNullTypes.length > 0) {
|
|
119
|
+
const result = {
|
|
120
|
+
type: "enum",
|
|
121
|
+
values: nonNullTypes.map((t) => t.value),
|
|
122
|
+
};
|
|
123
|
+
if (hasNull)
|
|
124
|
+
result.nullable = true;
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
127
|
+
// Number literal union = enum
|
|
128
|
+
const allNumberLiterals = nonNullTypes.every((t) => t.isNumberLiteral());
|
|
129
|
+
if (allNumberLiterals && nonNullTypes.length > 0) {
|
|
130
|
+
const result = {
|
|
131
|
+
type: "enum",
|
|
132
|
+
values: nonNullTypes.map((t) => t.value),
|
|
133
|
+
};
|
|
134
|
+
if (hasNull)
|
|
135
|
+
result.nullable = true;
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
// Nullable single type
|
|
139
|
+
if (nonNullTypes.length === 1 && nonNullTypes[0]) {
|
|
140
|
+
const result = convertTypeToMetadata(nonNullTypes[0], checker, visited);
|
|
141
|
+
if (hasNull)
|
|
142
|
+
result.nullable = true;
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
return { type: "unknown" };
|
|
146
|
+
}
|
|
147
|
+
// Primitives
|
|
148
|
+
if (type.flags & ts.TypeFlags.String)
|
|
149
|
+
return { type: "string" };
|
|
150
|
+
if (type.flags & ts.TypeFlags.Number)
|
|
151
|
+
return { type: "number" };
|
|
152
|
+
if (type.flags & ts.TypeFlags.Boolean)
|
|
153
|
+
return { type: "boolean" };
|
|
154
|
+
// String literal
|
|
155
|
+
if (type.isStringLiteral()) {
|
|
156
|
+
return { type: "enum", values: [type.value] };
|
|
157
|
+
}
|
|
158
|
+
// Number literal
|
|
159
|
+
if (type.isNumberLiteral()) {
|
|
160
|
+
return { type: "enum", values: [type.value] };
|
|
161
|
+
}
|
|
162
|
+
// Arrays
|
|
163
|
+
if (checker.isArrayType(type)) {
|
|
164
|
+
const typeArgs = type.typeArguments;
|
|
165
|
+
return {
|
|
166
|
+
type: "array",
|
|
167
|
+
itemType: typeArgs?.[0]
|
|
168
|
+
? convertTypeToMetadata(typeArgs[0], checker, visited)
|
|
169
|
+
: { type: "unknown" },
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
// Objects
|
|
173
|
+
if (type.flags & ts.TypeFlags.Object) {
|
|
174
|
+
const properties = {};
|
|
175
|
+
for (const prop of type.getProperties()) {
|
|
176
|
+
// Skip properties without declarations (can't determine type safely)
|
|
177
|
+
const declaration = prop.valueDeclaration ?? prop.declarations?.[0];
|
|
178
|
+
if (!declaration)
|
|
179
|
+
continue;
|
|
180
|
+
const propType = checker.getTypeOfSymbolAtLocation(prop, declaration);
|
|
181
|
+
const propOptional = !!(prop.flags & ts.SymbolFlags.Optional);
|
|
182
|
+
const propMeta = convertTypeToMetadata(propType, checker, visited);
|
|
183
|
+
if (propOptional)
|
|
184
|
+
propMeta.optional = true;
|
|
185
|
+
properties[prop.name] = propMeta;
|
|
186
|
+
}
|
|
187
|
+
if (Object.keys(properties).length > 0) {
|
|
188
|
+
return { type: "object", properties };
|
|
189
|
+
}
|
|
190
|
+
return { type: "object" };
|
|
191
|
+
}
|
|
192
|
+
return { type: "unknown" };
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Generates the codegen output file content.
|
|
196
|
+
*/
|
|
197
|
+
export function generateCodegenOutput(classes, outputPath, baseDir) {
|
|
198
|
+
const outputDir = path.dirname(path.resolve(outputPath));
|
|
199
|
+
const lines = [
|
|
200
|
+
"/**",
|
|
201
|
+
" * Auto-generated by FormSpec CLI.",
|
|
202
|
+
" * DO NOT EDIT - changes will be overwritten.",
|
|
203
|
+
" *",
|
|
204
|
+
" * This file provides:",
|
|
205
|
+
" * - Type metadata patches for runtime schema generation",
|
|
206
|
+
" * - Inferred schema types (e.g., UserFormSchema)",
|
|
207
|
+
" * - Type-safe FormSpec accessors (e.g., getUserFormFormSpec())",
|
|
208
|
+
" *",
|
|
209
|
+
" * Usage:",
|
|
210
|
+
" * import { UserFormSchema, getUserFormFormSpec } from './__formspec_types__';",
|
|
211
|
+
" *",
|
|
212
|
+
" * const data: UserFormSchema = { name: 'Alice', country: 'us' };",
|
|
213
|
+
" * const spec = getUserFormFormSpec();",
|
|
214
|
+
" */",
|
|
215
|
+
"",
|
|
216
|
+
"/* eslint-disable @typescript-eslint/no-explicit-any */",
|
|
217
|
+
"",
|
|
218
|
+
];
|
|
219
|
+
// Generate imports
|
|
220
|
+
lines.push(`import { toFormSpec } from "@formspec/decorators";`);
|
|
221
|
+
for (const cls of classes) {
|
|
222
|
+
// Compute absolute source path, then relative from output dir
|
|
223
|
+
const absoluteSourcePath = path.resolve(baseDir, cls.sourcePath);
|
|
224
|
+
const importPath = getRelativeImportPath(outputDir, absoluteSourcePath);
|
|
225
|
+
lines.push(`import { ${cls.name} } from "${importPath}";`);
|
|
226
|
+
}
|
|
227
|
+
lines.push("");
|
|
228
|
+
lines.push("// =============================================================================");
|
|
229
|
+
lines.push("// Type Metadata Patches");
|
|
230
|
+
lines.push("// =============================================================================");
|
|
231
|
+
lines.push("");
|
|
232
|
+
// Generate patches
|
|
233
|
+
for (const cls of classes) {
|
|
234
|
+
const metadataJson = JSON.stringify(cls.typeMetadata, null, 2)
|
|
235
|
+
.split("\n")
|
|
236
|
+
.map((line, i) => (i === 0 ? line : " " + line))
|
|
237
|
+
.join("\n");
|
|
238
|
+
lines.push(`(${cls.name} as any).__formspec_types__ = ${metadataJson};`);
|
|
239
|
+
lines.push("");
|
|
240
|
+
}
|
|
241
|
+
lines.push("// =============================================================================");
|
|
242
|
+
lines.push("// Inferred Schema Types");
|
|
243
|
+
lines.push("// =============================================================================");
|
|
244
|
+
lines.push("");
|
|
245
|
+
// Generate schema types
|
|
246
|
+
for (const cls of classes) {
|
|
247
|
+
lines.push(generateSchemaType(cls));
|
|
248
|
+
lines.push("");
|
|
249
|
+
}
|
|
250
|
+
lines.push("// =============================================================================");
|
|
251
|
+
lines.push("// Type-Safe FormSpec Accessors");
|
|
252
|
+
lines.push("// =============================================================================");
|
|
253
|
+
lines.push("");
|
|
254
|
+
// Generate typed accessors
|
|
255
|
+
for (const cls of classes) {
|
|
256
|
+
lines.push(generateTypedAccessor(cls));
|
|
257
|
+
lines.push("");
|
|
258
|
+
}
|
|
259
|
+
return lines.join("\n");
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Converts TypeMetadata to a TypeScript type string.
|
|
263
|
+
*/
|
|
264
|
+
function metadataToTypeString(metadata) {
|
|
265
|
+
const baseType = metadataToBaseTypeString(metadata);
|
|
266
|
+
// Handle nullable and optional modifiers
|
|
267
|
+
if (metadata.nullable && metadata.optional) {
|
|
268
|
+
return `${baseType} | null | undefined`;
|
|
269
|
+
}
|
|
270
|
+
if (metadata.nullable) {
|
|
271
|
+
return `${baseType} | null`;
|
|
272
|
+
}
|
|
273
|
+
if (metadata.optional) {
|
|
274
|
+
return `${baseType} | undefined`;
|
|
275
|
+
}
|
|
276
|
+
return baseType;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Checks if a property key needs to be quoted in TypeScript object types.
|
|
280
|
+
*
|
|
281
|
+
* Property keys need quoting if they:
|
|
282
|
+
* - Contain characters invalid in JavaScript identifiers (spaces, hyphens, etc.)
|
|
283
|
+
* - Are reserved JavaScript/TypeScript keywords (class, function, etc.)
|
|
284
|
+
*
|
|
285
|
+
* @param key - The property name to check
|
|
286
|
+
* @returns true if the key requires quotes, false otherwise
|
|
287
|
+
*/
|
|
288
|
+
function needsPropertyQuoting(key) {
|
|
289
|
+
// Valid JS identifier: starts with letter/underscore/$, followed by alphanumeric/_/$
|
|
290
|
+
const validIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
291
|
+
if (!validIdentifier.test(key)) {
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
294
|
+
// Reserved words that need quoting (comprehensive list including ES6+)
|
|
295
|
+
const reservedWords = new Set([
|
|
296
|
+
// Keywords
|
|
297
|
+
"break", "case", "catch", "continue", "debugger", "default", "delete",
|
|
298
|
+
"do", "else", "finally", "for", "function", "if", "in", "instanceof",
|
|
299
|
+
"new", "return", "switch", "this", "throw", "try", "typeof", "var",
|
|
300
|
+
"void", "while", "with", "class", "const", "enum", "export", "extends",
|
|
301
|
+
"import", "super", "implements", "interface", "let", "package", "private",
|
|
302
|
+
"protected", "public", "static", "yield",
|
|
303
|
+
// ES6+ keywords
|
|
304
|
+
"async", "await",
|
|
305
|
+
// Literal values (not technically keywords but best to quote)
|
|
306
|
+
"null", "true", "false",
|
|
307
|
+
// Accessor keywords
|
|
308
|
+
"get", "set",
|
|
309
|
+
// Strict mode reserved
|
|
310
|
+
"arguments", "eval",
|
|
311
|
+
]);
|
|
312
|
+
return reservedWords.has(key);
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Escapes a property key for safe use in TypeScript type definitions.
|
|
316
|
+
*
|
|
317
|
+
* Wraps keys in double quotes if they need quoting, using JSON.stringify
|
|
318
|
+
* for robust escaping of special characters.
|
|
319
|
+
*
|
|
320
|
+
* @param key - The property name to escape
|
|
321
|
+
* @returns The escaped key, quoted if necessary
|
|
322
|
+
*/
|
|
323
|
+
function escapePropertyKey(key) {
|
|
324
|
+
if (needsPropertyQuoting(key)) {
|
|
325
|
+
return JSON.stringify(key);
|
|
326
|
+
}
|
|
327
|
+
return key;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Converts TypeMetadata to base type string (without null/optional modifiers).
|
|
331
|
+
*/
|
|
332
|
+
function metadataToBaseTypeString(metadata) {
|
|
333
|
+
switch (metadata.type) {
|
|
334
|
+
case "string":
|
|
335
|
+
return "string";
|
|
336
|
+
case "number":
|
|
337
|
+
return "number";
|
|
338
|
+
case "boolean":
|
|
339
|
+
return "boolean";
|
|
340
|
+
case "enum":
|
|
341
|
+
if (metadata.values && metadata.values.length > 0) {
|
|
342
|
+
return metadata.values
|
|
343
|
+
.map((v) => (typeof v === "string" ? JSON.stringify(v) : String(v)))
|
|
344
|
+
.join(" | ");
|
|
345
|
+
}
|
|
346
|
+
return "string";
|
|
347
|
+
case "array":
|
|
348
|
+
if (metadata.itemType) {
|
|
349
|
+
const itemType = metadataToTypeString(metadata.itemType);
|
|
350
|
+
// Wrap union types in parentheses for array
|
|
351
|
+
if (itemType.includes("|")) {
|
|
352
|
+
return `(${itemType})[]`;
|
|
353
|
+
}
|
|
354
|
+
return `${itemType}[]`;
|
|
355
|
+
}
|
|
356
|
+
return "unknown[]";
|
|
357
|
+
case "object":
|
|
358
|
+
if (metadata.properties && Object.keys(metadata.properties).length > 0) {
|
|
359
|
+
const props = Object.entries(metadata.properties)
|
|
360
|
+
.map(([key, propMeta]) => {
|
|
361
|
+
const optional = propMeta.optional ? "?" : "";
|
|
362
|
+
return `${escapePropertyKey(key)}${optional}: ${metadataToTypeString(propMeta)}`;
|
|
363
|
+
})
|
|
364
|
+
.join("; ");
|
|
365
|
+
return `{ ${props} }`;
|
|
366
|
+
}
|
|
367
|
+
return "Record<string, unknown>";
|
|
368
|
+
default:
|
|
369
|
+
return "unknown";
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Generates a TypeScript schema type for a class.
|
|
374
|
+
*/
|
|
375
|
+
function generateSchemaType(cls) {
|
|
376
|
+
const props = Object.entries(cls.typeMetadata)
|
|
377
|
+
.map(([fieldName, metadata]) => {
|
|
378
|
+
const optional = metadata.optional ? "?" : "";
|
|
379
|
+
const typeStr = metadataToTypeString(metadata);
|
|
380
|
+
return ` ${escapePropertyKey(fieldName)}${optional}: ${typeStr};`;
|
|
381
|
+
})
|
|
382
|
+
.join("\n");
|
|
383
|
+
return `export type ${cls.name}Schema = {\n${props}\n};`;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Maps TypeMetadata type strings to FormSpec field type strings.
|
|
387
|
+
*
|
|
388
|
+
* TypeMetadata uses generic type names (string, number), while FormSpec
|
|
389
|
+
* uses more specific field type names (text, number, enum).
|
|
390
|
+
*
|
|
391
|
+
* @param type - The TypeMetadata type string
|
|
392
|
+
* @returns The corresponding FormSpec field type
|
|
393
|
+
*/
|
|
394
|
+
function metadataTypeToFieldType(type) {
|
|
395
|
+
switch (type) {
|
|
396
|
+
case "string":
|
|
397
|
+
return "text";
|
|
398
|
+
case "number":
|
|
399
|
+
return "number";
|
|
400
|
+
case "boolean":
|
|
401
|
+
return "boolean";
|
|
402
|
+
case "enum":
|
|
403
|
+
return "enum";
|
|
404
|
+
case "array":
|
|
405
|
+
return "array";
|
|
406
|
+
case "object":
|
|
407
|
+
return "object";
|
|
408
|
+
default:
|
|
409
|
+
return "text";
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Generates typed FormSpec accessor for a class.
|
|
414
|
+
*
|
|
415
|
+
* Creates three exports:
|
|
416
|
+
* 1. Element tuple type (e.g., UserFormElements) - Exact readonly array type
|
|
417
|
+
* representing each field with its literal types preserved
|
|
418
|
+
* 2. FormSpec result type (e.g., UserFormFormSpec) - Type alias wrapping the elements
|
|
419
|
+
* 3. Accessor function (e.g., getUserFormFormSpec()) - Returns FormSpec with full
|
|
420
|
+
* type information for autocomplete and type checking
|
|
421
|
+
*
|
|
422
|
+
* These types enable the same level of type inference as the Chain DSL.
|
|
423
|
+
*
|
|
424
|
+
* @param cls - The decorated class information
|
|
425
|
+
* @returns TypeScript code defining the accessor function and types
|
|
426
|
+
*/
|
|
427
|
+
function generateTypedAccessor(cls) {
|
|
428
|
+
const lines = [];
|
|
429
|
+
// Generate the element type as a tuple
|
|
430
|
+
const elementTypes = Object.entries(cls.typeMetadata).map(([fieldName, metadata]) => {
|
|
431
|
+
const fieldType = metadataTypeToFieldType(metadata.type);
|
|
432
|
+
const required = !metadata.optional;
|
|
433
|
+
let elementType = `{ readonly _field: "${fieldType}"; readonly id: "${fieldName}"; readonly required: ${required}`;
|
|
434
|
+
// Add options for enum types
|
|
435
|
+
if (metadata.type === "enum" && metadata.values) {
|
|
436
|
+
const optionValues = metadata.values
|
|
437
|
+
.map((v) => (typeof v === "string" ? JSON.stringify(v) : String(v)))
|
|
438
|
+
.join(", ");
|
|
439
|
+
elementType += `; readonly options: readonly [${optionValues}]`;
|
|
440
|
+
}
|
|
441
|
+
elementType += " }";
|
|
442
|
+
return elementType;
|
|
443
|
+
});
|
|
444
|
+
// Export element tuple type
|
|
445
|
+
lines.push(`export type ${cls.name}Elements = readonly [\n ${elementTypes.join(",\n ")}\n];`);
|
|
446
|
+
lines.push("");
|
|
447
|
+
// Export typed FormSpec result type
|
|
448
|
+
lines.push(`export type ${cls.name}FormSpec = { readonly elements: ${cls.name}Elements };`);
|
|
449
|
+
lines.push("");
|
|
450
|
+
// Export typed accessor function
|
|
451
|
+
lines.push(`/**`);
|
|
452
|
+
lines.push(` * Type-safe FormSpec accessor for ${cls.name}.`);
|
|
453
|
+
lines.push(` * Returns the same result as toFormSpec(${cls.name}) but with full type information.`);
|
|
454
|
+
lines.push(` */`);
|
|
455
|
+
lines.push(`export function get${cls.name}FormSpec(): ${cls.name}FormSpec {`);
|
|
456
|
+
lines.push(` return toFormSpec(${cls.name}) as unknown as ${cls.name}FormSpec;`);
|
|
457
|
+
lines.push(`}`);
|
|
458
|
+
return lines.join("\n");
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Gets a relative import path from output to source.
|
|
462
|
+
*/
|
|
463
|
+
function getRelativeImportPath(outputDir, sourcePath) {
|
|
464
|
+
// sourcePath is already relative to baseDir
|
|
465
|
+
let relativePath = path.relative(outputDir, sourcePath);
|
|
466
|
+
// Ensure it starts with ./ or ../
|
|
467
|
+
if (!relativePath.startsWith(".")) {
|
|
468
|
+
relativePath = "./" + relativePath;
|
|
469
|
+
}
|
|
470
|
+
// Use forward slashes for imports
|
|
471
|
+
relativePath = relativePath.replace(/\\/g, "/");
|
|
472
|
+
// Add .js extension for ESM compatibility
|
|
473
|
+
return relativePath + ".js";
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Runs the code generation.
|
|
477
|
+
*/
|
|
478
|
+
export function runCodegen(options) {
|
|
479
|
+
const baseDir = options.baseDir ?? path.dirname(options.output);
|
|
480
|
+
const absoluteFiles = options.files.map((f) => path.resolve(f));
|
|
481
|
+
console.log(`Scanning ${absoluteFiles.length} file(s) for decorated classes...`);
|
|
482
|
+
const classes = findDecoratedClasses(absoluteFiles, baseDir);
|
|
483
|
+
if (classes.length === 0) {
|
|
484
|
+
console.log("No decorated classes found.");
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
console.log(`Found ${classes.length} decorated class(es):`);
|
|
488
|
+
for (const cls of classes) {
|
|
489
|
+
const fieldCount = Object.keys(cls.typeMetadata).length;
|
|
490
|
+
console.log(` - ${cls.name} (${fieldCount} field(s))`);
|
|
491
|
+
}
|
|
492
|
+
const output = generateCodegenOutput(classes, options.output, baseDir);
|
|
493
|
+
// Ensure output directory exists
|
|
494
|
+
const outputDir = path.dirname(options.output);
|
|
495
|
+
if (!fs.existsSync(outputDir)) {
|
|
496
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
497
|
+
}
|
|
498
|
+
fs.writeFileSync(options.output, output);
|
|
499
|
+
console.log(`\nGenerated: ${options.output}`);
|
|
500
|
+
}
|
|
501
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/codegen/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Class schema generator.
|
|
3
|
+
*
|
|
4
|
+
* Generates JSON Schema and FormSpec/UI Schema from statically analyzed
|
|
5
|
+
* class fields and decorators.
|
|
6
|
+
*/
|
|
7
|
+
import type * as ts from "typescript";
|
|
8
|
+
import type { ClassAnalysis, FieldInfo } from "../analyzer/class-analyzer.js";
|
|
9
|
+
import { type JsonSchema, type FormSpecField } from "../analyzer/type-converter.js";
|
|
10
|
+
/**
|
|
11
|
+
* Generated schemas for a class.
|
|
12
|
+
*/
|
|
13
|
+
export interface ClassSchemas {
|
|
14
|
+
/** JSON Schema for validation */
|
|
15
|
+
jsonSchema: JsonSchema;
|
|
16
|
+
/** FormSpec/UI Schema for rendering */
|
|
17
|
+
uxSpec: {
|
|
18
|
+
elements: FormSpecField[];
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Generates JSON Schema and FormSpec from a class analysis.
|
|
23
|
+
*
|
|
24
|
+
* Uses static type information and decorator metadata to build
|
|
25
|
+
* complete schema definitions for a class's fields.
|
|
26
|
+
*
|
|
27
|
+
* @param analysis - The class analysis result
|
|
28
|
+
* @param checker - TypeScript type checker
|
|
29
|
+
* @returns Generated JSON Schema and FormSpec
|
|
30
|
+
*/
|
|
31
|
+
export declare function generateClassSchemas(analysis: ClassAnalysis, checker: ts.TypeChecker): ClassSchemas;
|
|
32
|
+
/**
|
|
33
|
+
* Generates JSON Schema for a single field.
|
|
34
|
+
*
|
|
35
|
+
* Useful for generating schemas for method return types
|
|
36
|
+
* or individual field extraction.
|
|
37
|
+
*
|
|
38
|
+
* @param field - The field information
|
|
39
|
+
* @param checker - TypeScript type checker
|
|
40
|
+
* @returns JSON Schema for the field's type
|
|
41
|
+
*/
|
|
42
|
+
export declare function generateFieldSchema(field: FieldInfo, checker: ts.TypeChecker): JsonSchema;
|
|
43
|
+
//# sourceMappingURL=class-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"class-schema.d.ts","sourceRoot":"","sources":["../../src/generators/class-schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC9E,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,aAAa,EACnB,MAAM,+BAA+B,CAAC;AAEvC;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,iCAAiC;IACjC,UAAU,EAAE,UAAU,CAAC;IACvB,uCAAuC;IACvC,MAAM,EAAE;QACN,QAAQ,EAAE,aAAa,EAAE,CAAC;KAC3B,CAAC;CACH;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,aAAa,EACvB,OAAO,EAAE,EAAE,CAAC,WAAW,GACtB,YAAY,CAwCd;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,EAAE,CAAC,WAAW,GACtB,UAAU,CAGZ"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Class schema generator.
|
|
3
|
+
*
|
|
4
|
+
* Generates JSON Schema and FormSpec/UI Schema from statically analyzed
|
|
5
|
+
* class fields and decorators.
|
|
6
|
+
*/
|
|
7
|
+
import { convertType, applyDecoratorsToSchema, createFormSpecField, } from "../analyzer/type-converter.js";
|
|
8
|
+
/**
|
|
9
|
+
* Generates JSON Schema and FormSpec from a class analysis.
|
|
10
|
+
*
|
|
11
|
+
* Uses static type information and decorator metadata to build
|
|
12
|
+
* complete schema definitions for a class's fields.
|
|
13
|
+
*
|
|
14
|
+
* @param analysis - The class analysis result
|
|
15
|
+
* @param checker - TypeScript type checker
|
|
16
|
+
* @returns Generated JSON Schema and FormSpec
|
|
17
|
+
*/
|
|
18
|
+
export function generateClassSchemas(analysis, checker) {
|
|
19
|
+
const properties = {};
|
|
20
|
+
const required = [];
|
|
21
|
+
const uxElements = [];
|
|
22
|
+
for (const field of analysis.fields) {
|
|
23
|
+
// Generate JSON Schema for field
|
|
24
|
+
const { jsonSchema: baseSchema } = convertType(field.type, checker);
|
|
25
|
+
const fieldSchema = applyDecoratorsToSchema(baseSchema, field.decorators);
|
|
26
|
+
properties[field.name] = fieldSchema;
|
|
27
|
+
// Track required fields
|
|
28
|
+
if (!field.optional) {
|
|
29
|
+
required.push(field.name);
|
|
30
|
+
}
|
|
31
|
+
// Generate FormSpec field
|
|
32
|
+
const formSpecField = createFormSpecField(field.name, field.type, field.decorators, field.optional, checker);
|
|
33
|
+
uxElements.push(formSpecField);
|
|
34
|
+
}
|
|
35
|
+
// Build complete JSON Schema
|
|
36
|
+
const jsonSchema = {
|
|
37
|
+
type: "object",
|
|
38
|
+
properties,
|
|
39
|
+
...(required.length > 0 ? { required } : {}),
|
|
40
|
+
};
|
|
41
|
+
// Build FormSpec/UI Schema
|
|
42
|
+
const uxSpec = {
|
|
43
|
+
elements: uxElements,
|
|
44
|
+
};
|
|
45
|
+
return { jsonSchema, uxSpec };
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Generates JSON Schema for a single field.
|
|
49
|
+
*
|
|
50
|
+
* Useful for generating schemas for method return types
|
|
51
|
+
* or individual field extraction.
|
|
52
|
+
*
|
|
53
|
+
* @param field - The field information
|
|
54
|
+
* @param checker - TypeScript type checker
|
|
55
|
+
* @returns JSON Schema for the field's type
|
|
56
|
+
*/
|
|
57
|
+
export function generateFieldSchema(field, checker) {
|
|
58
|
+
const { jsonSchema: baseSchema } = convertType(field.type, checker);
|
|
59
|
+
return applyDecoratorsToSchema(baseSchema, field.decorators);
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=class-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"class-schema.js","sourceRoot":"","sources":["../../src/generators/class-schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EACL,WAAW,EACX,uBAAuB,EACvB,mBAAmB,GAGpB,MAAM,+BAA+B,CAAC;AAcvC;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAuB,EACvB,OAAuB;IAEvB,MAAM,UAAU,GAA+B,EAAE,CAAC;IAClD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,UAAU,GAAoB,EAAE,CAAC;IAEvC,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;QACpC,iCAAiC;QACjC,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACpE,MAAM,WAAW,GAAG,uBAAuB,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;QAC1E,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC;QAErC,wBAAwB;QACxB,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;YACpB,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;QAED,0BAA0B;QAC1B,MAAM,aAAa,GAAG,mBAAmB,CACvC,KAAK,CAAC,IAAI,EACV,KAAK,CAAC,IAAI,EACV,KAAK,CAAC,UAAU,EAChB,KAAK,CAAC,QAAQ,EACd,OAAO,CACR,CAAC;QACF,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACjC,CAAC;IAED,6BAA6B;IAC7B,MAAM,UAAU,GAAe;QAC7B,IAAI,EAAE,QAAQ;QACd,UAAU;QACV,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7C,CAAC;IAEF,2BAA2B;IAC3B,MAAM,MAAM,GAAG;QACb,QAAQ,EAAE,UAAU;KACrB,CAAC;IAEF,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;AAChC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CACjC,KAAgB,EAChB,OAAuB;IAEvB,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACpE,OAAO,uBAAuB,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;AAC/D,CAAC"}
|