Skip to content

Commit fe0ad30

Browse files
authored
Add benjie's suggested changes to schema-coordinates (#4478)
1 parent fd6ce88 commit fe0ad30

File tree

5 files changed

+110
-32
lines changed

5 files changed

+110
-32
lines changed

cspell.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ ignoreRegExpList:
4848

4949
words:
5050
- graphiql
51+
- metafield
5152
- uncoerce
5253
- uncoerced
5354

src/language/__tests__/parser-test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,60 @@ describe('Parser', () => {
790790
});
791791
});
792792

793+
it('parses __Type', () => {
794+
const result = parseSchemaCoordinate('__Type');
795+
expectJSON(result).toDeepEqual({
796+
kind: Kind.TYPE_COORDINATE,
797+
loc: { start: 0, end: 6 },
798+
name: {
799+
kind: Kind.NAME,
800+
loc: { start: 0, end: 6 },
801+
value: '__Type',
802+
},
803+
});
804+
});
805+
806+
it('parses Type.__metafield', () => {
807+
const result = parseSchemaCoordinate('Type.__metafield');
808+
expectJSON(result).toDeepEqual({
809+
kind: Kind.MEMBER_COORDINATE,
810+
loc: { start: 0, end: 16 },
811+
name: {
812+
kind: Kind.NAME,
813+
loc: { start: 0, end: 4 },
814+
value: 'Type',
815+
},
816+
memberName: {
817+
kind: Kind.NAME,
818+
loc: { start: 5, end: 16 },
819+
value: '__metafield',
820+
},
821+
});
822+
});
823+
824+
it('parses Type.__metafield(arg:)', () => {
825+
const result = parseSchemaCoordinate('Type.__metafield(arg:)');
826+
expectJSON(result).toDeepEqual({
827+
kind: Kind.ARGUMENT_COORDINATE,
828+
loc: { start: 0, end: 22 },
829+
name: {
830+
kind: Kind.NAME,
831+
loc: { start: 0, end: 4 },
832+
value: 'Type',
833+
},
834+
fieldName: {
835+
kind: Kind.NAME,
836+
loc: { start: 5, end: 16 },
837+
value: '__metafield',
838+
},
839+
argumentName: {
840+
kind: Kind.NAME,
841+
loc: { start: 17, end: 20 },
842+
value: 'arg',
843+
},
844+
});
845+
});
846+
793847
it('rejects @ Name . Name', () => {
794848
expect(() => parseSchemaCoordinate('@myDirective.field'))
795849
.to.throw()

src/language/__tests__/printer-test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,13 @@ describe('Printer: Query document', () => {
308308
);
309309
expect(print(parseSchemaCoordinate('@name'))).to.equal('@name');
310310
expect(print(parseSchemaCoordinate('@name(arg:)'))).to.equal('@name(arg:)');
311+
expect(print(parseSchemaCoordinate('__Type'))).to.equal('__Type');
312+
expect(print(parseSchemaCoordinate('Type.__metafield'))).to.equal(
313+
'Type.__metafield',
314+
);
315+
expect(print(parseSchemaCoordinate('Type.__metafield(arg:)'))).to.equal(
316+
'Type.__metafield(arg:)',
317+
);
311318
});
312319

313320
it('throws syntax error for ignored tokens in schema coordinates', () => {

src/utilities/__tests__/resolveSchemaCoordinate-test.ts

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { expect } from 'chai';
1+
import { assert, expect } from 'chai';
22
import { describe, it } from 'mocha';
33

44
import type {
@@ -12,32 +12,32 @@ import type { GraphQLDirective } from '../../type/directives.js';
1212
import { buildSchema } from '../buildASTSchema.js';
1313
import { resolveSchemaCoordinate } from '../resolveSchemaCoordinate.js';
1414

15-
describe('resolveSchemaCoordinate', () => {
16-
const schema = buildSchema(`
17-
type Query {
18-
searchBusiness(criteria: SearchCriteria!): [Business]
19-
}
20-
21-
input SearchCriteria {
22-
name: String
23-
filter: SearchFilter
24-
}
25-
26-
enum SearchFilter {
27-
OPEN_NOW
28-
DELIVERS_TAKEOUT
29-
VEGETARIAN_MENU
30-
}
31-
32-
type Business {
33-
id: ID
34-
name: String
35-
email: String @private(scope: "loggedIn")
36-
}
37-
38-
directive @private(scope: String!) on FIELD_DEFINITION
39-
`);
15+
const schema = buildSchema(`
16+
type Query {
17+
searchBusiness(criteria: SearchCriteria!): [Business]
18+
}
19+
20+
input SearchCriteria {
21+
name: String
22+
filter: SearchFilter
23+
}
24+
25+
enum SearchFilter {
26+
OPEN_NOW
27+
DELIVERS_TAKEOUT
28+
VEGETARIAN_MENU
29+
}
30+
31+
type Business {
32+
id: ID
33+
name: String
34+
email: String @private(scope: "loggedIn")
35+
}
4036
37+
directive @private(scope: String!) on FIELD_DEFINITION
38+
`);
39+
40+
describe('resolveSchemaCoordinate', () => {
4141
it('resolves a Named Type', () => {
4242
expect(resolveSchemaCoordinate(schema, 'Business')).to.deep.equal({
4343
kind: 'NamedType',
@@ -181,10 +181,20 @@ describe('resolveSchemaCoordinate', () => {
181181
'Expected "unknown" to be defined as a directive in the schema.',
182182
);
183183
});
184+
});
184185

186+
/*
187+
* NOTE: the following are not required for spec compliance; resolution
188+
* of meta-fields is implementation-defined.
189+
*
190+
* These tests are here to ensure a change of behavior will only be made
191+
* in a semver-major release of GraphQL.js.
192+
*/
193+
describe('resolveSchemaCoordinate (meta-fields and introspection types)', () => {
185194
it('resolves a meta-field', () => {
186195
const type = schema.getType('Business') as GraphQLObjectType;
187196
const field = schema.getField(type, '__typename');
197+
assert.ok(field);
188198
expect(
189199
resolveSchemaCoordinate(schema, 'Business.__typename'),
190200
).to.deep.equal({

src/utilities/resolveSchemaCoordinate.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ import type { Source } from '../language/source.js';
1414

1515
import type {
1616
GraphQLArgument,
17+
GraphQLEnumType,
1718
GraphQLEnumValue,
1819
GraphQLField,
1920
GraphQLInputField,
21+
GraphQLInputObjectType,
22+
GraphQLInterfaceType,
2023
GraphQLNamedType,
24+
GraphQLObjectType,
2125
} from '../type/definition.js';
2226
import {
2327
isEnumType,
@@ -38,25 +42,25 @@ export interface ResolvedNamedType {
3842

3943
export interface ResolvedField {
4044
readonly kind: 'Field';
41-
readonly type: GraphQLNamedType;
45+
readonly type: GraphQLObjectType | GraphQLInterfaceType;
4246
readonly field: GraphQLField<unknown, unknown>;
4347
}
4448

4549
export interface ResolvedInputField {
4650
readonly kind: 'InputField';
47-
readonly type: GraphQLNamedType;
51+
readonly type: GraphQLInputObjectType;
4852
readonly inputField: GraphQLInputField;
4953
}
5054

5155
export interface ResolvedEnumValue {
5256
readonly kind: 'EnumValue';
53-
readonly type: GraphQLNamedType;
57+
readonly type: GraphQLEnumType;
5458
readonly enumValue: GraphQLEnumValue;
5559
}
5660

5761
export interface ResolvedFieldArgument {
5862
readonly kind: 'FieldArgument';
59-
readonly type: GraphQLNamedType;
63+
readonly type: GraphQLObjectType | GraphQLInterfaceType;
6064
readonly field: GraphQLField<unknown, unknown>;
6165
readonly fieldArgument: GraphQLArgument;
6266
}
@@ -83,8 +87,10 @@ export type ResolvedSchemaElement =
8387

8488
/**
8589
* A schema coordinate is resolved in the context of a GraphQL schema to
86-
* uniquely identifies a schema element. It returns undefined if the schema
87-
* coordinate does not resolve to a schema element.
90+
* uniquely identify a schema element. It returns undefined if the schema
91+
* coordinate does not resolve to a schema element, meta-field, or introspection
92+
* schema element. It will throw if the containing schema element (if
93+
* applicable) does not exist.
8894
*
8995
* https://spec.graphql.org/draft/#sec-Schema-Coordinates.Semantics
9096
*/

0 commit comments

Comments
 (0)