@nmarks/graphql-codegen-per-operation-file-preset 1.0.1 → 1.0.3

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 +104 -2
  2. package/esm/index.js +105 -3
  3. package/package.json +1 -1
package/cjs/index.js CHANGED
@@ -5,7 +5,6 @@ const tslib_1 = require("tslib");
5
5
  const path_1 = require("path");
6
6
  const graphql_1 = require("graphql");
7
7
  const add_1 = tslib_1.__importDefault(require("@graphql-codegen/add"));
8
- const plugin_helpers_1 = require("@graphql-codegen/plugin-helpers");
9
8
  const visitor_plugin_common_1 = require("@graphql-codegen/visitor-plugin-common");
10
9
  const resolve_document_imports_js_1 = require("./resolve-document-imports.js");
11
10
  const utils_js_1 = require("./utils.js");
@@ -24,6 +23,109 @@ function extractDefinitions(document) {
24
23
  }
25
24
  return definitions;
26
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 that aren't mapped to primitives
31
+ * - Input types (in variables)
32
+ *
33
+ * Does NOT return true for just referencing object types.
34
+ */
35
+ function needsSchemaTypesImport(document, schema, config) {
36
+ const builtInScalars = ['String', 'Int', 'Float', 'Boolean', 'ID'];
37
+ const primitiveTypes = ['any', 'string', 'number', 'boolean', 'null', 'undefined', 'void', 'never', 'unknown'];
38
+ let needsImport = false;
39
+ // Get scalar mappings from config
40
+ const scalarMappings = config.scalars || {};
41
+ // Collect all type names referenced in the document
42
+ const referencedTypeNames = new Set();
43
+ (0, graphql_1.visit)(document, {
44
+ // Check variable types for input types or custom scalars
45
+ VariableDefinition: (node) => {
46
+ const typeName = getBaseTypeName(node.type);
47
+ referencedTypeNames.add(typeName);
48
+ },
49
+ // Collect fragment type conditions
50
+ FragmentDefinition: (node) => {
51
+ referencedTypeNames.add(node.typeCondition.name.value);
52
+ },
53
+ });
54
+ // Helper to recursively check if a type needs importing
55
+ const checkType = (type) => {
56
+ if (!type)
57
+ return false;
58
+ // Unwrap lists and non-null
59
+ while ('ofType' in type && type.ofType) {
60
+ type = type.ofType;
61
+ }
62
+ // Enums always need to be imported
63
+ if ((0, graphql_1.isEnumType)(type)) {
64
+ return true;
65
+ }
66
+ // Custom scalars need to be imported UNLESS mapped to primitives
67
+ if ((0, graphql_1.isScalarType)(type) && !builtInScalars.includes(type.name)) {
68
+ // Check if this scalar is mapped to a primitive type
69
+ const mapping = scalarMappings[type.name];
70
+ if (mapping) {
71
+ // If mapped to a primitive type string, no import needed
72
+ if (typeof mapping === 'string' && primitiveTypes.includes(mapping)) {
73
+ return false;
74
+ }
75
+ // If mapped to an object like { input: 'any', output: 'any' }, check both
76
+ if (typeof mapping === 'object') {
77
+ const inputMapping = mapping.input || mapping.output;
78
+ const outputMapping = mapping.output || mapping.input;
79
+ if (primitiveTypes.includes(inputMapping) && primitiveTypes.includes(outputMapping)) {
80
+ return false;
81
+ }
82
+ }
83
+ }
84
+ else {
85
+ // No mapping specified, defaults to 'any', so no import needed
86
+ return false;
87
+ }
88
+ // Scalar is mapped to something non-primitive, needs import
89
+ return true;
90
+ }
91
+ // Input types need to be imported
92
+ if ((0, graphql_1.isInputObjectType)(type)) {
93
+ return true;
94
+ }
95
+ return false;
96
+ };
97
+ // Check variable types
98
+ for (const typeName of referencedTypeNames) {
99
+ const type = schema.getType(typeName);
100
+ if (checkType(type)) {
101
+ return true;
102
+ }
103
+ }
104
+ // Now we need to check all fields in the document to see if any return enums/custom scalars
105
+ // We'll do a more thorough traversal with TypeInfo
106
+ const typeInfo = new graphql_1.TypeInfo(schema);
107
+ (0, graphql_1.visit)(document, (0, graphql_1.visitWithTypeInfo)(typeInfo, {
108
+ Field: () => {
109
+ const fieldType = typeInfo.getType();
110
+ if (checkType(fieldType)) {
111
+ needsImport = true;
112
+ }
113
+ },
114
+ }));
115
+ return needsImport;
116
+ }
117
+ /**
118
+ * Extract the base type name from a type node
119
+ */
120
+ function getBaseTypeName(type) {
121
+ if (type.kind === 'NamedType') {
122
+ return type.name.value;
123
+ }
124
+ if (type.kind === 'ListType' || type.kind === 'NonNullType') {
125
+ return getBaseTypeName(type.type);
126
+ }
127
+ return '';
128
+ }
27
129
  exports.preset = {
28
130
  buildGeneratesSection: options => {
29
131
  var _a, _b;
@@ -84,7 +186,7 @@ exports.preset = {
84
186
  ...source.externalFragments.map(fragment => fragment.node),
85
187
  ],
86
188
  };
87
- const needsTypesImport = (0, plugin_helpers_1.isUsingTypes)(singleDefDocumentWithFragments, [], schemaObject);
189
+ const needsTypesImport = needsSchemaTypesImport(singleDefDocumentWithFragments, schemaObject, options.config);
88
190
  // Generate the types import statement if needed
89
191
  const importStatements = [];
90
192
  if (needsTypesImport && !options.config.globalNamespace) {
package/esm/index.js CHANGED
@@ -1,7 +1,6 @@
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 { isUsingTypes } from '@graphql-codegen/plugin-helpers';
5
4
  import { generateImportStatement, getConfigValue, resolveImportSource, } from '@graphql-codegen/visitor-plugin-common';
6
5
  import { resolveDocumentImports } from './resolve-document-imports.js';
7
6
  import { generateOperationFilePath } from './utils.js';
@@ -20,6 +19,109 @@ function extractDefinitions(document) {
20
19
  }
21
20
  return definitions;
22
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 that aren't mapped to primitives
27
+ * - Input types (in variables)
28
+ *
29
+ * Does NOT return true for just referencing object types.
30
+ */
31
+ function needsSchemaTypesImport(document, schema, config) {
32
+ const builtInScalars = ['String', 'Int', 'Float', 'Boolean', 'ID'];
33
+ const primitiveTypes = ['any', 'string', 'number', 'boolean', 'null', 'undefined', 'void', 'never', 'unknown'];
34
+ let needsImport = false;
35
+ // Get scalar mappings from config
36
+ const scalarMappings = config.scalars || {};
37
+ // Collect all type names referenced in the document
38
+ const referencedTypeNames = new Set();
39
+ visit(document, {
40
+ // Check variable types for input types or custom scalars
41
+ VariableDefinition: (node) => {
42
+ const typeName = getBaseTypeName(node.type);
43
+ referencedTypeNames.add(typeName);
44
+ },
45
+ // Collect fragment type conditions
46
+ FragmentDefinition: (node) => {
47
+ referencedTypeNames.add(node.typeCondition.name.value);
48
+ },
49
+ });
50
+ // Helper to recursively check if a type needs importing
51
+ const checkType = (type) => {
52
+ if (!type)
53
+ return false;
54
+ // Unwrap lists and non-null
55
+ while ('ofType' in type && type.ofType) {
56
+ type = type.ofType;
57
+ }
58
+ // Enums always need to be imported
59
+ if (isEnumType(type)) {
60
+ return true;
61
+ }
62
+ // Custom scalars need to be imported UNLESS mapped to primitives
63
+ if (isScalarType(type) && !builtInScalars.includes(type.name)) {
64
+ // Check if this scalar is mapped to a primitive type
65
+ const mapping = scalarMappings[type.name];
66
+ if (mapping) {
67
+ // If mapped to a primitive type string, no import needed
68
+ if (typeof mapping === 'string' && primitiveTypes.includes(mapping)) {
69
+ return false;
70
+ }
71
+ // If mapped to an object like { input: 'any', output: 'any' }, check both
72
+ if (typeof mapping === 'object') {
73
+ const inputMapping = mapping.input || mapping.output;
74
+ const outputMapping = mapping.output || mapping.input;
75
+ if (primitiveTypes.includes(inputMapping) && primitiveTypes.includes(outputMapping)) {
76
+ return false;
77
+ }
78
+ }
79
+ }
80
+ else {
81
+ // No mapping specified, defaults to 'any', so no import needed
82
+ return false;
83
+ }
84
+ // Scalar is mapped to something non-primitive, needs import
85
+ return true;
86
+ }
87
+ // Input types need to be imported
88
+ if (isInputObjectType(type)) {
89
+ return true;
90
+ }
91
+ return false;
92
+ };
93
+ // Check variable types
94
+ for (const typeName of referencedTypeNames) {
95
+ const type = schema.getType(typeName);
96
+ if (checkType(type)) {
97
+ return true;
98
+ }
99
+ }
100
+ // Now we need to check all fields in the document to see if any return enums/custom scalars
101
+ // We'll do a more thorough traversal with TypeInfo
102
+ const typeInfo = new TypeInfo(schema);
103
+ visit(document, visitWithTypeInfo(typeInfo, {
104
+ Field: () => {
105
+ const fieldType = typeInfo.getType();
106
+ if (checkType(fieldType)) {
107
+ needsImport = true;
108
+ }
109
+ },
110
+ }));
111
+ return needsImport;
112
+ }
113
+ /**
114
+ * Extract the base type name from a type node
115
+ */
116
+ function getBaseTypeName(type) {
117
+ if (type.kind === 'NamedType') {
118
+ return type.name.value;
119
+ }
120
+ if (type.kind === 'ListType' || type.kind === 'NonNullType') {
121
+ return getBaseTypeName(type.type);
122
+ }
123
+ return '';
124
+ }
23
125
  export const preset = {
24
126
  buildGeneratesSection: options => {
25
127
  var _a, _b;
@@ -80,7 +182,7 @@ export const preset = {
80
182
  ...source.externalFragments.map(fragment => fragment.node),
81
183
  ],
82
184
  };
83
- const needsTypesImport = isUsingTypes(singleDefDocumentWithFragments, [], schemaObject);
185
+ const needsTypesImport = needsSchemaTypesImport(singleDefDocumentWithFragments, schemaObject, options.config);
84
186
  // Generate the types import statement if needed
85
187
  const importStatements = [];
86
188
  if (needsTypesImport && !options.config.globalNamespace) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nmarks/graphql-codegen-per-operation-file-preset",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
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"