Skip to content

Commit ae36a0e

Browse files
mattkrickardatan
andcommitted
fix: coerce enum directive arguments to internal values when printing (#8117)
* fix: coerce enum directive arguments to internal values when printing schema Signed-off-by: Matt Krick <matt.krick@gmail.com> * Fix error * changest * .. * lets go --------- Signed-off-by: Matt Krick <matt.krick@gmail.com> Co-authored-by: Arda TANRIKULU <ardatanrikulu@gmail.com>
1 parent 75301ed commit ae36a0e

File tree

3 files changed

+102
-18
lines changed

3 files changed

+102
-18
lines changed

.changeset/real-poets-work.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@graphql-tools/utils': patch
3+
---
4+
5+
Handle enum values correctly if they are arguments of directives defined in the extensions

packages/utils/src/astFromValue.ts

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { inspect } from 'cross-inspect';
21
import {
32
GraphQLInputType,
43
isEnumType,
@@ -95,29 +94,33 @@ export function astFromValue(value: unknown, type: GraphQLInputType): Maybe<Valu
9594
if (isLeafType(type)) {
9695
// Since value is an internally represented value, it must be serialized
9796
// to an externally represented value before converting into an AST.
98-
const serialized = type.serialize(value);
99-
if (serialized == null) {
100-
return null;
101-
}
102-
10397
if (isEnumType(type)) {
104-
return { kind: Kind.ENUM, value: serialized as string };
98+
const values = type.getValues();
99+
for (const enumValue of values) {
100+
if (enumValue.value === value) {
101+
value = enumValue.name;
102+
break;
103+
}
104+
if (enumValue.name === value) {
105+
value = enumValue.name;
106+
break;
107+
}
108+
}
109+
return { kind: Kind.ENUM, value: value as string };
110+
} else {
111+
value = type.serialize(value);
112+
}
113+
if (value == null) {
114+
return null;
105115
}
106116

107117
// ID types can use Int literals.
108-
if (
109-
type.name === 'ID' &&
110-
typeof serialized === 'string' &&
111-
integerStringRegExp.test(serialized)
112-
) {
113-
return { kind: Kind.INT, value: serialized };
118+
if (type.name === 'ID' && typeof value === 'string' && integerStringRegExp.test(value)) {
119+
return { kind: Kind.INT, value };
114120
}
115-
116-
return astFromValueUntyped(serialized);
117121
}
118-
/* c8 ignore next 3 */
119-
// Not reachable, all possible types have been considered.
120-
console.assert(false, 'Unexpected input type: ' + inspect(type));
122+
123+
return astFromValueUntyped(value);
121124
}
122125

123126
/**

packages/utils/tests/print-schema-with-directives.spec.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,44 @@ describe('printSchemaWithDirectives', () => {
404404
expect(output).toContain('input OneOfInput @oneOf');
405405
}
406406
});
407+
it('should print enum directive arg by name when internal value differs', () => {
408+
const OAuthScopeEnum = new GraphQLEnumType({
409+
name: 'OAuthScopeEnum',
410+
values: {
411+
TEAMS_WRITE: { value: 'teams:write' },
412+
},
413+
});
414+
415+
const scopeDirective = new GraphQLDirective({
416+
name: 'scope',
417+
args: {
418+
name: { type: new GraphQLNonNull(OAuthScopeEnum) },
419+
},
420+
locations: ['FIELD_DEFINITION'] as any,
421+
});
422+
423+
const schema = new GraphQLSchema({
424+
directives: [...specifiedDirectives, scopeDirective],
425+
query: new GraphQLObjectType({
426+
name: 'Query',
427+
fields: {
428+
me: {
429+
type: GraphQLString,
430+
extensions: {
431+
directives: {
432+
scope: { name: 'TEAMS_WRITE' },
433+
},
434+
},
435+
},
436+
},
437+
}),
438+
types: [OAuthScopeEnum],
439+
});
440+
441+
const output = printSchemaWithDirectives(schema);
442+
expect(output).toContain('me: String @scope(name: TEAMS_WRITE)');
443+
});
444+
407445
it('prints a federation-style subgraph schema correctly', () => {
408446
const sdl = stripIgnoredCharacters(/* GraphQL */ `
409447
extend schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key"])
@@ -417,4 +455,42 @@ describe('printSchemaWithDirectives', () => {
417455
const printedSchema = stripIgnoredCharacters(printSchemaWithDirectives(userSubgraph));
418456
expect(printedSchema).toBe(sdl);
419457
});
458+
459+
it('should print enum directive arg by name when internal value differs', () => {
460+
const OAuthScopeEnum = new GraphQLEnumType({
461+
name: 'OAuthScopeEnum',
462+
values: {
463+
TEAMS_WRITE: { value: 'teams:write' },
464+
},
465+
});
466+
467+
const scopeDirective = new GraphQLDirective({
468+
name: 'scope',
469+
args: {
470+
name: { type: new GraphQLNonNull(OAuthScopeEnum) },
471+
},
472+
locations: ['FIELD_DEFINITION'] as any,
473+
});
474+
475+
const schema = new GraphQLSchema({
476+
directives: [...specifiedDirectives, scopeDirective],
477+
query: new GraphQLObjectType({
478+
name: 'Query',
479+
fields: {
480+
me: {
481+
type: GraphQLString,
482+
extensions: {
483+
directives: {
484+
scope: { name: 'TEAMS_WRITE' },
485+
},
486+
},
487+
},
488+
},
489+
}),
490+
types: [OAuthScopeEnum],
491+
});
492+
493+
const output = printSchemaWithDirectives(schema);
494+
expect(output).toContain('me: String @scope(name: TEAMS_WRITE)');
495+
});
420496
});

0 commit comments

Comments
 (0)