@constructive-io/graphql-codegen 2.23.3 → 2.24.0
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 +147 -2
- package/cli/codegen/babel-ast.d.ts +46 -0
- package/cli/codegen/babel-ast.js +145 -0
- package/cli/codegen/barrel.d.ts +7 -2
- package/cli/codegen/barrel.js +159 -97
- package/cli/codegen/client.js +61 -0
- package/cli/codegen/custom-mutations.d.ts +2 -12
- package/cli/codegen/custom-mutations.js +116 -124
- package/cli/codegen/custom-queries.d.ts +2 -10
- package/cli/codegen/custom-queries.js +246 -335
- package/cli/codegen/index.d.ts +3 -0
- package/cli/codegen/index.js +72 -3
- package/cli/codegen/invalidation.d.ts +20 -0
- package/cli/codegen/invalidation.js +327 -0
- package/cli/codegen/mutation-keys.d.ts +24 -0
- package/cli/codegen/mutation-keys.js +247 -0
- package/cli/codegen/mutations.d.ts +3 -19
- package/cli/codegen/mutations.js +372 -383
- package/cli/codegen/orm/barrel.d.ts +1 -1
- package/cli/codegen/orm/barrel.js +42 -10
- package/cli/codegen/orm/client-generator.d.ts +1 -19
- package/cli/codegen/orm/client-generator.js +108 -77
- package/cli/codegen/orm/custom-ops-generator.d.ts +1 -12
- package/cli/codegen/orm/custom-ops-generator.js +192 -235
- package/cli/codegen/orm/input-types-generator.d.ts +13 -1
- package/cli/codegen/orm/input-types-generator.js +403 -147
- package/cli/codegen/orm/model-generator.d.ts +1 -19
- package/cli/codegen/orm/model-generator.js +229 -234
- package/cli/codegen/queries.d.ts +3 -11
- package/cli/codegen/queries.js +582 -389
- package/cli/codegen/query-keys.d.ts +15 -0
- package/cli/codegen/query-keys.js +477 -0
- package/cli/codegen/scalars.js +1 -0
- package/cli/codegen/schema-types-generator.d.ts +15 -10
- package/cli/codegen/schema-types-generator.js +87 -175
- package/cli/codegen/type-resolver.d.ts +1 -30
- package/cli/codegen/type-resolver.js +0 -53
- package/cli/codegen/types.d.ts +1 -1
- package/cli/codegen/types.js +76 -21
- package/esm/cli/codegen/babel-ast.d.ts +46 -0
- package/esm/cli/codegen/babel-ast.js +97 -0
- package/esm/cli/codegen/barrel.d.ts +7 -2
- package/esm/cli/codegen/barrel.js +126 -97
- package/esm/cli/codegen/client.js +61 -0
- package/esm/cli/codegen/custom-mutations.d.ts +2 -12
- package/esm/cli/codegen/custom-mutations.js +83 -124
- package/esm/cli/codegen/custom-queries.d.ts +2 -10
- package/esm/cli/codegen/custom-queries.js +214 -336
- package/esm/cli/codegen/index.d.ts +3 -0
- package/esm/cli/codegen/index.js +68 -2
- package/esm/cli/codegen/invalidation.d.ts +20 -0
- package/esm/cli/codegen/invalidation.js +291 -0
- package/esm/cli/codegen/mutation-keys.d.ts +24 -0
- package/esm/cli/codegen/mutation-keys.js +211 -0
- package/esm/cli/codegen/mutations.d.ts +3 -19
- package/esm/cli/codegen/mutations.js +340 -384
- package/esm/cli/codegen/orm/barrel.d.ts +1 -1
- package/esm/cli/codegen/orm/barrel.js +10 -11
- package/esm/cli/codegen/orm/client-generator.d.ts +1 -19
- package/esm/cli/codegen/orm/client-generator.js +76 -78
- package/esm/cli/codegen/orm/custom-ops-generator.d.ts +1 -12
- package/esm/cli/codegen/orm/custom-ops-generator.js +160 -236
- package/esm/cli/codegen/orm/input-types-generator.d.ts +13 -1
- package/esm/cli/codegen/orm/input-types-generator.js +371 -148
- package/esm/cli/codegen/orm/model-generator.d.ts +1 -19
- package/esm/cli/codegen/orm/model-generator.js +197 -235
- package/esm/cli/codegen/queries.d.ts +3 -11
- package/esm/cli/codegen/queries.js +550 -390
- package/esm/cli/codegen/query-keys.d.ts +15 -0
- package/esm/cli/codegen/query-keys.js +441 -0
- package/esm/cli/codegen/scalars.js +1 -0
- package/esm/cli/codegen/schema-types-generator.d.ts +15 -10
- package/esm/cli/codegen/schema-types-generator.js +54 -175
- package/esm/cli/codegen/type-resolver.d.ts +1 -30
- package/esm/cli/codegen/type-resolver.js +0 -49
- package/esm/cli/codegen/types.d.ts +1 -1
- package/esm/cli/codegen/types.js +44 -22
- package/esm/types/config.d.ts +75 -0
- package/esm/types/config.js +18 -0
- package/package.json +6 -4
- package/types/config.d.ts +75 -0
- package/types/config.js +19 -1
- package/cli/codegen/ts-ast.d.ts +0 -124
- package/cli/codegen/ts-ast.js +0 -280
- package/esm/cli/codegen/ts-ast.d.ts +0 -124
- package/esm/cli/codegen/ts-ast.js +0 -260
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as t from '@babel/types';
|
|
2
|
+
import { generateCode } from './babel-ast';
|
|
2
3
|
import { getTypeBaseName } from './type-resolver';
|
|
3
4
|
import { scalarToTsType, SCALAR_NAMES, BASE_FILTER_TYPE_NAMES, } from './scalars';
|
|
4
|
-
|
|
5
|
-
// Constants
|
|
6
|
-
// ============================================================================
|
|
7
|
-
/**
|
|
8
|
-
* Types that should not be generated (scalars, built-ins, types generated elsewhere)
|
|
9
|
-
*/
|
|
5
|
+
import { getGeneratedFileHeader } from './utils';
|
|
10
6
|
const SKIP_TYPES = new Set([
|
|
11
7
|
...SCALAR_NAMES,
|
|
12
|
-
// GraphQL built-ins
|
|
13
8
|
'Query',
|
|
14
9
|
'Mutation',
|
|
15
10
|
'Subscription',
|
|
@@ -19,27 +14,9 @@ const SKIP_TYPES = new Set([
|
|
|
19
14
|
'__InputValue',
|
|
20
15
|
'__EnumValue',
|
|
21
16
|
'__Directive',
|
|
22
|
-
// Note: PageInfo and Cursor are NOT skipped - they're needed by Connection types
|
|
23
|
-
// Base filter types (generated in types.ts via filters.ts)
|
|
24
17
|
...BASE_FILTER_TYPE_NAMES,
|
|
25
18
|
]);
|
|
26
|
-
|
|
27
|
-
* Type name patterns to skip (regex patterns)
|
|
28
|
-
*
|
|
29
|
-
* Note: We intentionally DO NOT skip Connection, Edge, Filter, Patch, Condition,
|
|
30
|
-
* or OrderBy types because they may be referenced by custom operations.
|
|
31
|
-
* Previously Condition and OrderBy were skipped but they ARE needed for
|
|
32
|
-
* custom queries like `schemata`, `apiSchemata`, etc.
|
|
33
|
-
*/
|
|
34
|
-
const SKIP_TYPE_PATTERNS = [
|
|
35
|
-
// Currently no patterns are skipped - all types may be needed by custom operations
|
|
36
|
-
];
|
|
37
|
-
// ============================================================================
|
|
38
|
-
// Type Conversion Utilities
|
|
39
|
-
// ============================================================================
|
|
40
|
-
/**
|
|
41
|
-
* Convert a CleanTypeRef to TypeScript type string
|
|
42
|
-
*/
|
|
19
|
+
const SKIP_TYPE_PATTERNS = [];
|
|
43
20
|
function typeRefToTs(typeRef) {
|
|
44
21
|
if (typeRef.kind === 'NON_NULL') {
|
|
45
22
|
if (typeRef.ofType) {
|
|
@@ -53,48 +30,26 @@ function typeRefToTs(typeRef) {
|
|
|
53
30
|
}
|
|
54
31
|
return 'unknown[]';
|
|
55
32
|
}
|
|
56
|
-
// Scalar or named type
|
|
57
33
|
const name = typeRef.name ?? 'unknown';
|
|
58
34
|
return scalarToTsType(name, { unknownScalar: 'name' });
|
|
59
35
|
}
|
|
60
|
-
/**
|
|
61
|
-
* Check if a type is required (NON_NULL)
|
|
62
|
-
*/
|
|
63
36
|
function isRequired(typeRef) {
|
|
64
37
|
return typeRef.kind === 'NON_NULL';
|
|
65
38
|
}
|
|
66
|
-
/**
|
|
67
|
-
* Check if a type should be skipped
|
|
68
|
-
*/
|
|
69
39
|
function shouldSkipType(typeName, tableTypeNames) {
|
|
70
|
-
// Skip scalars and built-ins
|
|
71
40
|
if (SKIP_TYPES.has(typeName))
|
|
72
41
|
return true;
|
|
73
|
-
// Skip table entity types (already in types.ts)
|
|
74
42
|
if (tableTypeNames.has(typeName))
|
|
75
43
|
return true;
|
|
76
|
-
// Skip types matching patterns
|
|
77
44
|
for (const pattern of SKIP_TYPE_PATTERNS) {
|
|
78
45
|
if (pattern.test(typeName))
|
|
79
46
|
return true;
|
|
80
47
|
}
|
|
81
|
-
// Skip table-specific types that would conflict with inline types in table-based hooks.
|
|
82
|
-
// Note: Patch and CreateInput are now NOT exported from hooks (isExported: false),
|
|
83
|
-
// so we only skip Filter types here.
|
|
84
|
-
// The Filter and OrderBy types are generated inline (non-exported) by table query hooks,
|
|
85
|
-
// but schema-types should still generate them for custom operations that need them.
|
|
86
|
-
// Actually, we don't skip any table-based types now since hooks don't export them.
|
|
87
48
|
return false;
|
|
88
49
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
// ============================================================================
|
|
92
|
-
/**
|
|
93
|
-
* Add ENUM types to source file
|
|
94
|
-
*/
|
|
95
|
-
function addEnumTypes(sourceFile, typeRegistry, tableTypeNames) {
|
|
50
|
+
function generateEnumTypes(typeRegistry, tableTypeNames) {
|
|
51
|
+
const statements = [];
|
|
96
52
|
const generatedTypes = new Set();
|
|
97
|
-
addSectionComment(sourceFile, 'Enum Types');
|
|
98
53
|
for (const [typeName, typeInfo] of typeRegistry) {
|
|
99
54
|
if (typeInfo.kind !== 'ENUM')
|
|
100
55
|
continue;
|
|
@@ -102,23 +57,17 @@ function addEnumTypes(sourceFile, typeRegistry, tableTypeNames) {
|
|
|
102
57
|
continue;
|
|
103
58
|
if (!typeInfo.enumValues || typeInfo.enumValues.length === 0)
|
|
104
59
|
continue;
|
|
105
|
-
const
|
|
106
|
-
|
|
60
|
+
const unionType = t.tsUnionType(typeInfo.enumValues.map((v) => t.tsLiteralType(t.stringLiteral(v))));
|
|
61
|
+
const typeAlias = t.tsTypeAliasDeclaration(t.identifier(typeName), null, unionType);
|
|
62
|
+
statements.push(t.exportNamedDeclaration(typeAlias));
|
|
107
63
|
generatedTypes.add(typeName);
|
|
108
64
|
}
|
|
109
|
-
return generatedTypes;
|
|
65
|
+
return { statements, generatedTypes };
|
|
110
66
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
// ============================================================================
|
|
114
|
-
/**
|
|
115
|
-
* Add INPUT_OBJECT types to source file
|
|
116
|
-
* Uses iteration to handle nested input types
|
|
117
|
-
*/
|
|
118
|
-
function addInputObjectTypes(sourceFile, typeRegistry, tableTypeNames, alreadyGenerated) {
|
|
67
|
+
function generateInputObjectTypes(typeRegistry, tableTypeNames, alreadyGenerated) {
|
|
68
|
+
const statements = [];
|
|
119
69
|
const generatedTypes = new Set(alreadyGenerated);
|
|
120
70
|
const typesToGenerate = new Set();
|
|
121
|
-
// Collect all INPUT_OBJECT types
|
|
122
71
|
for (const [typeName, typeInfo] of typeRegistry) {
|
|
123
72
|
if (typeInfo.kind !== 'INPUT_OBJECT')
|
|
124
73
|
continue;
|
|
@@ -128,10 +77,6 @@ function addInputObjectTypes(sourceFile, typeRegistry, tableTypeNames, alreadyGe
|
|
|
128
77
|
continue;
|
|
129
78
|
typesToGenerate.add(typeName);
|
|
130
79
|
}
|
|
131
|
-
if (typesToGenerate.size === 0)
|
|
132
|
-
return generatedTypes;
|
|
133
|
-
addSectionComment(sourceFile, 'Input Object Types');
|
|
134
|
-
// Process all types - no artificial limit
|
|
135
80
|
while (typesToGenerate.size > 0) {
|
|
136
81
|
const typeNameResult = typesToGenerate.values().next();
|
|
137
82
|
if (typeNameResult.done)
|
|
@@ -144,18 +89,14 @@ function addInputObjectTypes(sourceFile, typeRegistry, tableTypeNames, alreadyGe
|
|
|
144
89
|
if (!typeInfo || typeInfo.kind !== 'INPUT_OBJECT')
|
|
145
90
|
continue;
|
|
146
91
|
generatedTypes.add(typeName);
|
|
92
|
+
const properties = [];
|
|
147
93
|
if (typeInfo.inputFields && typeInfo.inputFields.length > 0) {
|
|
148
|
-
const properties = [];
|
|
149
94
|
for (const field of typeInfo.inputFields) {
|
|
150
95
|
const optional = !isRequired(field.type);
|
|
151
96
|
const tsType = typeRefToTs(field.type);
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
optional,
|
|
156
|
-
docs: field.description ? [field.description] : undefined,
|
|
157
|
-
});
|
|
158
|
-
// Follow nested Input types
|
|
97
|
+
const prop = t.tsPropertySignature(t.identifier(field.name), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(tsType))));
|
|
98
|
+
prop.optional = optional;
|
|
99
|
+
properties.push(prop);
|
|
159
100
|
const baseType = getTypeBaseName(field.type);
|
|
160
101
|
if (baseType &&
|
|
161
102
|
!generatedTypes.has(baseType) &&
|
|
@@ -166,25 +107,15 @@ function addInputObjectTypes(sourceFile, typeRegistry, tableTypeNames, alreadyGe
|
|
|
166
107
|
}
|
|
167
108
|
}
|
|
168
109
|
}
|
|
169
|
-
sourceFile.addInterface(createInterface(typeName, properties));
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
// Empty input object
|
|
173
|
-
sourceFile.addInterface(createInterface(typeName, []));
|
|
174
110
|
}
|
|
111
|
+
const interfaceDecl = t.tsInterfaceDeclaration(t.identifier(typeName), null, null, t.tsInterfaceBody(properties));
|
|
112
|
+
statements.push(t.exportNamedDeclaration(interfaceDecl));
|
|
175
113
|
}
|
|
176
|
-
return generatedTypes;
|
|
114
|
+
return { statements, generatedTypes };
|
|
177
115
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
// ============================================================================
|
|
181
|
-
/**
|
|
182
|
-
* Add UNION types to source file
|
|
183
|
-
*/
|
|
184
|
-
function addUnionTypes(sourceFile, typeRegistry, tableTypeNames, alreadyGenerated) {
|
|
116
|
+
function generateUnionTypes(typeRegistry, tableTypeNames, alreadyGenerated) {
|
|
117
|
+
const statements = [];
|
|
185
118
|
const generatedTypes = new Set(alreadyGenerated);
|
|
186
|
-
const unionTypesToGenerate = new Set();
|
|
187
|
-
// Collect all UNION types
|
|
188
119
|
for (const [typeName, typeInfo] of typeRegistry) {
|
|
189
120
|
if (typeInfo.kind !== 'UNION')
|
|
190
121
|
continue;
|
|
@@ -192,32 +123,17 @@ function addUnionTypes(sourceFile, typeRegistry, tableTypeNames, alreadyGenerate
|
|
|
192
123
|
continue;
|
|
193
124
|
if (generatedTypes.has(typeName))
|
|
194
125
|
continue;
|
|
195
|
-
unionTypesToGenerate.add(typeName);
|
|
196
|
-
}
|
|
197
|
-
if (unionTypesToGenerate.size === 0)
|
|
198
|
-
return generatedTypes;
|
|
199
|
-
addSectionComment(sourceFile, 'Union Types');
|
|
200
|
-
for (const typeName of unionTypesToGenerate) {
|
|
201
|
-
const typeInfo = typeRegistry.get(typeName);
|
|
202
|
-
if (!typeInfo || typeInfo.kind !== 'UNION')
|
|
203
|
-
continue;
|
|
204
126
|
if (!typeInfo.possibleTypes || typeInfo.possibleTypes.length === 0)
|
|
205
127
|
continue;
|
|
206
|
-
|
|
207
|
-
const
|
|
208
|
-
|
|
128
|
+
const unionType = t.tsUnionType(typeInfo.possibleTypes.map((pt) => t.tsTypeReference(t.identifier(pt))));
|
|
129
|
+
const typeAlias = t.tsTypeAliasDeclaration(t.identifier(typeName), null, unionType);
|
|
130
|
+
statements.push(t.exportNamedDeclaration(typeAlias));
|
|
209
131
|
generatedTypes.add(typeName);
|
|
210
132
|
}
|
|
211
|
-
return generatedTypes;
|
|
133
|
+
return { statements, generatedTypes };
|
|
212
134
|
}
|
|
213
|
-
/**
|
|
214
|
-
* Collect return types from Query and Mutation root types
|
|
215
|
-
* This dynamically discovers what OBJECT types need to be generated
|
|
216
|
-
* based on actual schema structure, not pattern matching
|
|
217
|
-
*/
|
|
218
135
|
function collectReturnTypesFromRootTypes(typeRegistry, tableTypeNames) {
|
|
219
136
|
const returnTypes = new Set();
|
|
220
|
-
// Get Query and Mutation root types
|
|
221
137
|
const queryType = typeRegistry.get('Query');
|
|
222
138
|
const mutationType = typeRegistry.get('Mutation');
|
|
223
139
|
const processFields = (fields) => {
|
|
@@ -239,30 +155,16 @@ function collectReturnTypesFromRootTypes(typeRegistry, tableTypeNames) {
|
|
|
239
155
|
processFields(mutationType.fields);
|
|
240
156
|
return returnTypes;
|
|
241
157
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
* These are return types from mutations (e.g., LoginPayload, BootstrapUserPayload)
|
|
245
|
-
*
|
|
246
|
-
* Also tracks which table entity types are referenced so they can be imported.
|
|
247
|
-
*
|
|
248
|
-
* Uses dynamic type discovery from Query/Mutation return types instead of pattern matching.
|
|
249
|
-
*/
|
|
250
|
-
function addPayloadObjectTypes(sourceFile, typeRegistry, tableTypeNames, alreadyGenerated) {
|
|
158
|
+
function generatePayloadObjectTypes(typeRegistry, tableTypeNames, alreadyGenerated) {
|
|
159
|
+
const statements = [];
|
|
251
160
|
const generatedTypes = new Set(alreadyGenerated);
|
|
252
161
|
const referencedTableTypes = new Set();
|
|
253
|
-
// Dynamically collect return types from Query and Mutation
|
|
254
162
|
const typesToGenerate = collectReturnTypesFromRootTypes(typeRegistry, tableTypeNames);
|
|
255
|
-
// Filter out already generated types
|
|
256
163
|
for (const typeName of Array.from(typesToGenerate)) {
|
|
257
164
|
if (generatedTypes.has(typeName)) {
|
|
258
165
|
typesToGenerate.delete(typeName);
|
|
259
166
|
}
|
|
260
167
|
}
|
|
261
|
-
if (typesToGenerate.size === 0) {
|
|
262
|
-
return { generatedTypes, referencedTableTypes };
|
|
263
|
-
}
|
|
264
|
-
addSectionComment(sourceFile, 'Payload/Return Object Types');
|
|
265
|
-
// Process all types - no artificial limit
|
|
266
168
|
while (typesToGenerate.size > 0) {
|
|
267
169
|
const typeNameResult = typesToGenerate.values().next();
|
|
268
170
|
if (typeNameResult.done)
|
|
@@ -275,26 +177,21 @@ function addPayloadObjectTypes(sourceFile, typeRegistry, tableTypeNames, already
|
|
|
275
177
|
if (!typeInfo || typeInfo.kind !== 'OBJECT')
|
|
276
178
|
continue;
|
|
277
179
|
generatedTypes.add(typeName);
|
|
180
|
+
const properties = [];
|
|
278
181
|
if (typeInfo.fields && typeInfo.fields.length > 0) {
|
|
279
|
-
const properties = [];
|
|
280
182
|
for (const field of typeInfo.fields) {
|
|
281
183
|
const baseType = getTypeBaseName(field.type);
|
|
282
|
-
// Skip Query and Mutation fields
|
|
283
184
|
if (baseType === 'Query' || baseType === 'Mutation')
|
|
284
185
|
continue;
|
|
285
186
|
const tsType = typeRefToTs(field.type);
|
|
286
187
|
const isNullable = !isRequired(field.type);
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
docs: field.description ? [field.description] : undefined,
|
|
292
|
-
});
|
|
293
|
-
// Track table entity types that are referenced
|
|
188
|
+
const finalType = isNullable ? `${tsType} | null` : tsType;
|
|
189
|
+
const prop = t.tsPropertySignature(t.identifier(field.name), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(finalType))));
|
|
190
|
+
prop.optional = isNullable;
|
|
191
|
+
properties.push(prop);
|
|
294
192
|
if (baseType && tableTypeNames.has(baseType)) {
|
|
295
193
|
referencedTableTypes.add(baseType);
|
|
296
194
|
}
|
|
297
|
-
// Follow nested OBJECT types that aren't table types
|
|
298
195
|
if (baseType &&
|
|
299
196
|
!generatedTypes.has(baseType) &&
|
|
300
197
|
!shouldSkipType(baseType, tableTypeNames)) {
|
|
@@ -304,59 +201,41 @@ function addPayloadObjectTypes(sourceFile, typeRegistry, tableTypeNames, already
|
|
|
304
201
|
}
|
|
305
202
|
}
|
|
306
203
|
}
|
|
307
|
-
sourceFile.addInterface(createInterface(typeName, properties));
|
|
308
|
-
}
|
|
309
|
-
else {
|
|
310
|
-
// Empty payload object
|
|
311
|
-
sourceFile.addInterface(createInterface(typeName, []));
|
|
312
204
|
}
|
|
205
|
+
const interfaceDecl = t.tsInterfaceDeclaration(t.identifier(typeName), null, null, t.tsInterfaceBody(properties));
|
|
206
|
+
statements.push(t.exportNamedDeclaration(interfaceDecl));
|
|
313
207
|
}
|
|
314
|
-
return { generatedTypes, referencedTableTypes };
|
|
208
|
+
return { statements, generatedTypes, referencedTableTypes };
|
|
315
209
|
}
|
|
316
|
-
// ============================================================================
|
|
317
|
-
// Main Generator
|
|
318
|
-
// ============================================================================
|
|
319
|
-
/**
|
|
320
|
-
* Generate comprehensive schema-types.ts file using ts-morph AST
|
|
321
|
-
*
|
|
322
|
-
* This generates all Input/Payload/Enum types from the TypeRegistry
|
|
323
|
-
* that are needed by custom mutation/query hooks.
|
|
324
|
-
*/
|
|
325
210
|
export function generateSchemaTypesFile(options) {
|
|
326
211
|
const { typeRegistry, tableTypeNames } = options;
|
|
327
|
-
const
|
|
328
|
-
const sourceFile = createSourceFile(project, 'schema-types.ts');
|
|
329
|
-
// Add file header
|
|
330
|
-
sourceFile.insertText(0, createFileHeader('GraphQL schema types for custom operations') + '\n');
|
|
331
|
-
// Track all generated types
|
|
212
|
+
const allStatements = [];
|
|
332
213
|
let generatedTypes = new Set();
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
const
|
|
338
|
-
generatedTypes = new Set([...generatedTypes, ...
|
|
339
|
-
|
|
340
|
-
const inputTypes = addInputObjectTypes(sourceFile, typeRegistry, tableTypeNames, generatedTypes);
|
|
341
|
-
generatedTypes = new Set([...generatedTypes, ...inputTypes]);
|
|
342
|
-
// 4. Generate Payload OBJECT types
|
|
343
|
-
const payloadResult = addPayloadObjectTypes(sourceFile, typeRegistry, tableTypeNames, generatedTypes);
|
|
344
|
-
// 5. Add imports from types.ts (table entity types + base filter types)
|
|
214
|
+
const enumResult = generateEnumTypes(typeRegistry, tableTypeNames);
|
|
215
|
+
generatedTypes = new Set([...generatedTypes, ...enumResult.generatedTypes]);
|
|
216
|
+
const unionResult = generateUnionTypes(typeRegistry, tableTypeNames, generatedTypes);
|
|
217
|
+
generatedTypes = new Set([...generatedTypes, ...unionResult.generatedTypes]);
|
|
218
|
+
const inputResult = generateInputObjectTypes(typeRegistry, tableTypeNames, generatedTypes);
|
|
219
|
+
generatedTypes = new Set([...generatedTypes, ...inputResult.generatedTypes]);
|
|
220
|
+
const payloadResult = generatePayloadObjectTypes(typeRegistry, tableTypeNames, generatedTypes);
|
|
345
221
|
const referencedTableTypes = Array.from(payloadResult.referencedTableTypes).sort();
|
|
346
|
-
// Always import base filter types since generated Filter interfaces reference them
|
|
347
222
|
const baseFilterImports = Array.from(BASE_FILTER_TYPE_NAMES).sort();
|
|
348
223
|
const allTypesImports = [...referencedTableTypes, ...baseFilterImports];
|
|
349
224
|
if (allTypesImports.length > 0) {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
const headerEndIndex = sourceFile.getFullText().indexOf('*/') + 3;
|
|
354
|
-
sourceFile.insertText(headerEndIndex, '\n' + importStatement);
|
|
225
|
+
const typesImport = t.importDeclaration(allTypesImports.map((ti) => t.importSpecifier(t.identifier(ti), t.identifier(ti))), t.stringLiteral('./types'));
|
|
226
|
+
typesImport.importKind = 'type';
|
|
227
|
+
allStatements.push(typesImport);
|
|
355
228
|
}
|
|
229
|
+
allStatements.push(...enumResult.statements);
|
|
230
|
+
allStatements.push(...unionResult.statements);
|
|
231
|
+
allStatements.push(...inputResult.statements);
|
|
232
|
+
allStatements.push(...payloadResult.statements);
|
|
233
|
+
const code = generateCode(allStatements);
|
|
234
|
+
const content = getGeneratedFileHeader('GraphQL schema types for custom operations') + '\n\n' + code;
|
|
356
235
|
return {
|
|
357
236
|
fileName: 'schema-types.ts',
|
|
358
|
-
content
|
|
359
|
-
generatedEnums: Array.from(
|
|
237
|
+
content,
|
|
238
|
+
generatedEnums: Array.from(enumResult.generatedTypes).sort(),
|
|
360
239
|
referencedTableTypes,
|
|
361
240
|
};
|
|
362
241
|
}
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
* Utilities for converting CleanTypeRef and other GraphQL types
|
|
5
5
|
* into TypeScript type strings and interface definitions.
|
|
6
6
|
*/
|
|
7
|
-
import type { CleanTypeRef,
|
|
8
|
-
import type { InterfaceProperty } from './ts-ast';
|
|
7
|
+
import type { CleanTypeRef, CleanObjectField } from '../../types/schema';
|
|
9
8
|
/**
|
|
10
9
|
* Interface for tracking referenced types during code generation
|
|
11
10
|
*/
|
|
@@ -70,34 +69,6 @@ export declare function getTypeBaseName(typeRef: CleanTypeRef): string | null;
|
|
|
70
69
|
* Get the base type kind (unwrapping LIST and NON_NULL)
|
|
71
70
|
*/
|
|
72
71
|
export declare function getBaseTypeKind(typeRef: CleanTypeRef): CleanTypeRef['kind'];
|
|
73
|
-
/**
|
|
74
|
-
* Convert CleanArgument to InterfaceProperty for ts-morph
|
|
75
|
-
*
|
|
76
|
-
* @param arg - The GraphQL argument
|
|
77
|
-
* @param tracker - Optional TypeTracker to collect referenced types
|
|
78
|
-
*/
|
|
79
|
-
export declare function argumentToInterfaceProperty(arg: CleanArgument, tracker?: TypeTracker): InterfaceProperty;
|
|
80
|
-
/**
|
|
81
|
-
* Convert CleanObjectField to InterfaceProperty for ts-morph
|
|
82
|
-
*
|
|
83
|
-
* @param field - The GraphQL object field
|
|
84
|
-
* @param tracker - Optional TypeTracker to collect referenced types
|
|
85
|
-
*/
|
|
86
|
-
export declare function fieldToInterfaceProperty(field: CleanObjectField, tracker?: TypeTracker): InterfaceProperty;
|
|
87
|
-
/**
|
|
88
|
-
* Convert an array of CleanArguments to InterfaceProperty array
|
|
89
|
-
*
|
|
90
|
-
* @param args - The GraphQL arguments
|
|
91
|
-
* @param tracker - Optional TypeTracker to collect referenced types
|
|
92
|
-
*/
|
|
93
|
-
export declare function argumentsToInterfaceProperties(args: CleanArgument[], tracker?: TypeTracker): InterfaceProperty[];
|
|
94
|
-
/**
|
|
95
|
-
* Convert an array of CleanObjectFields to InterfaceProperty array
|
|
96
|
-
*
|
|
97
|
-
* @param fields - The GraphQL object fields
|
|
98
|
-
* @param tracker - Optional TypeTracker to collect referenced types
|
|
99
|
-
*/
|
|
100
|
-
export declare function fieldsToInterfaceProperties(fields: CleanObjectField[], tracker?: TypeTracker): InterfaceProperty[];
|
|
101
72
|
/**
|
|
102
73
|
* Check if a field should be skipped in selections
|
|
103
74
|
*/
|
|
@@ -161,55 +161,6 @@ export function getBaseTypeKind(typeRef) {
|
|
|
161
161
|
return typeRef.kind;
|
|
162
162
|
}
|
|
163
163
|
// ============================================================================
|
|
164
|
-
// Interface Property Generation
|
|
165
|
-
// ============================================================================
|
|
166
|
-
/**
|
|
167
|
-
* Convert CleanArgument to InterfaceProperty for ts-morph
|
|
168
|
-
*
|
|
169
|
-
* @param arg - The GraphQL argument
|
|
170
|
-
* @param tracker - Optional TypeTracker to collect referenced types
|
|
171
|
-
*/
|
|
172
|
-
export function argumentToInterfaceProperty(arg, tracker) {
|
|
173
|
-
return {
|
|
174
|
-
name: arg.name,
|
|
175
|
-
type: typeRefToTsType(arg.type, tracker),
|
|
176
|
-
optional: !isTypeRequired(arg.type),
|
|
177
|
-
docs: arg.description ? [arg.description] : undefined,
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* Convert CleanObjectField to InterfaceProperty for ts-morph
|
|
182
|
-
*
|
|
183
|
-
* @param field - The GraphQL object field
|
|
184
|
-
* @param tracker - Optional TypeTracker to collect referenced types
|
|
185
|
-
*/
|
|
186
|
-
export function fieldToInterfaceProperty(field, tracker) {
|
|
187
|
-
return {
|
|
188
|
-
name: field.name,
|
|
189
|
-
type: typeRefToNullableTsType(field.type, tracker),
|
|
190
|
-
optional: false, // Fields are always present, just potentially null
|
|
191
|
-
docs: field.description ? [field.description] : undefined,
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* Convert an array of CleanArguments to InterfaceProperty array
|
|
196
|
-
*
|
|
197
|
-
* @param args - The GraphQL arguments
|
|
198
|
-
* @param tracker - Optional TypeTracker to collect referenced types
|
|
199
|
-
*/
|
|
200
|
-
export function argumentsToInterfaceProperties(args, tracker) {
|
|
201
|
-
return args.map((arg) => argumentToInterfaceProperty(arg, tracker));
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* Convert an array of CleanObjectFields to InterfaceProperty array
|
|
205
|
-
*
|
|
206
|
-
* @param fields - The GraphQL object fields
|
|
207
|
-
* @param tracker - Optional TypeTracker to collect referenced types
|
|
208
|
-
*/
|
|
209
|
-
export function fieldsToInterfaceProperties(fields, tracker) {
|
|
210
|
-
return fields.map((field) => fieldToInterfaceProperty(field, tracker));
|
|
211
|
-
}
|
|
212
|
-
// ============================================================================
|
|
213
164
|
// Type Filtering
|
|
214
165
|
// ============================================================================
|
|
215
166
|
/**
|
package/esm/cli/codegen/types.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import * as t from '@babel/types';
|
|
2
|
+
import { generateCode } from './babel-ast';
|
|
3
|
+
import { getScalarFields, fieldTypeToTs, getGeneratedFileHeader } from './utils';
|
|
3
4
|
/** All filter type configurations - scalar and list filters */
|
|
4
5
|
const FILTER_CONFIGS = [
|
|
5
6
|
// Scalar filters
|
|
@@ -64,16 +65,42 @@ function buildFilterProperties(tsType, operators) {
|
|
|
64
65
|
}
|
|
65
66
|
return props;
|
|
66
67
|
}
|
|
68
|
+
function parseTypeAnnotation(typeStr) {
|
|
69
|
+
if (typeStr === 'string')
|
|
70
|
+
return t.tsStringKeyword();
|
|
71
|
+
if (typeStr === 'number')
|
|
72
|
+
return t.tsNumberKeyword();
|
|
73
|
+
if (typeStr === 'boolean')
|
|
74
|
+
return t.tsBooleanKeyword();
|
|
75
|
+
if (typeStr === 'unknown')
|
|
76
|
+
return t.tsUnknownKeyword();
|
|
77
|
+
if (typeStr.includes(' | ')) {
|
|
78
|
+
const parts = typeStr.split(' | ').map((p) => parseTypeAnnotation(p.trim()));
|
|
79
|
+
return t.tsUnionType(parts);
|
|
80
|
+
}
|
|
81
|
+
if (typeStr.endsWith('[]')) {
|
|
82
|
+
return t.tsArrayType(parseTypeAnnotation(typeStr.slice(0, -2)));
|
|
83
|
+
}
|
|
84
|
+
if (typeStr === 'null')
|
|
85
|
+
return t.tsNullKeyword();
|
|
86
|
+
return t.tsTypeReference(t.identifier(typeStr));
|
|
87
|
+
}
|
|
88
|
+
function createInterfaceDeclaration(name, properties) {
|
|
89
|
+
const props = properties.map((prop) => {
|
|
90
|
+
const propSig = t.tsPropertySignature(t.identifier(prop.name), t.tsTypeAnnotation(parseTypeAnnotation(prop.type)));
|
|
91
|
+
propSig.optional = prop.optional ?? false;
|
|
92
|
+
return propSig;
|
|
93
|
+
});
|
|
94
|
+
const interfaceDecl = t.tsInterfaceDeclaration(t.identifier(name), null, null, t.tsInterfaceBody(props));
|
|
95
|
+
return t.exportNamedDeclaration(interfaceDecl);
|
|
96
|
+
}
|
|
67
97
|
/**
|
|
68
98
|
* Generate types.ts content with all entity interfaces and base filter types
|
|
69
99
|
*/
|
|
70
100
|
export function generateTypesFile(tables, options = {}) {
|
|
71
101
|
const { enumsFromSchemaTypes = [] } = options;
|
|
72
102
|
const enumSet = new Set(enumsFromSchemaTypes);
|
|
73
|
-
const
|
|
74
|
-
const sourceFile = createSourceFile(project, 'types.ts');
|
|
75
|
-
// Add file header
|
|
76
|
-
sourceFile.insertText(0, createFileHeader('Entity types and filter types') + '\n\n');
|
|
103
|
+
const statements = [];
|
|
77
104
|
// Collect which enums are actually used by entity fields
|
|
78
105
|
const usedEnums = new Set();
|
|
79
106
|
for (const table of tables) {
|
|
@@ -88,16 +115,13 @@ export function generateTypesFile(tables, options = {}) {
|
|
|
88
115
|
}
|
|
89
116
|
// Add import for enum types from schema-types if any are used
|
|
90
117
|
if (usedEnums.size > 0) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
118
|
+
const specifiers = Array.from(usedEnums)
|
|
119
|
+
.sort()
|
|
120
|
+
.map((name) => t.importSpecifier(t.identifier(name), t.identifier(name)));
|
|
121
|
+
const importDecl = t.importDeclaration(specifiers, t.stringLiteral('./schema-types'));
|
|
122
|
+
importDecl.importKind = 'type';
|
|
123
|
+
statements.push(importDecl);
|
|
96
124
|
}
|
|
97
|
-
// Add section comment for entity types
|
|
98
|
-
sourceFile.addStatements('// ============================================================================');
|
|
99
|
-
sourceFile.addStatements('// Entity types');
|
|
100
|
-
sourceFile.addStatements('// ============================================================================\n');
|
|
101
125
|
// Generate entity interfaces
|
|
102
126
|
for (const table of tables) {
|
|
103
127
|
const scalarFields = getScalarFields(table);
|
|
@@ -105,15 +129,13 @@ export function generateTypesFile(tables, options = {}) {
|
|
|
105
129
|
name: field.name,
|
|
106
130
|
type: `${fieldTypeToTs(field.type)} | null`,
|
|
107
131
|
}));
|
|
108
|
-
|
|
132
|
+
statements.push(createInterfaceDeclaration(table.name, properties));
|
|
109
133
|
}
|
|
110
|
-
// Add section comment for filter types
|
|
111
|
-
sourceFile.addStatements('\n// ============================================================================');
|
|
112
|
-
sourceFile.addStatements('// Filter types (shared PostGraphile filter interfaces)');
|
|
113
|
-
sourceFile.addStatements('// ============================================================================\n');
|
|
114
134
|
// Generate all filter types
|
|
115
135
|
for (const { name, tsType, operators } of FILTER_CONFIGS) {
|
|
116
|
-
|
|
136
|
+
statements.push(createInterfaceDeclaration(name, buildFilterProperties(tsType, operators)));
|
|
117
137
|
}
|
|
118
|
-
|
|
138
|
+
const header = getGeneratedFileHeader('Entity types and filter types');
|
|
139
|
+
const code = generateCode(statements);
|
|
140
|
+
return header + '\n' + code;
|
|
119
141
|
}
|