Skip to content

Commit c18b33c

Browse files
committed
move validation of names into validateSchema
1 parent ef042cf commit c18b33c

File tree

11 files changed

+507
-230
lines changed

11 files changed

+507
-230
lines changed

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ export {
151151
validateSchema,
152152
assertValidSchema,
153153
// Upholds the spec rules about naming.
154+
assertHasValidName,
154155
assertName,
155156
assertEnumValueName,
156157
} from './type/index.js';

src/language/__tests__/schema-parser-test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,28 @@ describe('Schema Parser', () => {
109109
});
110110
});
111111

112+
it('parses type with reserved name', () => {
113+
const doc = parse(dedent`
114+
type __Reserved
115+
`);
116+
117+
expectJSON(doc).toDeepEqual({
118+
kind: 'Document',
119+
definitions: [
120+
{
121+
kind: 'ObjectTypeDefinition',
122+
name: nameNode('__Reserved', { start: 5, end: 15 }),
123+
description: undefined,
124+
interfaces: undefined,
125+
directives: undefined,
126+
fields: undefined,
127+
loc: { start: 0, end: 15 },
128+
},
129+
],
130+
loc: { start: 0, end: 15 },
131+
});
132+
});
133+
112134
it('parses type with description string', () => {
113135
const doc = parse(dedent`
114136
"Description"
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { expect } from 'chai';
2+
import { describe, it } from 'mocha';
3+
4+
import { assertHasValidName } from '../assertHasValidName.js';
5+
import type { GraphQLEnumValue } from '../index.js';
6+
import { __Type, GraphQLEnumType, GraphQLObjectType } from '../index.js';
7+
8+
describe(assertHasValidName.name, () => {
9+
it('passthrough valid name', () => {
10+
expect(
11+
assertHasValidName(
12+
new GraphQLObjectType({
13+
name: '_ValidName123',
14+
fields: {},
15+
}),
16+
),
17+
).to.equal('_ValidName123');
18+
});
19+
20+
it('throws on empty strings', () => {
21+
expect(() =>
22+
assertHasValidName(
23+
new GraphQLObjectType({
24+
name: '',
25+
fields: {},
26+
}),
27+
),
28+
).to.throw('Expected name of type "" to be a non-empty string.');
29+
});
30+
31+
it('throws for names with invalid characters', () => {
32+
expect(() =>
33+
assertHasValidName(
34+
new GraphQLObjectType({
35+
name: 'Some-Object',
36+
fields: {},
37+
}),
38+
),
39+
).to.throw('Name of type "Some-Object" must only contain [_a-zA-Z0-9].');
40+
});
41+
42+
it('throws for names starting with invalid characters', () => {
43+
expect(() =>
44+
assertHasValidName(
45+
new GraphQLObjectType({
46+
name: '1_ObjectType',
47+
fields: {},
48+
}),
49+
),
50+
).to.throw('Name of type "1_ObjectType" must start with [_a-zA-Z].');
51+
});
52+
53+
it('throws for reserved names', () => {
54+
expect(() =>
55+
assertHasValidName(
56+
new GraphQLObjectType({
57+
name: '__SomeObject',
58+
fields: {},
59+
}),
60+
),
61+
).to.throw(
62+
'Name of type "__SomeObject" must not begin with "__", which is reserved by GraphQL introspection.',
63+
);
64+
});
65+
66+
it('allows reserved names when specified', () => {
67+
expect(assertHasValidName(__Type, true)).to.equal('__Type');
68+
});
69+
70+
it('throws for reserved names in enum values', () => {
71+
const someEnum = new GraphQLEnumType({
72+
name: 'SomeEnum',
73+
values: {
74+
true: {},
75+
},
76+
});
77+
const value = someEnum.getValue('true') as GraphQLEnumValue;
78+
expect(() => assertHasValidName(value)).to.throw(
79+
'Name "true" of enum value "SomeEnum.true" cannot be: true.',
80+
);
81+
});
82+
});

src/type/__tests__/definition-test.ts

Lines changed: 0 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -414,52 +414,6 @@ describe('Type System: Objects', () => {
414414
});
415415
expect(() => objType.getFields()).to.not.throw();
416416
});
417-
418-
it('rejects an Object type with invalid name', () => {
419-
expect(
420-
() => new GraphQLObjectType({ name: 'bad-name', fields: {} }),
421-
).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.');
422-
});
423-
424-
it('rejects an Object type with incorrectly named fields', () => {
425-
const objType = new GraphQLObjectType({
426-
name: 'SomeObject',
427-
fields: {
428-
'bad-name': { type: ScalarType },
429-
},
430-
});
431-
expect(() => objType.getFields()).to.throw(
432-
'Names must only contain [_a-zA-Z0-9] but "bad-name" does not.',
433-
);
434-
});
435-
436-
it('rejects an Object type with a field function that returns incorrect type', () => {
437-
const objType = new GraphQLObjectType({
438-
name: 'SomeObject',
439-
// @ts-expect-error (Wrong type of return)
440-
fields() {
441-
return [{ field: ScalarType }];
442-
},
443-
});
444-
expect(() => objType.getFields()).to.throw();
445-
});
446-
447-
it('rejects an Object type with incorrectly named field args', () => {
448-
const objType = new GraphQLObjectType({
449-
name: 'SomeObject',
450-
fields: {
451-
badField: {
452-
type: ScalarType,
453-
args: {
454-
'bad-name': { type: ScalarType },
455-
},
456-
},
457-
},
458-
});
459-
expect(() => objType.getFields()).to.throw(
460-
'Names must only contain [_a-zA-Z0-9] but "bad-name" does not.',
461-
);
462-
});
463417
});
464418

465419
describe('Type System: Interfaces', () => {
@@ -563,12 +517,6 @@ describe('Type System: Interfaces', () => {
563517
});
564518
expect(implementing.getInterfaces()).to.deep.equal([InterfaceType]);
565519
});
566-
567-
it('rejects an Interface type with invalid name', () => {
568-
expect(
569-
() => new GraphQLInterfaceType({ name: 'bad-name', fields: {} }),
570-
).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.');
571-
});
572520
});
573521

574522
describe('Type System: Unions', () => {
@@ -635,12 +583,6 @@ describe('Type System: Unions', () => {
635583
});
636584
expect(unionType.getTypes()).to.deep.equal([]);
637585
});
638-
639-
it('rejects an Union type with invalid name', () => {
640-
expect(
641-
() => new GraphQLUnionType({ name: 'bad-name', types: [] }),
642-
).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.');
643-
});
644586
});
645587

646588
describe('Type System: Enums', () => {
@@ -786,24 +728,6 @@ describe('Type System: Enums', () => {
786728
expect(enumType.getValue('FOO')).has.property('value', 10);
787729
expect(enumType.getValue('BAR')).has.property('value', 20);
788730
});
789-
790-
it('rejects an Enum type with invalid name', () => {
791-
expect(
792-
() => new GraphQLEnumType({ name: 'bad-name', values: {} }),
793-
).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.');
794-
});
795-
796-
it('rejects an Enum type with incorrectly named values', () => {
797-
expect(
798-
() =>
799-
new GraphQLEnumType({
800-
name: 'SomeEnum',
801-
values: {
802-
'bad-name': {},
803-
},
804-
}),
805-
).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.');
806-
});
807731
});
808732

809733
describe('Type System: Input Objects', () => {
@@ -887,26 +811,6 @@ describe('Type System: Input Objects', () => {
887811
astNode: undefined,
888812
});
889813
});
890-
891-
it('rejects an Input Object type with invalid name', () => {
892-
expect(
893-
() => new GraphQLInputObjectType({ name: 'bad-name', fields: {} }),
894-
).to.throw(
895-
'Names must only contain [_a-zA-Z0-9] but "bad-name" does not.',
896-
);
897-
});
898-
899-
it('rejects an Input Object type with incorrectly named fields', () => {
900-
const inputObjType = new GraphQLInputObjectType({
901-
name: 'SomeInputObject',
902-
fields: {
903-
'bad-name': { type: ScalarType },
904-
},
905-
});
906-
expect(() => inputObjType.getFields()).to.throw(
907-
'Names must only contain [_a-zA-Z0-9] but "bad-name" does not.',
908-
);
909-
});
910814
});
911815

912816
it('Deprecation reason is preserved on fields', () => {

src/type/__tests__/directive-test.ts

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -91,27 +91,4 @@ describe('Type System: Directive', () => {
9191
'[object GraphQLDirective]',
9292
);
9393
});
94-
95-
it('rejects a directive with invalid name', () => {
96-
expect(
97-
() =>
98-
new GraphQLDirective({
99-
name: 'bad-name',
100-
locations: [DirectiveLocation.QUERY],
101-
}),
102-
).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.');
103-
});
104-
105-
it('rejects a directive with incorrectly named arg', () => {
106-
expect(
107-
() =>
108-
new GraphQLDirective({
109-
name: 'Foo',
110-
locations: [DirectiveLocation.QUERY],
111-
args: {
112-
'bad-name': { type: GraphQLString },
113-
},
114-
}),
115-
).to.throw('Names must only contain [_a-zA-Z0-9] but "bad-name" does not.');
116-
});
11794
});

0 commit comments

Comments
 (0)