@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.
- package/cjs/index.js +111 -6
- package/esm/index.js +113 -8
- 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
|
-
...(
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
...(
|
|
76
|
-
|
|
77
|
-
|
|
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.
|
|
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"
|