@depup/graphql-codegen__typescript-operations 5.0.9-depup.0 → 6.1.1-depup.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/LICENSE +21 -0
- package/README.md +5 -6
- package/changes.json +4 -8
- package/cjs/index.js +65 -28
- package/cjs/ts-operation-variables-to-object.js +47 -2
- package/cjs/ts-selection-set-processor.js +4 -10
- package/cjs/visitor.js +502 -31
- package/esm/index.js +48 -21
- package/esm/ts-operation-variables-to-object.js +47 -2
- package/esm/ts-selection-set-processor.js +4 -10
- package/esm/visitor.js +503 -32
- package/package.json +17 -19
- package/typings/config.d.cts +184 -89
- package/typings/config.d.ts +184 -89
- package/typings/index.d.cts +1 -2
- package/typings/index.d.ts +1 -2
- package/typings/ts-operation-variables-to-object.d.cts +16 -2
- package/typings/ts-operation-variables-to-object.d.ts +16 -2
- package/typings/ts-selection-set-processor.d.cts +1 -1
- package/typings/ts-selection-set-processor.d.ts +1 -1
- package/typings/visitor.d.cts +50 -5
- package/typings/visitor.d.ts +50 -5
package/esm/visitor.js
CHANGED
|
@@ -1,72 +1,543 @@
|
|
|
1
|
-
import { BaseDocumentsVisitor, generateFragmentImportStatement, getConfigValue, normalizeAvoidOptionals, PreResolveTypesProcessor, SelectionSetToObject, wrapTypeWithModifiers, } from '@graphql-codegen/visitor-plugin-common';
|
|
2
1
|
import autoBind from 'auto-bind';
|
|
3
|
-
import { isEnumType,
|
|
2
|
+
import { getNamedType, GraphQLEnumType, GraphQLInputObjectType, GraphQLScalarType, isEnumType, Kind, TypeInfo, visit, visitWithTypeInfo, } from 'graphql';
|
|
3
|
+
import { normalizeImportExtension } from '@graphql-codegen/plugin-helpers';
|
|
4
|
+
import { BaseDocumentsVisitor, buildTypeImport, convertSchemaEnumToDeclarationBlockString, DeclarationBlock, DEFAULT_INPUT_SCALARS, generateFragmentImportStatement, generateImportStatement, getConfigValue, getEnumsImports, getNodeComment, indent, isNativeNamedType, isOneOfInputObjectType, parseEnumValues, PreResolveTypesProcessor, printTypeScriptMaybeType, SelectionSetToObject, wrapTypeWithModifiers, } from '@graphql-codegen/visitor-plugin-common';
|
|
4
5
|
import { TypeScriptOperationVariablesToObject } from './ts-operation-variables-to-object.js';
|
|
5
|
-
import { TypeScriptSelectionSetProcessor } from './ts-selection-set-processor.js';
|
|
6
6
|
export class TypeScriptDocumentsVisitor extends BaseDocumentsVisitor {
|
|
7
|
-
|
|
7
|
+
_usedSchemaTypes = {};
|
|
8
|
+
_needsExactUtilityType = false;
|
|
9
|
+
_outputPath;
|
|
10
|
+
constructor(schema, config, documentNode, outputPath) {
|
|
8
11
|
super(config, {
|
|
9
12
|
arrayInputCoercion: getConfigValue(config.arrayInputCoercion, true),
|
|
10
13
|
noExport: getConfigValue(config.noExport, false),
|
|
11
|
-
avoidOptionals: normalizeAvoidOptionals(getConfigValue(config.avoidOptionals, false)),
|
|
12
14
|
immutableTypes: getConfigValue(config.immutableTypes, false),
|
|
13
15
|
nonOptionalTypename: getConfigValue(config.nonOptionalTypename, false),
|
|
14
|
-
preResolveTypes: getConfigValue(config.preResolveTypes, true),
|
|
15
16
|
mergeFragmentTypes: getConfigValue(config.mergeFragmentTypes, false),
|
|
16
17
|
allowUndefinedQueryVariables: getConfigValue(config.allowUndefinedQueryVariables, false),
|
|
18
|
+
enumType: getConfigValue(config.enumType, 'string-literal'),
|
|
19
|
+
ignoreEnumValuesFromSchema: getConfigValue(config.ignoreEnumValuesFromSchema, false),
|
|
20
|
+
futureProofEnums: getConfigValue(config.futureProofEnums, false),
|
|
21
|
+
maybeValue: getConfigValue(config.maybeValue, 'T | null'),
|
|
22
|
+
inputMaybeValue: getConfigValue(config.inputMaybeValue, 'T | null | undefined'),
|
|
17
23
|
}, schema);
|
|
24
|
+
this.config.enumValues = parseEnumValues({
|
|
25
|
+
schema,
|
|
26
|
+
mapOrStr: config.enumValues,
|
|
27
|
+
ignoreEnumValuesFromSchema: config.ignoreEnumValuesFromSchema,
|
|
28
|
+
naming: {
|
|
29
|
+
convert: this.config.convert,
|
|
30
|
+
options: {
|
|
31
|
+
typesPrefix: this.config.typesPrefix,
|
|
32
|
+
typesSuffix: this.config.typesSuffix,
|
|
33
|
+
useTypesPrefix: this.config.enumPrefix,
|
|
34
|
+
useTypesSuffix: this.config.enumSuffix,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
this._outputPath = outputPath;
|
|
18
39
|
autoBind(this);
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return (this.config.immutableTypes ? `readonly ${name}` : name) + (optional ? '?' : '');
|
|
40
|
+
const allFragments = [
|
|
41
|
+
...documentNode.definitions.filter(d => d.kind === Kind.FRAGMENT_DEFINITION).map(fragmentDef => ({
|
|
42
|
+
node: fragmentDef,
|
|
43
|
+
name: fragmentDef.name.value,
|
|
44
|
+
onType: fragmentDef.typeCondition.name.value,
|
|
45
|
+
isExternal: false,
|
|
46
|
+
})),
|
|
47
|
+
...(config.externalFragments || []),
|
|
48
|
+
];
|
|
49
|
+
// Create a combined document that includes operations, internal and external fragments for enum collection
|
|
50
|
+
const documentWithAllFragments = {
|
|
51
|
+
...documentNode,
|
|
52
|
+
definitions: [
|
|
53
|
+
...documentNode.definitions.filter(d => d.kind !== Kind.FRAGMENT_DEFINITION),
|
|
54
|
+
...allFragments.map(f => f.node),
|
|
55
|
+
],
|
|
36
56
|
};
|
|
57
|
+
this._usedSchemaTypes = this.collectUsedSchemaTypesToGenerate({
|
|
58
|
+
schema,
|
|
59
|
+
documentNode: documentWithAllFragments,
|
|
60
|
+
});
|
|
37
61
|
const processorConfig = {
|
|
38
62
|
namespacedImportName: this.config.namespacedImportName,
|
|
39
63
|
convertName: this.convertName.bind(this),
|
|
40
64
|
enumPrefix: this.config.enumPrefix,
|
|
41
65
|
enumSuffix: this.config.enumSuffix,
|
|
42
66
|
scalars: this.scalars,
|
|
43
|
-
formatNamedField,
|
|
44
|
-
|
|
45
|
-
|
|
67
|
+
formatNamedField: ({ name, isOptional }) => {
|
|
68
|
+
return (this.config.immutableTypes ? `readonly ${name}` : name) + (isOptional ? '?' : '');
|
|
69
|
+
},
|
|
70
|
+
wrapTypeWithModifiers: (baseType, type) => {
|
|
71
|
+
return wrapTypeWithModifiers(baseType, type, {
|
|
72
|
+
wrapOptional: type => printTypeScriptMaybeType({
|
|
73
|
+
type,
|
|
74
|
+
pattern: this.config.maybeValue,
|
|
75
|
+
}),
|
|
76
|
+
wrapArray: type => {
|
|
77
|
+
const listModifier = this.config.immutableTypes ? 'ReadonlyArray' : 'Array';
|
|
78
|
+
return `${listModifier}<${type}>`;
|
|
79
|
+
},
|
|
80
|
+
});
|
|
46
81
|
},
|
|
47
|
-
avoidOptionals: this.config.avoidOptionals,
|
|
48
82
|
printFieldsOnNewLines: this.config.printFieldsOnNewLines,
|
|
49
83
|
};
|
|
50
|
-
|
|
51
|
-
this.setSelectionSetHandler(new SelectionSetToObject(processor, this.scalars, this.schema, this.convertName.bind(this), this.getFragmentSuffix.bind(this), allFragments, this.config));
|
|
84
|
+
this.setSelectionSetHandler(new SelectionSetToObject(new PreResolveTypesProcessor(processorConfig), this.scalars, this.schema, this.convertName.bind(this), this.getFragmentSuffix.bind(this), allFragments, this.config));
|
|
52
85
|
const enumsNames = Object.keys(schema.getTypeMap()).filter(typeName => isEnumType(schema.getType(typeName)));
|
|
53
|
-
this.setVariablesTransformer(new TypeScriptOperationVariablesToObject(
|
|
86
|
+
this.setVariablesTransformer(new TypeScriptOperationVariablesToObject({
|
|
87
|
+
avoidOptionals: this.config.avoidOptionals,
|
|
88
|
+
immutableTypes: this.config.immutableTypes,
|
|
89
|
+
inputMaybeValue: this.config.inputMaybeValue,
|
|
90
|
+
}, this.scalars, this.convertName.bind(this), this.config.namespacedImportName, enumsNames, this.config.enumPrefix, this.config.enumSuffix, this.config.enumValues, this.config.arrayInputCoercion));
|
|
54
91
|
this._declarationBlockConfig = {
|
|
55
92
|
ignoreExport: this.config.noExport,
|
|
93
|
+
enumNameValueSeparator: ' =',
|
|
56
94
|
};
|
|
57
95
|
}
|
|
96
|
+
EnumTypeDefinition(node) {
|
|
97
|
+
const enumName = node.name.value;
|
|
98
|
+
if (!this._usedSchemaTypes[enumName] || // If not used...
|
|
99
|
+
this.config.importSchemaTypesFrom // ... Or, is imported from a shared file
|
|
100
|
+
) {
|
|
101
|
+
return null; // ... then, don't generate in this file
|
|
102
|
+
}
|
|
103
|
+
return convertSchemaEnumToDeclarationBlockString({
|
|
104
|
+
schema: this._schema,
|
|
105
|
+
node,
|
|
106
|
+
declarationBlockConfig: this._declarationBlockConfig,
|
|
107
|
+
enumName,
|
|
108
|
+
enumValues: this.config.enumValues,
|
|
109
|
+
futureProofEnums: this.config.futureProofEnums,
|
|
110
|
+
ignoreEnumValuesFromSchema: this.config.ignoreEnumValuesFromSchema,
|
|
111
|
+
outputType: this.config.enumType,
|
|
112
|
+
naming: {
|
|
113
|
+
convert: this.config.convert,
|
|
114
|
+
options: {
|
|
115
|
+
typesPrefix: this.config.typesPrefix,
|
|
116
|
+
typesSuffix: this.config.typesSuffix,
|
|
117
|
+
useTypesPrefix: this.config.enumPrefix,
|
|
118
|
+
useTypesSuffix: this.config.enumSuffix,
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
InputObjectTypeDefinition(node) {
|
|
124
|
+
const inputTypeName = node.name.value;
|
|
125
|
+
if (!this._usedSchemaTypes[inputTypeName] || // If not used...
|
|
126
|
+
this.config.importSchemaTypesFrom // ... Or, is imported from a shared file
|
|
127
|
+
) {
|
|
128
|
+
return null; // ... then, don't generate in this file
|
|
129
|
+
}
|
|
130
|
+
// Note: we usually don't need to export this type,
|
|
131
|
+
// however, it's not possible to know if another file is using this type e.g. using `importSchemaTypesFrom`,
|
|
132
|
+
// so it's better export the types.
|
|
133
|
+
if (isOneOfInputObjectType(this._schema.getType(inputTypeName))) {
|
|
134
|
+
return new DeclarationBlock(this._declarationBlockConfig)
|
|
135
|
+
.export()
|
|
136
|
+
.asKind(this.config.declarationKind.input)
|
|
137
|
+
.withName(this.convertName(node))
|
|
138
|
+
.withComment(node.description?.value)
|
|
139
|
+
.withContent(`\n` + (node.fields || []).join('\n |')).string;
|
|
140
|
+
}
|
|
141
|
+
return new DeclarationBlock(this._declarationBlockConfig)
|
|
142
|
+
.export()
|
|
143
|
+
.asKind(this.config.declarationKind.input)
|
|
144
|
+
.withName(this.convertName(node))
|
|
145
|
+
.withComment(node.description?.value)
|
|
146
|
+
.withBlock((node.fields || []).join('\n')).string;
|
|
147
|
+
}
|
|
148
|
+
InputValueDefinition(node, _key, _parent, _path, ancestors) {
|
|
149
|
+
const oneOfDetails = parseOneOfInputValue({
|
|
150
|
+
node,
|
|
151
|
+
schema: this._schema,
|
|
152
|
+
ancestors,
|
|
153
|
+
});
|
|
154
|
+
// 1. Flatten GraphQL type nodes to make it easier to turn into string
|
|
155
|
+
// GraphQL type nodes may have `NonNullType` type before each `ListType` or `NamedType`
|
|
156
|
+
// This make it a bit harder to know whether a `ListType` or `Namedtype` is nullable without looking at the node before it.
|
|
157
|
+
// Flattening it into an array where the nullability is in `ListType` and `NamedType` makes it easier to code,
|
|
158
|
+
//
|
|
159
|
+
// So, we recursively call `collectAndFlattenTypeNodes` to handle the following scenarios:
|
|
160
|
+
// - [Thing]
|
|
161
|
+
// - [Thing!]
|
|
162
|
+
// - [Thing]!
|
|
163
|
+
// - [Thing!]!
|
|
164
|
+
const typeNodes = [];
|
|
165
|
+
collectAndFlattenTypeNodes({
|
|
166
|
+
currentTypeNode: node.type,
|
|
167
|
+
isPreviousNodeNonNullable: oneOfDetails.isOneOfInputValue, // If the InputValue is part of @oneOf input, we treat it as non-null (even if it must be null in the schema)
|
|
168
|
+
typeNodes,
|
|
169
|
+
});
|
|
170
|
+
// 2. Generate the type of a TypeScript field declaration
|
|
171
|
+
// e.g. `field?: string`, then the `string` is the `typePart`
|
|
172
|
+
let typePart = '';
|
|
173
|
+
// We call `.reverse()` here to get the base type node first
|
|
174
|
+
for (const typeNode of typeNodes.reverse()) {
|
|
175
|
+
if (typeNode.type === 'NamedType') {
|
|
176
|
+
const usedInputType = this._usedSchemaTypes[typeNode.name];
|
|
177
|
+
if (!usedInputType) {
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
typePart = usedInputType.tsType; // If the schema is correct, when reversing typeNodes, the first node would be `NamedType`, which means we can safely set it as the base for typePart
|
|
181
|
+
if (!typeNode.isNonNullable) {
|
|
182
|
+
typePart = printTypeScriptMaybeType({
|
|
183
|
+
type: typePart,
|
|
184
|
+
pattern: this.config.inputMaybeValue,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (typeNode.type === 'ListType') {
|
|
190
|
+
const listModifier = this.config.immutableTypes ? 'ReadonlyArray' : 'Array';
|
|
191
|
+
typePart = `${listModifier}<${typePart}>`;
|
|
192
|
+
if (!typeNode.isNonNullable) {
|
|
193
|
+
typePart = printTypeScriptMaybeType({
|
|
194
|
+
type: typePart,
|
|
195
|
+
pattern: this.config.inputMaybeValue,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const addOptionalSign = !oneOfDetails.isOneOfInputValue &&
|
|
201
|
+
!this.config.avoidOptionals.inputValue &&
|
|
202
|
+
(node.type.kind !== Kind.NON_NULL_TYPE ||
|
|
203
|
+
(!this.config.avoidOptionals.defaultValue && node.defaultValue !== undefined));
|
|
204
|
+
// 3. Generate the keyPart of the TypeScript field declaration
|
|
205
|
+
// e.g. `field?: string`, then the `field?` is the `keyPart`
|
|
206
|
+
const keyPart = `${node.name.value}${addOptionalSign ? '?' : ''}`;
|
|
207
|
+
// 4. other parts of TypeScript field declaration
|
|
208
|
+
const commentPart = getNodeComment(node);
|
|
209
|
+
const readonlyPart = this.config.immutableTypes ? 'readonly ' : '';
|
|
210
|
+
const currentInputValue = commentPart + indent(`${readonlyPart}${keyPart}: ${typePart};`);
|
|
211
|
+
// 5. Check if field is part of `@oneOf` input type
|
|
212
|
+
// If yes, we must generate a union member where the current inputValue must be provieded, and the others are not
|
|
213
|
+
// e.g.
|
|
214
|
+
// ```graphql
|
|
215
|
+
// input UserInput {
|
|
216
|
+
// byId: ID
|
|
217
|
+
// byEmail: String
|
|
218
|
+
// byLegacyId: ID
|
|
219
|
+
// }
|
|
220
|
+
// ```
|
|
221
|
+
//
|
|
222
|
+
// Then, the generated type is:
|
|
223
|
+
// ```ts
|
|
224
|
+
// type UserInput =
|
|
225
|
+
// | { byId: string | number; byEmail?: never; byLegacyId?: never }
|
|
226
|
+
// | { byId?: never; byEmail: string; byLegacyId?: never }
|
|
227
|
+
// | { byId?: never; byEmail?: never; byLegacyId: string | number }
|
|
228
|
+
// ```
|
|
229
|
+
if (oneOfDetails.isOneOfInputValue) {
|
|
230
|
+
const fieldParts = [];
|
|
231
|
+
for (const fieldName of Object.keys(oneOfDetails.parentType.getFields())) {
|
|
232
|
+
if (fieldName === node.name.value) {
|
|
233
|
+
fieldParts.push(currentInputValue);
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
fieldParts.push(`${readonlyPart}${fieldName}?: never;`);
|
|
237
|
+
}
|
|
238
|
+
return indent(`{ ${fieldParts.join(' ')} }`);
|
|
239
|
+
}
|
|
240
|
+
// If field is not part of @oneOf input type, then it's a input value, just return as-is
|
|
241
|
+
return currentInputValue;
|
|
242
|
+
}
|
|
58
243
|
getImports() {
|
|
59
244
|
return !this.config.globalNamespace &&
|
|
60
245
|
(this.config.inlineFragmentTypes === 'combine' || this.config.inlineFragmentTypes === 'mask')
|
|
61
246
|
? this.config.fragmentImports.map(fragmentImport => generateFragmentImportStatement(fragmentImport, 'type'))
|
|
62
247
|
: [];
|
|
63
248
|
}
|
|
249
|
+
getExternalSchemaTypeImports() {
|
|
250
|
+
if (!this.config.importSchemaTypesFrom) {
|
|
251
|
+
return [];
|
|
252
|
+
}
|
|
253
|
+
const hasTypesToImport = Object.values(this._usedSchemaTypes).filter(value => value.type === 'GraphQLEnumType' || value.type === 'GraphQLInputObjectType').length > 0;
|
|
254
|
+
if (!hasTypesToImport) {
|
|
255
|
+
return [];
|
|
256
|
+
}
|
|
257
|
+
return [
|
|
258
|
+
generateImportStatement({
|
|
259
|
+
baseDir: process.cwd(),
|
|
260
|
+
baseOutputDir: '',
|
|
261
|
+
outputPath: this._outputPath,
|
|
262
|
+
importSource: {
|
|
263
|
+
path: this.config.importSchemaTypesFrom,
|
|
264
|
+
namespace: this.config.namespacedImportName,
|
|
265
|
+
identifiers: [],
|
|
266
|
+
},
|
|
267
|
+
typesImport: true,
|
|
268
|
+
emitLegacyCommonJSImports: this.config.emitLegacyCommonJSImports,
|
|
269
|
+
importExtension: normalizeImportExtension({
|
|
270
|
+
emitLegacyCommonJSImports: this.config.emitLegacyCommonJSImports,
|
|
271
|
+
importExtension: this.config.importExtension,
|
|
272
|
+
}),
|
|
273
|
+
}),
|
|
274
|
+
];
|
|
275
|
+
}
|
|
276
|
+
getEnumsImports() {
|
|
277
|
+
const usedEnumMap = {};
|
|
278
|
+
for (const [enumName, enumDetails] of Object.entries(this.config.enumValues)) {
|
|
279
|
+
if (this._usedSchemaTypes[enumName]) {
|
|
280
|
+
usedEnumMap[enumName] = enumDetails;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return getEnumsImports({
|
|
284
|
+
enumValues: usedEnumMap,
|
|
285
|
+
useTypeImports: this.config.useTypeImports,
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
getScalarsImports() {
|
|
289
|
+
const fileType = this.config.importSchemaTypesFrom
|
|
290
|
+
? 'multi-file-operation-file'
|
|
291
|
+
: this.config.generateOperationTypes
|
|
292
|
+
? 'single-file-operation-file'
|
|
293
|
+
: 'multi-file-shared-type-file';
|
|
294
|
+
const imports = {};
|
|
295
|
+
for (const [scalarName, parsedScalar] of Object.entries(this.config.scalars)) {
|
|
296
|
+
const usedScalar = this._usedSchemaTypes[scalarName];
|
|
297
|
+
if (!usedScalar || usedScalar.type !== 'GraphQLScalarType') {
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
if (parsedScalar.input.isExternal &&
|
|
301
|
+
(((usedScalar.useCases.input || usedScalar.useCases.variables) &&
|
|
302
|
+
fileType === 'single-file-operation-file') ||
|
|
303
|
+
(usedScalar.useCases.input && fileType === 'multi-file-shared-type-file') ||
|
|
304
|
+
(usedScalar.useCases.variables && fileType === 'multi-file-operation-file'))) {
|
|
305
|
+
imports[parsedScalar.input.source] ||= { identifiers: {} };
|
|
306
|
+
imports[parsedScalar.input.source].identifiers[parsedScalar.input.import] = {
|
|
307
|
+
asDefault: parsedScalar.input.default,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
if (parsedScalar.output.isExternal &&
|
|
311
|
+
usedScalar.useCases.output &&
|
|
312
|
+
(fileType === 'single-file-operation-file' || fileType === 'multi-file-operation-file')) {
|
|
313
|
+
imports[parsedScalar.output.source] ||= { identifiers: {} };
|
|
314
|
+
imports[parsedScalar.output.source].identifiers[parsedScalar.output.import] = {
|
|
315
|
+
asDefault: parsedScalar.output.default,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return Object.entries(imports).reduce((res, [importSource, importParams]) => {
|
|
320
|
+
// One import statement cannot have multiple defaults.
|
|
321
|
+
// So:
|
|
322
|
+
// - split each defaults into its own statements
|
|
323
|
+
// - the named imports can all go together, tracked by `namedImports`
|
|
324
|
+
const namedImports = [];
|
|
325
|
+
for (const [identifier, identifierMetadata] of Object.entries(importParams.identifiers)) {
|
|
326
|
+
if (identifierMetadata.asDefault) {
|
|
327
|
+
res.push(buildTypeImport({
|
|
328
|
+
identifier,
|
|
329
|
+
source: importSource,
|
|
330
|
+
asDefault: true,
|
|
331
|
+
useTypeImports: this.config.useTypeImports,
|
|
332
|
+
}));
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
namedImports.push(identifier);
|
|
336
|
+
}
|
|
337
|
+
if (namedImports.length > 0) {
|
|
338
|
+
res.push(buildTypeImport({
|
|
339
|
+
identifier: namedImports.join(', '),
|
|
340
|
+
source: importSource,
|
|
341
|
+
asDefault: false,
|
|
342
|
+
useTypeImports: this.config.useTypeImports,
|
|
343
|
+
}));
|
|
344
|
+
}
|
|
345
|
+
return res;
|
|
346
|
+
}, []);
|
|
347
|
+
}
|
|
64
348
|
getPunctuation(_declarationKind) {
|
|
65
349
|
return ';';
|
|
66
350
|
}
|
|
67
351
|
applyVariablesWrapper(variablesBlock, operationType) {
|
|
68
|
-
const prefix = this.config.namespacedImportName ? `${this.config.namespacedImportName}.` : '';
|
|
69
352
|
const extraType = this.config.allowUndefinedQueryVariables && operationType === 'Query' ? ' | undefined' : '';
|
|
70
|
-
|
|
353
|
+
this._needsExactUtilityType = true;
|
|
354
|
+
return `Exact<${variablesBlock === '{}' ? `{ [key: string]: never; }` : variablesBlock}>${extraType}`;
|
|
355
|
+
}
|
|
356
|
+
collectInnerTypesRecursively({ node, usedSchemaTypes, location, }) {
|
|
357
|
+
if (node instanceof GraphQLEnumType) {
|
|
358
|
+
if (usedSchemaTypes[node.name]) {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
usedSchemaTypes[node.name] = {
|
|
362
|
+
type: 'GraphQLEnumType',
|
|
363
|
+
node,
|
|
364
|
+
tsType: this.convertName(node.name),
|
|
365
|
+
};
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
if (node instanceof GraphQLScalarType) {
|
|
369
|
+
const scalarType = usedSchemaTypes[node.name] || {
|
|
370
|
+
type: 'GraphQLScalarType',
|
|
371
|
+
node,
|
|
372
|
+
tsType: this.config.scalars?.[node.name]?.input.type ??
|
|
373
|
+
DEFAULT_INPUT_SCALARS[node.name]?.input ??
|
|
374
|
+
'unknown',
|
|
375
|
+
useCases: {
|
|
376
|
+
variables: location === 'variables',
|
|
377
|
+
input: location === 'input',
|
|
378
|
+
output: false,
|
|
379
|
+
},
|
|
380
|
+
};
|
|
381
|
+
if (scalarType.type !== 'GraphQLScalarType') {
|
|
382
|
+
throw new Error(`${node.name} has been incorrectly parsed as Scalar. This should not happen.`);
|
|
383
|
+
}
|
|
384
|
+
// ensure scalar's useCases is updated to have `useCases.input:true` or `useCases.variables:true`, depending on the use case
|
|
385
|
+
// this is required because if the scalar has been parsed previously, it may only have `useCases.output:true`, and not `useCases.input:true` or `useCases.variables:true`
|
|
386
|
+
if (location === 'input') {
|
|
387
|
+
scalarType.useCases.input = true;
|
|
388
|
+
}
|
|
389
|
+
if (location === 'variables') {
|
|
390
|
+
scalarType.useCases.variables = true;
|
|
391
|
+
}
|
|
392
|
+
usedSchemaTypes[node.name] = scalarType;
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
// GraphQLInputObjectType
|
|
396
|
+
if (usedSchemaTypes[node.name]) {
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
usedSchemaTypes[node.name] = {
|
|
400
|
+
type: 'GraphQLInputObjectType',
|
|
401
|
+
node,
|
|
402
|
+
tsType: this.convertName(node.name),
|
|
403
|
+
};
|
|
404
|
+
const fields = node.getFields();
|
|
405
|
+
for (const field of Object.values(fields)) {
|
|
406
|
+
const fieldType = getNamedType(field.type);
|
|
407
|
+
this.collectInnerTypesRecursively({
|
|
408
|
+
node: fieldType,
|
|
409
|
+
usedSchemaTypes,
|
|
410
|
+
location: 'input',
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* @description collects schema types used in operations:
|
|
416
|
+
* - used Enums for Variables
|
|
417
|
+
* - used Scalars for Variables
|
|
418
|
+
* - used Input for Variables (recursively)
|
|
419
|
+
*
|
|
420
|
+
* - used Enums for Result
|
|
421
|
+
* - used Scalars for Result
|
|
422
|
+
*/
|
|
423
|
+
collectUsedSchemaTypesToGenerate({ schema, documentNode, }) {
|
|
424
|
+
const schemaTypes = schema.getTypeMap();
|
|
425
|
+
const usedSchemaTypes = {};
|
|
426
|
+
// Collect input enums and input types
|
|
427
|
+
visit(documentNode, {
|
|
428
|
+
VariableDefinition: variableDefinitionNode => {
|
|
429
|
+
visit(variableDefinitionNode, {
|
|
430
|
+
NamedType: namedTypeNode => {
|
|
431
|
+
const foundInputType = schemaTypes[namedTypeNode.name.value];
|
|
432
|
+
if (foundInputType &&
|
|
433
|
+
(foundInputType instanceof GraphQLInputObjectType ||
|
|
434
|
+
foundInputType instanceof GraphQLScalarType ||
|
|
435
|
+
foundInputType instanceof GraphQLEnumType) &&
|
|
436
|
+
!isNativeNamedType(foundInputType)) {
|
|
437
|
+
this.collectInnerTypesRecursively({
|
|
438
|
+
node: foundInputType,
|
|
439
|
+
usedSchemaTypes,
|
|
440
|
+
location: 'variables',
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
},
|
|
444
|
+
});
|
|
445
|
+
},
|
|
446
|
+
});
|
|
447
|
+
// Collect output enums
|
|
448
|
+
const typeInfo = new TypeInfo(schema);
|
|
449
|
+
visit(documentNode,
|
|
450
|
+
// AST doesn’t include field types (they are defined in the schema) - only names.
|
|
451
|
+
// TypeInfo is a stateful helper that tracks typing context while walking the AST
|
|
452
|
+
// visitWithTypeInfo wires that context into a visitor.
|
|
453
|
+
visitWithTypeInfo(typeInfo, {
|
|
454
|
+
Field: () => {
|
|
455
|
+
const fieldType = typeInfo.getType();
|
|
456
|
+
if (fieldType) {
|
|
457
|
+
const namedType = getNamedType(fieldType);
|
|
458
|
+
if (namedType instanceof GraphQLEnumType) {
|
|
459
|
+
usedSchemaTypes[namedType.name] = {
|
|
460
|
+
type: 'GraphQLEnumType',
|
|
461
|
+
node: namedType,
|
|
462
|
+
tsType: this.convertName(namedType.name),
|
|
463
|
+
};
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
if (namedType instanceof GraphQLScalarType) {
|
|
467
|
+
const scalarType = usedSchemaTypes[namedType.name] || {
|
|
468
|
+
type: 'GraphQLScalarType',
|
|
469
|
+
node: namedType,
|
|
470
|
+
tsType: this.convertName(namedType.name),
|
|
471
|
+
useCases: { variables: false, input: false, output: true },
|
|
472
|
+
};
|
|
473
|
+
if (scalarType.type !== 'GraphQLScalarType') {
|
|
474
|
+
throw new Error(`${namedType.name} has been incorrectly parsed as Scalar. This should not happen.`);
|
|
475
|
+
}
|
|
476
|
+
// ensure scalar's useCases is updated to have `useCases.output:true`
|
|
477
|
+
// this is required because if the scalar has been parsed previously, it may only have `useCases.input:true` or `useCases.variables:true`, not `useCases.output:true`
|
|
478
|
+
scalarType.useCases.output = true;
|
|
479
|
+
usedSchemaTypes[namedType.name] = scalarType;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
},
|
|
483
|
+
}));
|
|
484
|
+
return usedSchemaTypes;
|
|
485
|
+
}
|
|
486
|
+
getExactUtilityType() {
|
|
487
|
+
if (!this.config.generateOperationTypes || // 1. If we don't generate operation types, definitely do not need `Exact`
|
|
488
|
+
!this._needsExactUtilityType // 2. Even if we generate operation types, we may not need `Exact` if there's no operations in the documents i.e. only fragments found
|
|
489
|
+
) {
|
|
490
|
+
return null;
|
|
491
|
+
}
|
|
492
|
+
return `${internalUtilityTypeWarning}type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };`;
|
|
493
|
+
}
|
|
494
|
+
getIncrementalUtilityType() {
|
|
495
|
+
if (!this.config.generateOperationTypes) {
|
|
496
|
+
return null;
|
|
497
|
+
}
|
|
498
|
+
// Note: `export` here is important for 2 reasons
|
|
499
|
+
// 1. It is not always used in the rest of the file, so this is a safe way to avoid lint rules (in tsconfig or eslint) complaining it's not used in the current file.
|
|
500
|
+
// 2. In Client Preset, it is used by fragment-masking.ts, so it needs `export`
|
|
501
|
+
return `${internalUtilityTypeWarning}export type Incremental<T> = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never };`;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
const internalUtilityTypeWarning = '/** Internal type. DO NOT USE DIRECTLY. */\n';
|
|
505
|
+
function parseOneOfInputValue({ node, schema, ancestors, }) {
|
|
506
|
+
const realParentDef = ancestors?.[ancestors.length - 1];
|
|
507
|
+
if (realParentDef) {
|
|
508
|
+
const parentType = schema.getType(realParentDef.name.value);
|
|
509
|
+
if (isOneOfInputObjectType(parentType)) {
|
|
510
|
+
if (node.type.kind === Kind.NON_NULL_TYPE) {
|
|
511
|
+
throw new Error('Fields on an input object type can not be non-nullable. It seems like the schema was not validated.');
|
|
512
|
+
}
|
|
513
|
+
return { isOneOfInputValue: true, realParentDef, parentType };
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
return { isOneOfInputValue: false };
|
|
517
|
+
}
|
|
518
|
+
function collectAndFlattenTypeNodes({ currentTypeNode, isPreviousNodeNonNullable, typeNodes, }) {
|
|
519
|
+
if (currentTypeNode.kind === Kind.NON_NULL_TYPE) {
|
|
520
|
+
const nextTypeNode = currentTypeNode.type;
|
|
521
|
+
collectAndFlattenTypeNodes({
|
|
522
|
+
currentTypeNode: nextTypeNode,
|
|
523
|
+
isPreviousNodeNonNullable: true,
|
|
524
|
+
typeNodes,
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
else if (currentTypeNode.kind === Kind.LIST_TYPE) {
|
|
528
|
+
typeNodes.push({ type: 'ListType', isNonNullable: isPreviousNodeNonNullable });
|
|
529
|
+
const nextTypeNode = currentTypeNode.type;
|
|
530
|
+
collectAndFlattenTypeNodes({
|
|
531
|
+
currentTypeNode: nextTypeNode,
|
|
532
|
+
isPreviousNodeNonNullable: false,
|
|
533
|
+
typeNodes,
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
else if (currentTypeNode.kind === Kind.NAMED_TYPE) {
|
|
537
|
+
typeNodes.push({
|
|
538
|
+
type: 'NamedType',
|
|
539
|
+
isNonNullable: isPreviousNodeNonNullable,
|
|
540
|
+
name: currentTypeNode.name.value,
|
|
541
|
+
});
|
|
71
542
|
}
|
|
72
543
|
}
|
package/package.json
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@depup/graphql-codegen__typescript-operations",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "6.1.1-depup.0",
|
|
4
|
+
"description": "GraphQL Code Generator plugin for generating TypeScript types for GraphQL queries, mutations, subscriptions and fragments (with updated dependencies)",
|
|
5
5
|
"peerDependenciesMeta": {
|
|
6
6
|
"graphql-sock": {
|
|
7
7
|
"optional": true
|
|
8
8
|
}
|
|
9
9
|
},
|
|
10
10
|
"peerDependencies": {
|
|
11
|
-
"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",
|
|
11
|
+
"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 || ^17.0.0",
|
|
12
12
|
"graphql-sock": "^1.0.0"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@graphql-codegen/plugin-helpers": "^6.2.0",
|
|
16
|
-
"@graphql-codegen/typescript": "^5.0.9",
|
|
17
|
-
"@graphql-codegen/visitor-plugin-common": "^6.2.4",
|
|
18
15
|
"auto-bind": "^5.0.1",
|
|
19
|
-
"tslib": "^2.8.1"
|
|
16
|
+
"tslib": "^2.8.1",
|
|
17
|
+
"@graphql-codegen/plugin-helpers": "^7.1.0",
|
|
18
|
+
"@graphql-codegen/visitor-plugin-common": "^7.2.1",
|
|
19
|
+
"@graphql-codegen/schema-ast": "^6.1.0"
|
|
20
20
|
},
|
|
21
21
|
"repository": {
|
|
22
22
|
"type": "git",
|
|
@@ -52,30 +52,28 @@
|
|
|
52
52
|
"./package.json": "./package.json"
|
|
53
53
|
},
|
|
54
54
|
"keywords": [
|
|
55
|
+
"@graphql-codegen/typescript-operations",
|
|
55
56
|
"depup",
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
57
|
+
"updated-dependencies",
|
|
58
|
+
"security",
|
|
59
|
+
"latest",
|
|
60
|
+
"patched"
|
|
59
61
|
],
|
|
60
62
|
"depup": {
|
|
61
63
|
"changes": {
|
|
62
|
-
"@graphql-codegen/plugin-helpers": {
|
|
63
|
-
"from": "^6.1.1",
|
|
64
|
-
"to": "^6.2.0"
|
|
65
|
-
},
|
|
66
64
|
"auto-bind": {
|
|
67
|
-
"from": "
|
|
65
|
+
"from": "^5.0.0",
|
|
68
66
|
"to": "^5.0.1"
|
|
69
67
|
},
|
|
70
68
|
"tslib": {
|
|
71
|
-
"from": "
|
|
69
|
+
"from": "^2.8.0",
|
|
72
70
|
"to": "^2.8.1"
|
|
73
71
|
}
|
|
74
72
|
},
|
|
75
|
-
"depsUpdated":
|
|
73
|
+
"depsUpdated": 2,
|
|
76
74
|
"originalPackage": "@graphql-codegen/typescript-operations",
|
|
77
|
-
"originalVersion": "
|
|
78
|
-
"processedAt": "2026-
|
|
75
|
+
"originalVersion": "6.1.1",
|
|
76
|
+
"processedAt": "2026-07-21T16:04:51.544Z",
|
|
79
77
|
"smokeTest": "passed"
|
|
80
78
|
}
|
|
81
79
|
}
|