Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e2002dc

Browse files
committedJun 1, 2021
Preserve defaultValue literals
Fixes #3051 This change solves the problem of default values defined via SDL not always resolving correctly through introspection by preserving the original GraphQL literal in the schema definition. This changes argument and input field definitions `defaultValue` field from just the "value" to a new `GraphQLDefaultValueUsage` type which contains either or both "value" and "literal" fields. Since either of these fields may be set, new functions for resolving a value or literal from either have been added - `getLiteralDefaultValue` and `getCoercedDefaultValue` - these replace uses that either assumed a set value or were manually converting a value back to a literal. Here is the flow for how a default value defined in an SDL would be converted into a functional schema and back to an SDL: **Before this change:** ``` (SDL) --parse-> (AST) --coerceInputLiteral--> (defaultValue config) --valueToAST--> (AST) --print --> (SDL) ``` `coerceInputLiteral` performs coercion which is a one-way function, and `valueToAST` is unsafe and set to be deprecated in #3049. **After this change:** ``` (SDL) --parse-> (defaultValue literal config) --print --> (SDL) ```
1 parent 2f04eed commit e2002dc

17 files changed

+235
-50
lines changed
 

‎src/execution/values.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { typeFromAST } from '../utilities/typeFromAST';
2323
import {
2424
coerceInputValue,
2525
coerceInputLiteral,
26+
coerceDefaultValue,
2627
} from '../utilities/coerceInputValue';
2728

2829
type CoercedVariableValues =
@@ -179,8 +180,11 @@ export function getArgumentValues(
179180
const argumentNode = argNodeMap[name];
180181

181182
if (!argumentNode) {
182-
if (argDef.defaultValue !== undefined) {
183-
coercedValues[name] = argDef.defaultValue;
183+
if (argDef.defaultValue) {
184+
coercedValues[name] = coerceDefaultValue(
185+
argDef.defaultValue,
186+
argDef.type,
187+
);
184188
} else if (isNonNullType(argType)) {
185189
throw new GraphQLError(
186190
`Argument "${name}" of required type "${inspect(argType)}" ` +
@@ -200,8 +204,11 @@ export function getArgumentValues(
200204
variableValues == null ||
201205
!hasOwnProperty(variableValues, variableName)
202206
) {
203-
if (argDef.defaultValue !== undefined) {
204-
coercedValues[name] = argDef.defaultValue;
207+
if (argDef.defaultValue) {
208+
coercedValues[name] = coerceDefaultValue(
209+
argDef.defaultValue,
210+
argDef.type,
211+
);
205212
} else if (isNonNullType(argType)) {
206213
throw new GraphQLError(
207214
`Argument "${name}" of required type "${inspect(argType)}" ` +

‎src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ export type {
181181
GraphQLScalarSerializer,
182182
GraphQLScalarValueParser,
183183
GraphQLScalarLiteralParser,
184+
GraphQLDefaultValueUsage,
184185
} from './type/index';
185186

186187
/** Parse and operate on GraphQL language source files. */

‎src/type/__tests__/definition-test.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,69 @@ describe('Type System: Input Objects', () => {
826826
);
827827
});
828828
});
829+
830+
describe('Input Object fields may have default values', () => {
831+
it('accepts an Input Object type with a default value', () => {
832+
const inputObjType = new GraphQLInputObjectType({
833+
name: 'SomeInputObject',
834+
fields: {
835+
f: { type: ScalarType, defaultValue: 3 },
836+
},
837+
});
838+
expect(inputObjType.getFields()).to.deep.equal({
839+
f: {
840+
coordinate: 'SomeInputObject.f',
841+
name: 'f',
842+
description: undefined,
843+
type: ScalarType,
844+
defaultValue: { value: 3 },
845+
deprecationReason: undefined,
846+
extensions: undefined,
847+
astNode: undefined,
848+
},
849+
});
850+
});
851+
852+
it('accepts an Input Object type with a default value literal', () => {
853+
const inputObjType = new GraphQLInputObjectType({
854+
name: 'SomeInputObject',
855+
fields: {
856+
f: {
857+
type: ScalarType,
858+
defaultValueLiteral: { kind: 'IntValue', value: '3' },
859+
},
860+
},
861+
});
862+
expect(inputObjType.getFields()).to.deep.equal({
863+
f: {
864+
coordinate: 'SomeInputObject.f',
865+
name: 'f',
866+
description: undefined,
867+
type: ScalarType,
868+
defaultValue: { literal: { kind: 'IntValue', value: '3' } },
869+
deprecationReason: undefined,
870+
extensions: undefined,
871+
astNode: undefined,
872+
},
873+
});
874+
});
875+
876+
it('rejects an Input Object type with potentially conflicting default values', () => {
877+
const inputObjType = new GraphQLInputObjectType({
878+
name: 'SomeInputObject',
879+
fields: {
880+
f: {
881+
type: ScalarType,
882+
defaultValue: 3,
883+
defaultValueLiteral: { kind: 'IntValue', value: '3' },
884+
},
885+
},
886+
});
887+
expect(() => inputObjType.getFields()).to.throw(
888+
'f has both a defaultValue and a defaultValueLiteral property, but only one must be provided.',
889+
);
890+
});
891+
});
829892
});
830893

831894
describe('Type System: List', () => {

‎src/type/definition.ts

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { print } from '../language/printer';
2121
import type {
2222
FieldNode,
2323
ValueNode,
24+
ConstValueNode,
2425
OperationDefinitionNode,
2526
FragmentDefinitionNode,
2627
ScalarTypeDefinitionNode,
@@ -964,6 +965,7 @@ export interface GraphQLArgumentConfig {
964965
description?: Maybe<string>;
965966
type: GraphQLInputType;
966967
defaultValue?: unknown;
968+
defaultValueLiteral?: ConstValueNode;
967969
deprecationReason?: Maybe<string>;
968970
extensions?: Maybe<Readonly<GraphQLArgumentExtensions>>;
969971
astNode?: Maybe<InputValueDefinitionNode>;
@@ -1049,7 +1051,7 @@ export class GraphQLArgument extends GraphQLSchemaElement {
10491051
name: string;
10501052
description: Maybe<string>;
10511053
type: GraphQLInputType;
1052-
defaultValue: unknown;
1054+
defaultValue: GraphQLDefaultValueUsage | undefined;
10531055
deprecationReason: Maybe<string>;
10541056
extensions: Maybe<Readonly<GraphQLArgumentExtensions>>;
10551057
astNode: Maybe<InputValueDefinitionNode>;
@@ -1064,7 +1066,7 @@ export class GraphQLArgument extends GraphQLSchemaElement {
10641066
this.name = name;
10651067
this.description = config.description;
10661068
this.type = config.type;
1067-
this.defaultValue = config.defaultValue;
1069+
this.defaultValue = defineDefaultValue(coordinate, config);
10681070
this.deprecationReason = config.deprecationReason;
10691071
this.extensions = config.extensions && toObjMap(config.extensions);
10701072
this.astNode = config.astNode;
@@ -1074,7 +1076,8 @@ export class GraphQLArgument extends GraphQLSchemaElement {
10741076
return {
10751077
description: this.description,
10761078
type: this.type,
1077-
defaultValue: this.defaultValue,
1079+
defaultValue: this.defaultValue?.value,
1080+
defaultValueLiteral: this.defaultValue?.literal,
10781081
deprecationReason: this.deprecationReason,
10791082
extensions: this.extensions,
10801083
astNode: this.astNode,
@@ -1090,6 +1093,26 @@ export type GraphQLFieldMap<TSource, TContext> = ObjMap<
10901093
GraphQLField<TSource, TContext>
10911094
>;
10921095

1096+
export type GraphQLDefaultValueUsage =
1097+
| { value: unknown; literal?: never }
1098+
| { literal: ConstValueNode; value?: never };
1099+
1100+
function defineDefaultValue(
1101+
coordinate: string,
1102+
config: GraphQLArgumentConfig | GraphQLInputFieldConfig,
1103+
): GraphQLDefaultValueUsage | undefined {
1104+
if (config.defaultValue === undefined && !config.defaultValueLiteral) {
1105+
return;
1106+
}
1107+
devAssert(
1108+
!(config.defaultValue !== undefined && config.defaultValueLiteral),
1109+
`${coordinate} has both a defaultValue and a defaultValueLiteral property, but only one must be provided.`,
1110+
);
1111+
return config.defaultValueLiteral
1112+
? { literal: config.defaultValueLiteral }
1113+
: { value: config.defaultValue };
1114+
}
1115+
10931116
/**
10941117
* Custom extensions
10951118
*
@@ -1694,6 +1717,7 @@ export interface GraphQLInputFieldConfig {
16941717
description?: Maybe<string>;
16951718
type: GraphQLInputType;
16961719
defaultValue?: unknown;
1720+
defaultValueLiteral?: ConstValueNode;
16971721
deprecationReason?: Maybe<string>;
16981722
extensions?: Maybe<Readonly<GraphQLInputFieldExtensions>>;
16991723
astNode?: Maybe<InputValueDefinitionNode>;
@@ -1705,7 +1729,7 @@ export class GraphQLInputField extends GraphQLSchemaElement {
17051729
name: string;
17061730
description: Maybe<string>;
17071731
type: GraphQLInputType;
1708-
defaultValue: unknown;
1732+
defaultValue: GraphQLDefaultValueUsage | undefined;
17091733
deprecationReason: Maybe<string>;
17101734
extensions: Maybe<Readonly<GraphQLInputFieldExtensions>>;
17111735
astNode: Maybe<InputValueDefinitionNode>;
@@ -1726,7 +1750,7 @@ export class GraphQLInputField extends GraphQLSchemaElement {
17261750
this.name = name;
17271751
this.description = config.description;
17281752
this.type = config.type;
1729-
this.defaultValue = config.defaultValue;
1753+
this.defaultValue = defineDefaultValue(coordinate, config);
17301754
this.deprecationReason = config.deprecationReason;
17311755
this.extensions = config.extensions && toObjMap(config.extensions);
17321756
this.astNode = config.astNode;
@@ -1736,7 +1760,8 @@ export class GraphQLInputField extends GraphQLSchemaElement {
17361760
return {
17371761
description: this.description,
17381762
type: this.type,
1739-
defaultValue: this.defaultValue,
1763+
defaultValue: this.defaultValue?.value,
1764+
defaultValueLiteral: this.defaultValue?.literal,
17401765
extensions: this.extensions,
17411766
astNode: this.astNode,
17421767
};

‎src/type/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ export type {
116116
GraphQLScalarSerializer,
117117
GraphQLScalarValueParser,
118118
GraphQLScalarLiteralParser,
119+
GraphQLDefaultValueUsage,
119120
} from './definition';
120121

121122
export {

‎src/type/introspection.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,8 +384,13 @@ export const __InputValue: GraphQLObjectType = new GraphQLObjectType({
384384
'A GraphQL-formatted string representing the default value for this input value.',
385385
resolve(inputValue) {
386386
const { type, defaultValue } = inputValue;
387-
const valueAST = astFromValue(defaultValue, type);
388-
return valueAST ? print(valueAST) : null;
387+
if (!defaultValue) {
388+
return null;
389+
}
390+
const literal =
391+
defaultValue.literal ?? astFromValue(defaultValue.value, type);
392+
invariant(literal, 'Invalid default value');
393+
return print(literal);
389394
},
390395
},
391396
isDeprecated: {

‎src/utilities/TypeInfo.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import type {
1717
GraphQLArgument,
1818
GraphQLInputField,
1919
GraphQLEnumValue,
20+
GraphQLDefaultValueUsage,
2021
} from '../type/definition';
2122
import {
2223
isObjectType,
@@ -49,7 +50,7 @@ export class TypeInfo {
4950
private _parentTypeStack: Array<Maybe<GraphQLCompositeType>>;
5051
private _inputTypeStack: Array<Maybe<GraphQLInputType>>;
5152
private _fieldDefStack: Array<Maybe<GraphQLField<unknown, unknown>>>;
52-
private _defaultValueStack: Array<Maybe<unknown>>;
53+
private _defaultValueStack: Array<GraphQLDefaultValueUsage | undefined>;
5354
private _directive: Maybe<GraphQLDirective>;
5455
private _argument: Maybe<GraphQLArgument>;
5556
private _enumValue: Maybe<GraphQLEnumValue>;
@@ -119,7 +120,7 @@ export class TypeInfo {
119120
}
120121
}
121122

122-
getDefaultValue(): Maybe<unknown> {
123+
getDefaultValue(): GraphQLDefaultValueUsage | undefined {
123124
if (this._defaultValueStack.length > 0) {
124125
return this._defaultValueStack[this._defaultValueStack.length - 1];
125126
}

‎src/utilities/__tests__/buildClientSchema-test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,7 @@ describe('Type System: build schema from introspection', () => {
444444
}
445445
446446
type Query {
447+
defaultID(intArg: ID = "123"): String
447448
defaultInt(intArg: Int = 30): String
448449
defaultList(listArg: [Int] = [1, 2, 3]): String
449450
defaultObject(objArg: Geo = {lat: 37.485, lon: -122.148}): String
@@ -599,6 +600,28 @@ describe('Type System: build schema from introspection', () => {
599600
expect(result.data).to.deep.equal({ foo: 'bar' });
600601
});
601602

603+
it('can use client schema for execution if resolvers are added', () => {
604+
const schema = buildSchema(`
605+
type Query {
606+
foo(bar: String = "abc"): String
607+
}
608+
`);
609+
610+
const introspection = introspectionFromSchema(schema);
611+
const clientSchema = buildClientSchema(introspection);
612+
613+
const QueryType: GraphQLObjectType = clientSchema.getType('Query') as any;
614+
QueryType.getFields().foo.resolve = (_value, args) => args.bar;
615+
616+
const result = graphqlSync({
617+
schema: clientSchema,
618+
source: '{ foo }',
619+
});
620+
621+
expect(result.data).to.deep.equal({ foo: 'abc' });
622+
expect(result.data).to.deep.equal({ foo: 'abc' });
623+
});
624+
602625
it('can build invalid schema', () => {
603626
const schema = buildSchema('type Query', { assumeValid: true });
604627

‎src/utilities/__tests__/coerceInputValue-test.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ import {
2424
GraphQLInputObjectType,
2525
} from '../../type/definition';
2626

27-
import { coerceInputValue, coerceInputLiteral } from '../coerceInputValue';
27+
import {
28+
coerceInputValue,
29+
coerceInputLiteral,
30+
coerceDefaultValue,
31+
} from '../coerceInputValue';
2832

2933
interface CoerceResult {
3034
value: unknown;
@@ -610,10 +614,14 @@ describe('coerceInputLiteral', () => {
610614
name: 'TestInput',
611615
fields: {
612616
int: { type: GraphQLInt, defaultValue: 42 },
617+
float: {
618+
type: GraphQLFloat,
619+
defaultValueLiteral: { kind: 'FloatValue', value: '3.14' },
620+
},
613621
},
614622
});
615623

616-
test('{}', type, { int: 42 });
624+
test('{}', type, { int: 42, float: 3.14 });
617625
});
618626

619627
const testInputObj = new GraphQLInputObjectType({
@@ -681,3 +689,26 @@ describe('coerceInputLiteral', () => {
681689
});
682690
});
683691
});
692+
693+
describe('coerceDefaultValue', () => {
694+
it('memoizes coercion', () => {
695+
const parseValueCalls: any = [];
696+
697+
const spyScalar = new GraphQLScalarType({
698+
name: 'SpyScalar',
699+
parseValue(value) {
700+
parseValueCalls.push(value);
701+
return value;
702+
},
703+
});
704+
705+
const defaultValueUsage = {
706+
literal: { kind: 'StringValue', value: 'hello' },
707+
} as const;
708+
expect(coerceDefaultValue(defaultValueUsage, spyScalar)).to.equal('hello');
709+
710+
// Call a second time
711+
expect(coerceDefaultValue(defaultValueUsage, spyScalar)).to.equal('hello');
712+
expect(parseValueCalls).to.deep.equal(['hello']);
713+
});
714+
});

‎src/utilities/astFromValue.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { isObjectLike } from '../jsutils/isObjectLike';
44
import { isIterableObject } from '../jsutils/isIterableObject';
55
import type { Maybe } from '../jsutils/Maybe';
66

7-
import type { ValueNode } from '../language/ast';
7+
import type { ConstValueNode } from '../language/ast';
88
import { Kind } from '../language/kinds';
99

1010
import type { GraphQLInputType } from '../type/definition';
@@ -41,7 +41,7 @@ import {
4141
export function astFromValue(
4242
value: unknown,
4343
type: GraphQLInputType,
44-
): Maybe<ValueNode> {
44+
): Maybe<ConstValueNode> {
4545
if (isNonNullType(type)) {
4646
const astValue = astFromValue(value, type.ofType);
4747
if (astValue?.kind === Kind.NULL) {

‎src/utilities/buildClientSchema.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ import type {
4747
IntrospectionTypeRef,
4848
IntrospectionNamedTypeRef,
4949
} from './getIntrospectionQuery';
50-
import { coerceInputLiteral } from './coerceInputValue';
5150

5251
/**
5352
* Build a GraphQLSchema for use by client tools.
@@ -366,17 +365,13 @@ export function buildClientSchema(
366365
);
367366
}
368367

369-
const defaultValue =
370-
inputValueIntrospection.defaultValue != null
371-
? coerceInputLiteral(
372-
parseConstValue(inputValueIntrospection.defaultValue),
373-
type,
374-
)
375-
: undefined;
376368
return {
377369
description: inputValueIntrospection.description,
378370
type,
379-
defaultValue,
371+
defaultValueLiteral:
372+
inputValueIntrospection.defaultValue != null
373+
? parseConstValue(inputValueIntrospection.defaultValue)
374+
: undefined,
380375
deprecationReason: inputValueIntrospection.deprecationReason,
381376
};
382377
}

‎src/utilities/coerceInputValue.ts

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ import { isIterableObject } from '../jsutils/isIterableObject';
1414

1515
import { GraphQLError } from '../error/GraphQLError';
1616

17-
import type { GraphQLInputType } from '../type/definition';
17+
import type {
18+
GraphQLInputType,
19+
GraphQLDefaultValueUsage,
20+
} from '../type/definition';
1821
import {
1922
isLeafType,
2023
isInputObjectType,
@@ -110,8 +113,11 @@ function coerceInputValueImpl(
110113
const fieldValue = inputValue[field.name];
111114

112115
if (fieldValue === undefined) {
113-
if (field.defaultValue !== undefined) {
114-
coercedValue[field.name] = field.defaultValue;
116+
if (field.defaultValue) {
117+
coercedValue[field.name] = coerceDefaultValue(
118+
field.defaultValue,
119+
field.type,
120+
);
115121
} else if (isNonNullType(field.type)) {
116122
const typeStr = inspect(field.type);
117123
onError(
@@ -278,8 +284,11 @@ export function coerceInputLiteral(
278284
if (isRequiredInputField(field)) {
279285
return; // Invalid: intentionally return no value.
280286
}
281-
if (field.defaultValue !== undefined) {
282-
coercedValue[field.name] = field.defaultValue;
287+
if (field.defaultValue) {
288+
coercedValue[field.name] = coerceDefaultValue(
289+
field.defaultValue,
290+
field.type,
291+
);
283292
}
284293
} else {
285294
const fieldValue = coerceInputLiteral(
@@ -320,3 +329,23 @@ function isMissingVariable(
320329
(variables == null || variables[valueNode.name.value] === undefined)
321330
);
322331
}
332+
333+
/**
334+
* @internal
335+
*/
336+
export function coerceDefaultValue(
337+
defaultValue: GraphQLDefaultValueUsage,
338+
type: GraphQLInputType,
339+
): unknown {
340+
// Memoize the result of coercing the default value in a hidden field.
341+
let coercedValue = (defaultValue as any)._memoizedCoercedValue;
342+
// istanbul ignore else (memoized case)
343+
if (coercedValue === undefined) {
344+
coercedValue = defaultValue.literal
345+
? coerceInputLiteral(defaultValue.literal, type)
346+
: defaultValue.value;
347+
invariant(coercedValue !== undefined);
348+
(defaultValue as any)._memoizedCoercedValue = coercedValue;
349+
}
350+
return coercedValue;
351+
}

‎src/utilities/extendSchema.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,6 @@ import {
8080
GraphQLInputObjectType,
8181
} from '../type/definition';
8282

83-
import { coerceInputLiteral } from './coerceInputValue';
84-
8583
interface Options extends GraphQLSchemaValidationOptions {
8684
/**
8785
* Set to true to assume the SDL is valid.
@@ -491,9 +489,7 @@ export function extendSchemaImpl(
491489
argConfigMap[arg.name.value] = {
492490
type,
493491
description: arg.description?.value,
494-
defaultValue: arg.defaultValue
495-
? coerceInputLiteral(arg.defaultValue, type)
496-
: undefined,
492+
defaultValueLiteral: arg.defaultValue,
497493
deprecationReason: getDeprecationReason(arg),
498494
astNode: arg,
499495
};
@@ -520,9 +516,7 @@ export function extendSchemaImpl(
520516
inputFieldMap[field.name.value] = {
521517
type,
522518
description: field.description?.value,
523-
defaultValue: field.defaultValue
524-
? coerceInputLiteral(field.defaultValue, type)
525-
: undefined,
519+
defaultValueLiteral: field.defaultValue,
526520
deprecationReason: getDeprecationReason(field),
527521
astNode: field,
528522
};

‎src/utilities/findBreakingChanges.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import type {
1717
GraphQLObjectType,
1818
GraphQLInterfaceType,
1919
GraphQLInputObjectType,
20+
GraphQLDefaultValueUsage,
2021
} from '../type/definition';
2122
import { isSpecifiedScalarType } from '../type/scalars';
2223
import {
@@ -527,10 +528,12 @@ function typeKindName(type: GraphQLNamedType): string {
527528
invariant(false, 'Unexpected type: ' + inspect(type));
528529
}
529530

530-
function stringifyValue(value: unknown, type: GraphQLInputType): string {
531-
const ast = astFromValue(value, type);
532-
invariant(ast != null);
533-
531+
function stringifyValue(
532+
defaultValue: GraphQLDefaultValueUsage,
533+
type: GraphQLInputType,
534+
): string {
535+
const ast = defaultValue.literal ?? astFromValue(defaultValue.value, type);
536+
invariant(ast);
534537
const sortedAST = visit(ast, {
535538
ObjectValue(objectNode) {
536539
// Make a copy since sort mutates array

‎src/utilities/printSchema.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,10 +259,13 @@ function printArgs(
259259
}
260260

261261
function printInputValue(arg: GraphQLInputField): string {
262-
const defaultAST = astFromValue(arg.defaultValue, arg.type);
263262
let argDecl = arg.name + ': ' + String(arg.type);
264-
if (defaultAST) {
265-
argDecl += ` = ${print(defaultAST)}`;
263+
if (arg.defaultValue) {
264+
const literal =
265+
arg.defaultValue.literal ??
266+
astFromValue(arg.defaultValue.value, arg.type);
267+
invariant(literal, 'Invalid default value');
268+
argDecl += ` = ${print(literal)}`;
266269
}
267270
return argDecl + printDeprecated(arg.deprecationReason);
268271
}

‎src/validation/ValidationContext.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import type {
2525
GraphQLField,
2626
GraphQLArgument,
2727
GraphQLEnumValue,
28+
GraphQLDefaultValueUsage,
2829
} from '../type/definition';
2930

3031
import { TypeInfo, visitWithTypeInfo } from '../utilities/TypeInfo';
@@ -33,7 +34,7 @@ type NodeWithSelectionSet = OperationDefinitionNode | FragmentDefinitionNode;
3334
interface VariableUsage {
3435
readonly node: VariableNode;
3536
readonly type: Maybe<GraphQLInputType>;
36-
readonly defaultValue: Maybe<unknown>;
37+
readonly defaultValue: GraphQLDefaultValueUsage | undefined;
3738
}
3839

3940
/**

‎src/validation/rules/VariablesInAllowedPositionRule.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ import type { ValueNode } from '../../language/ast';
77
import type { ASTVisitor } from '../../language/visitor';
88

99
import type { GraphQLSchema } from '../../type/schema';
10-
import type { GraphQLType } from '../../type/definition';
10+
import type {
11+
GraphQLType,
12+
GraphQLDefaultValueUsage,
13+
} from '../../type/definition';
1114
import { isNonNullType } from '../../type/definition';
1215

1316
import { typeFromAST } from '../../utilities/typeFromAST';
@@ -79,7 +82,7 @@ function allowedVariableUsage(
7982
varType: GraphQLType,
8083
varDefaultValue: Maybe<ValueNode>,
8184
locationType: GraphQLType,
82-
locationDefaultValue: Maybe<unknown>,
85+
locationDefaultValue: GraphQLDefaultValueUsage | undefined,
8386
): boolean {
8487
if (isNonNullType(locationType) && !isNonNullType(varType)) {
8588
const hasNonNullVariableDefaultValue =

0 commit comments

Comments
 (0)
Please sign in to comment.