@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.
Files changed (90) hide show
  1. package/README.md +147 -2
  2. package/cli/codegen/babel-ast.d.ts +46 -0
  3. package/cli/codegen/babel-ast.js +145 -0
  4. package/cli/codegen/barrel.d.ts +7 -2
  5. package/cli/codegen/barrel.js +159 -97
  6. package/cli/codegen/client.js +61 -0
  7. package/cli/codegen/custom-mutations.d.ts +2 -12
  8. package/cli/codegen/custom-mutations.js +116 -124
  9. package/cli/codegen/custom-queries.d.ts +2 -10
  10. package/cli/codegen/custom-queries.js +246 -335
  11. package/cli/codegen/index.d.ts +3 -0
  12. package/cli/codegen/index.js +72 -3
  13. package/cli/codegen/invalidation.d.ts +20 -0
  14. package/cli/codegen/invalidation.js +327 -0
  15. package/cli/codegen/mutation-keys.d.ts +24 -0
  16. package/cli/codegen/mutation-keys.js +247 -0
  17. package/cli/codegen/mutations.d.ts +3 -19
  18. package/cli/codegen/mutations.js +372 -383
  19. package/cli/codegen/orm/barrel.d.ts +1 -1
  20. package/cli/codegen/orm/barrel.js +42 -10
  21. package/cli/codegen/orm/client-generator.d.ts +1 -19
  22. package/cli/codegen/orm/client-generator.js +108 -77
  23. package/cli/codegen/orm/custom-ops-generator.d.ts +1 -12
  24. package/cli/codegen/orm/custom-ops-generator.js +192 -235
  25. package/cli/codegen/orm/input-types-generator.d.ts +13 -1
  26. package/cli/codegen/orm/input-types-generator.js +403 -147
  27. package/cli/codegen/orm/model-generator.d.ts +1 -19
  28. package/cli/codegen/orm/model-generator.js +229 -234
  29. package/cli/codegen/queries.d.ts +3 -11
  30. package/cli/codegen/queries.js +582 -389
  31. package/cli/codegen/query-keys.d.ts +15 -0
  32. package/cli/codegen/query-keys.js +477 -0
  33. package/cli/codegen/scalars.js +1 -0
  34. package/cli/codegen/schema-types-generator.d.ts +15 -10
  35. package/cli/codegen/schema-types-generator.js +87 -175
  36. package/cli/codegen/type-resolver.d.ts +1 -30
  37. package/cli/codegen/type-resolver.js +0 -53
  38. package/cli/codegen/types.d.ts +1 -1
  39. package/cli/codegen/types.js +76 -21
  40. package/cli/commands/generate.js +1 -0
  41. package/cli/index.js +1 -0
  42. package/esm/cli/codegen/babel-ast.d.ts +46 -0
  43. package/esm/cli/codegen/babel-ast.js +97 -0
  44. package/esm/cli/codegen/barrel.d.ts +7 -2
  45. package/esm/cli/codegen/barrel.js +126 -97
  46. package/esm/cli/codegen/client.js +61 -0
  47. package/esm/cli/codegen/custom-mutations.d.ts +2 -12
  48. package/esm/cli/codegen/custom-mutations.js +83 -124
  49. package/esm/cli/codegen/custom-queries.d.ts +2 -10
  50. package/esm/cli/codegen/custom-queries.js +214 -336
  51. package/esm/cli/codegen/index.d.ts +3 -0
  52. package/esm/cli/codegen/index.js +68 -2
  53. package/esm/cli/codegen/invalidation.d.ts +20 -0
  54. package/esm/cli/codegen/invalidation.js +291 -0
  55. package/esm/cli/codegen/mutation-keys.d.ts +24 -0
  56. package/esm/cli/codegen/mutation-keys.js +211 -0
  57. package/esm/cli/codegen/mutations.d.ts +3 -19
  58. package/esm/cli/codegen/mutations.js +340 -384
  59. package/esm/cli/codegen/orm/barrel.d.ts +1 -1
  60. package/esm/cli/codegen/orm/barrel.js +10 -11
  61. package/esm/cli/codegen/orm/client-generator.d.ts +1 -19
  62. package/esm/cli/codegen/orm/client-generator.js +76 -78
  63. package/esm/cli/codegen/orm/custom-ops-generator.d.ts +1 -12
  64. package/esm/cli/codegen/orm/custom-ops-generator.js +160 -236
  65. package/esm/cli/codegen/orm/input-types-generator.d.ts +13 -1
  66. package/esm/cli/codegen/orm/input-types-generator.js +371 -148
  67. package/esm/cli/codegen/orm/model-generator.d.ts +1 -19
  68. package/esm/cli/codegen/orm/model-generator.js +197 -235
  69. package/esm/cli/codegen/queries.d.ts +3 -11
  70. package/esm/cli/codegen/queries.js +550 -390
  71. package/esm/cli/codegen/query-keys.d.ts +15 -0
  72. package/esm/cli/codegen/query-keys.js +441 -0
  73. package/esm/cli/codegen/scalars.js +1 -0
  74. package/esm/cli/codegen/schema-types-generator.d.ts +15 -10
  75. package/esm/cli/codegen/schema-types-generator.js +54 -175
  76. package/esm/cli/codegen/type-resolver.d.ts +1 -30
  77. package/esm/cli/codegen/type-resolver.js +0 -49
  78. package/esm/cli/codegen/types.d.ts +1 -1
  79. package/esm/cli/codegen/types.js +44 -22
  80. package/esm/cli/commands/generate.js +1 -0
  81. package/esm/cli/index.js +1 -0
  82. package/esm/types/config.d.ts +75 -0
  83. package/esm/types/config.js +19 -1
  84. package/package.json +6 -4
  85. package/types/config.d.ts +75 -0
  86. package/types/config.js +20 -2
  87. package/cli/codegen/ts-ast.d.ts +0 -124
  88. package/cli/codegen/ts-ast.js +0 -280
  89. package/esm/cli/codegen/ts-ast.d.ts +0 -124
  90. package/esm/cli/codegen/ts-ast.js +0 -260
@@ -1,17 +1,55 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.generateCustomMutationHook = generateCustomMutationHook;
4
37
  exports.generateAllCustomMutationHooks = generateAllCustomMutationHooks;
5
- const ts_ast_1 = require("./ts-ast");
38
+ const t = __importStar(require("@babel/types"));
39
+ const babel_ast_1 = require("./babel-ast");
6
40
  const schema_gql_ast_1 = require("./schema-gql-ast");
7
41
  const type_resolver_1 = require("./type-resolver");
8
- /**
9
- * Generate a custom mutation hook file
10
- * When reactQueryEnabled is false, returns null since mutations require React Query
11
- */
42
+ const utils_1 = require("./utils");
43
+ function generateVariablesProperties(args, tracker) {
44
+ return args.map((arg) => ({
45
+ name: arg.name,
46
+ type: (0, type_resolver_1.typeRefToTsType)(arg.type, tracker),
47
+ optional: !(0, type_resolver_1.isTypeRequired)(arg.type),
48
+ docs: arg.description ? [arg.description] : undefined,
49
+ }));
50
+ }
12
51
  function generateCustomMutationHook(options) {
13
52
  const { operation, reactQueryEnabled = true } = options;
14
- // Mutations require React Query - skip generation when disabled
15
53
  if (!reactQueryEnabled) {
16
54
  return null;
17
55
  }
@@ -25,150 +63,103 @@ function generateCustomMutationHook(options) {
25
63
  }
26
64
  }
27
65
  function generateCustomMutationHookInternal(options) {
28
- const { operation, typeRegistry, maxDepth = 2, skipQueryField = true, tableTypeNames } = options;
29
- const project = (0, ts_ast_1.createProject)();
66
+ const { operation, typeRegistry, maxDepth = 2, skipQueryField = true, tableTypeNames, useCentralizedKeys = true, } = options;
30
67
  const hookName = (0, type_resolver_1.getOperationHookName)(operation.name, 'mutation');
31
68
  const fileName = (0, type_resolver_1.getOperationFileName)(operation.name, 'mutation');
32
69
  const variablesTypeName = (0, type_resolver_1.getOperationVariablesTypeName)(operation.name, 'mutation');
33
70
  const resultTypeName = (0, type_resolver_1.getOperationResultTypeName)(operation.name, 'mutation');
34
71
  const documentConstName = (0, type_resolver_1.getDocumentConstName)(operation.name, 'mutation');
35
- // Create type tracker to collect referenced types (with table type awareness)
36
72
  const tracker = (0, type_resolver_1.createTypeTracker)({ tableTypeNames });
37
- // Generate GraphQL document
38
73
  const mutationDocument = (0, schema_gql_ast_1.buildCustomMutationString)({
39
74
  operation,
40
75
  typeRegistry,
41
76
  maxDepth,
42
77
  skipQueryField,
43
78
  });
44
- const sourceFile = (0, ts_ast_1.createSourceFile)(project, fileName);
45
- // Add file header
46
- sourceFile.insertText(0, (0, ts_ast_1.createFileHeader)(`Custom mutation hook for ${operation.name}`) + '\n\n');
47
- // Generate variables interface if there are arguments (with tracking)
48
- let variablesProps = [];
49
- if (operation.args.length > 0) {
50
- variablesProps = generateVariablesProperties(operation.args, tracker);
51
- }
52
- // Generate result interface (with tracking)
79
+ const statements = [];
80
+ const variablesProps = operation.args.length > 0
81
+ ? generateVariablesProperties(operation.args, tracker)
82
+ : [];
53
83
  const resultType = (0, type_resolver_1.typeRefToTsType)(operation.returnType, tracker);
54
- const resultProps = [
55
- { name: operation.name, type: resultType },
56
- ];
57
- // Get importable types from tracker (separated by source)
58
- const schemaTypes = tracker.getImportableTypes(); // From schema-types.ts
59
- const tableTypes = tracker.getTableTypes(); // From types.ts
60
- // Add imports
61
- const imports = [
62
- (0, ts_ast_1.createImport)({
63
- moduleSpecifier: '@tanstack/react-query',
64
- namedImports: ['useMutation'],
65
- typeOnlyNamedImports: ['UseMutationOptions'],
66
- }),
67
- (0, ts_ast_1.createImport)({
68
- moduleSpecifier: '../client',
69
- namedImports: ['execute'],
70
- }),
71
- ];
72
- // Add types.ts import for table entity types
84
+ const schemaTypes = tracker.getImportableTypes();
85
+ const tableTypes = tracker.getTableTypes();
86
+ const reactQueryImport = t.importDeclaration([t.importSpecifier(t.identifier('useMutation'), t.identifier('useMutation'))], t.stringLiteral('@tanstack/react-query'));
87
+ statements.push(reactQueryImport);
88
+ const reactQueryTypeImport = t.importDeclaration([t.importSpecifier(t.identifier('UseMutationOptions'), t.identifier('UseMutationOptions'))], t.stringLiteral('@tanstack/react-query'));
89
+ reactQueryTypeImport.importKind = 'type';
90
+ statements.push(reactQueryTypeImport);
91
+ const clientImport = t.importDeclaration([t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], t.stringLiteral('../client'));
92
+ statements.push(clientImport);
73
93
  if (tableTypes.length > 0) {
74
- imports.push((0, ts_ast_1.createImport)({
75
- moduleSpecifier: '../types',
76
- typeOnlyNamedImports: tableTypes,
77
- }));
94
+ const typesImport = t.importDeclaration(tableTypes.map((tt) => t.importSpecifier(t.identifier(tt), t.identifier(tt))), t.stringLiteral('../types'));
95
+ typesImport.importKind = 'type';
96
+ statements.push(typesImport);
78
97
  }
79
- // Add schema-types import for Input/Payload/Enum types
80
98
  if (schemaTypes.length > 0) {
81
- imports.push((0, ts_ast_1.createImport)({
82
- moduleSpecifier: '../schema-types',
83
- typeOnlyNamedImports: schemaTypes,
84
- }));
99
+ const schemaTypesImport = t.importDeclaration(schemaTypes.map((st) => t.importSpecifier(t.identifier(st), t.identifier(st))), t.stringLiteral('../schema-types'));
100
+ schemaTypesImport.importKind = 'type';
101
+ statements.push(schemaTypesImport);
85
102
  }
86
- sourceFile.addImportDeclarations(imports);
87
- // Add mutation document constant
88
- sourceFile.addVariableStatement((0, ts_ast_1.createConst)(documentConstName, '`\n' + mutationDocument + '`', {
89
- docs: ['GraphQL mutation document'],
90
- }));
91
- // Add variables interface
103
+ if (useCentralizedKeys) {
104
+ const mutationKeyImport = t.importDeclaration([t.importSpecifier(t.identifier('customMutationKeys'), t.identifier('customMutationKeys'))], t.stringLiteral('../mutation-keys'));
105
+ statements.push(mutationKeyImport);
106
+ }
107
+ const mutationDocConst = t.variableDeclaration('const', [
108
+ t.variableDeclarator(t.identifier(documentConstName), t.templateLiteral([t.templateElement({ raw: '\n' + mutationDocument, cooked: '\n' + mutationDocument }, true)], [])),
109
+ ]);
110
+ const mutationDocExport = t.exportNamedDeclaration(mutationDocConst);
111
+ (0, babel_ast_1.addJSDocComment)(mutationDocExport, ['GraphQL mutation document']);
112
+ statements.push(mutationDocExport);
92
113
  if (operation.args.length > 0) {
93
- sourceFile.addInterface((0, ts_ast_1.createInterface)(variablesTypeName, variablesProps));
114
+ const variablesInterfaceProps = variablesProps.map((vp) => {
115
+ const prop = t.tsPropertySignature(t.identifier(vp.name), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(vp.type))));
116
+ prop.optional = vp.optional;
117
+ return prop;
118
+ });
119
+ const variablesInterface = t.tsInterfaceDeclaration(t.identifier(variablesTypeName), null, null, t.tsInterfaceBody(variablesInterfaceProps));
120
+ statements.push(t.exportNamedDeclaration(variablesInterface));
94
121
  }
95
- // Add result interface
96
- sourceFile.addInterface((0, ts_ast_1.createInterface)(resultTypeName, resultProps));
97
- // Generate hook function
98
- const hookParams = generateHookParameters(operation, variablesTypeName, resultTypeName);
99
- const hookBody = generateHookBody(operation, documentConstName, variablesTypeName, resultTypeName);
100
- // Note: docs can cause ts-morph issues with certain content, so we skip them
101
- sourceFile.addFunction({
102
- name: hookName,
103
- isExported: true,
104
- parameters: hookParams,
105
- statements: hookBody,
106
- });
107
- return {
108
- fileName,
109
- content: (0, ts_ast_1.getFormattedOutput)(sourceFile),
110
- operationName: operation.name,
111
- };
112
- }
113
- // ============================================================================
114
- // Helper functions
115
- // ============================================================================
116
- /**
117
- * Generate interface properties from CleanArguments
118
- */
119
- function generateVariablesProperties(args, tracker) {
120
- return args.map((arg) => ({
121
- name: arg.name,
122
- type: (0, type_resolver_1.typeRefToTsType)(arg.type, tracker),
123
- optional: !(0, type_resolver_1.isTypeRequired)(arg.type),
124
- docs: arg.description ? [arg.description] : undefined,
125
- }));
126
- }
127
- /**
128
- * Generate hook function parameters
129
- */
130
- function generateHookParameters(operation, variablesTypeName, resultTypeName) {
131
- const hasArgs = operation.args.length > 0;
132
- // Mutation hooks use UseMutationOptions with variables as the second type param
133
- const optionsType = hasArgs
134
- ? `Omit<UseMutationOptions<${resultTypeName}, Error, ${variablesTypeName}>, 'mutationFn'>`
135
- : `Omit<UseMutationOptions<${resultTypeName}, Error, void>, 'mutationFn'>`;
136
- return [
137
- {
138
- name: 'options',
139
- type: optionsType,
140
- hasQuestionToken: true,
141
- },
142
- ];
143
- }
144
- /**
145
- * Generate hook function body
146
- */
147
- function generateHookBody(operation, documentConstName, variablesTypeName, resultTypeName) {
122
+ const resultInterfaceBody = t.tsInterfaceBody([
123
+ t.tsPropertySignature(t.identifier(operation.name), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(resultType)))),
124
+ ]);
125
+ const resultInterface = t.tsInterfaceDeclaration(t.identifier(resultTypeName), null, null, resultInterfaceBody);
126
+ statements.push(t.exportNamedDeclaration(resultInterface));
148
127
  const hasArgs = operation.args.length > 0;
128
+ const hookBodyStatements = [];
129
+ const mutationOptions = [];
130
+ if (useCentralizedKeys) {
131
+ mutationOptions.push(t.objectProperty(t.identifier('mutationKey'), t.callExpression(t.memberExpression(t.identifier('customMutationKeys'), t.identifier(operation.name)), [])));
132
+ }
149
133
  if (hasArgs) {
150
- return `return useMutation({
151
- mutationFn: (variables: ${variablesTypeName}) =>
152
- execute<${resultTypeName}, ${variablesTypeName}>(
153
- ${documentConstName},
154
- variables
155
- ),
156
- ...options,
157
- });`;
134
+ mutationOptions.push(t.objectProperty(t.identifier('mutationFn'), t.arrowFunctionExpression([(0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(variablesTypeName)))], t.callExpression(t.identifier('execute'), [
135
+ t.identifier(documentConstName),
136
+ t.identifier('variables'),
137
+ ]))));
158
138
  }
159
139
  else {
160
- return `return useMutation({
161
- mutationFn: () => execute<${resultTypeName}>(${documentConstName}),
162
- ...options,
163
- });`;
140
+ mutationOptions.push(t.objectProperty(t.identifier('mutationFn'), t.arrowFunctionExpression([], t.callExpression(t.identifier('execute'), [t.identifier(documentConstName)]))));
164
141
  }
142
+ mutationOptions.push(t.spreadElement(t.identifier('options')));
143
+ hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useMutation'), [t.objectExpression(mutationOptions)])));
144
+ const optionsType = hasArgs
145
+ ? `Omit<UseMutationOptions<${resultTypeName}, Error, ${variablesTypeName}>, 'mutationFn'>`
146
+ : `Omit<UseMutationOptions<${resultTypeName}, Error, void>, 'mutationFn'>`;
147
+ const optionsParam = t.identifier('options');
148
+ optionsParam.optional = true;
149
+ optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier(optionsType)));
150
+ const hookFunc = t.functionDeclaration(t.identifier(hookName), [optionsParam], t.blockStatement(hookBodyStatements));
151
+ const hookExport = t.exportNamedDeclaration(hookFunc);
152
+ statements.push(hookExport);
153
+ const code = (0, babel_ast_1.generateCode)(statements);
154
+ const content = (0, utils_1.getGeneratedFileHeader)(`Custom mutation hook for ${operation.name}`) + '\n\n' + code;
155
+ return {
156
+ fileName,
157
+ content,
158
+ operationName: operation.name,
159
+ };
165
160
  }
166
- /**
167
- * Generate all custom mutation hook files
168
- * When reactQueryEnabled is false, returns empty array since mutations require React Query
169
- */
170
161
  function generateAllCustomMutationHooks(options) {
171
- const { operations, typeRegistry, maxDepth = 2, skipQueryField = true, reactQueryEnabled = true, tableTypeNames } = options;
162
+ const { operations, typeRegistry, maxDepth = 2, skipQueryField = true, reactQueryEnabled = true, tableTypeNames, useCentralizedKeys = true, } = options;
172
163
  return operations
173
164
  .filter((op) => op.kind === 'mutation')
174
165
  .map((operation) => generateCustomMutationHook({
@@ -178,6 +169,7 @@ function generateAllCustomMutationHooks(options) {
178
169
  skipQueryField,
179
170
  reactQueryEnabled,
180
171
  tableTypeNames,
172
+ useCentralizedKeys,
181
173
  }))
182
174
  .filter((result) => result !== null);
183
175
  }
@@ -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[];