Skip to content

Commit

Permalink
feat: allow returning string literal types for resolvers returning en…
Browse files Browse the repository at this point in the history
…um values (#6237)
  • Loading branch information
n1ru4l authored Jul 5, 2021
1 parent 15b18aa commit 9005cc1
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 17 deletions.
7 changes: 7 additions & 0 deletions .changeset/swift-fishes-draw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@graphql-codegen/visitor-plugin-common': minor
'@graphql-codegen/typescript-resolvers': minor
'@graphql-codegen/typescript': minor
---

add `allowEnumStringTypes` option for allowing string literals as valid return types from resolvers in addition to enum values.\_
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export interface ParsedConfig {
immutableTypes: boolean;
useTypeImports: boolean;
dedupeFragments: boolean;
allowEnumStringTypes: boolean;
}

export interface RawConfig {
Expand Down Expand Up @@ -195,6 +196,10 @@ export interface RawConfig {
* @default false
*/
dedupeFragments?: boolean;
/**
* @ignore
*/
allowEnumStringTypes?: boolean;
}

export class BaseVisitor<TRawConfig extends RawConfig = RawConfig, TPluginConfig extends ParsedConfig = ParsedConfig> {
Expand All @@ -213,6 +218,7 @@ export class BaseVisitor<TRawConfig extends RawConfig = RawConfig, TPluginConfig
nonOptionalTypename: !!rawConfig.nonOptionalTypename,
useTypeImports: !!rawConfig.useTypeImports,
dedupeFragments: !!rawConfig.dedupeFragments,
allowEnumStringTypes: !!rawConfig.allowEnumStringTypes,
...((additionalConfig || {}) as any),
};

Expand Down
10 changes: 10 additions & 0 deletions packages/plugins/typescript/typescript/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,4 +276,14 @@ export interface TypeScriptPluginConfig extends RawTypesConfig {
* ```
*/
entireFieldWrapperValue?: string;
/**
* @description Allow using enum string values directly.
*
* @exampleMarkdown
* ```yml
* config:
* allowEnumStringTypes: true
* ```
*/
allowEnumStringTypes?: boolean;
}
43 changes: 26 additions & 17 deletions packages/plugins/typescript/typescript/src/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export class TsVisitor<
}

protected _getTypeForNode(node: NamedTypeNode): string {
const typeAsString = (node.name as any) as string;
const typeAsString = node.name as any as string;

if (this.config.useImplementingTypes) {
const allTypesMap = this._schema.getTypeMap();
Expand All @@ -114,7 +114,16 @@ export class TsVisitor<
}
}

return super._getTypeForNode(node);
const typeString = super._getTypeForNode(node);

if (this.config.allowEnumStringTypes === true) {
const schemaType = this._schema.getType(node.name as any as string);
if (isEnumType(schemaType)) {
return `${typeString} | ` + '`${' + typeString + '}`';
}
}

return typeString;
}

public getWrapperDefinitions(): string[] {
Expand Down Expand Up @@ -193,7 +202,7 @@ export class TsVisitor<
.export()
.asKind('type')
.withName(this.convertName(node))
.withComment((node.description as any) as string)
.withComment(node.description as any as string)
.withContent(possibleTypes).string;
// return super.UnionTypeDefinition(node, key, parent).concat(withFutureAddedValue).join("");
}
Expand All @@ -211,7 +220,7 @@ export class TsVisitor<
FieldDefinition(node: FieldDefinitionNode, key?: number | string, parent?: any): string {
const typeString = this.config.wrapEntireDefinitions
? `EntireFieldWrapper<${node.type}>`
: ((node.type as any) as string);
: (node.type as any as string);
const originalFieldNode = parent[key] as FieldDefinitionNode;
const addOptionalSign = !this.config.avoidOptionals.field && originalFieldNode.type.kind !== Kind.NON_NULL_TYPE;
const comment = this.getFieldComment(node);
Expand All @@ -233,7 +242,7 @@ export class TsVisitor<
!this.config.avoidOptionals.inputValue &&
(originalFieldNode.type.kind !== Kind.NON_NULL_TYPE ||
(!this.config.avoidOptionals.defaultValue && node.defaultValue !== undefined));
const comment = transformComment((node.description as any) as string, 1);
const comment = transformComment(node.description as any as string, 1);
const { type } = this.config.declarationKind;
return (
comment +
Expand All @@ -246,7 +255,7 @@ export class TsVisitor<
}

EnumTypeDefinition(node: EnumTypeDefinitionNode): string {
const enumName = (node.name as any) as string;
const enumName = node.name as any as string;

// In case of mapped external enum string
if (this.config.enumValues[enumName] && this.config.enumValues[enumName].sourceFile) {
Expand Down Expand Up @@ -274,15 +283,15 @@ export class TsVisitor<
return new DeclarationBlock(this._declarationBlockConfig)
.export()
.asKind('type')
.withComment((node.description as any) as string)
.withComment(node.description as any as string)
.withName(enumTypeName)
.withContent(
'\n' +
node.values
.map(enumOption => {
const name = (enumOption.name as unknown) as string;
const name = enumOption.name as unknown as string;
const enumValue: string | number = getValueFromConfig(name) ?? name;
const comment = transformComment((enumOption.description as any) as string, 1);
const comment = transformComment(enumOption.description as any as string, 1);

return comment + indent('| ' + wrapWithSingleQuotes(enumValue));
})
Expand All @@ -294,17 +303,17 @@ export class TsVisitor<
if (this.config.numericEnums) {
const block = new DeclarationBlock(this._declarationBlockConfig)
.export()
.withComment((node.description as any) as string)
.withComment(node.description as any as string)
.withName(enumTypeName)
.asKind('enum')
.withBlock(
node.values
.map((enumOption, i) => {
const valueFromConfig = getValueFromConfig((enumOption.name as unknown) as string);
const valueFromConfig = getValueFromConfig(enumOption.name as unknown as string);
const enumValue: string | number = valueFromConfig ?? i;
const comment = transformComment((enumOption.description as any) as string, 1);
const comment = transformComment(enumOption.description as any as string, 1);

return comment + indent((enumOption.name as unknown) as string) + ` = ${enumValue}`;
return comment + indent(enumOption.name as unknown as string) + ` = ${enumValue}`;
})
.concat(...withFutureAddedValue)
.join(',\n')
Expand All @@ -324,13 +333,13 @@ export class TsVisitor<
.export()
.asKind('const')
.withName(enumTypeName)
.withComment((node.description as any) as string)
.withComment(node.description as any as string)
.withBlock(
node.values
.map(enumOption => {
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 comment = transformComment(enumOption.description as any as string, 1);
const name = enumOption.name as unknown as string;
const enumValue: string | number = getValueFromConfig(name) ?? name;

return comment + indent(`${optionName}: ${wrapWithSingleQuotes(enumValue)}`);
Expand All @@ -345,7 +354,7 @@ export class TsVisitor<
.export()
.asKind(this.config.constEnums ? 'const enum' : 'enum')
.withName(enumTypeName)
.withComment((node.description as any) as string)
.withComment(node.description as any as string)
.withBlock(this.buildEnumValuesBlock(enumName, node.values)).string;
}

Expand Down
23 changes: 23 additions & 0 deletions packages/plugins/typescript/typescript/tests/typescript.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2908,6 +2908,29 @@ describe('TypeScript', () => {

validateTs(result);
});

it('allowEnumStringTypes', async () => {
const schema = buildSchema(/* GraphQL */ `
enum MyEnum {
A
B
C
}
type Query {
a: MyEnum
}
`);
const result = (await plugin(
schema,
[],
{ allowEnumStringTypes: true },
{ outputFile: '' }
)) as Types.ComplexPluginOutput;

validateTs(result);

expect(result.content).toBeSimilarStringTo('a?: Maybe<MyEnum | `${MyEnum}`>;');
});
});

it('should not have [object Object]', async () => {
Expand Down

0 comments on commit 9005cc1

Please sign in to comment.