diff --git a/.changeset/odd-snakes-act.md b/.changeset/odd-snakes-act.md new file mode 100644 index 00000000000..5ac3fe17154 --- /dev/null +++ b/.changeset/odd-snakes-act.md @@ -0,0 +1,6 @@ +--- +"@graphql-codegen/typescript": patch +"@graphql-codegen/visitor-plugin-common": patch +--- + +New option `onlyEnums` for Typescript diff --git a/dev-test/codegen.yml b/dev-test/codegen.yml index 27dedd67d36..2f10959c049 100644 --- a/dev-test/codegen.yml +++ b/dev-test/codegen.yml @@ -98,6 +98,13 @@ generates: plugins: - typescript - typescript-operations + ./dev-test/githunt/types.onlyEnums.ts: + schema: ./dev-test/githunt/schema.json + documents: ./dev-test/githunt/**/*.graphql + config: + onlyEnums: true + plugins: + - typescript ./dev-test/githunt/types.preResolveTypes.onlyOperationTypes.ts: schema: ./dev-test/githunt/schema.json documents: ./dev-test/githunt/**/*.graphql @@ -293,6 +300,13 @@ generates: plugins: - typescript - typescript-operations + ./dev-test/star-wars/types.OnlyEnums.ts: + schema: ./dev-test/star-wars/schema.json + documents: ./dev-test/star-wars/**/*.graphql + config: + onlyEnums: true + plugins: + - typescript ./dev-test/star-wars/types.preResolveTypes.onlyOperationTypes.ts: schema: ./dev-test/star-wars/schema.json documents: ./dev-test/star-wars/**/*.graphql diff --git a/dev-test/githunt/types.onlyEnums.ts b/dev-test/githunt/types.onlyEnums.ts new file mode 100644 index 00000000000..941573d8a76 --- /dev/null +++ b/dev-test/githunt/types.onlyEnums.ts @@ -0,0 +1,16 @@ +/** A list of options for the sort order of the feed */ +export enum FeedType { + /** Sort by a combination of freshness and score, using Reddit's algorithm */ + Hot = 'HOT', + /** Newest entries first */ + New = 'NEW', + /** Highest score entries first */ + Top = 'TOP', +} + +/** The type of vote to record, when submitting a vote */ +export enum VoteType { + Cancel = 'CANCEL', + Down = 'DOWN', + Up = 'UP', +} diff --git a/dev-test/star-wars/types.OnlyEnums.ts b/dev-test/star-wars/types.OnlyEnums.ts new file mode 100644 index 00000000000..0ef21c9bac1 --- /dev/null +++ b/dev-test/star-wars/types.OnlyEnums.ts @@ -0,0 +1,17 @@ +/** The episodes in the Star Wars trilogy */ +export enum Episode { + /** Star Wars Episode V: The Empire Strikes Back, released in 1980. */ + Empire = 'EMPIRE', + /** Star Wars Episode VI: Return of the Jedi, released in 1983. */ + Jedi = 'JEDI', + /** Star Wars Episode IV: A New Hope, released in 1977. */ + Newhope = 'NEWHOPE', +} + +/** Units of height */ +export enum LengthUnit { + /** Primarily used in the United States */ + Foot = 'FOOT', + /** The standard unit around the world */ + Meter = 'METER', +} diff --git a/dev-test/test-schema/types.onlyEnums.ts b/dev-test/test-schema/types.onlyEnums.ts new file mode 100644 index 00000000000..6e4207a4363 --- /dev/null +++ b/dev-test/test-schema/types.onlyEnums.ts @@ -0,0 +1,8 @@ +export type TestQueryVariables = Exact<{ [key: string]: never }>; + +export type TestQuery = { + __typename?: 'Query'; + testArr1?: Array | null; + testArr2: Array; + testArr3: Array; +}; diff --git a/packages/plugins/other/visitor-plugin-common/src/base-types-visitor.ts b/packages/plugins/other/visitor-plugin-common/src/base-types-visitor.ts index f0e899b350b..2d15f3b7a8b 100644 --- a/packages/plugins/other/visitor-plugin-common/src/base-types-visitor.ts +++ b/packages/plugins/other/visitor-plugin-common/src/base-types-visitor.ts @@ -49,6 +49,7 @@ export interface ParsedTypesConfig extends ParsedConfig { enumValues: ParsedEnumValuesMap; declarationKind: DeclarationKindConfig; addUnderscoreToArgsType: boolean; + onlyEnums: boolean; onlyOperationTypes: boolean; enumPrefix: boolean; fieldWrapperValue: string; @@ -170,6 +171,23 @@ export interface RawTypesConfig extends RawConfig { * ``` */ wrapFieldDefinitions?: boolean; + /** + * @description This will cause the generator to emit types for enums only + * @default false + * + * @exampleMarkdown + * ## Override all definition types + * + * ```yml + * generates: + * path/to/file.ts: + * plugins: + * - typescript + * config: + * onlyEnums: true + * ``` + */ + onlyEnums?: boolean; /** * @description This will cause the generator to emit types for operations only (basically only enums and scalars) * @default false @@ -294,6 +312,7 @@ export class BaseTypesVisitor< ) { super(rawConfig, { enumPrefix: getConfigValue(rawConfig.enumPrefix, true), + onlyEnums: getConfigValue(rawConfig.onlyEnums, false), onlyOperationTypes: getConfigValue(rawConfig.onlyOperationTypes, false), addUnderscoreToArgsType: getConfigValue(rawConfig.addUnderscoreToArgsType, false), enumValues: parseEnumValues({ @@ -368,6 +387,7 @@ export class BaseTypesVisitor< } public get scalarsDefinition(): string { + if (this.config.onlyEnums) return ''; const allScalars = Object.keys(this.config.scalars).map(scalarName => { const scalarValue = this.config.scalars[scalarName].type; const scalarType = this._schema.getType(scalarName); @@ -434,10 +454,14 @@ export class BaseTypesVisitor< } InputObjectTypeDefinition(node: InputObjectTypeDefinitionNode): string { + if (this.config.onlyEnums) return ''; + return this.getInputObjectDeclarationBlock(node).string; } InputValueDefinition(node: InputValueDefinitionNode): string { + if (this.config.onlyEnums) return ''; + const comment = transformComment(node.description as any as string, 1); const { input } = this._parsedConfig.declarationKind; @@ -454,6 +478,8 @@ export class BaseTypesVisitor< } FieldDefinition(node: FieldDefinitionNode): string { + if (this.config.onlyEnums) return ''; + const typeString = node.type as any as string; const { type } = this._parsedConfig.declarationKind; const comment = this.getNodeComment(node); @@ -462,7 +488,7 @@ export class BaseTypesVisitor< } UnionTypeDefinition(node: UnionTypeDefinitionNode, key: string | number | undefined, parent: any): string { - if (this.config.onlyOperationTypes) return ''; + if (this.config.onlyOperationTypes || this.config.onlyEnums) return ''; const originalNode = parent[key] as UnionTypeDefinitionNode; const possibleTypes = originalNode.types .map(t => (this.scalars[t.name.value] ? this._getScalar(t.name.value) : this.convertName(t))) @@ -531,7 +557,7 @@ export class BaseTypesVisitor< } ObjectTypeDefinition(node: ObjectTypeDefinitionNode, key: number | string, parent: any): string { - if (this.config.onlyOperationTypes) return ''; + if (this.config.onlyOperationTypes || this.config.onlyEnums) return ''; const originalNode = parent[key] as ObjectTypeDefinitionNode; return [this.getObjectTypeDeclarationBlock(node, originalNode).string, this.buildArgumentsBlock(originalNode)] @@ -553,7 +579,7 @@ export class BaseTypesVisitor< } InterfaceTypeDefinition(node: InterfaceTypeDefinitionNode, key: number | string, parent: any): string { - if (this.config.onlyOperationTypes) return ''; + if (this.config.onlyOperationTypes || this.config.onlyEnums) return ''; const originalNode = parent[key] as InterfaceTypeDefinitionNode; return [this.getInterfaceTypeDeclarationBlock(node, originalNode).string, this.buildArgumentsBlock(originalNode)] @@ -651,7 +677,10 @@ export class BaseTypesVisitor< return values .map(enumOption => { const optionName = this.makeValidEnumIdentifier( - this.convertName(enumOption, { useTypesPrefix: false, transformUnderscore: true }) + this.convertName(enumOption, { + useTypesPrefix: false, + transformUnderscore: true, + }) ); const comment = this.getNodeComment(enumOption); const schemaEnumValue = @@ -704,6 +733,7 @@ export class BaseTypesVisitor< name: string, field: FieldDefinitionNode ): string { + if (this.config.onlyEnums) return ''; return this.getArgumentsObjectDeclarationBlock(node, name, field).string; } diff --git a/packages/plugins/typescript/typescript/src/config.ts b/packages/plugins/typescript/typescript/src/config.ts index 09f3a28eb77..cfdb21dbc3d 100644 --- a/packages/plugins/typescript/typescript/src/config.ts +++ b/packages/plugins/typescript/typescript/src/config.ts @@ -133,6 +133,21 @@ export interface TypeScriptPluginConfig extends RawTypesConfig { * ``` */ enumsAsConst?: boolean; + /** + * @description This will cause the generator to emit types for enums only. + * @default false + * + * @exampleMarkdown Override all definition types + * ```yml + * generates: + * path/to/file.ts: + * plugins: + * - typescript + * config: + * onlyEnums: true + * ``` + */ + onlyEnums?: boolean; /** * @description This will cause the generator to emit types for operations only (basically only enums and scalars). * Interacts well with `preResolveTypes: true` diff --git a/packages/plugins/typescript/typescript/src/visitor.ts b/packages/plugins/typescript/typescript/src/visitor.ts index 87c394b8bc3..b4ebfeb7f76 100644 --- a/packages/plugins/typescript/typescript/src/visitor.ts +++ b/packages/plugins/typescript/typescript/src/visitor.ts @@ -35,6 +35,7 @@ export interface TypeScriptPluginParsedConfig extends ParsedTypesConfig { futureProofUnions: boolean; enumsAsConst: boolean; numericEnums: boolean; + onlyEnums: boolean; onlyOperationTypes: boolean; immutableTypes: boolean; maybeValue: string; @@ -66,6 +67,7 @@ export class TsVisitor< futureProofUnions: getConfigValue(pluginConfig.futureProofUnions, false), enumsAsConst: getConfigValue(pluginConfig.enumsAsConst, false), numericEnums: getConfigValue(pluginConfig.numericEnums, false), + onlyEnums: getConfigValue(pluginConfig.onlyEnums, false), onlyOperationTypes: getConfigValue(pluginConfig.onlyOperationTypes, false), immutableTypes: getConfigValue(pluginConfig.immutableTypes, false), useImplementingTypes: getConfigValue(pluginConfig.useImplementingTypes, false), @@ -147,6 +149,8 @@ export class TsVisitor< } public getWrapperDefinitions(): string[] { + if (this.config.onlyEnums) return []; + const definitions: string[] = [ this.getMaybeValue(), this.getInputMaybeValue(), @@ -166,6 +170,8 @@ export class TsVisitor< } public getExactDefinition(): string { + if (this.config.onlyEnums) return ''; + return `${this.getExportPrefix()}${EXACT_SIGNATURE}`; } @@ -174,6 +180,8 @@ export class TsVisitor< } public getMakeMaybeDefinition(): string { + if (this.config.onlyEnums) return ''; + return `${this.getExportPrefix()}${MAKE_MAYBE_SIGNATURE}`; } @@ -220,7 +228,8 @@ export class TsVisitor< } UnionTypeDefinition(node: UnionTypeDefinitionNode, key: string | number | undefined, parent: any): string { - if (this.config.onlyOperationTypes) return ''; + if (this.config.onlyOperationTypes || this.config.onlyEnums) return ''; + let withFutureAddedValue: string[] = []; if (this.config.futureProofUnions) { withFutureAddedValue = [ @@ -318,7 +327,9 @@ export class TsVisitor< this.config.futureProofEnums ? [indent('| ' + wrapWithSingleQuotes('%future added value'))] : [], ]; - const enumTypeName = this.convertName(node, { useTypesPrefix: this.config.enumPrefix }); + const enumTypeName = this.convertName(node, { + useTypesPrefix: this.config.enumPrefix, + }); if (this.config.enumsAsTypes) { return new DeclarationBlock(this._declarationBlockConfig) @@ -354,7 +365,10 @@ export class TsVisitor< const enumValue: string | number = valueFromConfig ?? i; const comment = transformComment(enumOption.description as any as string, 1); const optionName = this.makeValidEnumIdentifier( - this.convertName(enumOption, { useTypesPrefix: false, transformUnderscore: true }) + this.convertName(enumOption, { + useTypesPrefix: false, + transformUnderscore: true, + }) ); return comment + indent(optionName) + ` = ${enumValue}`; }) @@ -380,7 +394,10 @@ export class TsVisitor< .withBlock( node.values .map(enumOption => { - const optionName = this.convertName(enumOption, { useTypesPrefix: false, transformUnderscore: true }); + const optionName = this.convertName(enumOption, { + useTypesPrefix: false, + transformUnderscore: true, + }); const comment = transformComment(enumOption.description as any as string, 1); const name = enumOption.name as unknown as string; const enumValue: string | number = getValueFromConfig(name) ?? name;