Skip to content

Commit 3490960

Browse files
committed
Add 'getDefinitionsMap' to 'ASTValidationContext'
1 parent 51eda7b commit 3490960

File tree

4 files changed

+47
-53
lines changed

4 files changed

+47
-53
lines changed

src/validation/ValidationContext.js

+27-13
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,19 +52,29 @@ type VariableUsage = {|
4652
export class ASTValidationContext {
4753
_ast: DocumentNode;
4854
_errors: Array<GraphQLError>;
49-
_fragments: ?ObjMap<FragmentDefinitionNode>;
55+
_fragments: ObjMap<FragmentDefinitionNode>;
5056
_fragmentSpreads: Map<SelectionSetNode, $ReadOnlyArray<FragmentSpreadNode>>;
5157
_recursivelyReferencedFragments: Map<
5258
OperationDefinitionNode,
5359
$ReadOnlyArray<FragmentDefinitionNode>,
5460
>;
61+
_defsByKind: KindToNodesMap;
5562

5663
constructor(ast: DocumentNode): void {
5764
this._ast = ast;
5865
this._errors = [];
59-
this._fragments = undefined;
6066
this._fragmentSpreads = new Map();
6167
this._recursivelyReferencedFragments = new Map();
68+
69+
const defsByKind = Object.create(null);
70+
for (const node of ast.definitions) {
71+
if (defsByKind[node.kind]) {
72+
defsByKind[node.kind].push(node);
73+
} else {
74+
defsByKind[node.kind] = [node];
75+
}
76+
}
77+
this._defsByKind = defsByKind;
6278
}
6379

6480
reportError(error: GraphQLError): void {
@@ -73,20 +89,18 @@ export class ASTValidationContext {
7389
return this._ast;
7490
}
7591

92+
getDefinitionsMap(): KindToNodesMap {
93+
return this._defsByKind;
94+
}
95+
7696
getFragment(name: string): ?FragmentDefinitionNode {
77-
let fragments = this._fragments;
78-
if (!fragments) {
79-
this._fragments = fragments = this.getDocument().definitions.reduce(
80-
(frags, statement) => {
81-
if (statement.kind === Kind.FRAGMENT_DEFINITION) {
82-
frags[statement.name.value] = statement;
83-
}
84-
return frags;
85-
},
86-
Object.create(null),
97+
if (!this._fragments) {
98+
this._fragments = keyMap(
99+
this.getDefinitionsMap().FragmentDefinition || [],
100+
def => def.name.value,
87101
);
88102
}
89-
return fragments[name];
103+
return this._fragments[name];
90104
}
91105

92106
getFragmentSpreads(

src/validation/rules/KnownDirectives.js

+3-5
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,9 @@ export function KnownDirectives(
4747
locationsMap[directive.name] = directive.locations;
4848
}
4949

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

5755
return {

src/validation/rules/LoneAnonymousOperation.js

+2-7
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

+15-28
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: ASTValidationContext): 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)