@constructive-io/graphql-codegen 2.23.2 → 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/cli/commands/generate.js +1 -0
- package/cli/index.js +1 -0
- 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/cli/commands/generate.js +1 -0
- package/esm/cli/index.js +1 -0
- package/esm/types/config.d.ts +75 -0
- package/esm/types/config.js +19 -1
- package/package.json +6 -4
- package/types/config.d.ts +75 -0
- package/types/config.js +20 -2
- 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,13 +1,18 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as t from '@babel/types';
|
|
2
|
+
import { generateCode, addJSDocComment, typedParam } from './babel-ast';
|
|
2
3
|
import { buildCustomMutationString } from './schema-gql-ast';
|
|
3
4
|
import { typeRefToTsType, isTypeRequired, getOperationHookName, getOperationFileName, getOperationVariablesTypeName, getOperationResultTypeName, getDocumentConstName, createTypeTracker, } from './type-resolver';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
import { getGeneratedFileHeader } from './utils';
|
|
6
|
+
function generateVariablesProperties(args, tracker) {
|
|
7
|
+
return args.map((arg) => ({
|
|
8
|
+
name: arg.name,
|
|
9
|
+
type: typeRefToTsType(arg.type, tracker),
|
|
10
|
+
optional: !isTypeRequired(arg.type),
|
|
11
|
+
docs: arg.description ? [arg.description] : undefined,
|
|
12
|
+
}));
|
|
13
|
+
}
|
|
8
14
|
export function generateCustomMutationHook(options) {
|
|
9
15
|
const { operation, reactQueryEnabled = true } = options;
|
|
10
|
-
// Mutations require React Query - skip generation when disabled
|
|
11
16
|
if (!reactQueryEnabled) {
|
|
12
17
|
return null;
|
|
13
18
|
}
|
|
@@ -21,150 +26,103 @@ export function generateCustomMutationHook(options) {
|
|
|
21
26
|
}
|
|
22
27
|
}
|
|
23
28
|
function generateCustomMutationHookInternal(options) {
|
|
24
|
-
const { operation, typeRegistry, maxDepth = 2, skipQueryField = true, tableTypeNames } = options;
|
|
25
|
-
const project = createProject();
|
|
29
|
+
const { operation, typeRegistry, maxDepth = 2, skipQueryField = true, tableTypeNames, useCentralizedKeys = true, } = options;
|
|
26
30
|
const hookName = getOperationHookName(operation.name, 'mutation');
|
|
27
31
|
const fileName = getOperationFileName(operation.name, 'mutation');
|
|
28
32
|
const variablesTypeName = getOperationVariablesTypeName(operation.name, 'mutation');
|
|
29
33
|
const resultTypeName = getOperationResultTypeName(operation.name, 'mutation');
|
|
30
34
|
const documentConstName = getDocumentConstName(operation.name, 'mutation');
|
|
31
|
-
// Create type tracker to collect referenced types (with table type awareness)
|
|
32
35
|
const tracker = createTypeTracker({ tableTypeNames });
|
|
33
|
-
// Generate GraphQL document
|
|
34
36
|
const mutationDocument = buildCustomMutationString({
|
|
35
37
|
operation,
|
|
36
38
|
typeRegistry,
|
|
37
39
|
maxDepth,
|
|
38
40
|
skipQueryField,
|
|
39
41
|
});
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
let variablesProps = [];
|
|
45
|
-
if (operation.args.length > 0) {
|
|
46
|
-
variablesProps = generateVariablesProperties(operation.args, tracker);
|
|
47
|
-
}
|
|
48
|
-
// Generate result interface (with tracking)
|
|
42
|
+
const statements = [];
|
|
43
|
+
const variablesProps = operation.args.length > 0
|
|
44
|
+
? generateVariablesProperties(operation.args, tracker)
|
|
45
|
+
: [];
|
|
49
46
|
const resultType = typeRefToTsType(operation.returnType, tracker);
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
];
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
moduleSpecifier: '@tanstack/react-query',
|
|
60
|
-
namedImports: ['useMutation'],
|
|
61
|
-
typeOnlyNamedImports: ['UseMutationOptions'],
|
|
62
|
-
}),
|
|
63
|
-
createImport({
|
|
64
|
-
moduleSpecifier: '../client',
|
|
65
|
-
namedImports: ['execute'],
|
|
66
|
-
}),
|
|
67
|
-
];
|
|
68
|
-
// Add types.ts import for table entity types
|
|
47
|
+
const schemaTypes = tracker.getImportableTypes();
|
|
48
|
+
const tableTypes = tracker.getTableTypes();
|
|
49
|
+
const reactQueryImport = t.importDeclaration([t.importSpecifier(t.identifier('useMutation'), t.identifier('useMutation'))], t.stringLiteral('@tanstack/react-query'));
|
|
50
|
+
statements.push(reactQueryImport);
|
|
51
|
+
const reactQueryTypeImport = t.importDeclaration([t.importSpecifier(t.identifier('UseMutationOptions'), t.identifier('UseMutationOptions'))], t.stringLiteral('@tanstack/react-query'));
|
|
52
|
+
reactQueryTypeImport.importKind = 'type';
|
|
53
|
+
statements.push(reactQueryTypeImport);
|
|
54
|
+
const clientImport = t.importDeclaration([t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], t.stringLiteral('../client'));
|
|
55
|
+
statements.push(clientImport);
|
|
69
56
|
if (tableTypes.length > 0) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}));
|
|
57
|
+
const typesImport = t.importDeclaration(tableTypes.map((tt) => t.importSpecifier(t.identifier(tt), t.identifier(tt))), t.stringLiteral('../types'));
|
|
58
|
+
typesImport.importKind = 'type';
|
|
59
|
+
statements.push(typesImport);
|
|
74
60
|
}
|
|
75
|
-
// Add schema-types import for Input/Payload/Enum types
|
|
76
61
|
if (schemaTypes.length > 0) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}));
|
|
62
|
+
const schemaTypesImport = t.importDeclaration(schemaTypes.map((st) => t.importSpecifier(t.identifier(st), t.identifier(st))), t.stringLiteral('../schema-types'));
|
|
63
|
+
schemaTypesImport.importKind = 'type';
|
|
64
|
+
statements.push(schemaTypesImport);
|
|
81
65
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
66
|
+
if (useCentralizedKeys) {
|
|
67
|
+
const mutationKeyImport = t.importDeclaration([t.importSpecifier(t.identifier('customMutationKeys'), t.identifier('customMutationKeys'))], t.stringLiteral('../mutation-keys'));
|
|
68
|
+
statements.push(mutationKeyImport);
|
|
69
|
+
}
|
|
70
|
+
const mutationDocConst = t.variableDeclaration('const', [
|
|
71
|
+
t.variableDeclarator(t.identifier(documentConstName), t.templateLiteral([t.templateElement({ raw: '\n' + mutationDocument, cooked: '\n' + mutationDocument }, true)], [])),
|
|
72
|
+
]);
|
|
73
|
+
const mutationDocExport = t.exportNamedDeclaration(mutationDocConst);
|
|
74
|
+
addJSDocComment(mutationDocExport, ['GraphQL mutation document']);
|
|
75
|
+
statements.push(mutationDocExport);
|
|
88
76
|
if (operation.args.length > 0) {
|
|
89
|
-
|
|
77
|
+
const variablesInterfaceProps = variablesProps.map((vp) => {
|
|
78
|
+
const prop = t.tsPropertySignature(t.identifier(vp.name), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(vp.type))));
|
|
79
|
+
prop.optional = vp.optional;
|
|
80
|
+
return prop;
|
|
81
|
+
});
|
|
82
|
+
const variablesInterface = t.tsInterfaceDeclaration(t.identifier(variablesTypeName), null, null, t.tsInterfaceBody(variablesInterfaceProps));
|
|
83
|
+
statements.push(t.exportNamedDeclaration(variablesInterface));
|
|
90
84
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
// Note: docs can cause ts-morph issues with certain content, so we skip them
|
|
97
|
-
sourceFile.addFunction({
|
|
98
|
-
name: hookName,
|
|
99
|
-
isExported: true,
|
|
100
|
-
parameters: hookParams,
|
|
101
|
-
statements: hookBody,
|
|
102
|
-
});
|
|
103
|
-
return {
|
|
104
|
-
fileName,
|
|
105
|
-
content: getFormattedOutput(sourceFile),
|
|
106
|
-
operationName: operation.name,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
// ============================================================================
|
|
110
|
-
// Helper functions
|
|
111
|
-
// ============================================================================
|
|
112
|
-
/**
|
|
113
|
-
* Generate interface properties from CleanArguments
|
|
114
|
-
*/
|
|
115
|
-
function generateVariablesProperties(args, tracker) {
|
|
116
|
-
return args.map((arg) => ({
|
|
117
|
-
name: arg.name,
|
|
118
|
-
type: typeRefToTsType(arg.type, tracker),
|
|
119
|
-
optional: !isTypeRequired(arg.type),
|
|
120
|
-
docs: arg.description ? [arg.description] : undefined,
|
|
121
|
-
}));
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Generate hook function parameters
|
|
125
|
-
*/
|
|
126
|
-
function generateHookParameters(operation, variablesTypeName, resultTypeName) {
|
|
127
|
-
const hasArgs = operation.args.length > 0;
|
|
128
|
-
// Mutation hooks use UseMutationOptions with variables as the second type param
|
|
129
|
-
const optionsType = hasArgs
|
|
130
|
-
? `Omit<UseMutationOptions<${resultTypeName}, Error, ${variablesTypeName}>, 'mutationFn'>`
|
|
131
|
-
: `Omit<UseMutationOptions<${resultTypeName}, Error, void>, 'mutationFn'>`;
|
|
132
|
-
return [
|
|
133
|
-
{
|
|
134
|
-
name: 'options',
|
|
135
|
-
type: optionsType,
|
|
136
|
-
hasQuestionToken: true,
|
|
137
|
-
},
|
|
138
|
-
];
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* Generate hook function body
|
|
142
|
-
*/
|
|
143
|
-
function generateHookBody(operation, documentConstName, variablesTypeName, resultTypeName) {
|
|
85
|
+
const resultInterfaceBody = t.tsInterfaceBody([
|
|
86
|
+
t.tsPropertySignature(t.identifier(operation.name), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(resultType)))),
|
|
87
|
+
]);
|
|
88
|
+
const resultInterface = t.tsInterfaceDeclaration(t.identifier(resultTypeName), null, null, resultInterfaceBody);
|
|
89
|
+
statements.push(t.exportNamedDeclaration(resultInterface));
|
|
144
90
|
const hasArgs = operation.args.length > 0;
|
|
91
|
+
const hookBodyStatements = [];
|
|
92
|
+
const mutationOptions = [];
|
|
93
|
+
if (useCentralizedKeys) {
|
|
94
|
+
mutationOptions.push(t.objectProperty(t.identifier('mutationKey'), t.callExpression(t.memberExpression(t.identifier('customMutationKeys'), t.identifier(operation.name)), [])));
|
|
95
|
+
}
|
|
145
96
|
if (hasArgs) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
variables
|
|
151
|
-
),
|
|
152
|
-
...options,
|
|
153
|
-
});`;
|
|
97
|
+
mutationOptions.push(t.objectProperty(t.identifier('mutationFn'), t.arrowFunctionExpression([typedParam('variables', t.tsTypeReference(t.identifier(variablesTypeName)))], t.callExpression(t.identifier('execute'), [
|
|
98
|
+
t.identifier(documentConstName),
|
|
99
|
+
t.identifier('variables'),
|
|
100
|
+
]))));
|
|
154
101
|
}
|
|
155
102
|
else {
|
|
156
|
-
|
|
157
|
-
mutationFn: () => execute<${resultTypeName}>(${documentConstName}),
|
|
158
|
-
...options,
|
|
159
|
-
});`;
|
|
103
|
+
mutationOptions.push(t.objectProperty(t.identifier('mutationFn'), t.arrowFunctionExpression([], t.callExpression(t.identifier('execute'), [t.identifier(documentConstName)]))));
|
|
160
104
|
}
|
|
105
|
+
mutationOptions.push(t.spreadElement(t.identifier('options')));
|
|
106
|
+
hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useMutation'), [t.objectExpression(mutationOptions)])));
|
|
107
|
+
const optionsType = hasArgs
|
|
108
|
+
? `Omit<UseMutationOptions<${resultTypeName}, Error, ${variablesTypeName}>, 'mutationFn'>`
|
|
109
|
+
: `Omit<UseMutationOptions<${resultTypeName}, Error, void>, 'mutationFn'>`;
|
|
110
|
+
const optionsParam = t.identifier('options');
|
|
111
|
+
optionsParam.optional = true;
|
|
112
|
+
optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier(optionsType)));
|
|
113
|
+
const hookFunc = t.functionDeclaration(t.identifier(hookName), [optionsParam], t.blockStatement(hookBodyStatements));
|
|
114
|
+
const hookExport = t.exportNamedDeclaration(hookFunc);
|
|
115
|
+
statements.push(hookExport);
|
|
116
|
+
const code = generateCode(statements);
|
|
117
|
+
const content = getGeneratedFileHeader(`Custom mutation hook for ${operation.name}`) + '\n\n' + code;
|
|
118
|
+
return {
|
|
119
|
+
fileName,
|
|
120
|
+
content,
|
|
121
|
+
operationName: operation.name,
|
|
122
|
+
};
|
|
161
123
|
}
|
|
162
|
-
/**
|
|
163
|
-
* Generate all custom mutation hook files
|
|
164
|
-
* When reactQueryEnabled is false, returns empty array since mutations require React Query
|
|
165
|
-
*/
|
|
166
124
|
export function generateAllCustomMutationHooks(options) {
|
|
167
|
-
const { operations, typeRegistry, maxDepth = 2, skipQueryField = true, reactQueryEnabled = true, tableTypeNames } = options;
|
|
125
|
+
const { operations, typeRegistry, maxDepth = 2, skipQueryField = true, reactQueryEnabled = true, tableTypeNames, useCentralizedKeys = true, } = options;
|
|
168
126
|
return operations
|
|
169
127
|
.filter((op) => op.kind === 'mutation')
|
|
170
128
|
.map((operation) => generateCustomMutationHook({
|
|
@@ -174,6 +132,7 @@ export function generateAllCustomMutationHooks(options) {
|
|
|
174
132
|
skipQueryField,
|
|
175
133
|
reactQueryEnabled,
|
|
176
134
|
tableTypeNames,
|
|
135
|
+
useCentralizedKeys,
|
|
177
136
|
}))
|
|
178
137
|
.filter((result) => result !== null);
|
|
179
138
|
}
|
|
@@ -21,26 +21,18 @@ export interface GenerateCustomQueryHookOptions {
|
|
|
21
21
|
typeRegistry: TypeRegistry;
|
|
22
22
|
maxDepth?: number;
|
|
23
23
|
skipQueryField?: boolean;
|
|
24
|
-
/** Whether to generate React Query hooks (default: true for backwards compatibility) */
|
|
25
24
|
reactQueryEnabled?: boolean;
|
|
26
|
-
/** Table entity type names (for import path resolution) */
|
|
27
25
|
tableTypeNames?: Set<string>;
|
|
26
|
+
useCentralizedKeys?: boolean;
|
|
28
27
|
}
|
|
29
|
-
/**
|
|
30
|
-
* Generate a custom query hook file
|
|
31
|
-
*/
|
|
32
28
|
export declare function generateCustomQueryHook(options: GenerateCustomQueryHookOptions): GeneratedCustomQueryFile;
|
|
33
29
|
export interface GenerateAllCustomQueryHooksOptions {
|
|
34
30
|
operations: CleanOperation[];
|
|
35
31
|
typeRegistry: TypeRegistry;
|
|
36
32
|
maxDepth?: number;
|
|
37
33
|
skipQueryField?: boolean;
|
|
38
|
-
/** Whether to generate React Query hooks (default: true for backwards compatibility) */
|
|
39
34
|
reactQueryEnabled?: boolean;
|
|
40
|
-
/** Table entity type names (for import path resolution) */
|
|
41
35
|
tableTypeNames?: Set<string>;
|
|
36
|
+
useCentralizedKeys?: boolean;
|
|
42
37
|
}
|
|
43
|
-
/**
|
|
44
|
-
* Generate all custom query hook files
|
|
45
|
-
*/
|
|
46
38
|
export declare function generateAllCustomQueryHooks(options: GenerateAllCustomQueryHooksOptions): GeneratedCustomQueryFile[];
|