Skip to content

Commit a0688c6

Browse files
committed
Provide reasonable default version of 'parseLiteral'
1 parent 313d66e commit a0688c6

File tree

7 files changed

+130
-20
lines changed

7 files changed

+130
-20
lines changed

src/type/definition.js

+6-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import invariant from '../jsutils/invariant';
1212
import isNullish from '../jsutils/isNullish';
1313
import * as Kind from '../language/kinds';
1414
import { assertValidName } from '../utilities/assertValidName';
15+
import { scalarValueFromAST } from '../utilities/scalarValueFromAST';
1516
import type {
1617
ScalarTypeDefinitionNode,
1718
ObjectTypeDefinitionNode,
@@ -345,7 +346,10 @@ export class GraphQLScalarType {
345346
// Parses an externally provided value to use as an input.
346347
parseValue(value: mixed): mixed {
347348
const parser = this._scalarConfig.parseValue;
348-
return parser && !isNullish(value) ? parser(value) : undefined;
349+
if (isNullish(value)) {
350+
return undefined;
351+
}
352+
return parser ? parser(value) : value;
349353
}
350354

351355
// Determines if an internal value is valid for this type.
@@ -357,7 +361,7 @@ export class GraphQLScalarType {
357361
// Parses an externally provided literal value to use as an input.
358362
parseLiteral(valueNode: ValueNode): mixed {
359363
const parser = this._scalarConfig.parseLiteral;
360-
return parser ? parser(valueNode) : undefined;
364+
return (parser || scalarValueFromAST)(valueNode);
361365
}
362366

363367
toString(): string {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
* Copyright (c) 2017, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
import { describe, it } from 'mocha';
11+
import { expect } from 'chai';
12+
import { scalarValueFromAST } from '../scalarValueFromAST';
13+
import { parseValue } from '../../language';
14+
15+
describe('scalarValueFromAST', () => {
16+
17+
function testCase(valueText, expected) {
18+
expect(
19+
scalarValueFromAST(parseValue(valueText))
20+
).to.deep.equal(expected);
21+
}
22+
23+
function testNegativeCase(valueText, errorMsg) {
24+
expect(
25+
() => scalarValueFromAST(parseValue(valueText))
26+
).to.throw(errorMsg);
27+
}
28+
29+
it('parses simple values', () => {
30+
testCase('null', null);
31+
testCase('true', true);
32+
testCase('false', false);
33+
testCase('123', 123);
34+
testCase('123.456', 123.456);
35+
testCase('"abc123"', 'abc123');
36+
});
37+
38+
it('parses lists of values', () => {
39+
testCase('[true, false]', [ true, false ]);
40+
testCase('[true, 123.45]', [ true, 123.45 ]);
41+
testCase('[true, null]', [ true, null ]);
42+
testCase('[true, ["foo", 1.2]]', [ true, [ 'foo', 1.2 ] ]);
43+
});
44+
45+
it('parses input objects', () => {
46+
testCase(
47+
'{ int: 123, requiredBool: false }',
48+
{ int: 123, requiredBool: false }
49+
);
50+
testCase(
51+
'{ foo: [{ bar: "baz"}]}',
52+
{ foo: [ { bar: 'baz'} ] }
53+
);
54+
});
55+
56+
it('rejects enum values and query variables', () => {
57+
testNegativeCase('TEST_ENUM_VALUE', 'Scalar value can not contain Enum.');
58+
testNegativeCase(
59+
'$test_variable',
60+
'Scalar value can not contain Query variable.'
61+
);
62+
testNegativeCase('[TEST_ENUM_VALUE]', 'Scalar value can not contain Enum.');
63+
testNegativeCase(
64+
'[$test_variable]',
65+
'Scalar value can not contain Query variable.'
66+
);
67+
testNegativeCase(
68+
'{foo: TEST_ENUM_VALUE}',
69+
'Scalar value can not contain Enum.'
70+
);
71+
testNegativeCase(
72+
'{bar: $test_variable}',
73+
'Scalar value can not contain Query variable.'
74+
);
75+
});
76+
77+
});

src/utilities/buildASTSchema.js

-6
Original file line numberDiff line numberDiff line change
@@ -448,12 +448,6 @@ export function buildASTSchema(ast: DocumentNode): GraphQLSchema {
448448
description: getDescription(def),
449449
astNode: def,
450450
serialize: () => null,
451-
// Note: validation calls the parse functions to determine if a
452-
// literal value is correct. Returning null would cause use of custom
453-
// scalars to always fail validation. Returning false causes them to
454-
// always pass validation.
455-
parseValue: () => false,
456-
parseLiteral: () => false,
457451
});
458452
}
459453

src/utilities/buildClientSchema.js

-6
Original file line numberDiff line numberDiff line change
@@ -227,12 +227,6 @@ export function buildClientSchema(
227227
name: scalarIntrospection.name,
228228
description: scalarIntrospection.description,
229229
serialize: id => id,
230-
// Note: validation calls the parse functions to determine if a
231-
// literal value is correct. Returning null would cause use of custom
232-
// scalars to always fail validation. Returning false causes them to
233-
// always pass validation.
234-
parseValue: () => false,
235-
parseLiteral: () => false,
236230
});
237231
}
238232

src/utilities/extendSchema.js

-6
Original file line numberDiff line numberDiff line change
@@ -499,12 +499,6 @@ export function extendSchema(
499499
description: getDescription(typeNode),
500500
astNode: typeNode,
501501
serialize: id => id,
502-
// Note: validation calls the parse functions to determine if a
503-
// literal value is correct. Returning null would cause use of custom
504-
// scalars to always fail validation. Returning false causes them to
505-
// always pass validation.
506-
parseValue: () => false,
507-
parseLiteral: () => false,
508502
});
509503
}
510504

src/utilities/index.js

+4
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ export { valueFromAST } from './valueFromAST';
5858
// Create a GraphQL language AST from a JavaScript value.
5959
export { astFromValue } from './astFromValue';
6060

61+
// Create a JavaScript value from a GraphQL language AST representation
62+
// of Scalar.
63+
export { scalarValueFromAST } from './scalarValueFromAST';
64+
6165
// A helper to use within recursive-descent visitors which need to be aware of
6266
// the GraphQL type system.
6367
export { TypeInfo } from './TypeInfo';

src/utilities/scalarValueFromAST.js

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* @flow */
2+
/**
3+
* Copyright (c) 2017, Facebook, Inc.
4+
* All rights reserved.
5+
*
6+
* This source code is licensed under the BSD-style license found in the
7+
* LICENSE file in the root directory of this source tree. An additional grant
8+
* of patent rights can be found in the PATENTS file in the same directory.
9+
*/
10+
11+
import keyValMap from '../jsutils/keyValMap';
12+
import * as Kind from '../language/kinds';
13+
import type { ValueNode } from '../language/ast';
14+
15+
/**
16+
* Create a JavaScript value from a GraphQL language AST representation
17+
* of Scalar.
18+
*/
19+
export function scalarValueFromAST(astValue: ValueNode): mixed {
20+
switch (astValue.kind) {
21+
case Kind.NULL:
22+
return null;
23+
case Kind.INT:
24+
return parseInt(astValue.value, 10);
25+
case Kind.FLOAT:
26+
return parseFloat(astValue.value);
27+
case Kind.STRING:
28+
case Kind.BOOLEAN:
29+
return astValue.value;
30+
case Kind.LIST:
31+
return astValue.values.map(scalarValueFromAST);
32+
case Kind.OBJECT:
33+
return keyValMap(
34+
astValue.fields,
35+
field => field.name.value,
36+
field => scalarValueFromAST(field.value),
37+
);
38+
case Kind.ENUM:
39+
throw new Error('Scalar value can not contain Enum.');
40+
case Kind.VARIABLE:
41+
throw new Error('Scalar value can not contain Query variable.');
42+
}
43+
}

0 commit comments

Comments
 (0)