@constructive-io/graphql-codegen 2.19.0 → 2.20.1
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 +1818 -113
- package/__tests__/codegen/input-types-generator.test.d.ts +1 -0
- package/__tests__/codegen/input-types-generator.test.js +635 -0
- package/cli/codegen/barrel.d.ts +27 -0
- package/cli/codegen/barrel.js +163 -0
- package/cli/codegen/client.d.ts +4 -0
- package/cli/codegen/client.js +170 -0
- package/cli/codegen/custom-mutations.d.ts +38 -0
- package/cli/codegen/custom-mutations.js +149 -0
- package/cli/codegen/custom-queries.d.ts +38 -0
- package/cli/codegen/custom-queries.js +358 -0
- package/cli/codegen/filters.d.ts +27 -0
- package/cli/codegen/filters.js +357 -0
- package/cli/codegen/gql-ast.d.ts +41 -0
- package/cli/codegen/gql-ast.js +329 -0
- package/cli/codegen/index.d.ts +71 -0
- package/cli/codegen/index.js +147 -0
- package/cli/codegen/mutations.d.ts +30 -0
- package/cli/codegen/mutations.js +410 -0
- package/cli/codegen/orm/barrel.d.ts +18 -0
- package/cli/codegen/orm/barrel.js +48 -0
- package/cli/codegen/orm/client-generator.d.ts +45 -0
- package/cli/codegen/orm/client-generator.js +646 -0
- package/cli/codegen/orm/custom-ops-generator.d.ts +30 -0
- package/cli/codegen/orm/custom-ops-generator.js +350 -0
- package/cli/codegen/orm/index.d.ts +38 -0
- package/cli/codegen/orm/index.js +88 -0
- package/cli/codegen/orm/input-types-generator.d.ts +21 -0
- package/cli/codegen/orm/input-types-generator.js +705 -0
- package/cli/codegen/orm/input-types-generator.test.d.ts +1 -0
- package/cli/codegen/orm/input-types-generator.test.js +75 -0
- package/cli/codegen/orm/model-generator.d.ts +32 -0
- package/cli/codegen/orm/model-generator.js +264 -0
- package/cli/codegen/orm/query-builder.d.ts +161 -0
- package/cli/codegen/orm/query-builder.js +366 -0
- package/cli/codegen/orm/select-types.d.ts +169 -0
- package/cli/codegen/orm/select-types.js +16 -0
- package/cli/codegen/orm/select-types.test.d.ts +11 -0
- package/cli/codegen/orm/select-types.test.js +22 -0
- package/cli/codegen/queries.d.ts +25 -0
- package/cli/codegen/queries.js +438 -0
- package/cli/codegen/scalars.d.ts +12 -0
- package/cli/codegen/scalars.js +71 -0
- package/cli/codegen/schema-gql-ast.d.ts +51 -0
- package/cli/codegen/schema-gql-ast.js +385 -0
- package/cli/codegen/ts-ast.d.ts +122 -0
- package/cli/codegen/ts-ast.js +280 -0
- package/cli/codegen/type-resolver.d.ts +96 -0
- package/cli/codegen/type-resolver.js +246 -0
- package/cli/codegen/types.d.ts +12 -0
- package/cli/codegen/types.js +69 -0
- package/cli/codegen/utils.d.ts +163 -0
- package/cli/codegen/utils.js +326 -0
- package/cli/commands/generate-orm.d.ts +37 -0
- package/cli/commands/generate-orm.js +195 -0
- package/cli/commands/generate.d.ts +39 -0
- package/cli/commands/generate.js +299 -0
- package/cli/commands/index.d.ts +7 -0
- package/cli/commands/index.js +12 -0
- package/cli/commands/init.d.ts +35 -0
- package/cli/commands/init.js +176 -0
- package/cli/index.d.ts +4 -0
- package/cli/index.js +291 -0
- package/cli/introspect/fetch-meta.d.ts +31 -0
- package/cli/introspect/fetch-meta.js +108 -0
- package/cli/introspect/fetch-schema.d.ts +21 -0
- package/cli/introspect/fetch-schema.js +86 -0
- package/cli/introspect/index.d.ts +8 -0
- package/cli/introspect/index.js +16 -0
- package/cli/introspect/meta-query.d.ts +111 -0
- package/cli/introspect/meta-query.js +191 -0
- package/cli/introspect/schema-query.d.ts +20 -0
- package/cli/introspect/schema-query.js +123 -0
- package/cli/introspect/transform-schema.d.ts +74 -0
- package/cli/introspect/transform-schema.js +269 -0
- package/cli/introspect/transform-schema.test.d.ts +1 -0
- package/cli/introspect/transform-schema.test.js +67 -0
- package/cli/introspect/transform.d.ts +21 -0
- package/cli/introspect/transform.js +216 -0
- package/cli/watch/cache.d.ts +45 -0
- package/cli/watch/cache.js +111 -0
- package/cli/watch/debounce.d.ts +19 -0
- package/cli/watch/debounce.js +89 -0
- package/cli/watch/hash.d.ts +17 -0
- package/cli/watch/hash.js +48 -0
- package/cli/watch/index.d.ts +10 -0
- package/cli/watch/index.js +22 -0
- package/cli/watch/orchestrator.d.ts +63 -0
- package/cli/watch/orchestrator.js +228 -0
- package/cli/watch/poller.d.ts +65 -0
- package/cli/watch/poller.js +203 -0
- package/cli/watch/types.d.ts +67 -0
- package/cli/watch/types.js +5 -0
- package/client/error.d.ts +95 -0
- package/client/error.js +255 -0
- package/client/execute.d.ts +57 -0
- package/client/execute.js +124 -0
- package/client/index.d.ts +6 -0
- package/client/index.js +18 -0
- package/client/typed-document.d.ts +31 -0
- package/client/typed-document.js +44 -0
- package/core/ast.d.ts +10 -0
- package/core/ast.js +593 -0
- package/core/custom-ast.d.ts +35 -0
- package/core/custom-ast.js +204 -0
- package/core/index.d.ts +8 -0
- package/core/index.js +33 -0
- package/core/meta-object/convert.d.ts +65 -0
- package/core/meta-object/convert.js +63 -0
- package/core/meta-object/format.json +93 -0
- package/core/meta-object/index.d.ts +2 -0
- package/core/meta-object/index.js +18 -0
- package/core/meta-object/validate.d.ts +9 -0
- package/core/meta-object/validate.js +34 -0
- package/core/query-builder.d.ts +46 -0
- package/core/query-builder.js +412 -0
- package/core/types.d.ts +139 -0
- package/core/types.js +28 -0
- package/esm/__tests__/codegen/input-types-generator.test.d.ts +1 -0
- package/esm/__tests__/codegen/input-types-generator.test.js +633 -0
- package/esm/cli/codegen/barrel.d.ts +27 -0
- package/esm/cli/codegen/barrel.js +156 -0
- package/esm/cli/codegen/client.d.ts +4 -0
- package/esm/cli/codegen/client.js +167 -0
- package/esm/cli/codegen/custom-mutations.d.ts +38 -0
- package/esm/cli/codegen/custom-mutations.js +145 -0
- package/esm/cli/codegen/custom-queries.d.ts +38 -0
- package/esm/cli/codegen/custom-queries.js +354 -0
- package/esm/cli/codegen/filters.d.ts +27 -0
- package/esm/cli/codegen/filters.js +351 -0
- package/esm/cli/codegen/gql-ast.d.ts +41 -0
- package/esm/cli/codegen/gql-ast.js +288 -0
- package/esm/cli/codegen/index.d.ts +71 -0
- package/esm/cli/codegen/index.js +124 -0
- package/esm/cli/codegen/mutations.d.ts +30 -0
- package/esm/cli/codegen/mutations.js +404 -0
- package/esm/cli/codegen/orm/barrel.d.ts +18 -0
- package/esm/cli/codegen/orm/barrel.js +44 -0
- package/esm/cli/codegen/orm/client-generator.d.ts +45 -0
- package/esm/cli/codegen/orm/client-generator.js +640 -0
- package/esm/cli/codegen/orm/custom-ops-generator.d.ts +30 -0
- package/esm/cli/codegen/orm/custom-ops-generator.js +346 -0
- package/esm/cli/codegen/orm/index.d.ts +38 -0
- package/esm/cli/codegen/orm/index.js +75 -0
- package/esm/cli/codegen/orm/input-types-generator.d.ts +21 -0
- package/esm/cli/codegen/orm/input-types-generator.js +700 -0
- package/esm/cli/codegen/orm/input-types-generator.test.d.ts +1 -0
- package/esm/cli/codegen/orm/input-types-generator.test.js +73 -0
- package/esm/cli/codegen/orm/model-generator.d.ts +32 -0
- package/esm/cli/codegen/orm/model-generator.js +260 -0
- package/esm/cli/codegen/orm/query-builder.d.ts +161 -0
- package/esm/cli/codegen/orm/query-builder.js +353 -0
- package/esm/cli/codegen/orm/select-types.d.ts +169 -0
- package/esm/cli/codegen/orm/select-types.js +15 -0
- package/esm/cli/codegen/orm/select-types.test.d.ts +11 -0
- package/esm/cli/codegen/orm/select-types.test.js +21 -0
- package/esm/cli/codegen/queries.d.ts +25 -0
- package/esm/cli/codegen/queries.js +433 -0
- package/esm/cli/codegen/scalars.d.ts +12 -0
- package/esm/cli/codegen/scalars.js +66 -0
- package/esm/cli/codegen/schema-gql-ast.d.ts +51 -0
- package/esm/cli/codegen/schema-gql-ast.js +343 -0
- package/esm/cli/codegen/ts-ast.d.ts +122 -0
- package/esm/cli/codegen/ts-ast.js +260 -0
- package/esm/cli/codegen/type-resolver.d.ts +96 -0
- package/esm/cli/codegen/type-resolver.js +224 -0
- package/esm/cli/codegen/types.d.ts +12 -0
- package/esm/cli/codegen/types.js +65 -0
- package/esm/cli/codegen/utils.d.ts +163 -0
- package/esm/cli/codegen/utils.js +288 -0
- package/esm/cli/commands/generate-orm.d.ts +37 -0
- package/esm/cli/commands/generate-orm.js +192 -0
- package/esm/cli/commands/generate.d.ts +39 -0
- package/esm/cli/commands/generate.js +262 -0
- package/esm/cli/commands/index.d.ts +7 -0
- package/esm/cli/commands/index.js +5 -0
- package/esm/cli/commands/init.d.ts +35 -0
- package/esm/cli/commands/init.js +138 -0
- package/esm/cli/index.d.ts +4 -0
- package/esm/cli/index.js +256 -0
- package/esm/cli/introspect/fetch-meta.d.ts +31 -0
- package/esm/cli/introspect/fetch-meta.js +104 -0
- package/esm/cli/introspect/fetch-schema.d.ts +21 -0
- package/esm/cli/introspect/fetch-schema.js +83 -0
- package/esm/cli/introspect/index.d.ts +8 -0
- package/esm/cli/introspect/index.js +6 -0
- package/esm/cli/introspect/meta-query.d.ts +111 -0
- package/esm/cli/introspect/meta-query.js +188 -0
- package/esm/cli/introspect/schema-query.d.ts +20 -0
- package/esm/cli/introspect/schema-query.js +120 -0
- package/esm/cli/introspect/transform-schema.d.ts +74 -0
- package/esm/cli/introspect/transform-schema.js +259 -0
- package/esm/cli/introspect/transform-schema.test.d.ts +1 -0
- package/esm/cli/introspect/transform-schema.test.js +65 -0
- package/esm/cli/introspect/transform.d.ts +21 -0
- package/esm/cli/introspect/transform.js +210 -0
- package/esm/cli/watch/cache.d.ts +45 -0
- package/esm/cli/watch/cache.js +73 -0
- package/esm/cli/watch/debounce.d.ts +19 -0
- package/esm/cli/watch/debounce.js +85 -0
- package/esm/cli/watch/hash.d.ts +17 -0
- package/esm/cli/watch/hash.js +43 -0
- package/esm/cli/watch/index.d.ts +10 -0
- package/esm/cli/watch/index.js +8 -0
- package/esm/cli/watch/orchestrator.d.ts +63 -0
- package/esm/cli/watch/orchestrator.js +223 -0
- package/esm/cli/watch/poller.d.ts +65 -0
- package/esm/cli/watch/poller.js +198 -0
- package/esm/cli/watch/types.d.ts +67 -0
- package/esm/cli/watch/types.js +4 -0
- package/esm/client/error.d.ts +95 -0
- package/esm/client/error.js +249 -0
- package/esm/client/execute.d.ts +57 -0
- package/esm/client/execute.js +120 -0
- package/esm/client/index.d.ts +6 -0
- package/esm/client/index.js +6 -0
- package/esm/client/typed-document.d.ts +31 -0
- package/esm/client/typed-document.js +40 -0
- package/esm/core/ast.d.ts +10 -0
- package/esm/core/ast.js +549 -0
- package/esm/core/custom-ast.d.ts +35 -0
- package/esm/core/custom-ast.js +161 -0
- package/esm/core/index.d.ts +8 -0
- package/esm/core/index.js +12 -0
- package/esm/core/meta-object/convert.d.ts +65 -0
- package/esm/core/meta-object/convert.js +60 -0
- package/esm/core/meta-object/format.json +93 -0
- package/esm/core/meta-object/index.d.ts +2 -0
- package/esm/core/meta-object/index.js +2 -0
- package/esm/core/meta-object/validate.d.ts +9 -0
- package/esm/core/meta-object/validate.js +28 -0
- package/esm/core/query-builder.d.ts +46 -0
- package/esm/core/query-builder.js +375 -0
- package/esm/core/types.d.ts +139 -0
- package/esm/core/types.js +24 -0
- package/esm/generators/field-selector.d.ts +30 -0
- package/esm/generators/field-selector.js +355 -0
- package/esm/generators/index.d.ts +6 -0
- package/esm/generators/index.js +9 -0
- package/esm/generators/mutations.d.ts +31 -0
- package/esm/generators/mutations.js +197 -0
- package/esm/generators/select.d.ts +50 -0
- package/esm/generators/select.js +636 -0
- package/esm/index.d.ts +12 -0
- package/esm/index.js +17 -3
- package/esm/react/index.d.ts +5 -0
- package/esm/react/index.js +6 -0
- package/esm/types/config.d.ts +199 -0
- package/esm/types/config.js +106 -0
- package/esm/types/index.d.ts +9 -0
- package/esm/types/index.js +4 -0
- package/esm/types/introspection.d.ts +121 -0
- package/esm/types/introspection.js +54 -0
- package/esm/types/mutation.d.ts +45 -0
- package/esm/types/mutation.js +4 -0
- package/esm/types/query.d.ts +82 -0
- package/esm/types/query.js +4 -0
- package/esm/types/schema.d.ts +253 -0
- package/esm/types/schema.js +5 -0
- package/esm/types/selection.d.ts +43 -0
- package/esm/types/selection.js +4 -0
- package/esm/utils/index.d.ts +4 -0
- package/esm/utils/index.js +4 -0
- package/generators/field-selector.d.ts +30 -0
- package/generators/field-selector.js +361 -0
- package/generators/index.d.ts +6 -0
- package/generators/index.js +27 -0
- package/generators/mutations.d.ts +31 -0
- package/generators/mutations.js +235 -0
- package/generators/select.d.ts +50 -0
- package/generators/select.js +679 -0
- package/index.d.ts +12 -3
- package/index.js +19 -3
- package/package.json +59 -38
- package/react/index.d.ts +5 -0
- package/react/index.js +9 -0
- package/types/config.d.ts +199 -0
- package/types/config.js +111 -0
- package/types/index.d.ts +9 -0
- package/types/index.js +10 -0
- package/types/introspection.d.ts +121 -0
- package/types/introspection.js +62 -0
- package/types/mutation.d.ts +45 -0
- package/types/mutation.js +5 -0
- package/types/query.d.ts +82 -0
- package/types/query.js +5 -0
- package/types/schema.d.ts +253 -0
- package/types/schema.js +6 -0
- package/types/selection.d.ts +43 -0
- package/types/selection.js +5 -0
- package/utils/index.d.ts +4 -0
- package/utils/index.js +7 -0
- package/codegen.d.ts +0 -13
- package/codegen.js +0 -293
- package/esm/codegen.js +0 -253
- package/esm/gql.js +0 -939
- package/esm/options.js +0 -27
- package/gql.d.ts +0 -188
- package/gql.js +0 -992
- package/options.d.ts +0 -45
- package/options.js +0 -31
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript AST builders using ts-morph
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for generating TypeScript code via AST manipulation
|
|
5
|
+
* instead of string concatenation.
|
|
6
|
+
*/
|
|
7
|
+
import { Project, StructureKind, VariableDeclarationKind, ScriptTarget, ModuleKind, } from 'ts-morph';
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Project management
|
|
10
|
+
// ============================================================================
|
|
11
|
+
/**
|
|
12
|
+
* Create a new ts-morph project for code generation
|
|
13
|
+
*/
|
|
14
|
+
export function createProject() {
|
|
15
|
+
return new Project({
|
|
16
|
+
useInMemoryFileSystem: true,
|
|
17
|
+
compilerOptions: {
|
|
18
|
+
declaration: true,
|
|
19
|
+
strict: true,
|
|
20
|
+
target: ScriptTarget.ESNext,
|
|
21
|
+
module: ModuleKind.ESNext,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Create a source file in the project
|
|
27
|
+
*/
|
|
28
|
+
export function createSourceFile(project, fileName) {
|
|
29
|
+
return project.createSourceFile(fileName, '', { overwrite: true });
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get formatted output from source file
|
|
33
|
+
*/
|
|
34
|
+
export function getFormattedOutput(sourceFile) {
|
|
35
|
+
sourceFile.formatText({
|
|
36
|
+
indentSize: 2,
|
|
37
|
+
convertTabsToSpaces: true,
|
|
38
|
+
});
|
|
39
|
+
return sourceFile.getFullText();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Get output with minimal formatting (preserves intentional blank lines)
|
|
43
|
+
* Post-processes to fix indentation and section comment spacing
|
|
44
|
+
*
|
|
45
|
+
* ts-morph generates type alias bodies with extra indentation:
|
|
46
|
+
* - Properties get 6 spaces (we want 2)
|
|
47
|
+
* - Closing brace gets 4 spaces (we want 0)
|
|
48
|
+
*
|
|
49
|
+
* For interfaces it uses 4 spaces which we convert to 2.
|
|
50
|
+
*/
|
|
51
|
+
export function getMinimalFormattedOutput(sourceFile) {
|
|
52
|
+
let text = sourceFile.getFullText();
|
|
53
|
+
// Process each line to fix indentation
|
|
54
|
+
// ts-morph uses inconsistent indentation for type alias bodies
|
|
55
|
+
// We halve all indentation: 4->2, 6->3 (rounds to 2), 8->4, etc.
|
|
56
|
+
text = text.split('\n').map(line => {
|
|
57
|
+
// Match leading whitespace
|
|
58
|
+
const match = line.match(/^(\s*)/);
|
|
59
|
+
if (!match)
|
|
60
|
+
return line;
|
|
61
|
+
const spaces = match[1].length;
|
|
62
|
+
const content = line.slice(spaces);
|
|
63
|
+
// Skip empty lines
|
|
64
|
+
if (content === '')
|
|
65
|
+
return line;
|
|
66
|
+
// No indentation - keep as-is
|
|
67
|
+
if (spaces === 0)
|
|
68
|
+
return line;
|
|
69
|
+
// Halve the indentation (minimum 0)
|
|
70
|
+
const newSpaces = Math.floor(spaces / 2);
|
|
71
|
+
return ' '.repeat(newSpaces) + content;
|
|
72
|
+
}).join('\n');
|
|
73
|
+
// Ensure blank line after section comment blocks
|
|
74
|
+
text = text.replace(/(\/\/ =+\n\/\/ .+\n\/\/ =+)\n(export|\/\/)/g, '$1\n\n$2');
|
|
75
|
+
// Add blank line between consecutive export declarations (type aliases, interfaces)
|
|
76
|
+
// Pattern: "}\nexport" or ";\nexport" should become "}\n\nexport" or ";\n\nexport"
|
|
77
|
+
text = text.replace(/(\}|\;)\n(export )/g, '$1\n\n$2');
|
|
78
|
+
// Remove trailing extra blank lines at end of file
|
|
79
|
+
text = text.replace(/\n\n+$/, '\n');
|
|
80
|
+
return text;
|
|
81
|
+
}
|
|
82
|
+
// ============================================================================
|
|
83
|
+
// Comment helpers
|
|
84
|
+
// ============================================================================
|
|
85
|
+
/**
|
|
86
|
+
* Create a file header comment
|
|
87
|
+
*/
|
|
88
|
+
export function createFileHeader(description) {
|
|
89
|
+
return [
|
|
90
|
+
'/**',
|
|
91
|
+
` * ${description}`,
|
|
92
|
+
' * @generated by @constructive-io/graphql-codegen',
|
|
93
|
+
' * DO NOT EDIT - changes will be overwritten',
|
|
94
|
+
' */',
|
|
95
|
+
].join('\n');
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Create JSDoc comment for a declaration
|
|
99
|
+
*/
|
|
100
|
+
export function createJsDoc(lines) {
|
|
101
|
+
if (lines.length === 1) {
|
|
102
|
+
return `/** ${lines[0]} */`;
|
|
103
|
+
}
|
|
104
|
+
return ['/**', ...lines.map((l) => ` * ${l}`), ' */'].join('\n');
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Create import declaration structure
|
|
108
|
+
*/
|
|
109
|
+
export function createImport(spec) {
|
|
110
|
+
const namedImports = [];
|
|
111
|
+
if (spec.namedImports) {
|
|
112
|
+
namedImports.push(...spec.namedImports.map((name) => ({ name })));
|
|
113
|
+
}
|
|
114
|
+
if (spec.typeOnlyNamedImports) {
|
|
115
|
+
namedImports.push(...spec.typeOnlyNamedImports.map((name) => ({ name, isTypeOnly: true })));
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
kind: StructureKind.ImportDeclaration,
|
|
119
|
+
moduleSpecifier: spec.moduleSpecifier,
|
|
120
|
+
defaultImport: spec.defaultImport,
|
|
121
|
+
namedImports: namedImports.length > 0 ? namedImports : undefined,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Create interface declaration structure
|
|
126
|
+
*/
|
|
127
|
+
export function createInterface(name, properties, options) {
|
|
128
|
+
return {
|
|
129
|
+
kind: StructureKind.Interface,
|
|
130
|
+
name,
|
|
131
|
+
isExported: options?.isExported ?? true,
|
|
132
|
+
extends: options?.extends,
|
|
133
|
+
docs: options?.docs ? [{ description: options.docs.join('\n') }] : undefined,
|
|
134
|
+
properties: properties.map((prop) => ({
|
|
135
|
+
kind: StructureKind.PropertySignature,
|
|
136
|
+
name: prop.name,
|
|
137
|
+
type: prop.type,
|
|
138
|
+
hasQuestionToken: prop.optional,
|
|
139
|
+
docs: prop.docs ? [{ description: prop.docs.join('\n') }] : undefined,
|
|
140
|
+
})),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Create filter interface with standard PostGraphile operators
|
|
145
|
+
*/
|
|
146
|
+
export function createFilterInterface(name, fieldFilters) {
|
|
147
|
+
const properties = [
|
|
148
|
+
...fieldFilters.map((f) => ({
|
|
149
|
+
name: f.fieldName,
|
|
150
|
+
type: f.filterType,
|
|
151
|
+
optional: true,
|
|
152
|
+
})),
|
|
153
|
+
{ name: 'and', type: `${name}[]`, optional: true, docs: ['Logical AND'] },
|
|
154
|
+
{ name: 'or', type: `${name}[]`, optional: true, docs: ['Logical OR'] },
|
|
155
|
+
{ name: 'not', type: name, optional: true, docs: ['Logical NOT'] },
|
|
156
|
+
];
|
|
157
|
+
return createInterface(name, properties);
|
|
158
|
+
}
|
|
159
|
+
// ============================================================================
|
|
160
|
+
// Type alias builders
|
|
161
|
+
// ============================================================================
|
|
162
|
+
/**
|
|
163
|
+
* Create type alias declaration structure
|
|
164
|
+
*/
|
|
165
|
+
export function createTypeAlias(name, type, options) {
|
|
166
|
+
return {
|
|
167
|
+
kind: StructureKind.TypeAlias,
|
|
168
|
+
name,
|
|
169
|
+
type,
|
|
170
|
+
isExported: options?.isExported ?? true,
|
|
171
|
+
docs: options?.docs ? [{ description: options.docs.join('\n') }] : undefined,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Create union type from string literals
|
|
176
|
+
*/
|
|
177
|
+
export function createUnionType(values) {
|
|
178
|
+
return values.map((v) => `'${v}'`).join(' | ');
|
|
179
|
+
}
|
|
180
|
+
// ============================================================================
|
|
181
|
+
// Variable/constant builders
|
|
182
|
+
// ============================================================================
|
|
183
|
+
/**
|
|
184
|
+
* Create const variable statement structure
|
|
185
|
+
*/
|
|
186
|
+
export function createConst(name, initializer, options) {
|
|
187
|
+
return {
|
|
188
|
+
kind: StructureKind.VariableStatement,
|
|
189
|
+
declarationKind: VariableDeclarationKind.Const,
|
|
190
|
+
isExported: options?.isExported ?? true,
|
|
191
|
+
docs: options?.docs ? [{ description: options.docs.join('\n') }] : undefined,
|
|
192
|
+
declarations: [
|
|
193
|
+
{
|
|
194
|
+
name,
|
|
195
|
+
type: options?.type,
|
|
196
|
+
initializer,
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Create a template literal string (for GraphQL documents)
|
|
203
|
+
*/
|
|
204
|
+
export function createTemplateLiteral(content) {
|
|
205
|
+
return '`\n' + content + '\n`';
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Create function declaration structure
|
|
209
|
+
*/
|
|
210
|
+
export function createFunction(name, parameters, returnType, body, options) {
|
|
211
|
+
return {
|
|
212
|
+
kind: StructureKind.Function,
|
|
213
|
+
name,
|
|
214
|
+
isExported: options?.isExported ?? true,
|
|
215
|
+
isAsync: options?.isAsync,
|
|
216
|
+
parameters: parameters.map((p) => ({
|
|
217
|
+
name: p.name,
|
|
218
|
+
type: p.type,
|
|
219
|
+
hasQuestionToken: p.optional,
|
|
220
|
+
initializer: p.initializer,
|
|
221
|
+
})),
|
|
222
|
+
returnType,
|
|
223
|
+
statements: body,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
// ============================================================================
|
|
227
|
+
// Export builders
|
|
228
|
+
// ============================================================================
|
|
229
|
+
/**
|
|
230
|
+
* Create re-export statement
|
|
231
|
+
*/
|
|
232
|
+
export function createReExport(names, moduleSpecifier, isTypeOnly = false) {
|
|
233
|
+
const typePrefix = isTypeOnly ? 'type ' : '';
|
|
234
|
+
return `export ${typePrefix}{ ${names.join(', ')} } from '${moduleSpecifier}';`;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Create barrel export statement
|
|
238
|
+
*/
|
|
239
|
+
export function createBarrelExport(moduleSpecifier) {
|
|
240
|
+
return `export * from '${moduleSpecifier}';`;
|
|
241
|
+
}
|
|
242
|
+
// ============================================================================
|
|
243
|
+
// Section comment helpers
|
|
244
|
+
// ============================================================================
|
|
245
|
+
/**
|
|
246
|
+
* Create a section divider comment for generated code
|
|
247
|
+
*/
|
|
248
|
+
export function createSectionComment(title) {
|
|
249
|
+
return [
|
|
250
|
+
'// ============================================================================',
|
|
251
|
+
`// ${title}`,
|
|
252
|
+
'// ============================================================================',
|
|
253
|
+
].join('\n');
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Add a section comment to source file with proper spacing
|
|
257
|
+
*/
|
|
258
|
+
export function addSectionComment(sourceFile, title) {
|
|
259
|
+
sourceFile.addStatements(`\n${createSectionComment(title)}\n\n`);
|
|
260
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type Resolver - Convert GraphQL types to TypeScript
|
|
3
|
+
*
|
|
4
|
+
* Utilities for converting CleanTypeRef and other GraphQL types
|
|
5
|
+
* into TypeScript type strings and interface definitions.
|
|
6
|
+
*/
|
|
7
|
+
import type { CleanTypeRef, CleanArgument, CleanObjectField } from '../../types/schema';
|
|
8
|
+
import type { InterfaceProperty } from './ts-ast';
|
|
9
|
+
/**
|
|
10
|
+
* Convert a GraphQL scalar type to TypeScript type
|
|
11
|
+
*/
|
|
12
|
+
export declare function scalarToTsType(scalarName: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Convert a CleanTypeRef to a TypeScript type string
|
|
15
|
+
* Handles nested LIST and NON_NULL wrappers
|
|
16
|
+
*/
|
|
17
|
+
export declare function typeRefToTsType(typeRef: CleanTypeRef): string;
|
|
18
|
+
/**
|
|
19
|
+
* Convert a CleanTypeRef to a nullable TypeScript type string
|
|
20
|
+
* (for optional fields that can be null)
|
|
21
|
+
*/
|
|
22
|
+
export declare function typeRefToNullableTsType(typeRef: CleanTypeRef): string;
|
|
23
|
+
/**
|
|
24
|
+
* Check if a type reference is required (wrapped in NON_NULL)
|
|
25
|
+
*/
|
|
26
|
+
export declare function isTypeRequired(typeRef: CleanTypeRef): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Check if a type reference is a list
|
|
29
|
+
*/
|
|
30
|
+
export declare function isTypeList(typeRef: CleanTypeRef): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Get the base type name from a type reference (unwrapping wrappers)
|
|
33
|
+
*/
|
|
34
|
+
export declare function getTypeBaseName(typeRef: CleanTypeRef): string | null;
|
|
35
|
+
/**
|
|
36
|
+
* Get the base type kind (unwrapping LIST and NON_NULL)
|
|
37
|
+
*/
|
|
38
|
+
export declare function getBaseTypeKind(typeRef: CleanTypeRef): CleanTypeRef['kind'];
|
|
39
|
+
/**
|
|
40
|
+
* Convert CleanArgument to InterfaceProperty for ts-morph
|
|
41
|
+
*/
|
|
42
|
+
export declare function argumentToInterfaceProperty(arg: CleanArgument): InterfaceProperty;
|
|
43
|
+
/**
|
|
44
|
+
* Convert CleanObjectField to InterfaceProperty for ts-morph
|
|
45
|
+
*/
|
|
46
|
+
export declare function fieldToInterfaceProperty(field: CleanObjectField): InterfaceProperty;
|
|
47
|
+
/**
|
|
48
|
+
* Convert an array of CleanArguments to InterfaceProperty array
|
|
49
|
+
*/
|
|
50
|
+
export declare function argumentsToInterfaceProperties(args: CleanArgument[]): InterfaceProperty[];
|
|
51
|
+
/**
|
|
52
|
+
* Convert an array of CleanObjectFields to InterfaceProperty array
|
|
53
|
+
*/
|
|
54
|
+
export declare function fieldsToInterfaceProperties(fields: CleanObjectField[]): InterfaceProperty[];
|
|
55
|
+
/**
|
|
56
|
+
* Check if a field should be skipped in selections
|
|
57
|
+
*/
|
|
58
|
+
export declare function shouldSkipField(fieldName: string, skipQueryField: boolean): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Filter fields to only include selectable scalar and object fields
|
|
61
|
+
*/
|
|
62
|
+
export declare function getSelectableFields(fields: CleanObjectField[] | undefined, skipQueryField: boolean, maxDepth?: number, currentDepth?: number): CleanObjectField[];
|
|
63
|
+
/**
|
|
64
|
+
* Convert operation name to PascalCase for type names
|
|
65
|
+
*/
|
|
66
|
+
export declare function operationNameToPascal(name: string): string;
|
|
67
|
+
/**
|
|
68
|
+
* Generate variables type name for an operation
|
|
69
|
+
* e.g., "login" -> "LoginMutationVariables"
|
|
70
|
+
*/
|
|
71
|
+
export declare function getOperationVariablesTypeName(operationName: string, kind: 'query' | 'mutation'): string;
|
|
72
|
+
/**
|
|
73
|
+
* Generate result type name for an operation
|
|
74
|
+
* e.g., "login" -> "LoginMutationResult"
|
|
75
|
+
*/
|
|
76
|
+
export declare function getOperationResultTypeName(operationName: string, kind: 'query' | 'mutation'): string;
|
|
77
|
+
/**
|
|
78
|
+
* Generate hook name for an operation
|
|
79
|
+
* e.g., "login" -> "useLoginMutation", "currentUser" -> "useCurrentUserQuery"
|
|
80
|
+
*/
|
|
81
|
+
export declare function getOperationHookName(operationName: string, kind: 'query' | 'mutation'): string;
|
|
82
|
+
/**
|
|
83
|
+
* Generate file name for an operation hook
|
|
84
|
+
* e.g., "login" -> "useLoginMutation.ts"
|
|
85
|
+
*/
|
|
86
|
+
export declare function getOperationFileName(operationName: string, kind: 'query' | 'mutation'): string;
|
|
87
|
+
/**
|
|
88
|
+
* Generate query key factory name
|
|
89
|
+
* e.g., "currentUser" -> "currentUserQueryKey"
|
|
90
|
+
*/
|
|
91
|
+
export declare function getQueryKeyName(operationName: string): string;
|
|
92
|
+
/**
|
|
93
|
+
* Generate GraphQL document constant name
|
|
94
|
+
* e.g., "login" -> "loginMutationDocument"
|
|
95
|
+
*/
|
|
96
|
+
export declare function getDocumentConstName(operationName: string, kind: 'query' | 'mutation'): string;
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { scalarToTsType as resolveScalarToTs } from './scalars';
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// GraphQL to TypeScript Type Mapping
|
|
4
|
+
// ============================================================================
|
|
5
|
+
/**
|
|
6
|
+
* Convert a GraphQL scalar type to TypeScript type
|
|
7
|
+
*/
|
|
8
|
+
export function scalarToTsType(scalarName) {
|
|
9
|
+
return resolveScalarToTs(scalarName, { unknownScalar: 'unknown' });
|
|
10
|
+
}
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// CleanTypeRef to TypeScript
|
|
13
|
+
// ============================================================================
|
|
14
|
+
/**
|
|
15
|
+
* Convert a CleanTypeRef to a TypeScript type string
|
|
16
|
+
* Handles nested LIST and NON_NULL wrappers
|
|
17
|
+
*/
|
|
18
|
+
export function typeRefToTsType(typeRef) {
|
|
19
|
+
switch (typeRef.kind) {
|
|
20
|
+
case 'NON_NULL':
|
|
21
|
+
// Non-null wrapper - unwrap and return the inner type
|
|
22
|
+
if (typeRef.ofType) {
|
|
23
|
+
return typeRefToTsType(typeRef.ofType);
|
|
24
|
+
}
|
|
25
|
+
return 'unknown';
|
|
26
|
+
case 'LIST':
|
|
27
|
+
// List wrapper - wrap inner type in array
|
|
28
|
+
if (typeRef.ofType) {
|
|
29
|
+
const innerType = typeRefToTsType(typeRef.ofType);
|
|
30
|
+
return `${innerType}[]`;
|
|
31
|
+
}
|
|
32
|
+
return 'unknown[]';
|
|
33
|
+
case 'SCALAR':
|
|
34
|
+
// Scalar type - map to TS type
|
|
35
|
+
return scalarToTsType(typeRef.name ?? 'unknown');
|
|
36
|
+
case 'ENUM':
|
|
37
|
+
// Enum type - use the GraphQL enum name
|
|
38
|
+
return typeRef.name ?? 'string';
|
|
39
|
+
case 'OBJECT':
|
|
40
|
+
case 'INPUT_OBJECT':
|
|
41
|
+
// Object types - use the GraphQL type name
|
|
42
|
+
return typeRef.name ?? 'unknown';
|
|
43
|
+
default:
|
|
44
|
+
return 'unknown';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Convert a CleanTypeRef to a nullable TypeScript type string
|
|
49
|
+
* (for optional fields that can be null)
|
|
50
|
+
*/
|
|
51
|
+
export function typeRefToNullableTsType(typeRef) {
|
|
52
|
+
const baseType = typeRefToTsType(typeRef);
|
|
53
|
+
// If the outer type is NON_NULL, it's required
|
|
54
|
+
if (typeRef.kind === 'NON_NULL') {
|
|
55
|
+
return baseType;
|
|
56
|
+
}
|
|
57
|
+
// Otherwise, it can be null
|
|
58
|
+
return `${baseType} | null`;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Check if a type reference is required (wrapped in NON_NULL)
|
|
62
|
+
*/
|
|
63
|
+
export function isTypeRequired(typeRef) {
|
|
64
|
+
return typeRef.kind === 'NON_NULL';
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Check if a type reference is a list
|
|
68
|
+
*/
|
|
69
|
+
export function isTypeList(typeRef) {
|
|
70
|
+
if (typeRef.kind === 'LIST')
|
|
71
|
+
return true;
|
|
72
|
+
if (typeRef.kind === 'NON_NULL' && typeRef.ofType) {
|
|
73
|
+
return typeRef.ofType.kind === 'LIST';
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get the base type name from a type reference (unwrapping wrappers)
|
|
79
|
+
*/
|
|
80
|
+
export function getTypeBaseName(typeRef) {
|
|
81
|
+
if (typeRef.name)
|
|
82
|
+
return typeRef.name;
|
|
83
|
+
if (typeRef.ofType)
|
|
84
|
+
return getTypeBaseName(typeRef.ofType);
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get the base type kind (unwrapping LIST and NON_NULL)
|
|
89
|
+
*/
|
|
90
|
+
export function getBaseTypeKind(typeRef) {
|
|
91
|
+
if (typeRef.kind === 'LIST' || typeRef.kind === 'NON_NULL') {
|
|
92
|
+
if (typeRef.ofType) {
|
|
93
|
+
return getBaseTypeKind(typeRef.ofType);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return typeRef.kind;
|
|
97
|
+
}
|
|
98
|
+
// ============================================================================
|
|
99
|
+
// Interface Property Generation
|
|
100
|
+
// ============================================================================
|
|
101
|
+
/**
|
|
102
|
+
* Convert CleanArgument to InterfaceProperty for ts-morph
|
|
103
|
+
*/
|
|
104
|
+
export function argumentToInterfaceProperty(arg) {
|
|
105
|
+
return {
|
|
106
|
+
name: arg.name,
|
|
107
|
+
type: typeRefToTsType(arg.type),
|
|
108
|
+
optional: !isTypeRequired(arg.type),
|
|
109
|
+
docs: arg.description ? [arg.description] : undefined,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Convert CleanObjectField to InterfaceProperty for ts-morph
|
|
114
|
+
*/
|
|
115
|
+
export function fieldToInterfaceProperty(field) {
|
|
116
|
+
return {
|
|
117
|
+
name: field.name,
|
|
118
|
+
type: typeRefToNullableTsType(field.type),
|
|
119
|
+
optional: false, // Fields are always present, just potentially null
|
|
120
|
+
docs: field.description ? [field.description] : undefined,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Convert an array of CleanArguments to InterfaceProperty array
|
|
125
|
+
*/
|
|
126
|
+
export function argumentsToInterfaceProperties(args) {
|
|
127
|
+
return args.map(argumentToInterfaceProperty);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Convert an array of CleanObjectFields to InterfaceProperty array
|
|
131
|
+
*/
|
|
132
|
+
export function fieldsToInterfaceProperties(fields) {
|
|
133
|
+
return fields.map(fieldToInterfaceProperty);
|
|
134
|
+
}
|
|
135
|
+
// ============================================================================
|
|
136
|
+
// Type Filtering
|
|
137
|
+
// ============================================================================
|
|
138
|
+
/**
|
|
139
|
+
* Check if a field should be skipped in selections
|
|
140
|
+
*/
|
|
141
|
+
export function shouldSkipField(fieldName, skipQueryField) {
|
|
142
|
+
if (skipQueryField && fieldName === 'query')
|
|
143
|
+
return true;
|
|
144
|
+
if (fieldName === 'nodeId')
|
|
145
|
+
return true;
|
|
146
|
+
if (fieldName === '__typename')
|
|
147
|
+
return true;
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Filter fields to only include selectable scalar and object fields
|
|
152
|
+
*/
|
|
153
|
+
export function getSelectableFields(fields, skipQueryField, maxDepth = 2, currentDepth = 0) {
|
|
154
|
+
if (!fields || currentDepth >= maxDepth)
|
|
155
|
+
return [];
|
|
156
|
+
return fields.filter((field) => {
|
|
157
|
+
// Skip internal fields
|
|
158
|
+
if (shouldSkipField(field.name, skipQueryField))
|
|
159
|
+
return false;
|
|
160
|
+
// Get base type kind
|
|
161
|
+
const baseKind = getBaseTypeKind(field.type);
|
|
162
|
+
// Include scalars and enums
|
|
163
|
+
if (baseKind === 'SCALAR' || baseKind === 'ENUM')
|
|
164
|
+
return true;
|
|
165
|
+
// Include objects up to max depth
|
|
166
|
+
if (baseKind === 'OBJECT' && currentDepth < maxDepth - 1)
|
|
167
|
+
return true;
|
|
168
|
+
return false;
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
// ============================================================================
|
|
172
|
+
// Type Name Utilities
|
|
173
|
+
// ============================================================================
|
|
174
|
+
/**
|
|
175
|
+
* Convert operation name to PascalCase for type names
|
|
176
|
+
*/
|
|
177
|
+
export function operationNameToPascal(name) {
|
|
178
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Generate variables type name for an operation
|
|
182
|
+
* e.g., "login" -> "LoginMutationVariables"
|
|
183
|
+
*/
|
|
184
|
+
export function getOperationVariablesTypeName(operationName, kind) {
|
|
185
|
+
const pascal = operationNameToPascal(operationName);
|
|
186
|
+
return `${pascal}${kind === 'query' ? 'Query' : 'Mutation'}Variables`;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Generate result type name for an operation
|
|
190
|
+
* e.g., "login" -> "LoginMutationResult"
|
|
191
|
+
*/
|
|
192
|
+
export function getOperationResultTypeName(operationName, kind) {
|
|
193
|
+
const pascal = operationNameToPascal(operationName);
|
|
194
|
+
return `${pascal}${kind === 'query' ? 'Query' : 'Mutation'}Result`;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Generate hook name for an operation
|
|
198
|
+
* e.g., "login" -> "useLoginMutation", "currentUser" -> "useCurrentUserQuery"
|
|
199
|
+
*/
|
|
200
|
+
export function getOperationHookName(operationName, kind) {
|
|
201
|
+
const pascal = operationNameToPascal(operationName);
|
|
202
|
+
return `use${pascal}${kind === 'query' ? 'Query' : 'Mutation'}`;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Generate file name for an operation hook
|
|
206
|
+
* e.g., "login" -> "useLoginMutation.ts"
|
|
207
|
+
*/
|
|
208
|
+
export function getOperationFileName(operationName, kind) {
|
|
209
|
+
return `${getOperationHookName(operationName, kind)}.ts`;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Generate query key factory name
|
|
213
|
+
* e.g., "currentUser" -> "currentUserQueryKey"
|
|
214
|
+
*/
|
|
215
|
+
export function getQueryKeyName(operationName) {
|
|
216
|
+
return `${operationName}QueryKey`;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Generate GraphQL document constant name
|
|
220
|
+
* e.g., "login" -> "loginMutationDocument"
|
|
221
|
+
*/
|
|
222
|
+
export function getDocumentConstName(operationName, kind) {
|
|
223
|
+
return `${operationName}${kind === 'query' ? 'Query' : 'Mutation'}Document`;
|
|
224
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types generator - generates types.ts with entity interfaces using AST
|
|
3
|
+
*/
|
|
4
|
+
import type { CleanTable } from '../../types/schema';
|
|
5
|
+
/**
|
|
6
|
+
* Generate types.ts content with all entity interfaces and base filter types
|
|
7
|
+
*/
|
|
8
|
+
export declare function generateTypesFile(tables: CleanTable[]): string;
|
|
9
|
+
/**
|
|
10
|
+
* Generate a minimal entity type (just id and display fields)
|
|
11
|
+
*/
|
|
12
|
+
export declare function generateMinimalEntityType(table: CleanTable): string;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { createProject, createSourceFile, getFormattedOutput, createFileHeader, createInterface, } from './ts-ast';
|
|
2
|
+
import { getScalarFields, fieldTypeToTs } from './utils';
|
|
3
|
+
import { generateBaseFilterTypes } from './filters';
|
|
4
|
+
/**
|
|
5
|
+
* Generate types.ts content with all entity interfaces and base filter types
|
|
6
|
+
*/
|
|
7
|
+
export function generateTypesFile(tables) {
|
|
8
|
+
const project = createProject();
|
|
9
|
+
const sourceFile = createSourceFile(project, 'types.ts');
|
|
10
|
+
// Add file header
|
|
11
|
+
sourceFile.insertText(0, createFileHeader('Entity types and filter types') + '\n\n');
|
|
12
|
+
// Add section comment
|
|
13
|
+
sourceFile.addStatements('// ============================================================================');
|
|
14
|
+
sourceFile.addStatements('// Entity types');
|
|
15
|
+
sourceFile.addStatements('// ============================================================================\n');
|
|
16
|
+
// Generate entity interfaces
|
|
17
|
+
for (const table of tables) {
|
|
18
|
+
const scalarFields = getScalarFields(table);
|
|
19
|
+
const properties = scalarFields.map((field) => ({
|
|
20
|
+
name: field.name,
|
|
21
|
+
type: `${fieldTypeToTs(field.type)} | null`,
|
|
22
|
+
}));
|
|
23
|
+
sourceFile.addInterface(createInterface(table.name, properties));
|
|
24
|
+
}
|
|
25
|
+
// Add section comment for filters
|
|
26
|
+
sourceFile.addStatements('\n// ============================================================================');
|
|
27
|
+
sourceFile.addStatements('// Filter types (shared)');
|
|
28
|
+
sourceFile.addStatements('// ============================================================================\n');
|
|
29
|
+
// Add base filter types (using string concat for complex types - acceptable for static definitions)
|
|
30
|
+
const filterTypesContent = generateBaseFilterTypes();
|
|
31
|
+
// Extract just the interfaces part (skip the header)
|
|
32
|
+
const filterInterfaces = filterTypesContent
|
|
33
|
+
.split('\n')
|
|
34
|
+
.slice(6) // Skip header lines
|
|
35
|
+
.join('\n');
|
|
36
|
+
sourceFile.addStatements(filterInterfaces);
|
|
37
|
+
return getFormattedOutput(sourceFile);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Generate a minimal entity type (just id and display fields)
|
|
41
|
+
*/
|
|
42
|
+
export function generateMinimalEntityType(table) {
|
|
43
|
+
const project = createProject();
|
|
44
|
+
const sourceFile = createSourceFile(project, 'minimal.ts');
|
|
45
|
+
const scalarFields = getScalarFields(table);
|
|
46
|
+
// Find id and likely display fields
|
|
47
|
+
const displayFields = scalarFields.filter((f) => {
|
|
48
|
+
const name = f.name.toLowerCase();
|
|
49
|
+
return (name === 'id' ||
|
|
50
|
+
name === 'name' ||
|
|
51
|
+
name === 'title' ||
|
|
52
|
+
name === 'label' ||
|
|
53
|
+
name === 'email' ||
|
|
54
|
+
name.endsWith('name') ||
|
|
55
|
+
name.endsWith('title'));
|
|
56
|
+
});
|
|
57
|
+
// If no display fields found, take first 5 scalar fields
|
|
58
|
+
const fieldsToUse = displayFields.length > 0 ? displayFields : scalarFields.slice(0, 5);
|
|
59
|
+
const properties = fieldsToUse.map((field) => ({
|
|
60
|
+
name: field.name,
|
|
61
|
+
type: `${fieldTypeToTs(field.type)} | null`,
|
|
62
|
+
}));
|
|
63
|
+
sourceFile.addInterface(createInterface(`${table.name}Minimal`, properties));
|
|
64
|
+
return getFormattedOutput(sourceFile);
|
|
65
|
+
}
|