Skip to content

Commit 62bcd86

Browse files
committed
Add 'getDefinitionsMap' to 'ASTValidationContext'
1 parent 06b246f commit 62bcd86

File tree

4 files changed

+47
-53
lines changed

4 files changed

+47
-53
lines changed

src/validation/ValidationContext.js

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77
* @flow strict
88
*/
99

10+
import keyMap from '../jsutils/keyMap';
1011
import type { ObjMap } from '../jsutils/ObjMap';
1112
import type { GraphQLError } from '../error';
1213
import { visit, visitWithTypeInfo } from '../language/visitor';
1314
import { Kind } from '../language/kinds';
1415
import type {
16+
ASTKindToNode,
1517
DocumentNode,
1618
OperationDefinitionNode,
1719
VariableNode,
@@ -38,6 +40,10 @@ type VariableUsage = {|
3840
+defaultValue: ?mixed,
3941
|};
4042

43+
type KindToNodesMap = $Shape<
44+
$ObjMap<ASTKindToNode, <Node>(Node) => ?Array<Node>>,
45+
>;
46+
4147
/**
4248
* An instance of this class is passed as the "this" context to all validators,
4349
* allowing access to commonly useful contextual information from within a
@@ -46,10 +52,21 @@ type VariableUsage = {|
4652
export class ASTValidationContext {
4753
_ast: DocumentNode;
4854
_errors: Array<GraphQLError>;
55+
_defsByKind: KindToNodesMap;
4956

5057
constructor(ast: DocumentNode): void {
5158
this._ast = ast;
5259
this._errors = [];
60+
61+
const defsByKind = Object.create(null);
62+
for (const node of ast.definitions) {
63+
if (defsByKind[node.kind]) {
64+
defsByKind[node.kind].push(node);
65+
} else {
66+
defsByKind[node.kind] = [node];
67+
}
68+
}
69+
this._defsByKind = defsByKind;
5370
}
5471

5572
reportError(error: GraphQLError): void {
@@ -63,6 +80,10 @@ export class ASTValidationContext {
6380
getDocument(): DocumentNode {
6481
return this._ast;
6582
}
83+
84+
getDefinitionsMap(): KindToNodesMap {
85+
return this._defsByKind;
86+
}
6687
}
6788

6889
export class SDLValidationContext extends ASTValidationContext {
@@ -107,26 +128,18 @@ export class ValidationContext extends ASTValidationContext {
107128
this._recursivelyReferencedFragments = new Map();
108129
this._variableUsages = new Map();
109130
this._recursiveVariableUsages = new Map();
131+
this._fragments = keyMap(
132+
this.getDefinitionsMap().FragmentDefinition || [],
133+
def => def.name.value,
134+
);
110135
}
111136

112137
getSchema(): GraphQLSchema {
113138
return this._schema;
114139
}
115140

116141
getFragment(name: string): ?FragmentDefinitionNode {
117-
let fragments = this._fragments;
118-
if (!fragments) {
119-
this._fragments = fragments = this.getDocument().definitions.reduce(
120-
(frags, statement) => {
121-
if (statement.kind === Kind.FRAGMENT_DEFINITION) {
122-
frags[statement.name.value] = statement;
123-
}
124-
return frags;
125-
},
126-
Object.create(null),
127-
);
128-
}
129-
return fragments[name];
142+
return this._fragments[name];
130143
}
131144

132145
getFragmentSpreads(

src/validation/rules/KnownDirectives.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export function KnownDirectives(
3838
context: ValidationContext | SDLValidationContext,
3939
): ASTVisitor {
4040
const locationsMap = Object.create(null);
41+
4142
const schema = context.getSchema();
4243
const definedDirectives = schema
4344
? schema.getDirectives()
@@ -46,11 +47,9 @@ export function KnownDirectives(
4647
locationsMap[directive.name] = directive.locations;
4748
}
4849

49-
const astDefinitions = context.getDocument().definitions;
50-
for (const def of astDefinitions) {
51-
if (def.kind === Kind.DIRECTIVE_DEFINITION) {
52-
locationsMap[def.name.value] = def.locations.map(name => name.value);
53-
}
50+
const defNodes = context.getDefinitionsMap().DirectiveDefinition || [];
51+
for (const node of defNodes) {
52+
locationsMap[node.name.value] = node.locations.map(name => name.value);
5453
}
5554

5655
return {

src/validation/rules/LoneAnonymousOperation.js

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
import type { ASTValidationContext } from '../ValidationContext';
1111
import { GraphQLError } from '../../error/GraphQLError';
12-
import { Kind } from '../../language/kinds';
1312
import type { ASTVisitor } from '../../language/visitor';
1413

1514
export function anonOperationNotAloneMessage(): string {
@@ -25,13 +24,9 @@ export function anonOperationNotAloneMessage(): string {
2524
export function LoneAnonymousOperation(
2625
context: ASTValidationContext,
2726
): ASTVisitor {
28-
let operationCount = 0;
27+
const operationDefs = context.getDefinitionsMap().OperationDefinition;
28+
const operationCount = operationDefs ? operationDefs.length : 0;
2929
return {
30-
Document(node) {
31-
operationCount = node.definitions.filter(
32-
definition => definition.kind === Kind.OPERATION_DEFINITION,
33-
).length;
34-
},
3530
OperationDefinition(node) {
3631
if (!node.name && operationCount > 1) {
3732
context.reportError(

src/validation/rules/NoUnusedFragments.js

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -22,38 +22,25 @@ export function unusedFragMessage(fragName: string): string {
2222
* within operations, or spread within other fragments spread within operations.
2323
*/
2424
export function NoUnusedFragments(context: ValidationContext): ASTVisitor {
25-
const operationDefs = [];
26-
const fragmentDefs = [];
25+
const fragmentNameUsed = Object.create(null);
26+
const operationDefs = context.getDefinitionsMap().OperationDefinition || [];
27+
for (const operation of operationDefs) {
28+
for (const fragment of context.getRecursivelyReferencedFragments(
29+
operation,
30+
)) {
31+
fragmentNameUsed[fragment.name.value] = true;
32+
}
33+
}
2734

2835
return {
29-
OperationDefinition(node) {
30-
operationDefs.push(node);
31-
return false;
32-
},
3336
FragmentDefinition(node) {
34-
fragmentDefs.push(node);
37+
const fragName = node.name.value;
38+
if (fragmentNameUsed[fragName] !== true) {
39+
context.reportError(
40+
new GraphQLError(unusedFragMessage(fragName), [node]),
41+
);
42+
}
3543
return false;
3644
},
37-
Document: {
38-
leave() {
39-
const fragmentNameUsed = Object.create(null);
40-
for (const operation of operationDefs) {
41-
for (const fragment of context.getRecursivelyReferencedFragments(
42-
operation,
43-
)) {
44-
fragmentNameUsed[fragment.name.value] = true;
45-
}
46-
}
47-
48-
for (const fragmentDef of fragmentDefs) {
49-
const fragName = fragmentDef.name.value;
50-
if (fragmentNameUsed[fragName] !== true) {
51-
context.reportError(
52-
new GraphQLError(unusedFragMessage(fragName), [fragmentDef]),
53-
);
54-
}
55-
}
56-
},
57-
},
5845
};
5946
}

0 commit comments

Comments
 (0)