@nmarks/graphql-codegen-per-operation-file-preset 1.0.0 → 1.0.2

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 (3) hide show
  1. package/cjs/index.js +111 -6
  2. package/esm/index.js +113 -8
  3. package/package.json +1 -1
package/cjs/index.js CHANGED
@@ -23,9 +23,90 @@ function extractDefinitions(document) {
23
23
  }
24
24
  return definitions;
25
25
  }
26
+ /**
27
+ * Check if a document actually needs type imports from the schema.
28
+ * Only returns true if the document uses:
29
+ * - Enums
30
+ * - Custom scalars (not built-in)
31
+ * - Input types (in variables)
32
+ *
33
+ * Does NOT return true for just referencing object types.
34
+ */
35
+ function needsSchemaTypesImport(document, schema) {
36
+ const builtInScalars = ['String', 'Int', 'Float', 'Boolean', 'ID'];
37
+ let needsImport = false;
38
+ // Collect all type names referenced in the document
39
+ const referencedTypeNames = new Set();
40
+ (0, graphql_1.visit)(document, {
41
+ // Check variable types for input types or custom scalars
42
+ VariableDefinition: (node) => {
43
+ const typeName = getBaseTypeName(node.type);
44
+ referencedTypeNames.add(typeName);
45
+ },
46
+ // Collect fragment type conditions
47
+ FragmentDefinition: (node) => {
48
+ referencedTypeNames.add(node.typeCondition.name.value);
49
+ },
50
+ // We need to traverse into nested fields, so we'll collect all types
51
+ // This is a simplified approach - we'll check all types that might be used
52
+ });
53
+ // Helper to recursively check if a type needs importing
54
+ const checkType = (type) => {
55
+ if (!type)
56
+ return false;
57
+ // Unwrap lists and non-null
58
+ while ('ofType' in type && type.ofType) {
59
+ type = type.ofType;
60
+ }
61
+ // Enums need to be imported
62
+ if ((0, graphql_1.isEnumType)(type)) {
63
+ return true;
64
+ }
65
+ // Custom scalars (not built-in) need to be imported
66
+ if ((0, graphql_1.isScalarType)(type) && !builtInScalars.includes(type.name)) {
67
+ return true;
68
+ }
69
+ // Input types need to be imported
70
+ if ((0, graphql_1.isInputObjectType)(type)) {
71
+ return true;
72
+ }
73
+ return false;
74
+ };
75
+ // Check variable types
76
+ for (const typeName of referencedTypeNames) {
77
+ const type = schema.getType(typeName);
78
+ if (checkType(type)) {
79
+ return true;
80
+ }
81
+ }
82
+ // Now we need to check all fields in the document to see if any return enums/custom scalars
83
+ // We'll do a more thorough traversal with TypeInfo
84
+ const typeInfo = new graphql_1.TypeInfo(schema);
85
+ (0, graphql_1.visit)(document, (0, graphql_1.visitWithTypeInfo)(typeInfo, {
86
+ Field: () => {
87
+ const fieldType = typeInfo.getType();
88
+ if (checkType(fieldType)) {
89
+ needsImport = true;
90
+ }
91
+ },
92
+ }));
93
+ return needsImport;
94
+ }
95
+ /**
96
+ * Extract the base type name from a type node
97
+ */
98
+ function getBaseTypeName(type) {
99
+ if (type.kind === 'NamedType') {
100
+ return type.name.value;
101
+ }
102
+ if (type.kind === 'ListType' || type.kind === 'NonNullType') {
103
+ return getBaseTypeName(type.type);
104
+ }
105
+ return '';
106
+ }
26
107
  exports.preset = {
27
108
  buildGeneratesSection: options => {
28
- var _a;
109
+ var _a, _b;
29
110
  const schemaObject = options.schemaAst
30
111
  ? options.schemaAst
31
112
  : (0, graphql_1.buildASTSchema)(options.schema, options.config);
@@ -75,12 +156,36 @@ exports.preset = {
75
156
  ...fragmentImport,
76
157
  outputPath: filename, // Update to actual output path
77
158
  }));
159
+ // Check if THIS specific operation uses types (not the whole source file)
160
+ const singleDefDocumentWithFragments = {
161
+ ...singleDefDocument,
162
+ definitions: [
163
+ ...singleDefDocument.definitions,
164
+ ...source.externalFragments.map(fragment => fragment.node),
165
+ ],
166
+ };
167
+ const needsTypesImport = needsSchemaTypesImport(singleDefDocumentWithFragments, schemaObject);
168
+ // Generate the types import statement if needed
169
+ const importStatements = [];
170
+ if (needsTypesImport && !options.config.globalNamespace) {
171
+ const schemaTypesImportStatement = (0, visitor_plugin_common_1.generateImportStatement)({
172
+ baseDir,
173
+ emitLegacyCommonJSImports: options.config.emitLegacyCommonJSImports,
174
+ importExtension: options.config.importExtension,
175
+ importSource: (0, visitor_plugin_common_1.resolveImportSource)({
176
+ path: shouldAbsolute ? (0, path_1.join)(options.baseOutputDir, baseTypesPath) : baseTypesPath,
177
+ namespace: importTypesNamespace,
178
+ }),
179
+ baseOutputDir: options.baseOutputDir,
180
+ outputPath: filename,
181
+ typesImport: (_b = options.config.useTypeImports) !== null && _b !== void 0 ? _b : false,
182
+ });
183
+ importStatements.push(schemaTypesImportStatement);
184
+ }
78
185
  const plugins = [
79
- ...(options.config.globalNamespace
80
- ? []
81
- : source.importStatements.map(importStatement => ({
82
- add: { content: importStatement },
83
- }))),
186
+ ...importStatements.map(importStatement => ({
187
+ add: { content: importStatement },
188
+ })),
84
189
  ...options.plugins,
85
190
  ];
86
191
  const config = {
package/esm/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { join } from 'path';
2
- import { buildASTSchema, Kind } from 'graphql';
2
+ import { buildASTSchema, isEnumType, isInputObjectType, isScalarType, Kind, TypeInfo, visit, visitWithTypeInfo } from 'graphql';
3
3
  import addPlugin from '@graphql-codegen/add';
4
- import { getConfigValue, } from '@graphql-codegen/visitor-plugin-common';
4
+ import { generateImportStatement, getConfigValue, resolveImportSource, } from '@graphql-codegen/visitor-plugin-common';
5
5
  import { resolveDocumentImports } from './resolve-document-imports.js';
6
6
  import { generateOperationFilePath } from './utils.js';
7
7
  /**
@@ -19,9 +19,90 @@ function extractDefinitions(document) {
19
19
  }
20
20
  return definitions;
21
21
  }
22
+ /**
23
+ * Check if a document actually needs type imports from the schema.
24
+ * Only returns true if the document uses:
25
+ * - Enums
26
+ * - Custom scalars (not built-in)
27
+ * - Input types (in variables)
28
+ *
29
+ * Does NOT return true for just referencing object types.
30
+ */
31
+ function needsSchemaTypesImport(document, schema) {
32
+ const builtInScalars = ['String', 'Int', 'Float', 'Boolean', 'ID'];
33
+ let needsImport = false;
34
+ // Collect all type names referenced in the document
35
+ const referencedTypeNames = new Set();
36
+ visit(document, {
37
+ // Check variable types for input types or custom scalars
38
+ VariableDefinition: (node) => {
39
+ const typeName = getBaseTypeName(node.type);
40
+ referencedTypeNames.add(typeName);
41
+ },
42
+ // Collect fragment type conditions
43
+ FragmentDefinition: (node) => {
44
+ referencedTypeNames.add(node.typeCondition.name.value);
45
+ },
46
+ // We need to traverse into nested fields, so we'll collect all types
47
+ // This is a simplified approach - we'll check all types that might be used
48
+ });
49
+ // Helper to recursively check if a type needs importing
50
+ const checkType = (type) => {
51
+ if (!type)
52
+ return false;
53
+ // Unwrap lists and non-null
54
+ while ('ofType' in type && type.ofType) {
55
+ type = type.ofType;
56
+ }
57
+ // Enums need to be imported
58
+ if (isEnumType(type)) {
59
+ return true;
60
+ }
61
+ // Custom scalars (not built-in) need to be imported
62
+ if (isScalarType(type) && !builtInScalars.includes(type.name)) {
63
+ return true;
64
+ }
65
+ // Input types need to be imported
66
+ if (isInputObjectType(type)) {
67
+ return true;
68
+ }
69
+ return false;
70
+ };
71
+ // Check variable types
72
+ for (const typeName of referencedTypeNames) {
73
+ const type = schema.getType(typeName);
74
+ if (checkType(type)) {
75
+ return true;
76
+ }
77
+ }
78
+ // Now we need to check all fields in the document to see if any return enums/custom scalars
79
+ // We'll do a more thorough traversal with TypeInfo
80
+ const typeInfo = new TypeInfo(schema);
81
+ visit(document, visitWithTypeInfo(typeInfo, {
82
+ Field: () => {
83
+ const fieldType = typeInfo.getType();
84
+ if (checkType(fieldType)) {
85
+ needsImport = true;
86
+ }
87
+ },
88
+ }));
89
+ return needsImport;
90
+ }
91
+ /**
92
+ * Extract the base type name from a type node
93
+ */
94
+ function getBaseTypeName(type) {
95
+ if (type.kind === 'NamedType') {
96
+ return type.name.value;
97
+ }
98
+ if (type.kind === 'ListType' || type.kind === 'NonNullType') {
99
+ return getBaseTypeName(type.type);
100
+ }
101
+ return '';
102
+ }
22
103
  export const preset = {
23
104
  buildGeneratesSection: options => {
24
- var _a;
105
+ var _a, _b;
25
106
  const schemaObject = options.schemaAst
26
107
  ? options.schemaAst
27
108
  : buildASTSchema(options.schema, options.config);
@@ -71,12 +152,36 @@ export const preset = {
71
152
  ...fragmentImport,
72
153
  outputPath: filename, // Update to actual output path
73
154
  }));
155
+ // Check if THIS specific operation uses types (not the whole source file)
156
+ const singleDefDocumentWithFragments = {
157
+ ...singleDefDocument,
158
+ definitions: [
159
+ ...singleDefDocument.definitions,
160
+ ...source.externalFragments.map(fragment => fragment.node),
161
+ ],
162
+ };
163
+ const needsTypesImport = needsSchemaTypesImport(singleDefDocumentWithFragments, schemaObject);
164
+ // Generate the types import statement if needed
165
+ const importStatements = [];
166
+ if (needsTypesImport && !options.config.globalNamespace) {
167
+ const schemaTypesImportStatement = generateImportStatement({
168
+ baseDir,
169
+ emitLegacyCommonJSImports: options.config.emitLegacyCommonJSImports,
170
+ importExtension: options.config.importExtension,
171
+ importSource: resolveImportSource({
172
+ path: shouldAbsolute ? join(options.baseOutputDir, baseTypesPath) : baseTypesPath,
173
+ namespace: importTypesNamespace,
174
+ }),
175
+ baseOutputDir: options.baseOutputDir,
176
+ outputPath: filename,
177
+ typesImport: (_b = options.config.useTypeImports) !== null && _b !== void 0 ? _b : false,
178
+ });
179
+ importStatements.push(schemaTypesImportStatement);
180
+ }
74
181
  const plugins = [
75
- ...(options.config.globalNamespace
76
- ? []
77
- : source.importStatements.map(importStatement => ({
78
- add: { content: importStatement },
79
- }))),
182
+ ...importStatements.map(importStatement => ({
183
+ add: { content: importStatement },
184
+ })),
80
185
  ...options.plugins,
81
186
  ];
82
187
  const config = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nmarks/graphql-codegen-per-operation-file-preset",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "GraphQL Code Generator preset for generating one file per operation/fragment",
5
5
  "peerDependencies": {
6
6
  "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"