Skip to content

Commit 664cd6b

Browse files
authored
[typescript-operations] Add declarationKind support (#10654)
* typescript-operations: Add support for declarationKind option * Drive-by: add fixme * Add changeset
1 parent a34d3cf commit 664cd6b

7 files changed

Lines changed: 553 additions & 8 deletions

File tree

.changeset/beige-pets-talk.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@graphql-codegen/visitor-plugin-common': minor
3+
'@graphql-codegen/typescript-operations': minor
4+
---
5+
6+
Add support for declarationKind for typescript-operations
7+
8+
- Input: can only be `type` or `interface`
9+
- Variables: no support. It must always be `type` because it's an alias e.g. `Variables = Exact<{ something: type }>`
10+
- Result: can only be `type` or `interface`
11+
- Note: when `extractAllFieldsToTypes:true` or `extractAllFieldsToTypesCompact:true`, Results are used as type alias, so they are forced to be `type`. There is a console warning for users.

packages/plugins/other/visitor-plugin-common/src/base-documents-visitor.ts

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ import { SelectionSetToObject } from './selection-set-to-object.js';
1313
import { NormalizedScalarsMap, CustomDirectivesConfig } from './types.js';
1414
import { buildScalarsFromConfig, DeclarationBlock, DeclarationBlockConfig, getConfigValue } from './utils.js';
1515
import { OperationVariablesToObject } from './variables-to-object.js';
16+
import {
17+
normalizeOperationDeclarationKind,
18+
type OperationDeclarationKind,
19+
type OperationDeclarationKindConfig,
20+
} from './operation-declaration-kinds.js';
1621

1722
export interface ParsedDocumentsConfig extends ParsedConfig {
1823
extractAllFieldsToTypes: boolean;
@@ -30,6 +35,7 @@ export interface ParsedDocumentsConfig extends ParsedConfig {
3035
generateOperationTypes: boolean;
3136
importSchemaTypesFrom: string;
3237
namespacedImportName: string | null;
38+
declarationKind: OperationDeclarationKindConfig;
3339
}
3440

3541
export interface RawDocumentsConfig extends RawConfig {
@@ -248,6 +254,52 @@ export interface RawDocumentsConfig extends RawConfig {
248254
* When this option is enabled, `extractAllFieldsToTypes` is automatically enabled as well.
249255
*/
250256
extractAllFieldsToTypesCompact?: boolean;
257+
/**
258+
* @description Overrides the default output for various GraphQL types.
259+
* @default 'type'
260+
* @exampleMarkdown
261+
* ## Override all declarations
262+
*
263+
* ```ts filename="codegen.ts"
264+
* import type { CodegenConfig } from '@graphql-codegen/cli';
265+
*
266+
* const config: CodegenConfig = {
267+
* // ...
268+
* generates: {
269+
* 'path/to/file': {
270+
* // plugins...
271+
* config: {
272+
* declarationKind: 'interface'
273+
* },
274+
* },
275+
* },
276+
* };
277+
* export default config;
278+
* ```
279+
*
280+
* ## Override only specific declarations
281+
*
282+
* ```ts filename="codegen.ts"
283+
* import type { CodegenConfig } from '@graphql-codegen/cli';
284+
*
285+
* const config: CodegenConfig = {
286+
* // ...
287+
* generates: {
288+
* 'path/to/file': {
289+
* // plugins...
290+
* config: {
291+
* declarationKind: {
292+
* input: 'interface',
293+
* result: 'type'
294+
* }
295+
* },
296+
* },
297+
* },
298+
* };
299+
* export default config;
300+
* ```
301+
*/
302+
declarationKind?: OperationDeclarationKind | Partial<OperationDeclarationKindConfig>;
251303
}
252304

253305
export class BaseDocumentsVisitor<
@@ -266,6 +318,17 @@ export class BaseDocumentsVisitor<
266318
defaultScalars: NormalizedScalarsMap = DEFAULT_INPUT_SCALARS
267319
) {
268320
const importSchemaTypesFrom = getConfigValue(rawConfig.importSchemaTypesFrom, '');
321+
const extractAllFieldsToTypes =
322+
getConfigValue(rawConfig.extractAllFieldsToTypes, false) ||
323+
getConfigValue(rawConfig.extractAllFieldsToTypesCompact, false);
324+
const declarationKind = normalizeOperationDeclarationKind(getConfigValue(rawConfig.declarationKind, 'type'));
325+
if (extractAllFieldsToTypes) {
326+
// eslint-disable-next-line no-console
327+
console.warn(
328+
"`declarationKind.result` has been set to `'type'` because `extractAllFieldsToTypes` or `extractAllFieldsToTypesCompact` is true"
329+
);
330+
declarationKind.result = 'type';
331+
}
269332

270333
super(rawConfig, {
271334
exportFragmentSpreadSubTypes: getConfigValue(rawConfig.exportFragmentSpreadSubTypes, false),
@@ -281,10 +344,9 @@ export class BaseDocumentsVisitor<
281344
generateOperationTypes: getConfigValue(rawConfig.generateOperationTypes, true),
282345
importSchemaTypesFrom,
283346
namespacedImportName: getConfigValue(rawConfig.namespacedImportName, importSchemaTypesFrom ? 'Types' : null),
284-
extractAllFieldsToTypes:
285-
getConfigValue(rawConfig.extractAllFieldsToTypes, false) ||
286-
getConfigValue(rawConfig.extractAllFieldsToTypesCompact, false),
347+
extractAllFieldsToTypes,
287348
extractAllFieldsToTypesCompact: getConfigValue(rawConfig.extractAllFieldsToTypesCompact, false),
349+
declarationKind,
288350
...((additionalConfig || {}) as any),
289351
});
290352

@@ -404,7 +466,7 @@ export class BaseDocumentsVisitor<
404466
? ''
405467
: new DeclarationBlock(this._declarationBlockConfig)
406468
.export()
407-
.asKind('type')
469+
.asKind(this.config.declarationKind.result)
408470
.withName(operationResultName)
409471
.withContent(selectionSetObjects.mergedTypeString).string;
410472

@@ -413,7 +475,7 @@ export class BaseDocumentsVisitor<
413475
blockTransformer: t => this.applyVariablesWrapper(t, operationType),
414476
})
415477
.export()
416-
.asKind('type')
478+
.asKind('type') // Variables must always be `'type'` because it is an alias of `Exact<Something>`
417479
.withName(
418480
this.convertName(name, {
419481
suffix: operationTypeSuffix + 'Variables',
@@ -426,7 +488,7 @@ export class BaseDocumentsVisitor<
426488
i =>
427489
new DeclarationBlock(this._declarationBlockConfig)
428490
.export()
429-
.asKind('type')
491+
.asKind('type') // dependentTypes must always be `'type'` because they are alias types
430492
.withName(i.name)
431493
.withContent(i.content).string
432494
)

packages/plugins/other/visitor-plugin-common/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export * from './base-types-visitor.js';
55
export * from './base-visitor.js';
66
export * from './client-side-base-visitor.js';
77
export * from './declaration-kinds.js';
8+
export * from './operation-declaration-kinds.js';
89
export * from './enum-values.js';
910
export * from './imports.js';
1011
export * from './mappers.js';
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
export type OperationDeclarationKind = 'type' | 'interface';
2+
3+
export type OperationDeclarationKindConfig = {
4+
input: OperationDeclarationKind;
5+
result: OperationDeclarationKind; // Query, Mutation, Subscription
6+
};
7+
8+
const DEFAULT_OPERATION_DECLARATION_KINDS: OperationDeclarationKindConfig = {
9+
input: 'type',
10+
result: 'type',
11+
};
12+
13+
export function normalizeOperationDeclarationKind(
14+
declarationKind: OperationDeclarationKind | Partial<OperationDeclarationKindConfig>
15+
): OperationDeclarationKindConfig {
16+
if (typeof declarationKind === 'string') {
17+
return {
18+
input: declarationKind,
19+
result: declarationKind,
20+
};
21+
}
22+
23+
return {
24+
...DEFAULT_OPERATION_DECLARATION_KINDS,
25+
...declarationKind,
26+
};
27+
}

packages/plugins/typescript/operations/src/config.avoidOptionals.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ export interface AvoidOptionalsConfig {
99
}
1010
export type NormalizedAvoidOptionalsConfig = Required<AvoidOptionalsConfig>;
1111

12+
// FIXME:
13+
// 1. bring this to visitor-plugin-common
14+
// 2. param should not be optional
1215
export const normalizeAvoidOptionals = (
1316
avoidOptionals?: boolean | AvoidOptionalsConfig
1417
): NormalizedAvoidOptionalsConfig => {

packages/plugins/typescript/operations/src/visitor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,15 +248,15 @@ export class TypeScriptDocumentsVisitor extends BaseDocumentsVisitor<
248248
if (isOneOfInputObjectType(this._schema.getType(inputTypeName))) {
249249
return new DeclarationBlock(this._declarationBlockConfig)
250250
.export()
251-
.asKind('type')
251+
.asKind(this.config.declarationKind.input)
252252
.withName(this.convertName(node))
253253
.withComment(node.description?.value)
254254
.withContent(`\n` + (node.fields || []).join('\n |')).string;
255255
}
256256

257257
return new DeclarationBlock(this._declarationBlockConfig)
258258
.export()
259-
.asKind('type')
259+
.asKind(this.config.declarationKind.input)
260260
.withName(this.convertName(node))
261261
.withComment(node.description?.value)
262262
.withBlock((node.fields || []).join('\n')).string;

0 commit comments

Comments
 (0)