graphql
Version:
A Query Language and Runtime which can target any service.
123 lines • 4.92 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DeferStreamDirectiveOnValidOperationsRule = DeferStreamDirectiveOnValidOperationsRule;
const GraphQLError_ts_1 = require("../../error/GraphQLError.js");
const ast_ts_1 = require("../../language/ast.js");
const kinds_ts_1 = require("../../language/kinds.js");
const directives_ts_1 = require("../../type/directives.js");
function ifArgumentCanBeFalse(node) {
const ifArgument = node.arguments?.find((arg) => arg.name.value === 'if');
if (!ifArgument) {
return false;
}
if (ifArgument.value.kind === kinds_ts_1.Kind.BOOLEAN) {
if (ifArgument.value.value) {
return false;
}
}
else if (ifArgument.value.kind !== kinds_ts_1.Kind.VARIABLE) {
return false;
}
return true;
}
function canBeSkippedViaSkipDirective(node) {
const ifArgument = node.arguments?.find((arg) => arg.name.value === 'if');
if (!ifArgument) {
return true;
}
if (ifArgument.value.kind === kinds_ts_1.Kind.BOOLEAN) {
if (ifArgument.value.value) {
return true;
}
return false;
}
return true;
}
function canBeSkippedViaIncludeDirective(node) {
const ifArgument = node.arguments?.find((arg) => arg.name.value === 'if');
if (!ifArgument) {
return false;
}
if (ifArgument?.value.kind === kinds_ts_1.Kind.BOOLEAN) {
if (ifArgument.value.value) {
return false;
}
return true;
}
return true;
}
function DeferStreamDirectiveOnValidOperationsRule(context) {
return {
OperationDefinition(operation) {
if (operation.operation !== ast_ts_1.OperationTypeNode.SUBSCRIPTION) {
return;
}
const document = context.getDocument();
const fragments = new Map();
for (const definition of document.definitions) {
if (definition.kind === kinds_ts_1.Kind.FRAGMENT_DEFINITION) {
fragments.set(definition.name.value, definition);
}
}
const visitedFragments = new Set();
forbidUnconditionalDeferStream({
context,
fragments,
selectionSet: operation.selectionSet,
parentNodes: [],
visitedFragments,
});
},
};
}
function forbidUnconditionalDeferStream({ context, fragments, selectionSet, parentNodes, visitedFragments, }) {
for (const selection of selectionSet.selections) {
const skip = selection.directives?.find((d) => d.name.value === directives_ts_1.GraphQLSkipDirective.name);
if (skip && canBeSkippedViaSkipDirective(skip)) {
continue;
}
const include = selection.directives?.find((d) => d.name.value === directives_ts_1.GraphQLIncludeDirective.name);
if (include && canBeSkippedViaIncludeDirective(include)) {
continue;
}
for (const directive of selection.directives ?? []) {
if (directive.name.value === directives_ts_1.GraphQLDeferDirective.name) {
if (!ifArgumentCanBeFalse(directive)) {
context.reportError(new GraphQLError_ts_1.GraphQLError('Defer directive not supported on subscription operations. Disable `@defer` by setting the `if` argument to `false`.', { nodes: [directive, ...parentNodes] }));
}
}
else if (directive.name.value === directives_ts_1.GraphQLStreamDirective.name) {
if (!ifArgumentCanBeFalse(directive)) {
context.reportError(new GraphQLError_ts_1.GraphQLError('Stream directive not supported on subscription operations. Disable `@stream` by setting the `if` argument to `false`.', { nodes: [directive, ...parentNodes] }));
}
}
}
if (selection.kind === 'FragmentSpread') {
const fragmentName = selection.name.value;
if (visitedFragments.has(fragmentName)) {
continue;
}
visitedFragments.add(fragmentName);
const fragment = fragments.get(fragmentName);
if (fragment) {
forbidUnconditionalDeferStream({
context,
fragments,
parentNodes: [selection, ...parentNodes],
selectionSet: fragment?.selectionSet,
visitedFragments,
});
}
}
else if (selection.selectionSet) {
forbidUnconditionalDeferStream({
context,
fragments,
selectionSet: selection.selectionSet,
parentNodes,
visitedFragments,
});
}
}
}
//# sourceMappingURL=DeferStreamDirectiveOnValidOperationsRule.js.map