Skip to content

Commit 6b658cf

Browse files
committed
Be more explicit about forbidding skip/include
1 parent 77d5c89 commit 6b658cf

File tree

2 files changed

+22
-24
lines changed

2 files changed

+22
-24
lines changed

src/execution/collectFields.ts

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ export function collectFields(
7878
runtimeType: GraphQLObjectType,
7979
selectionSet: SelectionSetNode,
8080
hideSuggestions: boolean,
81+
forbidSkipInclude = false,
8182
): {
8283
groupedFieldSet: GroupedFieldSet;
8384
newDeferUsages: ReadonlyArray<DeferUsage>;
@@ -95,24 +96,22 @@ export function collectFields(
9596
forbiddenDirectiveInstances: [],
9697
};
9798

98-
collectFieldsImpl(context, selectionSet, groupedFieldSet, newDeferUsages);
99+
collectFieldsImpl(
100+
context,
101+
selectionSet,
102+
groupedFieldSet,
103+
newDeferUsages,
104+
undefined,
105+
undefined,
106+
forbidSkipInclude,
107+
);
99108
return {
100109
groupedFieldSet,
101110
newDeferUsages,
102111
forbiddenDirectiveInstances: context.forbiddenDirectiveInstances,
103112
};
104113
}
105114

106-
/**
107-
* This variable is the empty variables used during the validation phase (where
108-
* no variables exist) for field collection; if a `@skip` or `@include`
109-
* directive is ever seen when `variableValues` is set to this, it should
110-
* throw.
111-
*/
112-
export const VALIDATION_PHASE_EMPTY_VARIABLES: VariableValues = Object.freeze(
113-
Object.create(null),
114-
);
115-
116115
/**
117116
* Given an array of field nodes, collects all of the subfields of the passed
118117
* in fields, and returns them at the end.
@@ -134,6 +133,7 @@ export function collectSubfields(
134133
): {
135134
groupedFieldSet: GroupedFieldSet;
136135
newDeferUsages: ReadonlyArray<DeferUsage>;
136+
forbiddenDirectiveInstances: ReadonlyArray<DirectiveNode>;
137137
} {
138138
const context: CollectFieldsContext = {
139139
schema,
@@ -177,6 +177,7 @@ function collectFieldsImpl(
177177
newDeferUsages: Array<DeferUsage>,
178178
deferUsage?: DeferUsage,
179179
fragmentVariableValues?: VariableValues,
180+
forbidSkipInclude = false,
180181
): void {
181182
const {
182183
schema,
@@ -197,6 +198,7 @@ function collectFieldsImpl(
197198
variableValues,
198199
fragmentVariableValues,
199200
hideSuggestions,
201+
forbidSkipInclude,
200202
)
201203
) {
202204
continue;
@@ -216,6 +218,7 @@ function collectFieldsImpl(
216218
variableValues,
217219
fragmentVariableValues,
218220
hideSuggestions,
221+
forbidSkipInclude,
219222
) ||
220223
!doesFragmentConditionMatch(schema, selection, runtimeType)
221224
) {
@@ -263,6 +266,7 @@ function collectFieldsImpl(
263266
variableValues,
264267
fragmentVariableValues,
265268
hideSuggestions,
269+
forbidSkipInclude,
266270
)
267271
) {
268272
continue;
@@ -364,14 +368,12 @@ function shouldIncludeNode(
364368
variableValues: VariableValues,
365369
fragmentVariableValues: VariableValues | undefined,
366370
hideSuggestions: Maybe<boolean>,
371+
forbidSkipInclude: boolean,
367372
): boolean {
368373
const skipDirectiveNode = node.directives?.find(
369374
(directive) => directive.name.value === GraphQLSkipDirective.name,
370375
);
371-
if (
372-
skipDirectiveNode &&
373-
variableValues === VALIDATION_PHASE_EMPTY_VARIABLES
374-
) {
376+
if (skipDirectiveNode && forbidSkipInclude) {
375377
context.forbiddenDirectiveInstances.push(skipDirectiveNode);
376378
return false;
377379
}
@@ -391,10 +393,7 @@ function shouldIncludeNode(
391393
const includeDirectiveNode = node.directives?.find(
392394
(directive) => directive.name.value === GraphQLIncludeDirective.name,
393395
);
394-
if (
395-
includeDirectiveNode &&
396-
variableValues === VALIDATION_PHASE_EMPTY_VARIABLES
397-
) {
396+
if (includeDirectiveNode && forbidSkipInclude) {
398397
context.forbiddenDirectiveInstances.push(includeDirectiveNode);
399398
return false;
400399
}

src/validation/rules/SingleFieldSubscriptionsRule.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@ import type {
1010
FieldDetailsList,
1111
FragmentDetails,
1212
} from '../../execution/collectFields.js';
13-
import {
14-
collectFields,
15-
VALIDATION_PHASE_EMPTY_VARIABLES,
16-
} from '../../execution/collectFields.js';
13+
import { collectFields } from '../../execution/collectFields.js';
14+
import type { VariableValues } from '../../execution/values.js';
1715

1816
import type { ValidationContext } from '../ValidationContext.js';
1917

@@ -40,7 +38,7 @@ export function SingleFieldSubscriptionsRule(
4038
const subscriptionType = schema.getSubscriptionType();
4139
if (subscriptionType) {
4240
const operationName = node.name ? node.name.value : null;
43-
const variableValues = VALIDATION_PHASE_EMPTY_VARIABLES;
41+
const variableValues: VariableValues = Object.create(null);
4442
const document = context.getDocument();
4543
const fragments: ObjMap<FragmentDetails> = Object.create(null);
4644
for (const definition of document.definitions) {
@@ -56,6 +54,7 @@ export function SingleFieldSubscriptionsRule(
5654
subscriptionType,
5755
node.selectionSet,
5856
context.hideSuggestions,
57+
true,
5958
);
6059
if (forbiddenDirectiveInstances.length > 0) {
6160
context.reportError(

0 commit comments

Comments
 (0)