@graphql-codegen/typescript-operations 6.0.0-alpha-20251125123407-8babe46fb9b33e9f9a377cd50c9580282e7981d3 → 6.0.0-alpha-20251224115216-0c4a535bdb152e75b9296d4c259f7dad0a13158f

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/esm/visitor.js CHANGED
@@ -1,10 +1,12 @@
1
- import { BaseDocumentsVisitor, generateFragmentImportStatement, getConfigValue, normalizeAvoidOptionals, PreResolveTypesProcessor, SelectionSetToObject, wrapTypeWithModifiers, } from '@graphql-codegen/visitor-plugin-common';
1
+ import { BaseDocumentsVisitor, convertSchemaEnumToDeclarationBlockString, DeclarationBlock, generateFragmentImportStatement, generateImportStatement, getConfigValue, indent, isOneOfInputObjectType, getEnumsImports, isNativeNamedType, normalizeAvoidOptionals, parseEnumValues, PreResolveTypesProcessor, SelectionSetToObject, getNodeComment, wrapTypeWithModifiers, } from '@graphql-codegen/visitor-plugin-common';
2
2
  import autoBind from 'auto-bind';
3
- import { isEnumType, isNonNullType } from 'graphql';
4
- import { TypeScriptOperationVariablesToObject } from './ts-operation-variables-to-object.js';
3
+ import { getNamedType, GraphQLEnumType, GraphQLInputObjectType, GraphQLScalarType, isEnumType, Kind, TypeInfo, visit, visitWithTypeInfo, } from 'graphql';
4
+ import { TypeScriptOperationVariablesToObject, SCALARS } from './ts-operation-variables-to-object.js';
5
5
  import { TypeScriptSelectionSetProcessor } from './ts-selection-set-processor.js';
6
6
  export class TypeScriptDocumentsVisitor extends BaseDocumentsVisitor {
7
- constructor(schema, config, allFragments) {
7
+ _usedNamedInputTypes = {};
8
+ _outputPath;
9
+ constructor(schema, config, documentNode, outputPath) {
8
10
  super(config, {
9
11
  arrayInputCoercion: getConfigValue(config.arrayInputCoercion, true),
10
12
  noExport: getConfigValue(config.noExport, false),
@@ -14,7 +16,15 @@ export class TypeScriptDocumentsVisitor extends BaseDocumentsVisitor {
14
16
  preResolveTypes: getConfigValue(config.preResolveTypes, true),
15
17
  mergeFragmentTypes: getConfigValue(config.mergeFragmentTypes, false),
16
18
  allowUndefinedQueryVariables: getConfigValue(config.allowUndefinedQueryVariables, false),
19
+ enumType: getConfigValue(config.enumType, 'string-literal'),
20
+ enumValues: parseEnumValues({
21
+ schema,
22
+ mapOrStr: config.enumValues,
23
+ ignoreEnumValuesFromSchema: config.ignoreEnumValuesFromSchema,
24
+ }),
25
+ futureProofEnums: getConfigValue(config.futureProofEnums, false),
17
26
  }, schema);
27
+ this._outputPath = outputPath;
18
28
  autoBind(this);
19
29
  const preResolveTypes = getConfigValue(config.preResolveTypes, true);
20
30
  const defaultMaybeValue = 'T | null';
@@ -30,43 +40,348 @@ export class TypeScriptDocumentsVisitor extends BaseDocumentsVisitor {
30
40
  const listModifier = this.config.immutableTypes ? 'ReadonlyArray' : 'Array';
31
41
  return `${listModifier}<${type}>`;
32
42
  };
33
- const formatNamedField = (name, type, isConditional = false, isOptional = false) => {
34
- const optional = isOptional || isConditional || (!this.config.avoidOptionals.field && !!type && !isNonNullType(type));
35
- return (this.config.immutableTypes ? `readonly ${name}` : name) + (optional ? '?' : '');
36
- };
43
+ const allFragments = [
44
+ ...documentNode.definitions.filter(d => d.kind === Kind.FRAGMENT_DEFINITION).map(fragmentDef => ({
45
+ node: fragmentDef,
46
+ name: fragmentDef.name.value,
47
+ onType: fragmentDef.typeCondition.name.value,
48
+ isExternal: false,
49
+ })),
50
+ ...(config.externalFragments || []),
51
+ ];
52
+ this._usedNamedInputTypes = this.collectUsedInputTypes({ schema, documentNode });
37
53
  const processorConfig = {
38
54
  namespacedImportName: this.config.namespacedImportName,
39
55
  convertName: this.convertName.bind(this),
40
56
  enumPrefix: this.config.enumPrefix,
41
57
  enumSuffix: this.config.enumSuffix,
42
58
  scalars: this.scalars,
43
- formatNamedField,
59
+ formatNamedField: ({ name, isOptional }) => {
60
+ return (this.config.immutableTypes ? `readonly ${name}` : name) + (isOptional ? '?' : '');
61
+ },
44
62
  wrapTypeWithModifiers(baseType, type) {
45
63
  return wrapTypeWithModifiers(baseType, type, { wrapOptional, wrapArray });
46
64
  },
47
- avoidOptionals: this.config.avoidOptionals,
48
65
  printFieldsOnNewLines: this.config.printFieldsOnNewLines,
49
66
  };
50
67
  const processor = new (preResolveTypes ? PreResolveTypesProcessor : TypeScriptSelectionSetProcessor)(processorConfig);
51
68
  this.setSelectionSetHandler(new SelectionSetToObject(processor, this.scalars, this.schema, this.convertName.bind(this), this.getFragmentSuffix.bind(this), allFragments, this.config));
52
69
  const enumsNames = Object.keys(schema.getTypeMap()).filter(typeName => isEnumType(schema.getType(typeName)));
53
- this.setVariablesTransformer(new TypeScriptOperationVariablesToObject(this.scalars, this.convertName.bind(this), this.config.avoidOptionals, this.config.immutableTypes, this.config.namespacedImportName, enumsNames, this.config.enumPrefix, this.config.enumSuffix, this.config.enumValues, this.config.arrayInputCoercion, undefined, 'InputMaybe'));
70
+ this.setVariablesTransformer(new TypeScriptOperationVariablesToObject(this.scalars, this.convertName.bind(this),
71
+ // FIXME: this is the legacy avoidOptionals which was used to make Result fields non-optional. This use case is no longer valid.
72
+ // It's also being used for Variables so people could already be using it.
73
+ // Maybe it's better to deprecate and remove, to see what users think.
74
+ this.config.avoidOptionals, this.config.immutableTypes, this.config.namespacedImportName, enumsNames, this.config.enumPrefix, this.config.enumSuffix, this.config.enumValues, this.config.arrayInputCoercion, undefined, undefined));
54
75
  this._declarationBlockConfig = {
55
76
  ignoreExport: this.config.noExport,
77
+ enumNameValueSeparator: ' =',
56
78
  };
57
79
  }
80
+ EnumTypeDefinition(node) {
81
+ const enumName = node.name.value;
82
+ if (!this._usedNamedInputTypes[enumName] || this.config.importSchemaTypesFrom) {
83
+ return null;
84
+ }
85
+ return convertSchemaEnumToDeclarationBlockString({
86
+ schema: this._schema,
87
+ node,
88
+ declarationBlockConfig: this._declarationBlockConfig,
89
+ enumName,
90
+ enumValues: this.config.enumValues,
91
+ futureProofEnums: this.config.futureProofEnums,
92
+ ignoreEnumValuesFromSchema: this.config.ignoreEnumValuesFromSchema,
93
+ outputType: this.config.enumType,
94
+ naming: {
95
+ convert: this.config.convert,
96
+ typesPrefix: this.config.typesPrefix,
97
+ typesSuffix: this.config.typesSuffix,
98
+ useTypesPrefix: this.config.enumPrefix,
99
+ useTypesSuffix: this.config.enumSuffix,
100
+ },
101
+ });
102
+ }
103
+ InputObjectTypeDefinition(node) {
104
+ const inputTypeName = node.name.value;
105
+ if (!this._usedNamedInputTypes[inputTypeName]) {
106
+ return null;
107
+ }
108
+ if (isOneOfInputObjectType(this._schema.getType(inputTypeName))) {
109
+ return new DeclarationBlock(this._declarationBlockConfig)
110
+ .asKind('type')
111
+ .withName(this.convertName(node))
112
+ .withComment(node.description?.value)
113
+ .withContent(`\n` + (node.fields || []).join('\n |')).string;
114
+ }
115
+ return new DeclarationBlock(this._declarationBlockConfig)
116
+ .asKind('type')
117
+ .withName(this.convertName(node))
118
+ .withComment(node.description?.value)
119
+ .withBlock((node.fields || []).join('\n')).string;
120
+ }
121
+ InputValueDefinition(node, _key, _parent, _path, ancestors) {
122
+ const oneOfDetails = parseOneOfInputValue({
123
+ node,
124
+ schema: this._schema,
125
+ ancestors,
126
+ });
127
+ // 1. Flatten GraphQL type nodes to make it easier to turn into string
128
+ // GraphQL type nodes may have `NonNullType` type before each `ListType` or `NamedType`
129
+ // This make it a bit harder to know whether a `ListType` or `Namedtype` is nullable without looking at the node before it.
130
+ // Flattening it into an array where the nullability is in `ListType` and `NamedType` makes it easier to code,
131
+ //
132
+ // So, we recursively call `collectAndFlattenTypeNodes` to handle the following scenarios:
133
+ // - [Thing]
134
+ // - [Thing!]
135
+ // - [Thing]!
136
+ // - [Thing!]!
137
+ const typeNodes = [];
138
+ collectAndFlattenTypeNodes({
139
+ currentTypeNode: node.type,
140
+ 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)
141
+ typeNodes,
142
+ });
143
+ // 2. Generate the type of a TypeScript field declaration
144
+ // e.g. `field?: string`, then the `string` is the `typePart`
145
+ let typePart = '';
146
+ // We call `.reverse()` here to get the base type node first
147
+ for (const typeNode of typeNodes.reverse()) {
148
+ if (typeNode.type === 'NamedType') {
149
+ const usedInputType = this._usedNamedInputTypes[typeNode.name];
150
+ if (!usedInputType) {
151
+ continue;
152
+ }
153
+ 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
154
+ if (usedInputType.tsType !== 'any' && !typeNode.isNonNullable) {
155
+ typePart += ' | null | undefined';
156
+ }
157
+ continue;
158
+ }
159
+ if (typeNode.type === 'ListType') {
160
+ typePart = `Array<${typePart}>`;
161
+ if (!typeNode.isNonNullable) {
162
+ typePart += ' | null | undefined';
163
+ }
164
+ }
165
+ }
166
+ // TODO: eddeee888 check if we want to support `directiveArgumentAndInputFieldMappings` for operations
167
+ // if (node.directives && this.config.directiveArgumentAndInputFieldMappings) {
168
+ // typePart =
169
+ // getDirectiveOverrideType({
170
+ // directives: node.directives,
171
+ // directiveArgumentAndInputFieldMappings: this.config.directiveArgumentAndInputFieldMappings,
172
+ // }) || typePart;
173
+ // }
174
+ const addOptionalSign = !oneOfDetails.isOneOfInputValue &&
175
+ !this.config.avoidOptionals.inputValue &&
176
+ (node.type.kind !== Kind.NON_NULL_TYPE ||
177
+ (!this.config.avoidOptionals.defaultValue && node.defaultValue !== undefined));
178
+ // 3. Generate the keyPart of the TypeScript field declaration
179
+ // e.g. `field?: string`, then the `field?` is the `keyPart`
180
+ const keyPart = `${node.name.value}${addOptionalSign ? '?' : ''}`;
181
+ // 4. other parts of TypeScript field declaration
182
+ const commentPart = getNodeComment(node);
183
+ const readonlyPart = this.config.immutableTypes ? 'readonly ' : '';
184
+ const currentInputValue = commentPart + indent(`${readonlyPart}${keyPart}: ${typePart};`);
185
+ // 5. Check if field is part of `@oneOf` input type
186
+ // If yes, we must generate a union member where the current inputValue must be provieded, and the others are not
187
+ // e.g.
188
+ // ```graphql
189
+ // input UserInput {
190
+ // byId: ID
191
+ // byEmail: String
192
+ // byLegacyId: ID
193
+ // }
194
+ // ```
195
+ //
196
+ // Then, the generated type is:
197
+ // ```ts
198
+ // type UserInput =
199
+ // | { byId: string | number; byEmail?: never; byLegacyId?: never }
200
+ // | { byId?: never; byEmail: string; byLegacyId?: never }
201
+ // | { byId?: never; byEmail?: never; byLegacyId: string | number }
202
+ // ```
203
+ if (oneOfDetails.isOneOfInputValue) {
204
+ const fieldParts = [];
205
+ for (const fieldName of Object.keys(oneOfDetails.parentType.getFields())) {
206
+ if (fieldName === node.name.value) {
207
+ fieldParts.push(currentInputValue);
208
+ continue;
209
+ }
210
+ fieldParts.push(`${readonlyPart}${fieldName}?: never;`);
211
+ }
212
+ return indent(`{ ${fieldParts.join(' ')} }`);
213
+ }
214
+ // If field is not part of @oneOf input type, then it's a input value, just return as-is
215
+ return currentInputValue;
216
+ }
58
217
  getImports() {
59
218
  return !this.config.globalNamespace &&
60
219
  (this.config.inlineFragmentTypes === 'combine' || this.config.inlineFragmentTypes === 'mask')
61
220
  ? this.config.fragmentImports.map(fragmentImport => generateFragmentImportStatement(fragmentImport, 'type'))
62
221
  : [];
63
222
  }
223
+ getExternalSchemaTypeImports() {
224
+ if (!this.config.importSchemaTypesFrom) {
225
+ return [];
226
+ }
227
+ const hasTypesToImport = Object.keys(this._usedNamedInputTypes).length > 0;
228
+ if (!hasTypesToImport) {
229
+ return [];
230
+ }
231
+ return [
232
+ generateImportStatement({
233
+ baseDir: process.cwd(),
234
+ baseOutputDir: '',
235
+ outputPath: this._outputPath,
236
+ importSource: {
237
+ path: this.config.importSchemaTypesFrom,
238
+ namespace: this.config.namespacedImportName,
239
+ identifiers: [],
240
+ },
241
+ typesImport: true,
242
+ // FIXME: rebase with master for the new extension
243
+ emitLegacyCommonJSImports: true,
244
+ }),
245
+ ];
246
+ }
64
247
  getPunctuation(_declarationKind) {
65
248
  return ';';
66
249
  }
67
250
  applyVariablesWrapper(variablesBlock, operationType) {
68
- const prefix = this.config.namespacedImportName ? `${this.config.namespacedImportName}.` : '';
69
251
  const extraType = this.config.allowUndefinedQueryVariables && operationType === 'Query' ? ' | undefined' : '';
70
- return `${prefix}Exact<${variablesBlock === '{}' ? `{ [key: string]: never; }` : variablesBlock}>${extraType}`;
252
+ return `Exact<${variablesBlock === '{}' ? `{ [key: string]: never; }` : variablesBlock}>${extraType}`;
253
+ }
254
+ collectInnerTypesRecursively(node, usedInputTypes) {
255
+ if (usedInputTypes[node.name]) {
256
+ return;
257
+ }
258
+ if (node instanceof GraphQLEnumType) {
259
+ usedInputTypes[node.name] = {
260
+ type: 'GraphQLEnumType',
261
+ node,
262
+ tsType: this.convertName(node.name),
263
+ };
264
+ return;
265
+ }
266
+ if (node instanceof GraphQLScalarType) {
267
+ usedInputTypes[node.name] = {
268
+ type: 'GraphQLScalarType',
269
+ node,
270
+ tsType: (SCALARS[node.name] || this.config.scalars?.[node.name]?.input.type) ?? 'any',
271
+ };
272
+ return;
273
+ }
274
+ // GraphQLInputObjectType
275
+ usedInputTypes[node.name] = {
276
+ type: 'GraphQLInputObjectType',
277
+ node,
278
+ tsType: this.convertName(node.name),
279
+ };
280
+ const fields = node.getFields();
281
+ for (const field of Object.values(fields)) {
282
+ const fieldType = getNamedType(field.type);
283
+ this.collectInnerTypesRecursively(fieldType, usedInputTypes);
284
+ }
285
+ }
286
+ collectUsedInputTypes({ schema, documentNode, }) {
287
+ const schemaTypes = schema.getTypeMap();
288
+ const usedInputTypes = {};
289
+ // Collect input enums and input types
290
+ visit(documentNode, {
291
+ VariableDefinition: variableDefinitionNode => {
292
+ visit(variableDefinitionNode, {
293
+ NamedType: namedTypeNode => {
294
+ const foundInputType = schemaTypes[namedTypeNode.name.value];
295
+ if (foundInputType &&
296
+ (foundInputType instanceof GraphQLInputObjectType ||
297
+ foundInputType instanceof GraphQLScalarType ||
298
+ foundInputType instanceof GraphQLEnumType) &&
299
+ !isNativeNamedType(foundInputType)) {
300
+ this.collectInnerTypesRecursively(foundInputType, usedInputTypes);
301
+ }
302
+ },
303
+ });
304
+ },
305
+ });
306
+ // Collect output enums
307
+ const typeInfo = new TypeInfo(schema);
308
+ visit(documentNode,
309
+ // AST doesn’t include field types (they are defined in schema) - only names.
310
+ // TypeInfo is a stateful helper that tracks typing context while walking the AST
311
+ // visitWithTypeInfo wires that context into a visitor.
312
+ visitWithTypeInfo(typeInfo, {
313
+ Field: () => {
314
+ const fieldType = typeInfo.getType();
315
+ if (fieldType) {
316
+ const namedType = getNamedType(fieldType);
317
+ if (namedType instanceof GraphQLEnumType) {
318
+ usedInputTypes[namedType.name] = {
319
+ type: 'GraphQLEnumType',
320
+ node: namedType,
321
+ tsType: this.convertName(namedType.name),
322
+ };
323
+ }
324
+ }
325
+ },
326
+ }));
327
+ return usedInputTypes;
328
+ }
329
+ getEnumsImports() {
330
+ const usedEnumMap = {};
331
+ for (const [enumName, enumDetails] of Object.entries(this.config.enumValues)) {
332
+ if (this._usedNamedInputTypes[enumName]) {
333
+ usedEnumMap[enumName] = enumDetails;
334
+ }
335
+ }
336
+ return getEnumsImports({
337
+ enumValues: usedEnumMap,
338
+ useTypeImports: this.config.useTypeImports,
339
+ });
340
+ }
341
+ getExactUtilityType() {
342
+ if (!this.config.generatesOperationTypes) {
343
+ return null;
344
+ }
345
+ return 'type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };';
346
+ }
347
+ getIncrementalUtilityType() {
348
+ if (!this.config.generatesOperationTypes) {
349
+ return null;
350
+ }
351
+ // Note: `export` here is important for 2 reasons
352
+ // 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.
353
+ // 2. In Client Preset, it is used by fragment-masking.ts, so it needs `export`
354
+ return "export type Incremental<T> = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never };";
355
+ }
356
+ }
357
+ function parseOneOfInputValue({ node, schema, ancestors, }) {
358
+ const realParentDef = ancestors?.[ancestors.length - 1];
359
+ if (realParentDef) {
360
+ const parentType = schema.getType(realParentDef.name.value);
361
+ if (isOneOfInputObjectType(parentType)) {
362
+ if (node.type.kind === Kind.NON_NULL_TYPE) {
363
+ throw new Error('Fields on an input object type can not be non-nullable. It seems like the schema was not validated.');
364
+ }
365
+ return { isOneOfInputValue: true, realParentDef, parentType };
366
+ }
367
+ }
368
+ return { isOneOfInputValue: false };
369
+ }
370
+ function collectAndFlattenTypeNodes({ currentTypeNode, isPreviousNodeNonNullable, typeNodes, }) {
371
+ if (currentTypeNode.kind === Kind.NON_NULL_TYPE) {
372
+ const nextTypeNode = currentTypeNode.type;
373
+ collectAndFlattenTypeNodes({ currentTypeNode: nextTypeNode, isPreviousNodeNonNullable: true, typeNodes });
374
+ }
375
+ else if (currentTypeNode.kind === Kind.LIST_TYPE) {
376
+ typeNodes.push({ type: 'ListType', isNonNullable: isPreviousNodeNonNullable });
377
+ const nextTypeNode = currentTypeNode.type;
378
+ collectAndFlattenTypeNodes({ currentTypeNode: nextTypeNode, isPreviousNodeNonNullable: false, typeNodes });
379
+ }
380
+ else if (currentTypeNode.kind === Kind.NAMED_TYPE) {
381
+ typeNodes.push({
382
+ type: 'NamedType',
383
+ isNonNullable: isPreviousNodeNonNullable,
384
+ name: currentTypeNode.name.value,
385
+ });
71
386
  }
72
387
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphql-codegen/typescript-operations",
3
- "version": "6.0.0-alpha-20251125123407-8babe46fb9b33e9f9a377cd50c9580282e7981d3",
3
+ "version": "6.0.0-alpha-20251224115216-0c4a535bdb152e75b9296d4c259f7dad0a13158f",
4
4
  "description": "GraphQL Code Generator plugin for generating TypeScript types for GraphQL queries, mutations, subscriptions and fragments",
5
5
  "peerDependenciesMeta": {
6
6
  "graphql-sock": {
@@ -13,8 +13,9 @@
13
13
  },
14
14
  "dependencies": {
15
15
  "@graphql-codegen/plugin-helpers": "^6.0.0",
16
- "@graphql-codegen/typescript": "6.0.0-alpha-20251125123407-8babe46fb9b33e9f9a377cd50c9580282e7981d3",
17
- "@graphql-codegen/visitor-plugin-common": "7.0.0-alpha-20251125123407-8babe46fb9b33e9f9a377cd50c9580282e7981d3",
16
+ "@graphql-codegen/typescript": "6.0.0-alpha-20251224115216-0c4a535bdb152e75b9296d4c259f7dad0a13158f",
17
+ "@graphql-codegen/schema-ast": "^5.0.0",
18
+ "@graphql-codegen/visitor-plugin-common": "7.0.0-alpha-20251224115216-0c4a535bdb152e75b9296d4c259f7dad0a13158f",
18
19
  "auto-bind": "~4.0.0",
19
20
  "tslib": "~2.6.0"
20
21
  },
@@ -1,4 +1,4 @@
1
- import { AvoidOptionalsConfig, RawDocumentsConfig } from '@graphql-codegen/visitor-plugin-common';
1
+ import { AvoidOptionalsConfig, type ConvertSchemaEnumToDeclarationBlockString, type EnumValuesMap, RawDocumentsConfig } from '@graphql-codegen/visitor-plugin-common';
2
2
  /**
3
3
  * @description This plugin generates TypeScript types based on your GraphQLSchema _and_ your GraphQL operations and fragments.
4
4
  * It generates types for your GraphQL documents: Query, Mutation, Subscription and Fragment.
@@ -330,4 +330,118 @@ export interface TypeScriptDocumentsPluginConfig extends RawDocumentsConfig {
330
330
  nullability?: {
331
331
  errorHandlingClient: boolean;
332
332
  };
333
+ /**
334
+ * @description Controls the enum output type. Options: `string-literal` | `native-numeric` | `const` | `native-const` | `native`;
335
+ * @default `string-literal`
336
+ *
337
+ * @exampleMarkdown
338
+ * ```ts filename="codegen.ts"
339
+ * import type { CodegenConfig } from '@graphql-codegen/cli'
340
+ *
341
+ * const config: CodegenConfig = {
342
+ * // ...
343
+ * generates: {
344
+ * 'path/to/file.ts': {
345
+ * plugins: ['typescript-operations'],
346
+ * config: {
347
+ * enumType: 'string-literal',
348
+ * }
349
+ * }
350
+ * }
351
+ * }
352
+ * export default config
353
+ */
354
+ enumType?: ConvertSchemaEnumToDeclarationBlockString['outputType'];
355
+ /**
356
+ * @description Overrides the default value of enum values declared in your GraphQL schema.
357
+ * You can also map the entire enum to an external type by providing a string that of `module#type`.
358
+ *
359
+ * @exampleMarkdown
360
+ * ## With Custom Values
361
+ * ```ts filename="codegen.ts"
362
+ * import type { CodegenConfig } from '@graphql-codegen/cli';
363
+ *
364
+ * const config: CodegenConfig = {
365
+ * // ...
366
+ * generates: {
367
+ * 'path/to/file': {
368
+ * // plugins...
369
+ * config: {
370
+ * enumValues: {
371
+ * MyEnum: {
372
+ * A: 'foo'
373
+ * }
374
+ * }
375
+ * },
376
+ * },
377
+ * },
378
+ * };
379
+ * export default config;
380
+ * ```
381
+ *
382
+ * ## With External Enum
383
+ * ```ts filename="codegen.ts"
384
+ * import type { CodegenConfig } from '@graphql-codegen/cli';
385
+ *
386
+ * const config: CodegenConfig = {
387
+ * // ...
388
+ * generates: {
389
+ * 'path/to/file': {
390
+ * // plugins...
391
+ * config: {
392
+ * enumValues: {
393
+ * MyEnum: './my-file#MyCustomEnum',
394
+ * }
395
+ * },
396
+ * },
397
+ * },
398
+ * };
399
+ * export default config;
400
+ * ```
401
+ *
402
+ * ## Import All Enums from a file
403
+ * ```ts filename="codegen.ts"
404
+ * import type { CodegenConfig } from '@graphql-codegen/cli';
405
+ *
406
+ * const config: CodegenConfig = {
407
+ * // ...
408
+ * generates: {
409
+ * 'path/to/file': {
410
+ * // plugins...
411
+ * config: {
412
+ * enumValues: {
413
+ * MyEnum: './my-file',
414
+ * }
415
+ * },
416
+ * },
417
+ * },
418
+ * };
419
+ * export default config;
420
+ * ```
421
+ */
422
+ enumValues?: EnumValuesMap;
423
+ /**
424
+ * @description This option controls whether or not a catch-all entry is added to enum type definitions for values that may be added in the future.
425
+ * This is useful if you are using `relay`.
426
+ * @default false
427
+ *
428
+ * @exampleMarkdown
429
+ * ```ts filename="codegen.ts"
430
+ * import type { CodegenConfig } from '@graphql-codegen/cli'
431
+ *
432
+ * const config: CodegenConfig = {
433
+ * // ...
434
+ * generates: {
435
+ * 'path/to/file.ts': {
436
+ * plugins: ['typescript-operations'],
437
+ * config: {
438
+ * futureProofEnums: true
439
+ * }
440
+ * }
441
+ * }
442
+ * }
443
+ * export default config
444
+ * ```
445
+ */
446
+ futureProofEnums?: boolean;
333
447
  }
@@ -1,4 +1,4 @@
1
- import { AvoidOptionalsConfig, RawDocumentsConfig } from '@graphql-codegen/visitor-plugin-common';
1
+ import { AvoidOptionalsConfig, type ConvertSchemaEnumToDeclarationBlockString, type EnumValuesMap, RawDocumentsConfig } from '@graphql-codegen/visitor-plugin-common';
2
2
  /**
3
3
  * @description This plugin generates TypeScript types based on your GraphQLSchema _and_ your GraphQL operations and fragments.
4
4
  * It generates types for your GraphQL documents: Query, Mutation, Subscription and Fragment.
@@ -330,4 +330,118 @@ export interface TypeScriptDocumentsPluginConfig extends RawDocumentsConfig {
330
330
  nullability?: {
331
331
  errorHandlingClient: boolean;
332
332
  };
333
+ /**
334
+ * @description Controls the enum output type. Options: `string-literal` | `native-numeric` | `const` | `native-const` | `native`;
335
+ * @default `string-literal`
336
+ *
337
+ * @exampleMarkdown
338
+ * ```ts filename="codegen.ts"
339
+ * import type { CodegenConfig } from '@graphql-codegen/cli'
340
+ *
341
+ * const config: CodegenConfig = {
342
+ * // ...
343
+ * generates: {
344
+ * 'path/to/file.ts': {
345
+ * plugins: ['typescript-operations'],
346
+ * config: {
347
+ * enumType: 'string-literal',
348
+ * }
349
+ * }
350
+ * }
351
+ * }
352
+ * export default config
353
+ */
354
+ enumType?: ConvertSchemaEnumToDeclarationBlockString['outputType'];
355
+ /**
356
+ * @description Overrides the default value of enum values declared in your GraphQL schema.
357
+ * You can also map the entire enum to an external type by providing a string that of `module#type`.
358
+ *
359
+ * @exampleMarkdown
360
+ * ## With Custom Values
361
+ * ```ts filename="codegen.ts"
362
+ * import type { CodegenConfig } from '@graphql-codegen/cli';
363
+ *
364
+ * const config: CodegenConfig = {
365
+ * // ...
366
+ * generates: {
367
+ * 'path/to/file': {
368
+ * // plugins...
369
+ * config: {
370
+ * enumValues: {
371
+ * MyEnum: {
372
+ * A: 'foo'
373
+ * }
374
+ * }
375
+ * },
376
+ * },
377
+ * },
378
+ * };
379
+ * export default config;
380
+ * ```
381
+ *
382
+ * ## With External Enum
383
+ * ```ts filename="codegen.ts"
384
+ * import type { CodegenConfig } from '@graphql-codegen/cli';
385
+ *
386
+ * const config: CodegenConfig = {
387
+ * // ...
388
+ * generates: {
389
+ * 'path/to/file': {
390
+ * // plugins...
391
+ * config: {
392
+ * enumValues: {
393
+ * MyEnum: './my-file#MyCustomEnum',
394
+ * }
395
+ * },
396
+ * },
397
+ * },
398
+ * };
399
+ * export default config;
400
+ * ```
401
+ *
402
+ * ## Import All Enums from a file
403
+ * ```ts filename="codegen.ts"
404
+ * import type { CodegenConfig } from '@graphql-codegen/cli';
405
+ *
406
+ * const config: CodegenConfig = {
407
+ * // ...
408
+ * generates: {
409
+ * 'path/to/file': {
410
+ * // plugins...
411
+ * config: {
412
+ * enumValues: {
413
+ * MyEnum: './my-file',
414
+ * }
415
+ * },
416
+ * },
417
+ * },
418
+ * };
419
+ * export default config;
420
+ * ```
421
+ */
422
+ enumValues?: EnumValuesMap;
423
+ /**
424
+ * @description This option controls whether or not a catch-all entry is added to enum type definitions for values that may be added in the future.
425
+ * This is useful if you are using `relay`.
426
+ * @default false
427
+ *
428
+ * @exampleMarkdown
429
+ * ```ts filename="codegen.ts"
430
+ * import type { CodegenConfig } from '@graphql-codegen/cli'
431
+ *
432
+ * const config: CodegenConfig = {
433
+ * // ...
434
+ * generates: {
435
+ * 'path/to/file.ts': {
436
+ * plugins: ['typescript-operations'],
437
+ * config: {
438
+ * futureProofEnums: true
439
+ * }
440
+ * }
441
+ * }
442
+ * }
443
+ * export default config
444
+ * ```
445
+ */
446
+ futureProofEnums?: boolean;
333
447
  }
@@ -1,4 +1,11 @@
1
1
  import { TypeScriptOperationVariablesToObject as TSOperationVariablesToObject } from '@graphql-codegen/typescript';
2
+ export declare const SCALARS: {
3
+ ID: string;
4
+ String: string;
5
+ Int: string;
6
+ Float: string;
7
+ Boolean: string;
8
+ };
2
9
  export declare class TypeScriptOperationVariablesToObject extends TSOperationVariablesToObject {
3
10
  protected formatTypeString(fieldType: string, _isNonNullType: boolean, _hasDefaultValue: boolean): string;
4
11
  protected clearOptional(str: string): string;