Project files

This commit is contained in:
2023-11-09 18:47:11 +01:00
parent 695abe054b
commit c415135aae
8554 changed files with 858111 additions and 0 deletions

View File

@@ -0,0 +1,98 @@
import { Maybe } from '../jsutils/Maybe';
import { GraphQLError } from '../error/GraphQLError';
import { ASTVisitor } from '../language/visitor';
import {
DocumentNode,
OperationDefinitionNode,
VariableNode,
SelectionSetNode,
FragmentSpreadNode,
FragmentDefinitionNode,
} from '../language/ast';
import { GraphQLSchema } from '../type/schema';
import { GraphQLDirective } from '../type/directives';
import {
GraphQLInputType,
GraphQLOutputType,
GraphQLCompositeType,
GraphQLField,
GraphQLArgument,
GraphQLEnumValue,
} from '../type/definition';
import { TypeInfo } from '../utilities/TypeInfo';
type NodeWithSelectionSet = OperationDefinitionNode | FragmentDefinitionNode;
interface VariableUsage {
readonly node: VariableNode;
readonly type: Maybe<GraphQLInputType>;
readonly defaultValue: Maybe<any>;
}
/**
* An instance of this class is passed as the "this" context to all validators,
* allowing access to commonly useful contextual information from within a
* validation rule.
*/
export class ASTValidationContext {
constructor(ast: DocumentNode, onError: (err: GraphQLError) => void);
reportError(error: GraphQLError): undefined;
getDocument(): DocumentNode;
getFragment(name: string): Maybe<FragmentDefinitionNode>;
getFragmentSpreads(node: SelectionSetNode): ReadonlyArray<FragmentSpreadNode>;
getRecursivelyReferencedFragments(
operation: OperationDefinitionNode,
): ReadonlyArray<FragmentDefinitionNode>;
}
export class SDLValidationContext extends ASTValidationContext {
constructor(
ast: DocumentNode,
schema: Maybe<GraphQLSchema>,
onError: (err: GraphQLError) => void,
);
getSchema(): Maybe<GraphQLSchema>;
}
export type SDLValidationRule = (context: SDLValidationContext) => ASTVisitor;
export class ValidationContext extends ASTValidationContext {
constructor(
schema: GraphQLSchema,
ast: DocumentNode,
typeInfo: TypeInfo,
onError: (err: GraphQLError) => void,
);
getSchema(): GraphQLSchema;
getVariableUsages(node: NodeWithSelectionSet): ReadonlyArray<VariableUsage>;
getRecursivelyReferencedFragments(
operation: OperationDefinitionNode,
): ReadonlyArray<FragmentDefinitionNode>;
getType(): Maybe<GraphQLOutputType>;
getParentType(): Maybe<GraphQLCompositeType>;
getInputType(): Maybe<GraphQLInputType>;
getParentInputType(): Maybe<GraphQLInputType>;
getFieldDef(): Maybe<GraphQLField<any, any>>;
getDirective(): Maybe<GraphQLDirective>;
getArgument(): Maybe<GraphQLArgument>;
getEnumValue(): Maybe<GraphQLEnumValue>;
}
export type ValidationRule = (context: ValidationContext) => ASTVisitor;

View File

@@ -0,0 +1,241 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ValidationContext = exports.SDLValidationContext = exports.ASTValidationContext = void 0;
var _kinds = require("../language/kinds.js");
var _visitor = require("../language/visitor.js");
var _TypeInfo = require("../utilities/TypeInfo.js");
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
/**
* An instance of this class is passed as the "this" context to all validators,
* allowing access to commonly useful contextual information from within a
* validation rule.
*/
var ASTValidationContext = /*#__PURE__*/function () {
function ASTValidationContext(ast, onError) {
this._ast = ast;
this._fragments = undefined;
this._fragmentSpreads = new Map();
this._recursivelyReferencedFragments = new Map();
this._onError = onError;
}
var _proto = ASTValidationContext.prototype;
_proto.reportError = function reportError(error) {
this._onError(error);
};
_proto.getDocument = function getDocument() {
return this._ast;
};
_proto.getFragment = function getFragment(name) {
var fragments = this._fragments;
if (!fragments) {
this._fragments = fragments = this.getDocument().definitions.reduce(function (frags, statement) {
if (statement.kind === _kinds.Kind.FRAGMENT_DEFINITION) {
frags[statement.name.value] = statement;
}
return frags;
}, Object.create(null));
}
return fragments[name];
};
_proto.getFragmentSpreads = function getFragmentSpreads(node) {
var spreads = this._fragmentSpreads.get(node);
if (!spreads) {
spreads = [];
var setsToVisit = [node];
while (setsToVisit.length !== 0) {
var set = setsToVisit.pop();
for (var _i2 = 0, _set$selections2 = set.selections; _i2 < _set$selections2.length; _i2++) {
var selection = _set$selections2[_i2];
if (selection.kind === _kinds.Kind.FRAGMENT_SPREAD) {
spreads.push(selection);
} else if (selection.selectionSet) {
setsToVisit.push(selection.selectionSet);
}
}
}
this._fragmentSpreads.set(node, spreads);
}
return spreads;
};
_proto.getRecursivelyReferencedFragments = function getRecursivelyReferencedFragments(operation) {
var fragments = this._recursivelyReferencedFragments.get(operation);
if (!fragments) {
fragments = [];
var collectedNames = Object.create(null);
var nodesToVisit = [operation.selectionSet];
while (nodesToVisit.length !== 0) {
var node = nodesToVisit.pop();
for (var _i4 = 0, _this$getFragmentSpre2 = this.getFragmentSpreads(node); _i4 < _this$getFragmentSpre2.length; _i4++) {
var spread = _this$getFragmentSpre2[_i4];
var fragName = spread.name.value;
if (collectedNames[fragName] !== true) {
collectedNames[fragName] = true;
var fragment = this.getFragment(fragName);
if (fragment) {
fragments.push(fragment);
nodesToVisit.push(fragment.selectionSet);
}
}
}
}
this._recursivelyReferencedFragments.set(operation, fragments);
}
return fragments;
};
return ASTValidationContext;
}();
exports.ASTValidationContext = ASTValidationContext;
var SDLValidationContext = /*#__PURE__*/function (_ASTValidationContext) {
_inheritsLoose(SDLValidationContext, _ASTValidationContext);
function SDLValidationContext(ast, schema, onError) {
var _this;
_this = _ASTValidationContext.call(this, ast, onError) || this;
_this._schema = schema;
return _this;
}
var _proto2 = SDLValidationContext.prototype;
_proto2.getSchema = function getSchema() {
return this._schema;
};
return SDLValidationContext;
}(ASTValidationContext);
exports.SDLValidationContext = SDLValidationContext;
var ValidationContext = /*#__PURE__*/function (_ASTValidationContext2) {
_inheritsLoose(ValidationContext, _ASTValidationContext2);
function ValidationContext(schema, ast, typeInfo, onError) {
var _this2;
_this2 = _ASTValidationContext2.call(this, ast, onError) || this;
_this2._schema = schema;
_this2._typeInfo = typeInfo;
_this2._variableUsages = new Map();
_this2._recursiveVariableUsages = new Map();
return _this2;
}
var _proto3 = ValidationContext.prototype;
_proto3.getSchema = function getSchema() {
return this._schema;
};
_proto3.getVariableUsages = function getVariableUsages(node) {
var usages = this._variableUsages.get(node);
if (!usages) {
var newUsages = [];
var typeInfo = new _TypeInfo.TypeInfo(this._schema);
(0, _visitor.visit)(node, (0, _TypeInfo.visitWithTypeInfo)(typeInfo, {
VariableDefinition: function VariableDefinition() {
return false;
},
Variable: function Variable(variable) {
newUsages.push({
node: variable,
type: typeInfo.getInputType(),
defaultValue: typeInfo.getDefaultValue()
});
}
}));
usages = newUsages;
this._variableUsages.set(node, usages);
}
return usages;
};
_proto3.getRecursiveVariableUsages = function getRecursiveVariableUsages(operation) {
var usages = this._recursiveVariableUsages.get(operation);
if (!usages) {
usages = this.getVariableUsages(operation);
for (var _i6 = 0, _this$getRecursivelyR2 = this.getRecursivelyReferencedFragments(operation); _i6 < _this$getRecursivelyR2.length; _i6++) {
var frag = _this$getRecursivelyR2[_i6];
usages = usages.concat(this.getVariableUsages(frag));
}
this._recursiveVariableUsages.set(operation, usages);
}
return usages;
};
_proto3.getType = function getType() {
return this._typeInfo.getType();
};
_proto3.getParentType = function getParentType() {
return this._typeInfo.getParentType();
};
_proto3.getInputType = function getInputType() {
return this._typeInfo.getInputType();
};
_proto3.getParentInputType = function getParentInputType() {
return this._typeInfo.getParentInputType();
};
_proto3.getFieldDef = function getFieldDef() {
return this._typeInfo.getFieldDef();
};
_proto3.getDirective = function getDirective() {
return this._typeInfo.getDirective();
};
_proto3.getArgument = function getArgument() {
return this._typeInfo.getArgument();
};
_proto3.getEnumValue = function getEnumValue() {
return this._typeInfo.getEnumValue();
};
return ValidationContext;
}(ASTValidationContext);
exports.ValidationContext = ValidationContext;

View File

@@ -0,0 +1,254 @@
// @flow strict
import type { ObjMap } from '../jsutils/ObjMap';
import type { GraphQLError } from '../error/GraphQLError';
import type { ASTVisitor } from '../language/visitor';
import type {
DocumentNode,
OperationDefinitionNode,
VariableNode,
SelectionSetNode,
FragmentSpreadNode,
FragmentDefinitionNode,
} from '../language/ast';
import { Kind } from '../language/kinds';
import { visit } from '../language/visitor';
import type { GraphQLSchema } from '../type/schema';
import type { GraphQLDirective } from '../type/directives';
import type {
GraphQLInputType,
GraphQLOutputType,
GraphQLCompositeType,
GraphQLField,
GraphQLArgument,
GraphQLEnumValue,
} from '../type/definition';
import { TypeInfo, visitWithTypeInfo } from '../utilities/TypeInfo';
type NodeWithSelectionSet = OperationDefinitionNode | FragmentDefinitionNode;
type VariableUsage = {|
+node: VariableNode,
+type: ?GraphQLInputType,
+defaultValue: ?mixed,
|};
/**
* An instance of this class is passed as the "this" context to all validators,
* allowing access to commonly useful contextual information from within a
* validation rule.
*/
export class ASTValidationContext {
_ast: DocumentNode;
_onError: (err: GraphQLError) => void;
_fragments: ?ObjMap<FragmentDefinitionNode>;
_fragmentSpreads: Map<SelectionSetNode, $ReadOnlyArray<FragmentSpreadNode>>;
_recursivelyReferencedFragments: Map<
OperationDefinitionNode,
$ReadOnlyArray<FragmentDefinitionNode>,
>;
constructor(ast: DocumentNode, onError: (err: GraphQLError) => void) {
this._ast = ast;
this._fragments = undefined;
this._fragmentSpreads = new Map();
this._recursivelyReferencedFragments = new Map();
this._onError = onError;
}
reportError(error: GraphQLError): void {
this._onError(error);
}
getDocument(): DocumentNode {
return this._ast;
}
getFragment(name: string): ?FragmentDefinitionNode {
let fragments = this._fragments;
if (!fragments) {
this._fragments = fragments = this.getDocument().definitions.reduce(
(frags, statement) => {
if (statement.kind === Kind.FRAGMENT_DEFINITION) {
frags[statement.name.value] = statement;
}
return frags;
},
Object.create(null),
);
}
return fragments[name];
}
getFragmentSpreads(
node: SelectionSetNode,
): $ReadOnlyArray<FragmentSpreadNode> {
let spreads = this._fragmentSpreads.get(node);
if (!spreads) {
spreads = [];
const setsToVisit: Array<SelectionSetNode> = [node];
while (setsToVisit.length !== 0) {
const set = setsToVisit.pop();
for (const selection of set.selections) {
if (selection.kind === Kind.FRAGMENT_SPREAD) {
spreads.push(selection);
} else if (selection.selectionSet) {
setsToVisit.push(selection.selectionSet);
}
}
}
this._fragmentSpreads.set(node, spreads);
}
return spreads;
}
getRecursivelyReferencedFragments(
operation: OperationDefinitionNode,
): $ReadOnlyArray<FragmentDefinitionNode> {
let fragments = this._recursivelyReferencedFragments.get(operation);
if (!fragments) {
fragments = [];
const collectedNames = Object.create(null);
const nodesToVisit: Array<SelectionSetNode> = [operation.selectionSet];
while (nodesToVisit.length !== 0) {
const node = nodesToVisit.pop();
for (const spread of this.getFragmentSpreads(node)) {
const fragName = spread.name.value;
if (collectedNames[fragName] !== true) {
collectedNames[fragName] = true;
const fragment = this.getFragment(fragName);
if (fragment) {
fragments.push(fragment);
nodesToVisit.push(fragment.selectionSet);
}
}
}
}
this._recursivelyReferencedFragments.set(operation, fragments);
}
return fragments;
}
}
export type ASTValidationRule = (ASTValidationContext) => ASTVisitor;
export class SDLValidationContext extends ASTValidationContext {
_schema: ?GraphQLSchema;
constructor(
ast: DocumentNode,
schema: ?GraphQLSchema,
onError: (err: GraphQLError) => void,
) {
super(ast, onError);
this._schema = schema;
}
getSchema(): ?GraphQLSchema {
return this._schema;
}
}
export type SDLValidationRule = (SDLValidationContext) => ASTVisitor;
export class ValidationContext extends ASTValidationContext {
_schema: GraphQLSchema;
_typeInfo: TypeInfo;
_variableUsages: Map<NodeWithSelectionSet, $ReadOnlyArray<VariableUsage>>;
_recursiveVariableUsages: Map<
OperationDefinitionNode,
$ReadOnlyArray<VariableUsage>,
>;
constructor(
schema: GraphQLSchema,
ast: DocumentNode,
typeInfo: TypeInfo,
onError: (err: GraphQLError) => void,
) {
super(ast, onError);
this._schema = schema;
this._typeInfo = typeInfo;
this._variableUsages = new Map();
this._recursiveVariableUsages = new Map();
}
getSchema(): GraphQLSchema {
return this._schema;
}
getVariableUsages(node: NodeWithSelectionSet): $ReadOnlyArray<VariableUsage> {
let usages = this._variableUsages.get(node);
if (!usages) {
const newUsages = [];
const typeInfo = new TypeInfo(this._schema);
visit(
node,
visitWithTypeInfo(typeInfo, {
VariableDefinition: () => false,
Variable(variable) {
newUsages.push({
node: variable,
type: typeInfo.getInputType(),
defaultValue: typeInfo.getDefaultValue(),
});
},
}),
);
usages = newUsages;
this._variableUsages.set(node, usages);
}
return usages;
}
getRecursiveVariableUsages(
operation: OperationDefinitionNode,
): $ReadOnlyArray<VariableUsage> {
let usages = this._recursiveVariableUsages.get(operation);
if (!usages) {
usages = this.getVariableUsages(operation);
for (const frag of this.getRecursivelyReferencedFragments(operation)) {
usages = usages.concat(this.getVariableUsages(frag));
}
this._recursiveVariableUsages.set(operation, usages);
}
return usages;
}
getType(): ?GraphQLOutputType {
return this._typeInfo.getType();
}
getParentType(): ?GraphQLCompositeType {
return this._typeInfo.getParentType();
}
getInputType(): ?GraphQLInputType {
return this._typeInfo.getInputType();
}
getParentInputType(): ?GraphQLInputType {
return this._typeInfo.getParentInputType();
}
getFieldDef(): ?GraphQLField<mixed, mixed> {
return this._typeInfo.getFieldDef();
}
getDirective(): ?GraphQLDirective {
return this._typeInfo.getDirective();
}
getArgument(): ?GraphQLArgument {
return this._typeInfo.getArgument();
}
getEnumValue(): ?GraphQLEnumValue {
return this._typeInfo.getEnumValue();
}
}
export type ValidationRule = (ValidationContext) => ASTVisitor;

View File

@@ -0,0 +1,224 @@
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
import { Kind } from "../language/kinds.mjs";
import { visit } from "../language/visitor.mjs";
import { TypeInfo, visitWithTypeInfo } from "../utilities/TypeInfo.mjs";
/**
* An instance of this class is passed as the "this" context to all validators,
* allowing access to commonly useful contextual information from within a
* validation rule.
*/
export var ASTValidationContext = /*#__PURE__*/function () {
function ASTValidationContext(ast, onError) {
this._ast = ast;
this._fragments = undefined;
this._fragmentSpreads = new Map();
this._recursivelyReferencedFragments = new Map();
this._onError = onError;
}
var _proto = ASTValidationContext.prototype;
_proto.reportError = function reportError(error) {
this._onError(error);
};
_proto.getDocument = function getDocument() {
return this._ast;
};
_proto.getFragment = function getFragment(name) {
var fragments = this._fragments;
if (!fragments) {
this._fragments = fragments = this.getDocument().definitions.reduce(function (frags, statement) {
if (statement.kind === Kind.FRAGMENT_DEFINITION) {
frags[statement.name.value] = statement;
}
return frags;
}, Object.create(null));
}
return fragments[name];
};
_proto.getFragmentSpreads = function getFragmentSpreads(node) {
var spreads = this._fragmentSpreads.get(node);
if (!spreads) {
spreads = [];
var setsToVisit = [node];
while (setsToVisit.length !== 0) {
var set = setsToVisit.pop();
for (var _i2 = 0, _set$selections2 = set.selections; _i2 < _set$selections2.length; _i2++) {
var selection = _set$selections2[_i2];
if (selection.kind === Kind.FRAGMENT_SPREAD) {
spreads.push(selection);
} else if (selection.selectionSet) {
setsToVisit.push(selection.selectionSet);
}
}
}
this._fragmentSpreads.set(node, spreads);
}
return spreads;
};
_proto.getRecursivelyReferencedFragments = function getRecursivelyReferencedFragments(operation) {
var fragments = this._recursivelyReferencedFragments.get(operation);
if (!fragments) {
fragments = [];
var collectedNames = Object.create(null);
var nodesToVisit = [operation.selectionSet];
while (nodesToVisit.length !== 0) {
var node = nodesToVisit.pop();
for (var _i4 = 0, _this$getFragmentSpre2 = this.getFragmentSpreads(node); _i4 < _this$getFragmentSpre2.length; _i4++) {
var spread = _this$getFragmentSpre2[_i4];
var fragName = spread.name.value;
if (collectedNames[fragName] !== true) {
collectedNames[fragName] = true;
var fragment = this.getFragment(fragName);
if (fragment) {
fragments.push(fragment);
nodesToVisit.push(fragment.selectionSet);
}
}
}
}
this._recursivelyReferencedFragments.set(operation, fragments);
}
return fragments;
};
return ASTValidationContext;
}();
export var SDLValidationContext = /*#__PURE__*/function (_ASTValidationContext) {
_inheritsLoose(SDLValidationContext, _ASTValidationContext);
function SDLValidationContext(ast, schema, onError) {
var _this;
_this = _ASTValidationContext.call(this, ast, onError) || this;
_this._schema = schema;
return _this;
}
var _proto2 = SDLValidationContext.prototype;
_proto2.getSchema = function getSchema() {
return this._schema;
};
return SDLValidationContext;
}(ASTValidationContext);
export var ValidationContext = /*#__PURE__*/function (_ASTValidationContext2) {
_inheritsLoose(ValidationContext, _ASTValidationContext2);
function ValidationContext(schema, ast, typeInfo, onError) {
var _this2;
_this2 = _ASTValidationContext2.call(this, ast, onError) || this;
_this2._schema = schema;
_this2._typeInfo = typeInfo;
_this2._variableUsages = new Map();
_this2._recursiveVariableUsages = new Map();
return _this2;
}
var _proto3 = ValidationContext.prototype;
_proto3.getSchema = function getSchema() {
return this._schema;
};
_proto3.getVariableUsages = function getVariableUsages(node) {
var usages = this._variableUsages.get(node);
if (!usages) {
var newUsages = [];
var typeInfo = new TypeInfo(this._schema);
visit(node, visitWithTypeInfo(typeInfo, {
VariableDefinition: function VariableDefinition() {
return false;
},
Variable: function Variable(variable) {
newUsages.push({
node: variable,
type: typeInfo.getInputType(),
defaultValue: typeInfo.getDefaultValue()
});
}
}));
usages = newUsages;
this._variableUsages.set(node, usages);
}
return usages;
};
_proto3.getRecursiveVariableUsages = function getRecursiveVariableUsages(operation) {
var usages = this._recursiveVariableUsages.get(operation);
if (!usages) {
usages = this.getVariableUsages(operation);
for (var _i6 = 0, _this$getRecursivelyR2 = this.getRecursivelyReferencedFragments(operation); _i6 < _this$getRecursivelyR2.length; _i6++) {
var frag = _this$getRecursivelyR2[_i6];
usages = usages.concat(this.getVariableUsages(frag));
}
this._recursiveVariableUsages.set(operation, usages);
}
return usages;
};
_proto3.getType = function getType() {
return this._typeInfo.getType();
};
_proto3.getParentType = function getParentType() {
return this._typeInfo.getParentType();
};
_proto3.getInputType = function getInputType() {
return this._typeInfo.getInputType();
};
_proto3.getParentInputType = function getParentInputType() {
return this._typeInfo.getParentInputType();
};
_proto3.getFieldDef = function getFieldDef() {
return this._typeInfo.getFieldDef();
};
_proto3.getDirective = function getDirective() {
return this._typeInfo.getDirective();
};
_proto3.getArgument = function getArgument() {
return this._typeInfo.getArgument();
};
_proto3.getEnumValue = function getEnumValue() {
return this._typeInfo.getEnumValue();
};
return ValidationContext;
}(ASTValidationContext);

View File

@@ -0,0 +1,96 @@
export { validate } from './validate';
export { ValidationContext, ValidationRule } from './ValidationContext';
export { specifiedRules } from './specifiedRules';
// Spec Section: "Executable Definitions"
export { ExecutableDefinitionsRule } from './rules/ExecutableDefinitionsRule';
// Spec Section: "Field Selections on Objects, Interfaces, and Unions Types"
export { FieldsOnCorrectTypeRule } from './rules/FieldsOnCorrectTypeRule';
// Spec Section: "Fragments on Composite Types"
export { FragmentsOnCompositeTypesRule } from './rules/FragmentsOnCompositeTypesRule';
// Spec Section: "Argument Names"
export { KnownArgumentNamesRule } from './rules/KnownArgumentNamesRule';
// Spec Section: "Directives Are Defined"
export { KnownDirectivesRule } from './rules/KnownDirectivesRule';
// Spec Section: "Fragment spread target defined"
export { KnownFragmentNamesRule } from './rules/KnownFragmentNamesRule';
// Spec Section: "Fragment Spread Type Existence"
export { KnownTypeNamesRule } from './rules/KnownTypeNamesRule';
// Spec Section: "Lone Anonymous Operation"
export { LoneAnonymousOperationRule } from './rules/LoneAnonymousOperationRule';
// Spec Section: "Fragments must not form cycles"
export { NoFragmentCyclesRule } from './rules/NoFragmentCyclesRule';
// Spec Section: "All Variable Used Defined"
export { NoUndefinedVariablesRule } from './rules/NoUndefinedVariablesRule';
// Spec Section: "Fragments must be used"
export { NoUnusedFragmentsRule } from './rules/NoUnusedFragmentsRule';
// Spec Section: "All Variables Used"
export { NoUnusedVariablesRule } from './rules/NoUnusedVariablesRule';
// Spec Section: "Field Selection Merging"
export { OverlappingFieldsCanBeMergedRule } from './rules/OverlappingFieldsCanBeMergedRule';
// Spec Section: "Fragment spread is possible"
export { PossibleFragmentSpreadsRule } from './rules/PossibleFragmentSpreadsRule';
// Spec Section: "Argument Optionality"
export { ProvidedRequiredArgumentsRule } from './rules/ProvidedRequiredArgumentsRule';
// Spec Section: "Leaf Field Selections"
export { ScalarLeafsRule } from './rules/ScalarLeafsRule';
// Spec Section: "Subscriptions with Single Root Field"
export { SingleFieldSubscriptionsRule } from './rules/SingleFieldSubscriptionsRule';
// Spec Section: "Argument Uniqueness"
export { UniqueArgumentNamesRule } from './rules/UniqueArgumentNamesRule';
// Spec Section: "Directives Are Unique Per Location"
export { UniqueDirectivesPerLocationRule } from './rules/UniqueDirectivesPerLocationRule';
// Spec Section: "Fragment Name Uniqueness"
export { UniqueFragmentNamesRule } from './rules/UniqueFragmentNamesRule';
// Spec Section: "Input Object Field Uniqueness"
export { UniqueInputFieldNamesRule } from './rules/UniqueInputFieldNamesRule';
// Spec Section: "Operation Name Uniqueness"
export { UniqueOperationNamesRule } from './rules/UniqueOperationNamesRule';
// Spec Section: "Variable Uniqueness"
export { UniqueVariableNamesRule } from './rules/UniqueVariableNamesRule';
// Spec Section: "Values Type Correctness"
export { ValuesOfCorrectTypeRule } from './rules/ValuesOfCorrectTypeRule';
// Spec Section: "Variables are Input Types"
export { VariablesAreInputTypesRule } from './rules/VariablesAreInputTypesRule';
// Spec Section: "All Variable Usages Are Allowed"
export { VariablesInAllowedPositionRule } from './rules/VariablesInAllowedPositionRule';
// SDL-specific validation rules
export { LoneSchemaDefinitionRule } from './rules/LoneSchemaDefinitionRule';
export { UniqueOperationTypesRule } from './rules/UniqueOperationTypesRule';
export { UniqueTypeNamesRule } from './rules/UniqueTypeNamesRule';
export { UniqueEnumValueNamesRule } from './rules/UniqueEnumValueNamesRule';
export { UniqueFieldDefinitionNamesRule } from './rules/UniqueFieldDefinitionNamesRule';
export { UniqueDirectiveNamesRule } from './rules/UniqueDirectiveNamesRule';
export { PossibleTypeExtensionsRule } from './rules/PossibleTypeExtensionsRule';
// Optional rules not defined by the GraphQL Specification
export { NoDeprecatedCustomRule } from './rules/custom/NoDeprecatedCustomRule';
export { NoSchemaIntrospectionCustomRule } from './rules/custom/NoSchemaIntrospectionCustomRule';

View File

@@ -0,0 +1,309 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "validate", {
enumerable: true,
get: function get() {
return _validate.validate;
}
});
Object.defineProperty(exports, "ValidationContext", {
enumerable: true,
get: function get() {
return _ValidationContext.ValidationContext;
}
});
Object.defineProperty(exports, "specifiedRules", {
enumerable: true,
get: function get() {
return _specifiedRules.specifiedRules;
}
});
Object.defineProperty(exports, "ExecutableDefinitionsRule", {
enumerable: true,
get: function get() {
return _ExecutableDefinitionsRule.ExecutableDefinitionsRule;
}
});
Object.defineProperty(exports, "FieldsOnCorrectTypeRule", {
enumerable: true,
get: function get() {
return _FieldsOnCorrectTypeRule.FieldsOnCorrectTypeRule;
}
});
Object.defineProperty(exports, "FragmentsOnCompositeTypesRule", {
enumerable: true,
get: function get() {
return _FragmentsOnCompositeTypesRule.FragmentsOnCompositeTypesRule;
}
});
Object.defineProperty(exports, "KnownArgumentNamesRule", {
enumerable: true,
get: function get() {
return _KnownArgumentNamesRule.KnownArgumentNamesRule;
}
});
Object.defineProperty(exports, "KnownDirectivesRule", {
enumerable: true,
get: function get() {
return _KnownDirectivesRule.KnownDirectivesRule;
}
});
Object.defineProperty(exports, "KnownFragmentNamesRule", {
enumerable: true,
get: function get() {
return _KnownFragmentNamesRule.KnownFragmentNamesRule;
}
});
Object.defineProperty(exports, "KnownTypeNamesRule", {
enumerable: true,
get: function get() {
return _KnownTypeNamesRule.KnownTypeNamesRule;
}
});
Object.defineProperty(exports, "LoneAnonymousOperationRule", {
enumerable: true,
get: function get() {
return _LoneAnonymousOperationRule.LoneAnonymousOperationRule;
}
});
Object.defineProperty(exports, "NoFragmentCyclesRule", {
enumerable: true,
get: function get() {
return _NoFragmentCyclesRule.NoFragmentCyclesRule;
}
});
Object.defineProperty(exports, "NoUndefinedVariablesRule", {
enumerable: true,
get: function get() {
return _NoUndefinedVariablesRule.NoUndefinedVariablesRule;
}
});
Object.defineProperty(exports, "NoUnusedFragmentsRule", {
enumerable: true,
get: function get() {
return _NoUnusedFragmentsRule.NoUnusedFragmentsRule;
}
});
Object.defineProperty(exports, "NoUnusedVariablesRule", {
enumerable: true,
get: function get() {
return _NoUnusedVariablesRule.NoUnusedVariablesRule;
}
});
Object.defineProperty(exports, "OverlappingFieldsCanBeMergedRule", {
enumerable: true,
get: function get() {
return _OverlappingFieldsCanBeMergedRule.OverlappingFieldsCanBeMergedRule;
}
});
Object.defineProperty(exports, "PossibleFragmentSpreadsRule", {
enumerable: true,
get: function get() {
return _PossibleFragmentSpreadsRule.PossibleFragmentSpreadsRule;
}
});
Object.defineProperty(exports, "ProvidedRequiredArgumentsRule", {
enumerable: true,
get: function get() {
return _ProvidedRequiredArgumentsRule.ProvidedRequiredArgumentsRule;
}
});
Object.defineProperty(exports, "ScalarLeafsRule", {
enumerable: true,
get: function get() {
return _ScalarLeafsRule.ScalarLeafsRule;
}
});
Object.defineProperty(exports, "SingleFieldSubscriptionsRule", {
enumerable: true,
get: function get() {
return _SingleFieldSubscriptionsRule.SingleFieldSubscriptionsRule;
}
});
Object.defineProperty(exports, "UniqueArgumentNamesRule", {
enumerable: true,
get: function get() {
return _UniqueArgumentNamesRule.UniqueArgumentNamesRule;
}
});
Object.defineProperty(exports, "UniqueDirectivesPerLocationRule", {
enumerable: true,
get: function get() {
return _UniqueDirectivesPerLocationRule.UniqueDirectivesPerLocationRule;
}
});
Object.defineProperty(exports, "UniqueFragmentNamesRule", {
enumerable: true,
get: function get() {
return _UniqueFragmentNamesRule.UniqueFragmentNamesRule;
}
});
Object.defineProperty(exports, "UniqueInputFieldNamesRule", {
enumerable: true,
get: function get() {
return _UniqueInputFieldNamesRule.UniqueInputFieldNamesRule;
}
});
Object.defineProperty(exports, "UniqueOperationNamesRule", {
enumerable: true,
get: function get() {
return _UniqueOperationNamesRule.UniqueOperationNamesRule;
}
});
Object.defineProperty(exports, "UniqueVariableNamesRule", {
enumerable: true,
get: function get() {
return _UniqueVariableNamesRule.UniqueVariableNamesRule;
}
});
Object.defineProperty(exports, "ValuesOfCorrectTypeRule", {
enumerable: true,
get: function get() {
return _ValuesOfCorrectTypeRule.ValuesOfCorrectTypeRule;
}
});
Object.defineProperty(exports, "VariablesAreInputTypesRule", {
enumerable: true,
get: function get() {
return _VariablesAreInputTypesRule.VariablesAreInputTypesRule;
}
});
Object.defineProperty(exports, "VariablesInAllowedPositionRule", {
enumerable: true,
get: function get() {
return _VariablesInAllowedPositionRule.VariablesInAllowedPositionRule;
}
});
Object.defineProperty(exports, "LoneSchemaDefinitionRule", {
enumerable: true,
get: function get() {
return _LoneSchemaDefinitionRule.LoneSchemaDefinitionRule;
}
});
Object.defineProperty(exports, "UniqueOperationTypesRule", {
enumerable: true,
get: function get() {
return _UniqueOperationTypesRule.UniqueOperationTypesRule;
}
});
Object.defineProperty(exports, "UniqueTypeNamesRule", {
enumerable: true,
get: function get() {
return _UniqueTypeNamesRule.UniqueTypeNamesRule;
}
});
Object.defineProperty(exports, "UniqueEnumValueNamesRule", {
enumerable: true,
get: function get() {
return _UniqueEnumValueNamesRule.UniqueEnumValueNamesRule;
}
});
Object.defineProperty(exports, "UniqueFieldDefinitionNamesRule", {
enumerable: true,
get: function get() {
return _UniqueFieldDefinitionNamesRule.UniqueFieldDefinitionNamesRule;
}
});
Object.defineProperty(exports, "UniqueDirectiveNamesRule", {
enumerable: true,
get: function get() {
return _UniqueDirectiveNamesRule.UniqueDirectiveNamesRule;
}
});
Object.defineProperty(exports, "PossibleTypeExtensionsRule", {
enumerable: true,
get: function get() {
return _PossibleTypeExtensionsRule.PossibleTypeExtensionsRule;
}
});
Object.defineProperty(exports, "NoDeprecatedCustomRule", {
enumerable: true,
get: function get() {
return _NoDeprecatedCustomRule.NoDeprecatedCustomRule;
}
});
Object.defineProperty(exports, "NoSchemaIntrospectionCustomRule", {
enumerable: true,
get: function get() {
return _NoSchemaIntrospectionCustomRule.NoSchemaIntrospectionCustomRule;
}
});
var _validate = require("./validate.js");
var _ValidationContext = require("./ValidationContext.js");
var _specifiedRules = require("./specifiedRules.js");
var _ExecutableDefinitionsRule = require("./rules/ExecutableDefinitionsRule.js");
var _FieldsOnCorrectTypeRule = require("./rules/FieldsOnCorrectTypeRule.js");
var _FragmentsOnCompositeTypesRule = require("./rules/FragmentsOnCompositeTypesRule.js");
var _KnownArgumentNamesRule = require("./rules/KnownArgumentNamesRule.js");
var _KnownDirectivesRule = require("./rules/KnownDirectivesRule.js");
var _KnownFragmentNamesRule = require("./rules/KnownFragmentNamesRule.js");
var _KnownTypeNamesRule = require("./rules/KnownTypeNamesRule.js");
var _LoneAnonymousOperationRule = require("./rules/LoneAnonymousOperationRule.js");
var _NoFragmentCyclesRule = require("./rules/NoFragmentCyclesRule.js");
var _NoUndefinedVariablesRule = require("./rules/NoUndefinedVariablesRule.js");
var _NoUnusedFragmentsRule = require("./rules/NoUnusedFragmentsRule.js");
var _NoUnusedVariablesRule = require("./rules/NoUnusedVariablesRule.js");
var _OverlappingFieldsCanBeMergedRule = require("./rules/OverlappingFieldsCanBeMergedRule.js");
var _PossibleFragmentSpreadsRule = require("./rules/PossibleFragmentSpreadsRule.js");
var _ProvidedRequiredArgumentsRule = require("./rules/ProvidedRequiredArgumentsRule.js");
var _ScalarLeafsRule = require("./rules/ScalarLeafsRule.js");
var _SingleFieldSubscriptionsRule = require("./rules/SingleFieldSubscriptionsRule.js");
var _UniqueArgumentNamesRule = require("./rules/UniqueArgumentNamesRule.js");
var _UniqueDirectivesPerLocationRule = require("./rules/UniqueDirectivesPerLocationRule.js");
var _UniqueFragmentNamesRule = require("./rules/UniqueFragmentNamesRule.js");
var _UniqueInputFieldNamesRule = require("./rules/UniqueInputFieldNamesRule.js");
var _UniqueOperationNamesRule = require("./rules/UniqueOperationNamesRule.js");
var _UniqueVariableNamesRule = require("./rules/UniqueVariableNamesRule.js");
var _ValuesOfCorrectTypeRule = require("./rules/ValuesOfCorrectTypeRule.js");
var _VariablesAreInputTypesRule = require("./rules/VariablesAreInputTypesRule.js");
var _VariablesInAllowedPositionRule = require("./rules/VariablesInAllowedPositionRule.js");
var _LoneSchemaDefinitionRule = require("./rules/LoneSchemaDefinitionRule.js");
var _UniqueOperationTypesRule = require("./rules/UniqueOperationTypesRule.js");
var _UniqueTypeNamesRule = require("./rules/UniqueTypeNamesRule.js");
var _UniqueEnumValueNamesRule = require("./rules/UniqueEnumValueNamesRule.js");
var _UniqueFieldDefinitionNamesRule = require("./rules/UniqueFieldDefinitionNamesRule.js");
var _UniqueDirectiveNamesRule = require("./rules/UniqueDirectiveNamesRule.js");
var _PossibleTypeExtensionsRule = require("./rules/PossibleTypeExtensionsRule.js");
var _NoDeprecatedCustomRule = require("./rules/custom/NoDeprecatedCustomRule.js");
var _NoSchemaIntrospectionCustomRule = require("./rules/custom/NoSchemaIntrospectionCustomRule.js");

View File

@@ -0,0 +1,99 @@
// @flow strict
export { validate } from './validate';
export { ValidationContext } from './ValidationContext';
export type { ValidationRule } from './ValidationContext';
// All validation rules in the GraphQL Specification.
export { specifiedRules } from './specifiedRules';
// Spec Section: "Executable Definitions"
export { ExecutableDefinitionsRule } from './rules/ExecutableDefinitionsRule';
// Spec Section: "Field Selections on Objects, Interfaces, and Unions Types"
export { FieldsOnCorrectTypeRule } from './rules/FieldsOnCorrectTypeRule';
// Spec Section: "Fragments on Composite Types"
export { FragmentsOnCompositeTypesRule } from './rules/FragmentsOnCompositeTypesRule';
// Spec Section: "Argument Names"
export { KnownArgumentNamesRule } from './rules/KnownArgumentNamesRule';
// Spec Section: "Directives Are Defined"
export { KnownDirectivesRule } from './rules/KnownDirectivesRule';
// Spec Section: "Fragment spread target defined"
export { KnownFragmentNamesRule } from './rules/KnownFragmentNamesRule';
// Spec Section: "Fragment Spread Type Existence"
export { KnownTypeNamesRule } from './rules/KnownTypeNamesRule';
// Spec Section: "Lone Anonymous Operation"
export { LoneAnonymousOperationRule } from './rules/LoneAnonymousOperationRule';
// Spec Section: "Fragments must not form cycles"
export { NoFragmentCyclesRule } from './rules/NoFragmentCyclesRule';
// Spec Section: "All Variable Used Defined"
export { NoUndefinedVariablesRule } from './rules/NoUndefinedVariablesRule';
// Spec Section: "Fragments must be used"
export { NoUnusedFragmentsRule } from './rules/NoUnusedFragmentsRule';
// Spec Section: "All Variables Used"
export { NoUnusedVariablesRule } from './rules/NoUnusedVariablesRule';
// Spec Section: "Field Selection Merging"
export { OverlappingFieldsCanBeMergedRule } from './rules/OverlappingFieldsCanBeMergedRule';
// Spec Section: "Fragment spread is possible"
export { PossibleFragmentSpreadsRule } from './rules/PossibleFragmentSpreadsRule';
// Spec Section: "Argument Optionality"
export { ProvidedRequiredArgumentsRule } from './rules/ProvidedRequiredArgumentsRule';
// Spec Section: "Leaf Field Selections"
export { ScalarLeafsRule } from './rules/ScalarLeafsRule';
// Spec Section: "Subscriptions with Single Root Field"
export { SingleFieldSubscriptionsRule } from './rules/SingleFieldSubscriptionsRule';
// Spec Section: "Argument Uniqueness"
export { UniqueArgumentNamesRule } from './rules/UniqueArgumentNamesRule';
// Spec Section: "Directives Are Unique Per Location"
export { UniqueDirectivesPerLocationRule } from './rules/UniqueDirectivesPerLocationRule';
// Spec Section: "Fragment Name Uniqueness"
export { UniqueFragmentNamesRule } from './rules/UniqueFragmentNamesRule';
// Spec Section: "Input Object Field Uniqueness"
export { UniqueInputFieldNamesRule } from './rules/UniqueInputFieldNamesRule';
// Spec Section: "Operation Name Uniqueness"
export { UniqueOperationNamesRule } from './rules/UniqueOperationNamesRule';
// Spec Section: "Variable Uniqueness"
export { UniqueVariableNamesRule } from './rules/UniqueVariableNamesRule';
// Spec Section: "Values Type Correctness"
export { ValuesOfCorrectTypeRule } from './rules/ValuesOfCorrectTypeRule';
// Spec Section: "Variables are Input Types"
export { VariablesAreInputTypesRule } from './rules/VariablesAreInputTypesRule';
// Spec Section: "All Variable Usages Are Allowed"
export { VariablesInAllowedPositionRule } from './rules/VariablesInAllowedPositionRule';
// SDL-specific validation rules
export { LoneSchemaDefinitionRule } from './rules/LoneSchemaDefinitionRule';
export { UniqueOperationTypesRule } from './rules/UniqueOperationTypesRule';
export { UniqueTypeNamesRule } from './rules/UniqueTypeNamesRule';
export { UniqueEnumValueNamesRule } from './rules/UniqueEnumValueNamesRule';
export { UniqueFieldDefinitionNamesRule } from './rules/UniqueFieldDefinitionNamesRule';
export { UniqueDirectiveNamesRule } from './rules/UniqueDirectiveNamesRule';
export { PossibleTypeExtensionsRule } from './rules/PossibleTypeExtensionsRule';
// Optional rules not defined by the GraphQL Specification
export { NoDeprecatedCustomRule } from './rules/custom/NoDeprecatedCustomRule';
export { NoSchemaIntrospectionCustomRule } from './rules/custom/NoSchemaIntrospectionCustomRule';

View File

@@ -0,0 +1,67 @@
export { validate } from "./validate.mjs";
export { ValidationContext } from "./ValidationContext.mjs";
// All validation rules in the GraphQL Specification.
export { specifiedRules } from "./specifiedRules.mjs"; // Spec Section: "Executable Definitions"
export { ExecutableDefinitionsRule } from "./rules/ExecutableDefinitionsRule.mjs"; // Spec Section: "Field Selections on Objects, Interfaces, and Unions Types"
export { FieldsOnCorrectTypeRule } from "./rules/FieldsOnCorrectTypeRule.mjs"; // Spec Section: "Fragments on Composite Types"
export { FragmentsOnCompositeTypesRule } from "./rules/FragmentsOnCompositeTypesRule.mjs"; // Spec Section: "Argument Names"
export { KnownArgumentNamesRule } from "./rules/KnownArgumentNamesRule.mjs"; // Spec Section: "Directives Are Defined"
export { KnownDirectivesRule } from "./rules/KnownDirectivesRule.mjs"; // Spec Section: "Fragment spread target defined"
export { KnownFragmentNamesRule } from "./rules/KnownFragmentNamesRule.mjs"; // Spec Section: "Fragment Spread Type Existence"
export { KnownTypeNamesRule } from "./rules/KnownTypeNamesRule.mjs"; // Spec Section: "Lone Anonymous Operation"
export { LoneAnonymousOperationRule } from "./rules/LoneAnonymousOperationRule.mjs"; // Spec Section: "Fragments must not form cycles"
export { NoFragmentCyclesRule } from "./rules/NoFragmentCyclesRule.mjs"; // Spec Section: "All Variable Used Defined"
export { NoUndefinedVariablesRule } from "./rules/NoUndefinedVariablesRule.mjs"; // Spec Section: "Fragments must be used"
export { NoUnusedFragmentsRule } from "./rules/NoUnusedFragmentsRule.mjs"; // Spec Section: "All Variables Used"
export { NoUnusedVariablesRule } from "./rules/NoUnusedVariablesRule.mjs"; // Spec Section: "Field Selection Merging"
export { OverlappingFieldsCanBeMergedRule } from "./rules/OverlappingFieldsCanBeMergedRule.mjs"; // Spec Section: "Fragment spread is possible"
export { PossibleFragmentSpreadsRule } from "./rules/PossibleFragmentSpreadsRule.mjs"; // Spec Section: "Argument Optionality"
export { ProvidedRequiredArgumentsRule } from "./rules/ProvidedRequiredArgumentsRule.mjs"; // Spec Section: "Leaf Field Selections"
export { ScalarLeafsRule } from "./rules/ScalarLeafsRule.mjs"; // Spec Section: "Subscriptions with Single Root Field"
export { SingleFieldSubscriptionsRule } from "./rules/SingleFieldSubscriptionsRule.mjs"; // Spec Section: "Argument Uniqueness"
export { UniqueArgumentNamesRule } from "./rules/UniqueArgumentNamesRule.mjs"; // Spec Section: "Directives Are Unique Per Location"
export { UniqueDirectivesPerLocationRule } from "./rules/UniqueDirectivesPerLocationRule.mjs"; // Spec Section: "Fragment Name Uniqueness"
export { UniqueFragmentNamesRule } from "./rules/UniqueFragmentNamesRule.mjs"; // Spec Section: "Input Object Field Uniqueness"
export { UniqueInputFieldNamesRule } from "./rules/UniqueInputFieldNamesRule.mjs"; // Spec Section: "Operation Name Uniqueness"
export { UniqueOperationNamesRule } from "./rules/UniqueOperationNamesRule.mjs"; // Spec Section: "Variable Uniqueness"
export { UniqueVariableNamesRule } from "./rules/UniqueVariableNamesRule.mjs"; // Spec Section: "Values Type Correctness"
export { ValuesOfCorrectTypeRule } from "./rules/ValuesOfCorrectTypeRule.mjs"; // Spec Section: "Variables are Input Types"
export { VariablesAreInputTypesRule } from "./rules/VariablesAreInputTypesRule.mjs"; // Spec Section: "All Variable Usages Are Allowed"
export { VariablesInAllowedPositionRule } from "./rules/VariablesInAllowedPositionRule.mjs"; // SDL-specific validation rules
export { LoneSchemaDefinitionRule } from "./rules/LoneSchemaDefinitionRule.mjs";
export { UniqueOperationTypesRule } from "./rules/UniqueOperationTypesRule.mjs";
export { UniqueTypeNamesRule } from "./rules/UniqueTypeNamesRule.mjs";
export { UniqueEnumValueNamesRule } from "./rules/UniqueEnumValueNamesRule.mjs";
export { UniqueFieldDefinitionNamesRule } from "./rules/UniqueFieldDefinitionNamesRule.mjs";
export { UniqueDirectiveNamesRule } from "./rules/UniqueDirectiveNamesRule.mjs";
export { PossibleTypeExtensionsRule } from "./rules/PossibleTypeExtensionsRule.mjs"; // Optional rules not defined by the GraphQL Specification
export { NoDeprecatedCustomRule } from "./rules/custom/NoDeprecatedCustomRule.mjs";
export { NoSchemaIntrospectionCustomRule } from "./rules/custom/NoSchemaIntrospectionCustomRule.mjs";

View File

@@ -0,0 +1,8 @@
/**
* @deprecated and will be removed in v16
* Please use either:
* import { ExecutableDefinitionsRule } from 'graphql'
* or
* import { ExecutableDefinitionsRule } from 'graphql/validation'
*/
export { ExecutableDefinitionsRule as ExecutableDefinitions } from './ExecutableDefinitionsRule';

View File

@@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "ExecutableDefinitions", {
enumerable: true,
get: function get() {
return _ExecutableDefinitionsRule.ExecutableDefinitionsRule;
}
});
var _ExecutableDefinitionsRule = require("./ExecutableDefinitionsRule.js");

View File

@@ -0,0 +1,9 @@
// @flow strict
/**
* @deprecated and will be removed in v16
* Please use either:
* import { ExecutableDefinitionsRule } from 'graphql'
* or
* import { ExecutableDefinitionsRule } from 'graphql/validation'
*/
export { ExecutableDefinitionsRule as ExecutableDefinitions } from './ExecutableDefinitionsRule';

View File

@@ -0,0 +1,8 @@
/**
* @deprecated and will be removed in v16
* Please use either:
* import { ExecutableDefinitionsRule } from 'graphql'
* or
* import { ExecutableDefinitionsRule } from 'graphql/validation'
*/
export { ExecutableDefinitionsRule as ExecutableDefinitions } from "./ExecutableDefinitionsRule.mjs";

View File

@@ -0,0 +1,12 @@
import { ASTVisitor } from '../../language/visitor';
import { ASTValidationContext } from '../ValidationContext';
/**
* Executable definitions
*
* A GraphQL document is only valid for execution if all definitions are either
* operation or fragment definitions.
*/
export function ExecutableDefinitionsRule(
context: ASTValidationContext,
): ASTVisitor;

View File

@@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ExecutableDefinitionsRule = ExecutableDefinitionsRule;
var _GraphQLError = require("../../error/GraphQLError.js");
var _kinds = require("../../language/kinds.js");
var _predicates = require("../../language/predicates.js");
/**
* Executable definitions
*
* A GraphQL document is only valid for execution if all definitions are either
* operation or fragment definitions.
*/
function ExecutableDefinitionsRule(context) {
return {
Document: function Document(node) {
for (var _i2 = 0, _node$definitions2 = node.definitions; _i2 < _node$definitions2.length; _i2++) {
var definition = _node$definitions2[_i2];
if (!(0, _predicates.isExecutableDefinitionNode)(definition)) {
var defName = definition.kind === _kinds.Kind.SCHEMA_DEFINITION || definition.kind === _kinds.Kind.SCHEMA_EXTENSION ? 'schema' : '"' + definition.name.value + '"';
context.reportError(new _GraphQLError.GraphQLError("The ".concat(defName, " definition is not executable."), definition));
}
}
return false;
}
};
}

View File

@@ -0,0 +1,39 @@
// @flow strict
import { GraphQLError } from '../../error/GraphQLError';
import type { ASTVisitor } from '../../language/visitor';
import { Kind } from '../../language/kinds';
import { isExecutableDefinitionNode } from '../../language/predicates';
import type { ASTValidationContext } from '../ValidationContext';
/**
* Executable definitions
*
* A GraphQL document is only valid for execution if all definitions are either
* operation or fragment definitions.
*/
export function ExecutableDefinitionsRule(
context: ASTValidationContext,
): ASTVisitor {
return {
Document(node) {
for (const definition of node.definitions) {
if (!isExecutableDefinitionNode(definition)) {
const defName =
definition.kind === Kind.SCHEMA_DEFINITION ||
definition.kind === Kind.SCHEMA_EXTENSION
? 'schema'
: '"' + definition.name.value + '"';
context.reportError(
new GraphQLError(
`The ${defName} definition is not executable.`,
definition,
),
);
}
}
return false;
},
};
}

View File

@@ -0,0 +1,26 @@
import { GraphQLError } from "../../error/GraphQLError.mjs";
import { Kind } from "../../language/kinds.mjs";
import { isExecutableDefinitionNode } from "../../language/predicates.mjs";
/**
* Executable definitions
*
* A GraphQL document is only valid for execution if all definitions are either
* operation or fragment definitions.
*/
export function ExecutableDefinitionsRule(context) {
return {
Document: function Document(node) {
for (var _i2 = 0, _node$definitions2 = node.definitions; _i2 < _node$definitions2.length; _i2++) {
var definition = _node$definitions2[_i2];
if (!isExecutableDefinitionNode(definition)) {
var defName = definition.kind === Kind.SCHEMA_DEFINITION || definition.kind === Kind.SCHEMA_EXTENSION ? 'schema' : '"' + definition.name.value + '"';
context.reportError(new GraphQLError("The ".concat(defName, " definition is not executable."), definition));
}
}
return false;
}
};
}

View File

@@ -0,0 +1,10 @@
import { ASTVisitor } from '../../language/visitor';
import { ValidationContext } from '../ValidationContext';
/**
* Fields on correct type
*
* A GraphQL document is only valid if all fields selected are defined by the
* parent type, or are an allowed meta field such as __typename.
*/
export function FieldsOnCorrectTypeRule(context: ValidationContext): ASTVisitor;

View File

@@ -0,0 +1,132 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.FieldsOnCorrectTypeRule = FieldsOnCorrectTypeRule;
var _arrayFrom = _interopRequireDefault(require("../../polyfills/arrayFrom.js"));
var _didYouMean = _interopRequireDefault(require("../../jsutils/didYouMean.js"));
var _suggestionList = _interopRequireDefault(require("../../jsutils/suggestionList.js"));
var _naturalCompare = _interopRequireDefault(require("../../jsutils/naturalCompare.js"));
var _GraphQLError = require("../../error/GraphQLError.js");
var _definition = require("../../type/definition.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Fields on correct type
*
* A GraphQL document is only valid if all fields selected are defined by the
* parent type, or are an allowed meta field such as __typename.
*/
function FieldsOnCorrectTypeRule(context) {
return {
Field: function Field(node) {
var type = context.getParentType();
if (type) {
var fieldDef = context.getFieldDef();
if (!fieldDef) {
// This field doesn't exist, lets look for suggestions.
var schema = context.getSchema();
var fieldName = node.name.value; // First determine if there are any suggested types to condition on.
var suggestion = (0, _didYouMean.default)('to use an inline fragment on', getSuggestedTypeNames(schema, type, fieldName)); // If there are no suggested types, then perhaps this was a typo?
if (suggestion === '') {
suggestion = (0, _didYouMean.default)(getSuggestedFieldNames(type, fieldName));
} // Report an error, including helpful suggestions.
context.reportError(new _GraphQLError.GraphQLError("Cannot query field \"".concat(fieldName, "\" on type \"").concat(type.name, "\".") + suggestion, node));
}
}
}
};
}
/**
* Go through all of the implementations of type, as well as the interfaces that
* they implement. If any of those types include the provided field, suggest them,
* sorted by how often the type is referenced.
*/
function getSuggestedTypeNames(schema, type, fieldName) {
if (!(0, _definition.isAbstractType)(type)) {
// Must be an Object type, which does not have possible fields.
return [];
}
var suggestedTypes = new Set();
var usageCount = Object.create(null);
for (var _i2 = 0, _schema$getPossibleTy2 = schema.getPossibleTypes(type); _i2 < _schema$getPossibleTy2.length; _i2++) {
var possibleType = _schema$getPossibleTy2[_i2];
if (!possibleType.getFields()[fieldName]) {
continue;
} // This object type defines this field.
suggestedTypes.add(possibleType);
usageCount[possibleType.name] = 1;
for (var _i4 = 0, _possibleType$getInte2 = possibleType.getInterfaces(); _i4 < _possibleType$getInte2.length; _i4++) {
var _usageCount$possibleI;
var possibleInterface = _possibleType$getInte2[_i4];
if (!possibleInterface.getFields()[fieldName]) {
continue;
} // This interface type defines this field.
suggestedTypes.add(possibleInterface);
usageCount[possibleInterface.name] = ((_usageCount$possibleI = usageCount[possibleInterface.name]) !== null && _usageCount$possibleI !== void 0 ? _usageCount$possibleI : 0) + 1;
}
}
return (0, _arrayFrom.default)(suggestedTypes).sort(function (typeA, typeB) {
// Suggest both interface and object types based on how common they are.
var usageCountDiff = usageCount[typeB.name] - usageCount[typeA.name];
if (usageCountDiff !== 0) {
return usageCountDiff;
} // Suggest super types first followed by subtypes
if ((0, _definition.isInterfaceType)(typeA) && schema.isSubType(typeA, typeB)) {
return -1;
}
if ((0, _definition.isInterfaceType)(typeB) && schema.isSubType(typeB, typeA)) {
return 1;
}
return (0, _naturalCompare.default)(typeA.name, typeB.name);
}).map(function (x) {
return x.name;
});
}
/**
* For the field name provided, determine if there are any similar field names
* that may be the result of a typo.
*/
function getSuggestedFieldNames(type, fieldName) {
if ((0, _definition.isObjectType)(type) || (0, _definition.isInterfaceType)(type)) {
var possibleFieldNames = Object.keys(type.getFields());
return (0, _suggestionList.default)(fieldName, possibleFieldNames);
} // Otherwise, must be a Union type, which does not define fields.
return [];
}

View File

@@ -0,0 +1,146 @@
// @flow strict
import arrayFrom from '../../polyfills/arrayFrom';
import didYouMean from '../../jsutils/didYouMean';
import suggestionList from '../../jsutils/suggestionList';
import naturalCompare from '../../jsutils/naturalCompare';
import { GraphQLError } from '../../error/GraphQLError';
import type { FieldNode } from '../../language/ast';
import type { ASTVisitor } from '../../language/visitor';
import type { GraphQLSchema } from '../../type/schema';
import type {
GraphQLOutputType,
GraphQLObjectType,
GraphQLInterfaceType,
} from '../../type/definition';
import {
isObjectType,
isInterfaceType,
isAbstractType,
} from '../../type/definition';
import type { ValidationContext } from '../ValidationContext';
/**
* Fields on correct type
*
* A GraphQL document is only valid if all fields selected are defined by the
* parent type, or are an allowed meta field such as __typename.
*/
export function FieldsOnCorrectTypeRule(
context: ValidationContext,
): ASTVisitor {
return {
Field(node: FieldNode) {
const type = context.getParentType();
if (type) {
const fieldDef = context.getFieldDef();
if (!fieldDef) {
// This field doesn't exist, lets look for suggestions.
const schema = context.getSchema();
const fieldName = node.name.value;
// First determine if there are any suggested types to condition on.
let suggestion = didYouMean(
'to use an inline fragment on',
getSuggestedTypeNames(schema, type, fieldName),
);
// If there are no suggested types, then perhaps this was a typo?
if (suggestion === '') {
suggestion = didYouMean(getSuggestedFieldNames(type, fieldName));
}
// Report an error, including helpful suggestions.
context.reportError(
new GraphQLError(
`Cannot query field "${fieldName}" on type "${type.name}".` +
suggestion,
node,
),
);
}
}
},
};
}
/**
* Go through all of the implementations of type, as well as the interfaces that
* they implement. If any of those types include the provided field, suggest them,
* sorted by how often the type is referenced.
*/
function getSuggestedTypeNames(
schema: GraphQLSchema,
type: GraphQLOutputType,
fieldName: string,
): Array<string> {
if (!isAbstractType(type)) {
// Must be an Object type, which does not have possible fields.
return [];
}
const suggestedTypes: Set<
GraphQLObjectType | GraphQLInterfaceType,
> = new Set();
const usageCount = Object.create(null);
for (const possibleType of schema.getPossibleTypes(type)) {
if (!possibleType.getFields()[fieldName]) {
continue;
}
// This object type defines this field.
suggestedTypes.add(possibleType);
usageCount[possibleType.name] = 1;
for (const possibleInterface of possibleType.getInterfaces()) {
if (!possibleInterface.getFields()[fieldName]) {
continue;
}
// This interface type defines this field.
suggestedTypes.add(possibleInterface);
usageCount[possibleInterface.name] =
(usageCount[possibleInterface.name] ?? 0) + 1;
}
}
return arrayFrom(suggestedTypes)
.sort((typeA, typeB) => {
// Suggest both interface and object types based on how common they are.
const usageCountDiff = usageCount[typeB.name] - usageCount[typeA.name];
if (usageCountDiff !== 0) {
return usageCountDiff;
}
// Suggest super types first followed by subtypes
if (isInterfaceType(typeA) && schema.isSubType(typeA, typeB)) {
return -1;
}
if (isInterfaceType(typeB) && schema.isSubType(typeB, typeA)) {
return 1;
}
return naturalCompare(typeA.name, typeB.name);
})
.map((x) => x.name);
}
/**
* For the field name provided, determine if there are any similar field names
* that may be the result of a typo.
*/
function getSuggestedFieldNames(
type: GraphQLOutputType,
fieldName: string,
): Array<string> {
if (isObjectType(type) || isInterfaceType(type)) {
const possibleFieldNames = Object.keys(type.getFields());
return suggestionList(fieldName, possibleFieldNames);
}
// Otherwise, must be a Union type, which does not define fields.
return [];
}

View File

@@ -0,0 +1,117 @@
import arrayFrom from "../../polyfills/arrayFrom.mjs";
import didYouMean from "../../jsutils/didYouMean.mjs";
import suggestionList from "../../jsutils/suggestionList.mjs";
import naturalCompare from "../../jsutils/naturalCompare.mjs";
import { GraphQLError } from "../../error/GraphQLError.mjs";
import { isObjectType, isInterfaceType, isAbstractType } from "../../type/definition.mjs";
/**
* Fields on correct type
*
* A GraphQL document is only valid if all fields selected are defined by the
* parent type, or are an allowed meta field such as __typename.
*/
export function FieldsOnCorrectTypeRule(context) {
return {
Field: function Field(node) {
var type = context.getParentType();
if (type) {
var fieldDef = context.getFieldDef();
if (!fieldDef) {
// This field doesn't exist, lets look for suggestions.
var schema = context.getSchema();
var fieldName = node.name.value; // First determine if there are any suggested types to condition on.
var suggestion = didYouMean('to use an inline fragment on', getSuggestedTypeNames(schema, type, fieldName)); // If there are no suggested types, then perhaps this was a typo?
if (suggestion === '') {
suggestion = didYouMean(getSuggestedFieldNames(type, fieldName));
} // Report an error, including helpful suggestions.
context.reportError(new GraphQLError("Cannot query field \"".concat(fieldName, "\" on type \"").concat(type.name, "\".") + suggestion, node));
}
}
}
};
}
/**
* Go through all of the implementations of type, as well as the interfaces that
* they implement. If any of those types include the provided field, suggest them,
* sorted by how often the type is referenced.
*/
function getSuggestedTypeNames(schema, type, fieldName) {
if (!isAbstractType(type)) {
// Must be an Object type, which does not have possible fields.
return [];
}
var suggestedTypes = new Set();
var usageCount = Object.create(null);
for (var _i2 = 0, _schema$getPossibleTy2 = schema.getPossibleTypes(type); _i2 < _schema$getPossibleTy2.length; _i2++) {
var possibleType = _schema$getPossibleTy2[_i2];
if (!possibleType.getFields()[fieldName]) {
continue;
} // This object type defines this field.
suggestedTypes.add(possibleType);
usageCount[possibleType.name] = 1;
for (var _i4 = 0, _possibleType$getInte2 = possibleType.getInterfaces(); _i4 < _possibleType$getInte2.length; _i4++) {
var _usageCount$possibleI;
var possibleInterface = _possibleType$getInte2[_i4];
if (!possibleInterface.getFields()[fieldName]) {
continue;
} // This interface type defines this field.
suggestedTypes.add(possibleInterface);
usageCount[possibleInterface.name] = ((_usageCount$possibleI = usageCount[possibleInterface.name]) !== null && _usageCount$possibleI !== void 0 ? _usageCount$possibleI : 0) + 1;
}
}
return arrayFrom(suggestedTypes).sort(function (typeA, typeB) {
// Suggest both interface and object types based on how common they are.
var usageCountDiff = usageCount[typeB.name] - usageCount[typeA.name];
if (usageCountDiff !== 0) {
return usageCountDiff;
} // Suggest super types first followed by subtypes
if (isInterfaceType(typeA) && schema.isSubType(typeA, typeB)) {
return -1;
}
if (isInterfaceType(typeB) && schema.isSubType(typeB, typeA)) {
return 1;
}
return naturalCompare(typeA.name, typeB.name);
}).map(function (x) {
return x.name;
});
}
/**
* For the field name provided, determine if there are any similar field names
* that may be the result of a typo.
*/
function getSuggestedFieldNames(type, fieldName) {
if (isObjectType(type) || isInterfaceType(type)) {
var possibleFieldNames = Object.keys(type.getFields());
return suggestionList(fieldName, possibleFieldNames);
} // Otherwise, must be a Union type, which does not define fields.
return [];
}

View File

@@ -0,0 +1,13 @@
import { ASTVisitor } from '../../language/visitor';
import { ValidationContext } from '../ValidationContext';
/**
* Fragments on composite type
*
* Fragments use a type condition to determine if they apply, since fragments
* can only be spread into a composite type (object, interface, or union), the
* type condition must also be a composite type.
*/
export function FragmentsOnCompositeTypesRule(
context: ValidationContext,
): ASTVisitor;

View File

@@ -0,0 +1,46 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.FragmentsOnCompositeTypesRule = FragmentsOnCompositeTypesRule;
var _GraphQLError = require("../../error/GraphQLError.js");
var _printer = require("../../language/printer.js");
var _definition = require("../../type/definition.js");
var _typeFromAST = require("../../utilities/typeFromAST.js");
/**
* Fragments on composite type
*
* Fragments use a type condition to determine if they apply, since fragments
* can only be spread into a composite type (object, interface, or union), the
* type condition must also be a composite type.
*/
function FragmentsOnCompositeTypesRule(context) {
return {
InlineFragment: function InlineFragment(node) {
var typeCondition = node.typeCondition;
if (typeCondition) {
var type = (0, _typeFromAST.typeFromAST)(context.getSchema(), typeCondition);
if (type && !(0, _definition.isCompositeType)(type)) {
var typeStr = (0, _printer.print)(typeCondition);
context.reportError(new _GraphQLError.GraphQLError("Fragment cannot condition on non composite type \"".concat(typeStr, "\"."), typeCondition));
}
}
},
FragmentDefinition: function FragmentDefinition(node) {
var type = (0, _typeFromAST.typeFromAST)(context.getSchema(), node.typeCondition);
if (type && !(0, _definition.isCompositeType)(type)) {
var typeStr = (0, _printer.print)(node.typeCondition);
context.reportError(new _GraphQLError.GraphQLError("Fragment \"".concat(node.name.value, "\" cannot condition on non composite type \"").concat(typeStr, "\"."), node.typeCondition));
}
}
};
}

View File

@@ -0,0 +1,52 @@
// @flow strict
import { GraphQLError } from '../../error/GraphQLError';
import type { ASTVisitor } from '../../language/visitor';
import { print } from '../../language/printer';
import { isCompositeType } from '../../type/definition';
import { typeFromAST } from '../../utilities/typeFromAST';
import type { ValidationContext } from '../ValidationContext';
/**
* Fragments on composite type
*
* Fragments use a type condition to determine if they apply, since fragments
* can only be spread into a composite type (object, interface, or union), the
* type condition must also be a composite type.
*/
export function FragmentsOnCompositeTypesRule(
context: ValidationContext,
): ASTVisitor {
return {
InlineFragment(node) {
const typeCondition = node.typeCondition;
if (typeCondition) {
const type = typeFromAST(context.getSchema(), typeCondition);
if (type && !isCompositeType(type)) {
const typeStr = print(typeCondition);
context.reportError(
new GraphQLError(
`Fragment cannot condition on non composite type "${typeStr}".`,
typeCondition,
),
);
}
}
},
FragmentDefinition(node) {
const type = typeFromAST(context.getSchema(), node.typeCondition);
if (type && !isCompositeType(type)) {
const typeStr = print(node.typeCondition);
context.reportError(
new GraphQLError(
`Fragment "${node.name.value}" cannot condition on non composite type "${typeStr}".`,
node.typeCondition,
),
);
}
},
};
}

View File

@@ -0,0 +1,36 @@
import { GraphQLError } from "../../error/GraphQLError.mjs";
import { print } from "../../language/printer.mjs";
import { isCompositeType } from "../../type/definition.mjs";
import { typeFromAST } from "../../utilities/typeFromAST.mjs";
/**
* Fragments on composite type
*
* Fragments use a type condition to determine if they apply, since fragments
* can only be spread into a composite type (object, interface, or union), the
* type condition must also be a composite type.
*/
export function FragmentsOnCompositeTypesRule(context) {
return {
InlineFragment: function InlineFragment(node) {
var typeCondition = node.typeCondition;
if (typeCondition) {
var type = typeFromAST(context.getSchema(), typeCondition);
if (type && !isCompositeType(type)) {
var typeStr = print(typeCondition);
context.reportError(new GraphQLError("Fragment cannot condition on non composite type \"".concat(typeStr, "\"."), typeCondition));
}
}
},
FragmentDefinition: function FragmentDefinition(node) {
var type = typeFromAST(context.getSchema(), node.typeCondition);
if (type && !isCompositeType(type)) {
var typeStr = print(node.typeCondition);
context.reportError(new GraphQLError("Fragment \"".concat(node.name.value, "\" cannot condition on non composite type \"").concat(typeStr, "\"."), node.typeCondition));
}
}
};
}

View File

@@ -0,0 +1,17 @@
import { ValidationContext, SDLValidationContext } from '../ValidationContext';
import { ASTVisitor } from '../../language/visitor';
/**
* Known argument names
*
* A GraphQL field is only valid if all supplied arguments are defined by
* that field.
*/
export function KnownArgumentNamesRule(context: ValidationContext): ASTVisitor;
/**
* @internal
*/
export function KnownArgumentNamesOnDirectivesRule(
context: ValidationContext | SDLValidationContext,
): ASTVisitor;

View File

@@ -0,0 +1,104 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.KnownArgumentNamesRule = KnownArgumentNamesRule;
exports.KnownArgumentNamesOnDirectivesRule = KnownArgumentNamesOnDirectivesRule;
var _didYouMean = _interopRequireDefault(require("../../jsutils/didYouMean.js"));
var _suggestionList = _interopRequireDefault(require("../../jsutils/suggestionList.js"));
var _GraphQLError = require("../../error/GraphQLError.js");
var _kinds = require("../../language/kinds.js");
var _directives = require("../../type/directives.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
/**
* Known argument names
*
* A GraphQL field is only valid if all supplied arguments are defined by
* that field.
*/
function KnownArgumentNamesRule(context) {
return _objectSpread(_objectSpread({}, KnownArgumentNamesOnDirectivesRule(context)), {}, {
Argument: function Argument(argNode) {
var argDef = context.getArgument();
var fieldDef = context.getFieldDef();
var parentType = context.getParentType();
if (!argDef && fieldDef && parentType) {
var argName = argNode.name.value;
var knownArgsNames = fieldDef.args.map(function (arg) {
return arg.name;
});
var suggestions = (0, _suggestionList.default)(argName, knownArgsNames);
context.reportError(new _GraphQLError.GraphQLError("Unknown argument \"".concat(argName, "\" on field \"").concat(parentType.name, ".").concat(fieldDef.name, "\".") + (0, _didYouMean.default)(suggestions), argNode));
}
}
});
}
/**
* @internal
*/
function KnownArgumentNamesOnDirectivesRule(context) {
var directiveArgs = Object.create(null);
var schema = context.getSchema();
var definedDirectives = schema ? schema.getDirectives() : _directives.specifiedDirectives;
for (var _i2 = 0; _i2 < definedDirectives.length; _i2++) {
var directive = definedDirectives[_i2];
directiveArgs[directive.name] = directive.args.map(function (arg) {
return arg.name;
});
}
var astDefinitions = context.getDocument().definitions;
for (var _i4 = 0; _i4 < astDefinitions.length; _i4++) {
var def = astDefinitions[_i4];
if (def.kind === _kinds.Kind.DIRECTIVE_DEFINITION) {
var _def$arguments;
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var argsNodes = (_def$arguments = def.arguments) !== null && _def$arguments !== void 0 ? _def$arguments : [];
directiveArgs[def.name.value] = argsNodes.map(function (arg) {
return arg.name.value;
});
}
}
return {
Directive: function Directive(directiveNode) {
var directiveName = directiveNode.name.value;
var knownArgs = directiveArgs[directiveName];
if (directiveNode.arguments && knownArgs) {
for (var _i6 = 0, _directiveNode$argume2 = directiveNode.arguments; _i6 < _directiveNode$argume2.length; _i6++) {
var argNode = _directiveNode$argume2[_i6];
var argName = argNode.name.value;
if (knownArgs.indexOf(argName) === -1) {
var suggestions = (0, _suggestionList.default)(argName, knownArgs);
context.reportError(new _GraphQLError.GraphQLError("Unknown argument \"".concat(argName, "\" on directive \"@").concat(directiveName, "\".") + (0, _didYouMean.default)(suggestions), argNode));
}
}
}
return false;
}
};
}

View File

@@ -0,0 +1,98 @@
// @flow strict
import didYouMean from '../../jsutils/didYouMean';
import suggestionList from '../../jsutils/suggestionList';
import { GraphQLError } from '../../error/GraphQLError';
import type { ASTVisitor } from '../../language/visitor';
import { Kind } from '../../language/kinds';
import { specifiedDirectives } from '../../type/directives';
import type {
ValidationContext,
SDLValidationContext,
} from '../ValidationContext';
/**
* Known argument names
*
* A GraphQL field is only valid if all supplied arguments are defined by
* that field.
*/
export function KnownArgumentNamesRule(context: ValidationContext): ASTVisitor {
return {
// eslint-disable-next-line new-cap
...KnownArgumentNamesOnDirectivesRule(context),
Argument(argNode) {
const argDef = context.getArgument();
const fieldDef = context.getFieldDef();
const parentType = context.getParentType();
if (!argDef && fieldDef && parentType) {
const argName = argNode.name.value;
const knownArgsNames = fieldDef.args.map((arg) => arg.name);
const suggestions = suggestionList(argName, knownArgsNames);
context.reportError(
new GraphQLError(
`Unknown argument "${argName}" on field "${parentType.name}.${fieldDef.name}".` +
didYouMean(suggestions),
argNode,
),
);
}
},
};
}
/**
* @internal
*/
export function KnownArgumentNamesOnDirectivesRule(
context: ValidationContext | SDLValidationContext,
): ASTVisitor {
const directiveArgs = Object.create(null);
const schema = context.getSchema();
const definedDirectives = schema
? schema.getDirectives()
: specifiedDirectives;
for (const directive of definedDirectives) {
directiveArgs[directive.name] = directive.args.map((arg) => arg.name);
}
const astDefinitions = context.getDocument().definitions;
for (const def of astDefinitions) {
if (def.kind === Kind.DIRECTIVE_DEFINITION) {
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
const argsNodes = def.arguments ?? [];
directiveArgs[def.name.value] = argsNodes.map((arg) => arg.name.value);
}
}
return {
Directive(directiveNode) {
const directiveName = directiveNode.name.value;
const knownArgs = directiveArgs[directiveName];
if (directiveNode.arguments && knownArgs) {
for (const argNode of directiveNode.arguments) {
const argName = argNode.name.value;
if (knownArgs.indexOf(argName) === -1) {
const suggestions = suggestionList(argName, knownArgs);
context.reportError(
new GraphQLError(
`Unknown argument "${argName}" on directive "@${directiveName}".` +
didYouMean(suggestions),
argNode,
),
);
}
}
}
return false;
},
};
}

View File

@@ -0,0 +1,89 @@
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import didYouMean from "../../jsutils/didYouMean.mjs";
import suggestionList from "../../jsutils/suggestionList.mjs";
import { GraphQLError } from "../../error/GraphQLError.mjs";
import { Kind } from "../../language/kinds.mjs";
import { specifiedDirectives } from "../../type/directives.mjs";
/**
* Known argument names
*
* A GraphQL field is only valid if all supplied arguments are defined by
* that field.
*/
export function KnownArgumentNamesRule(context) {
return _objectSpread(_objectSpread({}, KnownArgumentNamesOnDirectivesRule(context)), {}, {
Argument: function Argument(argNode) {
var argDef = context.getArgument();
var fieldDef = context.getFieldDef();
var parentType = context.getParentType();
if (!argDef && fieldDef && parentType) {
var argName = argNode.name.value;
var knownArgsNames = fieldDef.args.map(function (arg) {
return arg.name;
});
var suggestions = suggestionList(argName, knownArgsNames);
context.reportError(new GraphQLError("Unknown argument \"".concat(argName, "\" on field \"").concat(parentType.name, ".").concat(fieldDef.name, "\".") + didYouMean(suggestions), argNode));
}
}
});
}
/**
* @internal
*/
export function KnownArgumentNamesOnDirectivesRule(context) {
var directiveArgs = Object.create(null);
var schema = context.getSchema();
var definedDirectives = schema ? schema.getDirectives() : specifiedDirectives;
for (var _i2 = 0; _i2 < definedDirectives.length; _i2++) {
var directive = definedDirectives[_i2];
directiveArgs[directive.name] = directive.args.map(function (arg) {
return arg.name;
});
}
var astDefinitions = context.getDocument().definitions;
for (var _i4 = 0; _i4 < astDefinitions.length; _i4++) {
var def = astDefinitions[_i4];
if (def.kind === Kind.DIRECTIVE_DEFINITION) {
var _def$arguments;
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var argsNodes = (_def$arguments = def.arguments) !== null && _def$arguments !== void 0 ? _def$arguments : [];
directiveArgs[def.name.value] = argsNodes.map(function (arg) {
return arg.name.value;
});
}
}
return {
Directive: function Directive(directiveNode) {
var directiveName = directiveNode.name.value;
var knownArgs = directiveArgs[directiveName];
if (directiveNode.arguments && knownArgs) {
for (var _i6 = 0, _directiveNode$argume2 = directiveNode.arguments; _i6 < _directiveNode$argume2.length; _i6++) {
var argNode = _directiveNode$argume2[_i6];
var argName = argNode.name.value;
if (knownArgs.indexOf(argName) === -1) {
var suggestions = suggestionList(argName, knownArgs);
context.reportError(new GraphQLError("Unknown argument \"".concat(argName, "\" on directive \"@").concat(directiveName, "\".") + didYouMean(suggestions), argNode));
}
}
}
return false;
}
};
}

View File

@@ -0,0 +1,12 @@
import { ASTVisitor } from '../../language/visitor';
import { ValidationContext, SDLValidationContext } from '../ValidationContext';
/**
* Known directives
*
* A GraphQL document is only valid if all `@directives` are known by the
* schema and legally positioned.
*/
export function KnownDirectivesRule(
context: ValidationContext | SDLValidationContext,
): ASTVisitor;

View File

@@ -0,0 +1,148 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.KnownDirectivesRule = KnownDirectivesRule;
var _inspect = _interopRequireDefault(require("../../jsutils/inspect.js"));
var _invariant = _interopRequireDefault(require("../../jsutils/invariant.js"));
var _GraphQLError = require("../../error/GraphQLError.js");
var _kinds = require("../../language/kinds.js");
var _directiveLocation = require("../../language/directiveLocation.js");
var _directives = require("../../type/directives.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Known directives
*
* A GraphQL document is only valid if all `@directives` are known by the
* schema and legally positioned.
*/
function KnownDirectivesRule(context) {
var locationsMap = Object.create(null);
var schema = context.getSchema();
var definedDirectives = schema ? schema.getDirectives() : _directives.specifiedDirectives;
for (var _i2 = 0; _i2 < definedDirectives.length; _i2++) {
var directive = definedDirectives[_i2];
locationsMap[directive.name] = directive.locations;
}
var astDefinitions = context.getDocument().definitions;
for (var _i4 = 0; _i4 < astDefinitions.length; _i4++) {
var def = astDefinitions[_i4];
if (def.kind === _kinds.Kind.DIRECTIVE_DEFINITION) {
locationsMap[def.name.value] = def.locations.map(function (name) {
return name.value;
});
}
}
return {
Directive: function Directive(node, _key, _parent, _path, ancestors) {
var name = node.name.value;
var locations = locationsMap[name];
if (!locations) {
context.reportError(new _GraphQLError.GraphQLError("Unknown directive \"@".concat(name, "\"."), node));
return;
}
var candidateLocation = getDirectiveLocationForASTPath(ancestors);
if (candidateLocation && locations.indexOf(candidateLocation) === -1) {
context.reportError(new _GraphQLError.GraphQLError("Directive \"@".concat(name, "\" may not be used on ").concat(candidateLocation, "."), node));
}
}
};
}
function getDirectiveLocationForASTPath(ancestors) {
var appliedTo = ancestors[ancestors.length - 1];
!Array.isArray(appliedTo) || (0, _invariant.default)(0);
switch (appliedTo.kind) {
case _kinds.Kind.OPERATION_DEFINITION:
return getDirectiveLocationForOperation(appliedTo.operation);
case _kinds.Kind.FIELD:
return _directiveLocation.DirectiveLocation.FIELD;
case _kinds.Kind.FRAGMENT_SPREAD:
return _directiveLocation.DirectiveLocation.FRAGMENT_SPREAD;
case _kinds.Kind.INLINE_FRAGMENT:
return _directiveLocation.DirectiveLocation.INLINE_FRAGMENT;
case _kinds.Kind.FRAGMENT_DEFINITION:
return _directiveLocation.DirectiveLocation.FRAGMENT_DEFINITION;
case _kinds.Kind.VARIABLE_DEFINITION:
return _directiveLocation.DirectiveLocation.VARIABLE_DEFINITION;
case _kinds.Kind.SCHEMA_DEFINITION:
case _kinds.Kind.SCHEMA_EXTENSION:
return _directiveLocation.DirectiveLocation.SCHEMA;
case _kinds.Kind.SCALAR_TYPE_DEFINITION:
case _kinds.Kind.SCALAR_TYPE_EXTENSION:
return _directiveLocation.DirectiveLocation.SCALAR;
case _kinds.Kind.OBJECT_TYPE_DEFINITION:
case _kinds.Kind.OBJECT_TYPE_EXTENSION:
return _directiveLocation.DirectiveLocation.OBJECT;
case _kinds.Kind.FIELD_DEFINITION:
return _directiveLocation.DirectiveLocation.FIELD_DEFINITION;
case _kinds.Kind.INTERFACE_TYPE_DEFINITION:
case _kinds.Kind.INTERFACE_TYPE_EXTENSION:
return _directiveLocation.DirectiveLocation.INTERFACE;
case _kinds.Kind.UNION_TYPE_DEFINITION:
case _kinds.Kind.UNION_TYPE_EXTENSION:
return _directiveLocation.DirectiveLocation.UNION;
case _kinds.Kind.ENUM_TYPE_DEFINITION:
case _kinds.Kind.ENUM_TYPE_EXTENSION:
return _directiveLocation.DirectiveLocation.ENUM;
case _kinds.Kind.ENUM_VALUE_DEFINITION:
return _directiveLocation.DirectiveLocation.ENUM_VALUE;
case _kinds.Kind.INPUT_OBJECT_TYPE_DEFINITION:
case _kinds.Kind.INPUT_OBJECT_TYPE_EXTENSION:
return _directiveLocation.DirectiveLocation.INPUT_OBJECT;
case _kinds.Kind.INPUT_VALUE_DEFINITION:
{
var parentNode = ancestors[ancestors.length - 3];
return parentNode.kind === _kinds.Kind.INPUT_OBJECT_TYPE_DEFINITION ? _directiveLocation.DirectiveLocation.INPUT_FIELD_DEFINITION : _directiveLocation.DirectiveLocation.ARGUMENT_DEFINITION;
}
}
}
function getDirectiveLocationForOperation(operation) {
switch (operation) {
case 'query':
return _directiveLocation.DirectiveLocation.QUERY;
case 'mutation':
return _directiveLocation.DirectiveLocation.MUTATION;
case 'subscription':
return _directiveLocation.DirectiveLocation.SUBSCRIPTION;
} // istanbul ignore next (Not reachable. All possible types have been considered)
false || (0, _invariant.default)(0, 'Unexpected operation: ' + (0, _inspect.default)(operation));
}

View File

@@ -0,0 +1,138 @@
// @flow strict
import inspect from '../../jsutils/inspect';
import invariant from '../../jsutils/invariant';
import { GraphQLError } from '../../error/GraphQLError';
import type { ASTVisitor } from '../../language/visitor';
import type { ASTNode, OperationTypeNode } from '../../language/ast';
import type { DirectiveLocationEnum } from '../../language/directiveLocation';
import { Kind } from '../../language/kinds';
import { DirectiveLocation } from '../../language/directiveLocation';
import { specifiedDirectives } from '../../type/directives';
import type {
ValidationContext,
SDLValidationContext,
} from '../ValidationContext';
/**
* Known directives
*
* A GraphQL document is only valid if all `@directives` are known by the
* schema and legally positioned.
*/
export function KnownDirectivesRule(
context: ValidationContext | SDLValidationContext,
): ASTVisitor {
const locationsMap = Object.create(null);
const schema = context.getSchema();
const definedDirectives = schema
? schema.getDirectives()
: specifiedDirectives;
for (const directive of definedDirectives) {
locationsMap[directive.name] = directive.locations;
}
const astDefinitions = context.getDocument().definitions;
for (const def of astDefinitions) {
if (def.kind === Kind.DIRECTIVE_DEFINITION) {
locationsMap[def.name.value] = def.locations.map((name) => name.value);
}
}
return {
Directive(node, _key, _parent, _path, ancestors) {
const name = node.name.value;
const locations = locationsMap[name];
if (!locations) {
context.reportError(
new GraphQLError(`Unknown directive "@${name}".`, node),
);
return;
}
const candidateLocation = getDirectiveLocationForASTPath(ancestors);
if (candidateLocation && locations.indexOf(candidateLocation) === -1) {
context.reportError(
new GraphQLError(
`Directive "@${name}" may not be used on ${candidateLocation}.`,
node,
),
);
}
},
};
}
function getDirectiveLocationForASTPath(
ancestors: $ReadOnlyArray<ASTNode | $ReadOnlyArray<ASTNode>>,
): DirectiveLocationEnum | void {
const appliedTo = ancestors[ancestors.length - 1];
invariant(!Array.isArray(appliedTo));
switch (appliedTo.kind) {
case Kind.OPERATION_DEFINITION:
return getDirectiveLocationForOperation(appliedTo.operation);
case Kind.FIELD:
return DirectiveLocation.FIELD;
case Kind.FRAGMENT_SPREAD:
return DirectiveLocation.FRAGMENT_SPREAD;
case Kind.INLINE_FRAGMENT:
return DirectiveLocation.INLINE_FRAGMENT;
case Kind.FRAGMENT_DEFINITION:
return DirectiveLocation.FRAGMENT_DEFINITION;
case Kind.VARIABLE_DEFINITION:
return DirectiveLocation.VARIABLE_DEFINITION;
case Kind.SCHEMA_DEFINITION:
case Kind.SCHEMA_EXTENSION:
return DirectiveLocation.SCHEMA;
case Kind.SCALAR_TYPE_DEFINITION:
case Kind.SCALAR_TYPE_EXTENSION:
return DirectiveLocation.SCALAR;
case Kind.OBJECT_TYPE_DEFINITION:
case Kind.OBJECT_TYPE_EXTENSION:
return DirectiveLocation.OBJECT;
case Kind.FIELD_DEFINITION:
return DirectiveLocation.FIELD_DEFINITION;
case Kind.INTERFACE_TYPE_DEFINITION:
case Kind.INTERFACE_TYPE_EXTENSION:
return DirectiveLocation.INTERFACE;
case Kind.UNION_TYPE_DEFINITION:
case Kind.UNION_TYPE_EXTENSION:
return DirectiveLocation.UNION;
case Kind.ENUM_TYPE_DEFINITION:
case Kind.ENUM_TYPE_EXTENSION:
return DirectiveLocation.ENUM;
case Kind.ENUM_VALUE_DEFINITION:
return DirectiveLocation.ENUM_VALUE;
case Kind.INPUT_OBJECT_TYPE_DEFINITION:
case Kind.INPUT_OBJECT_TYPE_EXTENSION:
return DirectiveLocation.INPUT_OBJECT;
case Kind.INPUT_VALUE_DEFINITION: {
const parentNode = ancestors[ancestors.length - 3];
return parentNode.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION
? DirectiveLocation.INPUT_FIELD_DEFINITION
: DirectiveLocation.ARGUMENT_DEFINITION;
}
}
}
function getDirectiveLocationForOperation(
operation: OperationTypeNode,
): DirectiveLocationEnum {
switch (operation) {
case 'query':
return DirectiveLocation.QUERY;
case 'mutation':
return DirectiveLocation.MUTATION;
case 'subscription':
return DirectiveLocation.SUBSCRIPTION;
}
// istanbul ignore next (Not reachable. All possible types have been considered)
invariant(false, 'Unexpected operation: ' + inspect((operation: empty)));
}

View File

@@ -0,0 +1,134 @@
import inspect from "../../jsutils/inspect.mjs";
import invariant from "../../jsutils/invariant.mjs";
import { GraphQLError } from "../../error/GraphQLError.mjs";
import { Kind } from "../../language/kinds.mjs";
import { DirectiveLocation } from "../../language/directiveLocation.mjs";
import { specifiedDirectives } from "../../type/directives.mjs";
/**
* Known directives
*
* A GraphQL document is only valid if all `@directives` are known by the
* schema and legally positioned.
*/
export function KnownDirectivesRule(context) {
var locationsMap = Object.create(null);
var schema = context.getSchema();
var definedDirectives = schema ? schema.getDirectives() : specifiedDirectives;
for (var _i2 = 0; _i2 < definedDirectives.length; _i2++) {
var directive = definedDirectives[_i2];
locationsMap[directive.name] = directive.locations;
}
var astDefinitions = context.getDocument().definitions;
for (var _i4 = 0; _i4 < astDefinitions.length; _i4++) {
var def = astDefinitions[_i4];
if (def.kind === Kind.DIRECTIVE_DEFINITION) {
locationsMap[def.name.value] = def.locations.map(function (name) {
return name.value;
});
}
}
return {
Directive: function Directive(node, _key, _parent, _path, ancestors) {
var name = node.name.value;
var locations = locationsMap[name];
if (!locations) {
context.reportError(new GraphQLError("Unknown directive \"@".concat(name, "\"."), node));
return;
}
var candidateLocation = getDirectiveLocationForASTPath(ancestors);
if (candidateLocation && locations.indexOf(candidateLocation) === -1) {
context.reportError(new GraphQLError("Directive \"@".concat(name, "\" may not be used on ").concat(candidateLocation, "."), node));
}
}
};
}
function getDirectiveLocationForASTPath(ancestors) {
var appliedTo = ancestors[ancestors.length - 1];
!Array.isArray(appliedTo) || invariant(0);
switch (appliedTo.kind) {
case Kind.OPERATION_DEFINITION:
return getDirectiveLocationForOperation(appliedTo.operation);
case Kind.FIELD:
return DirectiveLocation.FIELD;
case Kind.FRAGMENT_SPREAD:
return DirectiveLocation.FRAGMENT_SPREAD;
case Kind.INLINE_FRAGMENT:
return DirectiveLocation.INLINE_FRAGMENT;
case Kind.FRAGMENT_DEFINITION:
return DirectiveLocation.FRAGMENT_DEFINITION;
case Kind.VARIABLE_DEFINITION:
return DirectiveLocation.VARIABLE_DEFINITION;
case Kind.SCHEMA_DEFINITION:
case Kind.SCHEMA_EXTENSION:
return DirectiveLocation.SCHEMA;
case Kind.SCALAR_TYPE_DEFINITION:
case Kind.SCALAR_TYPE_EXTENSION:
return DirectiveLocation.SCALAR;
case Kind.OBJECT_TYPE_DEFINITION:
case Kind.OBJECT_TYPE_EXTENSION:
return DirectiveLocation.OBJECT;
case Kind.FIELD_DEFINITION:
return DirectiveLocation.FIELD_DEFINITION;
case Kind.INTERFACE_TYPE_DEFINITION:
case Kind.INTERFACE_TYPE_EXTENSION:
return DirectiveLocation.INTERFACE;
case Kind.UNION_TYPE_DEFINITION:
case Kind.UNION_TYPE_EXTENSION:
return DirectiveLocation.UNION;
case Kind.ENUM_TYPE_DEFINITION:
case Kind.ENUM_TYPE_EXTENSION:
return DirectiveLocation.ENUM;
case Kind.ENUM_VALUE_DEFINITION:
return DirectiveLocation.ENUM_VALUE;
case Kind.INPUT_OBJECT_TYPE_DEFINITION:
case Kind.INPUT_OBJECT_TYPE_EXTENSION:
return DirectiveLocation.INPUT_OBJECT;
case Kind.INPUT_VALUE_DEFINITION:
{
var parentNode = ancestors[ancestors.length - 3];
return parentNode.kind === Kind.INPUT_OBJECT_TYPE_DEFINITION ? DirectiveLocation.INPUT_FIELD_DEFINITION : DirectiveLocation.ARGUMENT_DEFINITION;
}
}
}
function getDirectiveLocationForOperation(operation) {
switch (operation) {
case 'query':
return DirectiveLocation.QUERY;
case 'mutation':
return DirectiveLocation.MUTATION;
case 'subscription':
return DirectiveLocation.SUBSCRIPTION;
} // istanbul ignore next (Not reachable. All possible types have been considered)
false || invariant(0, 'Unexpected operation: ' + inspect(operation));
}

View File

@@ -0,0 +1,10 @@
import { ASTVisitor } from '../../language/visitor';
import { ValidationContext } from '../ValidationContext';
/**
* Known fragment names
*
* A GraphQL document is only valid if all `...Fragment` fragment spreads refer
* to fragments defined in the same document.
*/
export function KnownFragmentNamesRule(context: ValidationContext): ASTVisitor;

View File

@@ -0,0 +1,27 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.KnownFragmentNamesRule = KnownFragmentNamesRule;
var _GraphQLError = require("../../error/GraphQLError.js");
/**
* Known fragment names
*
* A GraphQL document is only valid if all `...Fragment` fragment spreads refer
* to fragments defined in the same document.
*/
function KnownFragmentNamesRule(context) {
return {
FragmentSpread: function FragmentSpread(node) {
var fragmentName = node.name.value;
var fragment = context.getFragment(fragmentName);
if (!fragment) {
context.reportError(new _GraphQLError.GraphQLError("Unknown fragment \"".concat(fragmentName, "\"."), node.name));
}
}
};
}

View File

@@ -0,0 +1,26 @@
// @flow strict
import { GraphQLError } from '../../error/GraphQLError';
import type { ASTVisitor } from '../../language/visitor';
import type { ValidationContext } from '../ValidationContext';
/**
* Known fragment names
*
* A GraphQL document is only valid if all `...Fragment` fragment spreads refer
* to fragments defined in the same document.
*/
export function KnownFragmentNamesRule(context: ValidationContext): ASTVisitor {
return {
FragmentSpread(node) {
const fragmentName = node.name.value;
const fragment = context.getFragment(fragmentName);
if (!fragment) {
context.reportError(
new GraphQLError(`Unknown fragment "${fragmentName}".`, node.name),
);
}
},
};
}

View File

@@ -0,0 +1,20 @@
import { GraphQLError } from "../../error/GraphQLError.mjs";
/**
* Known fragment names
*
* A GraphQL document is only valid if all `...Fragment` fragment spreads refer
* to fragments defined in the same document.
*/
export function KnownFragmentNamesRule(context) {
return {
FragmentSpread: function FragmentSpread(node) {
var fragmentName = node.name.value;
var fragment = context.getFragment(fragmentName);
if (!fragment) {
context.reportError(new GraphQLError("Unknown fragment \"".concat(fragmentName, "\"."), node.name));
}
}
};
}

View File

@@ -0,0 +1,12 @@
import { ASTVisitor } from '../../language/visitor';
import { ValidationContext, SDLValidationContext } from '../ValidationContext';
/**
* Known type names
*
* A GraphQL document is only valid if referenced types (specifically
* variable definitions and fragment conditions) are defined by the type schema.
*/
export function KnownTypeNamesRule(
context: ValidationContext | SDLValidationContext,
): ASTVisitor;

View File

@@ -0,0 +1,73 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.KnownTypeNamesRule = KnownTypeNamesRule;
var _didYouMean = _interopRequireDefault(require("../../jsutils/didYouMean.js"));
var _suggestionList = _interopRequireDefault(require("../../jsutils/suggestionList.js"));
var _GraphQLError = require("../../error/GraphQLError.js");
var _predicates = require("../../language/predicates.js");
var _scalars = require("../../type/scalars.js");
var _introspection = require("../../type/introspection.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Known type names
*
* A GraphQL document is only valid if referenced types (specifically
* variable definitions and fragment conditions) are defined by the type schema.
*/
function KnownTypeNamesRule(context) {
var schema = context.getSchema();
var existingTypesMap = schema ? schema.getTypeMap() : Object.create(null);
var definedTypes = Object.create(null);
for (var _i2 = 0, _context$getDocument$2 = context.getDocument().definitions; _i2 < _context$getDocument$2.length; _i2++) {
var def = _context$getDocument$2[_i2];
if ((0, _predicates.isTypeDefinitionNode)(def)) {
definedTypes[def.name.value] = true;
}
}
var typeNames = Object.keys(existingTypesMap).concat(Object.keys(definedTypes));
return {
NamedType: function NamedType(node, _1, parent, _2, ancestors) {
var typeName = node.name.value;
if (!existingTypesMap[typeName] && !definedTypes[typeName]) {
var _ancestors$;
var definitionNode = (_ancestors$ = ancestors[2]) !== null && _ancestors$ !== void 0 ? _ancestors$ : parent;
var isSDL = definitionNode != null && isSDLNode(definitionNode);
if (isSDL && isStandardTypeName(typeName)) {
return;
}
var suggestedTypes = (0, _suggestionList.default)(typeName, isSDL ? standardTypeNames.concat(typeNames) : typeNames);
context.reportError(new _GraphQLError.GraphQLError("Unknown type \"".concat(typeName, "\".") + (0, _didYouMean.default)(suggestedTypes), node));
}
}
};
}
var standardTypeNames = [].concat(_scalars.specifiedScalarTypes, _introspection.introspectionTypes).map(function (type) {
return type.name;
});
function isStandardTypeName(typeName) {
return standardTypeNames.indexOf(typeName) !== -1;
}
function isSDLNode(value) {
return !Array.isArray(value) && ((0, _predicates.isTypeSystemDefinitionNode)(value) || (0, _predicates.isTypeSystemExtensionNode)(value));
}

View File

@@ -0,0 +1,84 @@
// @flow strict
import didYouMean from '../../jsutils/didYouMean';
import suggestionList from '../../jsutils/suggestionList';
import { GraphQLError } from '../../error/GraphQLError';
import type { ASTNode } from '../../language/ast';
import type { ASTVisitor } from '../../language/visitor';
import {
isTypeDefinitionNode,
isTypeSystemDefinitionNode,
isTypeSystemExtensionNode,
} from '../../language/predicates';
import { specifiedScalarTypes } from '../../type/scalars';
import { introspectionTypes } from '../../type/introspection';
import type {
ValidationContext,
SDLValidationContext,
} from '../ValidationContext';
/**
* Known type names
*
* A GraphQL document is only valid if referenced types (specifically
* variable definitions and fragment conditions) are defined by the type schema.
*/
export function KnownTypeNamesRule(
context: ValidationContext | SDLValidationContext,
): ASTVisitor {
const schema = context.getSchema();
const existingTypesMap = schema ? schema.getTypeMap() : Object.create(null);
const definedTypes = Object.create(null);
for (const def of context.getDocument().definitions) {
if (isTypeDefinitionNode(def)) {
definedTypes[def.name.value] = true;
}
}
const typeNames = Object.keys(existingTypesMap).concat(
Object.keys(definedTypes),
);
return {
NamedType(node, _1, parent, _2, ancestors) {
const typeName = node.name.value;
if (!existingTypesMap[typeName] && !definedTypes[typeName]) {
const definitionNode = ancestors[2] ?? parent;
const isSDL = definitionNode != null && isSDLNode(definitionNode);
if (isSDL && isStandardTypeName(typeName)) {
return;
}
const suggestedTypes = suggestionList(
typeName,
isSDL ? standardTypeNames.concat(typeNames) : typeNames,
);
context.reportError(
new GraphQLError(
`Unknown type "${typeName}".` + didYouMean(suggestedTypes),
node,
),
);
}
},
};
}
const standardTypeNames = [...specifiedScalarTypes, ...introspectionTypes].map(
(type) => type.name,
);
function isStandardTypeName(typeName: string): boolean {
return standardTypeNames.indexOf(typeName) !== -1;
}
function isSDLNode(value: ASTNode | $ReadOnlyArray<ASTNode>): boolean {
return (
!Array.isArray(value) &&
(isTypeSystemDefinitionNode(value) || isTypeSystemExtensionNode(value))
);
}

View File

@@ -0,0 +1,58 @@
import didYouMean from "../../jsutils/didYouMean.mjs";
import suggestionList from "../../jsutils/suggestionList.mjs";
import { GraphQLError } from "../../error/GraphQLError.mjs";
import { isTypeDefinitionNode, isTypeSystemDefinitionNode, isTypeSystemExtensionNode } from "../../language/predicates.mjs";
import { specifiedScalarTypes } from "../../type/scalars.mjs";
import { introspectionTypes } from "../../type/introspection.mjs";
/**
* Known type names
*
* A GraphQL document is only valid if referenced types (specifically
* variable definitions and fragment conditions) are defined by the type schema.
*/
export function KnownTypeNamesRule(context) {
var schema = context.getSchema();
var existingTypesMap = schema ? schema.getTypeMap() : Object.create(null);
var definedTypes = Object.create(null);
for (var _i2 = 0, _context$getDocument$2 = context.getDocument().definitions; _i2 < _context$getDocument$2.length; _i2++) {
var def = _context$getDocument$2[_i2];
if (isTypeDefinitionNode(def)) {
definedTypes[def.name.value] = true;
}
}
var typeNames = Object.keys(existingTypesMap).concat(Object.keys(definedTypes));
return {
NamedType: function NamedType(node, _1, parent, _2, ancestors) {
var typeName = node.name.value;
if (!existingTypesMap[typeName] && !definedTypes[typeName]) {
var _ancestors$;
var definitionNode = (_ancestors$ = ancestors[2]) !== null && _ancestors$ !== void 0 ? _ancestors$ : parent;
var isSDL = definitionNode != null && isSDLNode(definitionNode);
if (isSDL && isStandardTypeName(typeName)) {
return;
}
var suggestedTypes = suggestionList(typeName, isSDL ? standardTypeNames.concat(typeNames) : typeNames);
context.reportError(new GraphQLError("Unknown type \"".concat(typeName, "\".") + didYouMean(suggestedTypes), node));
}
}
};
}
var standardTypeNames = [].concat(specifiedScalarTypes, introspectionTypes).map(function (type) {
return type.name;
});
function isStandardTypeName(typeName) {
return standardTypeNames.indexOf(typeName) !== -1;
}
function isSDLNode(value) {
return !Array.isArray(value) && (isTypeSystemDefinitionNode(value) || isTypeSystemExtensionNode(value));
}

View File

@@ -0,0 +1,12 @@
import { ASTVisitor } from '../../language/visitor';
import { ASTValidationContext } from '../ValidationContext';
/**
* Lone anonymous operation
*
* A GraphQL document is only valid if when it contains an anonymous operation
* (the query short-hand) that it contains only that one operation definition.
*/
export function LoneAnonymousOperationRule(
context: ASTValidationContext,
): ASTVisitor;

View File

@@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.LoneAnonymousOperationRule = LoneAnonymousOperationRule;
var _GraphQLError = require("../../error/GraphQLError.js");
var _kinds = require("../../language/kinds.js");
/**
* Lone anonymous operation
*
* A GraphQL document is only valid if when it contains an anonymous operation
* (the query short-hand) that it contains only that one operation definition.
*/
function LoneAnonymousOperationRule(context) {
var operationCount = 0;
return {
Document: function Document(node) {
operationCount = node.definitions.filter(function (definition) {
return definition.kind === _kinds.Kind.OPERATION_DEFINITION;
}).length;
},
OperationDefinition: function OperationDefinition(node) {
if (!node.name && operationCount > 1) {
context.reportError(new _GraphQLError.GraphQLError('This anonymous operation must be the only defined operation.', node));
}
}
};
}

View File

@@ -0,0 +1,36 @@
// @flow strict
import { GraphQLError } from '../../error/GraphQLError';
import type { ASTVisitor } from '../../language/visitor';
import { Kind } from '../../language/kinds';
import type { ASTValidationContext } from '../ValidationContext';
/**
* Lone anonymous operation
*
* A GraphQL document is only valid if when it contains an anonymous operation
* (the query short-hand) that it contains only that one operation definition.
*/
export function LoneAnonymousOperationRule(
context: ASTValidationContext,
): ASTVisitor {
let operationCount = 0;
return {
Document(node) {
operationCount = node.definitions.filter(
(definition) => definition.kind === Kind.OPERATION_DEFINITION,
).length;
},
OperationDefinition(node) {
if (!node.name && operationCount > 1) {
context.reportError(
new GraphQLError(
'This anonymous operation must be the only defined operation.',
node,
),
);
}
},
};
}

View File

@@ -0,0 +1,24 @@
import { GraphQLError } from "../../error/GraphQLError.mjs";
import { Kind } from "../../language/kinds.mjs";
/**
* Lone anonymous operation
*
* A GraphQL document is only valid if when it contains an anonymous operation
* (the query short-hand) that it contains only that one operation definition.
*/
export function LoneAnonymousOperationRule(context) {
var operationCount = 0;
return {
Document: function Document(node) {
operationCount = node.definitions.filter(function (definition) {
return definition.kind === Kind.OPERATION_DEFINITION;
}).length;
},
OperationDefinition: function OperationDefinition(node) {
if (!node.name && operationCount > 1) {
context.reportError(new GraphQLError('This anonymous operation must be the only defined operation.', node));
}
}
};
}

View File

@@ -0,0 +1,8 @@
/**
* @deprecated and will be removed in v16
* Please use either:
* import { LoneSchemaDefinitionRule } from 'graphql'
* or
* import { LoneSchemaDefinitionRule } from 'graphql/validation'
*/
export { LoneSchemaDefinitionRule as LoneSchemaDefinition } from './LoneSchemaDefinitionRule';

View File

@@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "LoneSchemaDefinition", {
enumerable: true,
get: function get() {
return _LoneSchemaDefinitionRule.LoneSchemaDefinitionRule;
}
});
var _LoneSchemaDefinitionRule = require("./LoneSchemaDefinitionRule.js");

View File

@@ -0,0 +1,9 @@
// @flow strict
/**
* @deprecated and will be removed in v16
* Please use either:
* import { LoneSchemaDefinitionRule } from 'graphql'
* or
* import { LoneSchemaDefinitionRule } from 'graphql/validation'
*/
export { LoneSchemaDefinitionRule as LoneSchemaDefinition } from './LoneSchemaDefinitionRule';

View File

@@ -0,0 +1,8 @@
/**
* @deprecated and will be removed in v16
* Please use either:
* import { LoneSchemaDefinitionRule } from 'graphql'
* or
* import { LoneSchemaDefinitionRule } from 'graphql/validation'
*/
export { LoneSchemaDefinitionRule as LoneSchemaDefinition } from "./LoneSchemaDefinitionRule.mjs";

View File

@@ -0,0 +1,11 @@
import { ASTVisitor } from '../../language/visitor';
import { SDLValidationContext } from '../ValidationContext';
/**
* Lone Schema definition
*
* A GraphQL document is only valid if it contains only one schema definition.
*/
export function LoneSchemaDefinitionRule(
context: SDLValidationContext,
): ASTVisitor;

View File

@@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.LoneSchemaDefinitionRule = LoneSchemaDefinitionRule;
var _GraphQLError = require("../../error/GraphQLError.js");
/**
* Lone Schema definition
*
* A GraphQL document is only valid if it contains only one schema definition.
*/
function LoneSchemaDefinitionRule(context) {
var _ref, _ref2, _oldSchema$astNode;
var oldSchema = context.getSchema();
var alreadyDefined = (_ref = (_ref2 = (_oldSchema$astNode = oldSchema === null || oldSchema === void 0 ? void 0 : oldSchema.astNode) !== null && _oldSchema$astNode !== void 0 ? _oldSchema$astNode : oldSchema === null || oldSchema === void 0 ? void 0 : oldSchema.getQueryType()) !== null && _ref2 !== void 0 ? _ref2 : oldSchema === null || oldSchema === void 0 ? void 0 : oldSchema.getMutationType()) !== null && _ref !== void 0 ? _ref : oldSchema === null || oldSchema === void 0 ? void 0 : oldSchema.getSubscriptionType();
var schemaDefinitionsCount = 0;
return {
SchemaDefinition: function SchemaDefinition(node) {
if (alreadyDefined) {
context.reportError(new _GraphQLError.GraphQLError('Cannot define a new schema within a schema extension.', node));
return;
}
if (schemaDefinitionsCount > 0) {
context.reportError(new _GraphQLError.GraphQLError('Must provide only one schema definition.', node));
}
++schemaDefinitionsCount;
}
};
}

View File

@@ -0,0 +1,43 @@
// @flow strict
import { GraphQLError } from '../../error/GraphQLError';
import type { ASTVisitor } from '../../language/visitor';
import type { SDLValidationContext } from '../ValidationContext';
/**
* Lone Schema definition
*
* A GraphQL document is only valid if it contains only one schema definition.
*/
export function LoneSchemaDefinitionRule(
context: SDLValidationContext,
): ASTVisitor {
const oldSchema = context.getSchema();
const alreadyDefined =
oldSchema?.astNode ??
oldSchema?.getQueryType() ??
oldSchema?.getMutationType() ??
oldSchema?.getSubscriptionType();
let schemaDefinitionsCount = 0;
return {
SchemaDefinition(node) {
if (alreadyDefined) {
context.reportError(
new GraphQLError(
'Cannot define a new schema within a schema extension.',
node,
),
);
return;
}
if (schemaDefinitionsCount > 0) {
context.reportError(
new GraphQLError('Must provide only one schema definition.', node),
);
}
++schemaDefinitionsCount;
},
};
}

View File

@@ -0,0 +1,28 @@
import { GraphQLError } from "../../error/GraphQLError.mjs";
/**
* Lone Schema definition
*
* A GraphQL document is only valid if it contains only one schema definition.
*/
export function LoneSchemaDefinitionRule(context) {
var _ref, _ref2, _oldSchema$astNode;
var oldSchema = context.getSchema();
var alreadyDefined = (_ref = (_ref2 = (_oldSchema$astNode = oldSchema === null || oldSchema === void 0 ? void 0 : oldSchema.astNode) !== null && _oldSchema$astNode !== void 0 ? _oldSchema$astNode : oldSchema === null || oldSchema === void 0 ? void 0 : oldSchema.getQueryType()) !== null && _ref2 !== void 0 ? _ref2 : oldSchema === null || oldSchema === void 0 ? void 0 : oldSchema.getMutationType()) !== null && _ref !== void 0 ? _ref : oldSchema === null || oldSchema === void 0 ? void 0 : oldSchema.getSubscriptionType();
var schemaDefinitionsCount = 0;
return {
SchemaDefinition: function SchemaDefinition(node) {
if (alreadyDefined) {
context.reportError(new GraphQLError('Cannot define a new schema within a schema extension.', node));
return;
}
if (schemaDefinitionsCount > 0) {
context.reportError(new GraphQLError('Must provide only one schema definition.', node));
}
++schemaDefinitionsCount;
}
};
}

View File

@@ -0,0 +1,4 @@
import { ASTVisitor } from '../../language/visitor';
import { ValidationContext } from '../ValidationContext';
export function NoFragmentCyclesRule(context: ValidationContext): ASTVisitor;

View File

@@ -0,0 +1,70 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.NoFragmentCyclesRule = NoFragmentCyclesRule;
var _GraphQLError = require("../../error/GraphQLError.js");
function NoFragmentCyclesRule(context) {
// Tracks already visited fragments to maintain O(N) and to ensure that cycles
// are not redundantly reported.
var visitedFrags = Object.create(null); // Array of AST nodes used to produce meaningful errors
var spreadPath = []; // Position in the spread path
var spreadPathIndexByName = Object.create(null);
return {
OperationDefinition: function OperationDefinition() {
return false;
},
FragmentDefinition: function FragmentDefinition(node) {
detectCycleRecursive(node);
return false;
}
}; // This does a straight-forward DFS to find cycles.
// It does not terminate when a cycle was found but continues to explore
// the graph to find all possible cycles.
function detectCycleRecursive(fragment) {
if (visitedFrags[fragment.name.value]) {
return;
}
var fragmentName = fragment.name.value;
visitedFrags[fragmentName] = true;
var spreadNodes = context.getFragmentSpreads(fragment.selectionSet);
if (spreadNodes.length === 0) {
return;
}
spreadPathIndexByName[fragmentName] = spreadPath.length;
for (var _i2 = 0; _i2 < spreadNodes.length; _i2++) {
var spreadNode = spreadNodes[_i2];
var spreadName = spreadNode.name.value;
var cycleIndex = spreadPathIndexByName[spreadName];
spreadPath.push(spreadNode);
if (cycleIndex === undefined) {
var spreadFragment = context.getFragment(spreadName);
if (spreadFragment) {
detectCycleRecursive(spreadFragment);
}
} else {
var cyclePath = spreadPath.slice(cycleIndex);
var viaPath = cyclePath.slice(0, -1).map(function (s) {
return '"' + s.name.value + '"';
}).join(', ');
context.reportError(new _GraphQLError.GraphQLError("Cannot spread fragment \"".concat(spreadName, "\" within itself") + (viaPath !== '' ? " via ".concat(viaPath, ".") : '.'), cyclePath));
}
spreadPath.pop();
}
spreadPathIndexByName[fragmentName] = undefined;
}
}

View File

@@ -0,0 +1,78 @@
// @flow strict
import { GraphQLError } from '../../error/GraphQLError';
import type { ASTVisitor } from '../../language/visitor';
import type { FragmentDefinitionNode } from '../../language/ast';
import type { ASTValidationContext } from '../ValidationContext';
export function NoFragmentCyclesRule(
context: ASTValidationContext,
): ASTVisitor {
// Tracks already visited fragments to maintain O(N) and to ensure that cycles
// are not redundantly reported.
const visitedFrags = Object.create(null);
// Array of AST nodes used to produce meaningful errors
const spreadPath = [];
// Position in the spread path
const spreadPathIndexByName = Object.create(null);
return {
OperationDefinition: () => false,
FragmentDefinition(node) {
detectCycleRecursive(node);
return false;
},
};
// This does a straight-forward DFS to find cycles.
// It does not terminate when a cycle was found but continues to explore
// the graph to find all possible cycles.
function detectCycleRecursive(fragment: FragmentDefinitionNode): void {
if (visitedFrags[fragment.name.value]) {
return;
}
const fragmentName = fragment.name.value;
visitedFrags[fragmentName] = true;
const spreadNodes = context.getFragmentSpreads(fragment.selectionSet);
if (spreadNodes.length === 0) {
return;
}
spreadPathIndexByName[fragmentName] = spreadPath.length;
for (const spreadNode of spreadNodes) {
const spreadName = spreadNode.name.value;
const cycleIndex = spreadPathIndexByName[spreadName];
spreadPath.push(spreadNode);
if (cycleIndex === undefined) {
const spreadFragment = context.getFragment(spreadName);
if (spreadFragment) {
detectCycleRecursive(spreadFragment);
}
} else {
const cyclePath = spreadPath.slice(cycleIndex);
const viaPath = cyclePath
.slice(0, -1)
.map((s) => '"' + s.name.value + '"')
.join(', ');
context.reportError(
new GraphQLError(
`Cannot spread fragment "${spreadName}" within itself` +
(viaPath !== '' ? ` via ${viaPath}.` : '.'),
cyclePath,
),
);
}
spreadPath.pop();
}
spreadPathIndexByName[fragmentName] = undefined;
}
}

View File

@@ -0,0 +1,62 @@
import { GraphQLError } from "../../error/GraphQLError.mjs";
export function NoFragmentCyclesRule(context) {
// Tracks already visited fragments to maintain O(N) and to ensure that cycles
// are not redundantly reported.
var visitedFrags = Object.create(null); // Array of AST nodes used to produce meaningful errors
var spreadPath = []; // Position in the spread path
var spreadPathIndexByName = Object.create(null);
return {
OperationDefinition: function OperationDefinition() {
return false;
},
FragmentDefinition: function FragmentDefinition(node) {
detectCycleRecursive(node);
return false;
}
}; // This does a straight-forward DFS to find cycles.
// It does not terminate when a cycle was found but continues to explore
// the graph to find all possible cycles.
function detectCycleRecursive(fragment) {
if (visitedFrags[fragment.name.value]) {
return;
}
var fragmentName = fragment.name.value;
visitedFrags[fragmentName] = true;
var spreadNodes = context.getFragmentSpreads(fragment.selectionSet);
if (spreadNodes.length === 0) {
return;
}
spreadPathIndexByName[fragmentName] = spreadPath.length;
for (var _i2 = 0; _i2 < spreadNodes.length; _i2++) {
var spreadNode = spreadNodes[_i2];
var spreadName = spreadNode.name.value;
var cycleIndex = spreadPathIndexByName[spreadName];
spreadPath.push(spreadNode);
if (cycleIndex === undefined) {
var spreadFragment = context.getFragment(spreadName);
if (spreadFragment) {
detectCycleRecursive(spreadFragment);
}
} else {
var cyclePath = spreadPath.slice(cycleIndex);
var viaPath = cyclePath.slice(0, -1).map(function (s) {
return '"' + s.name.value + '"';
}).join(', ');
context.reportError(new GraphQLError("Cannot spread fragment \"".concat(spreadName, "\" within itself") + (viaPath !== '' ? " via ".concat(viaPath, ".") : '.'), cyclePath));
}
spreadPath.pop();
}
spreadPathIndexByName[fragmentName] = undefined;
}
}

View File

@@ -0,0 +1,12 @@
import { ASTVisitor } from '../../language/visitor';
import { ValidationContext } from '../ValidationContext';
/**
* No undefined variables
*
* A GraphQL operation is only valid if all variables encountered, both directly
* and via fragment spreads, are defined by that operation.
*/
export function NoUndefinedVariablesRule(
context: ValidationContext,
): ASTVisitor;

View File

@@ -0,0 +1,41 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.NoUndefinedVariablesRule = NoUndefinedVariablesRule;
var _GraphQLError = require("../../error/GraphQLError.js");
/**
* No undefined variables
*
* A GraphQL operation is only valid if all variables encountered, both directly
* and via fragment spreads, are defined by that operation.
*/
function NoUndefinedVariablesRule(context) {
var variableNameDefined = Object.create(null);
return {
OperationDefinition: {
enter: function enter() {
variableNameDefined = Object.create(null);
},
leave: function leave(operation) {
var usages = context.getRecursiveVariableUsages(operation);
for (var _i2 = 0; _i2 < usages.length; _i2++) {
var _ref2 = usages[_i2];
var node = _ref2.node;
var varName = node.name.value;
if (variableNameDefined[varName] !== true) {
context.reportError(new _GraphQLError.GraphQLError(operation.name ? "Variable \"$".concat(varName, "\" is not defined by operation \"").concat(operation.name.value, "\".") : "Variable \"$".concat(varName, "\" is not defined."), [node, operation]));
}
}
}
},
VariableDefinition: function VariableDefinition(node) {
variableNameDefined[node.variable.name.value] = true;
}
};
}

View File

@@ -0,0 +1,46 @@
// @flow strict
import { GraphQLError } from '../../error/GraphQLError';
import type { ASTVisitor } from '../../language/visitor';
import type { ValidationContext } from '../ValidationContext';
/**
* No undefined variables
*
* A GraphQL operation is only valid if all variables encountered, both directly
* and via fragment spreads, are defined by that operation.
*/
export function NoUndefinedVariablesRule(
context: ValidationContext,
): ASTVisitor {
let variableNameDefined = Object.create(null);
return {
OperationDefinition: {
enter() {
variableNameDefined = Object.create(null);
},
leave(operation) {
const usages = context.getRecursiveVariableUsages(operation);
for (const { node } of usages) {
const varName = node.name.value;
if (variableNameDefined[varName] !== true) {
context.reportError(
new GraphQLError(
operation.name
? `Variable "$${varName}" is not defined by operation "${operation.name.value}".`
: `Variable "$${varName}" is not defined.`,
[node, operation],
),
);
}
}
},
},
VariableDefinition(node) {
variableNameDefined[node.variable.name.value] = true;
},
};
}

View File

@@ -0,0 +1,34 @@
import { GraphQLError } from "../../error/GraphQLError.mjs";
/**
* No undefined variables
*
* A GraphQL operation is only valid if all variables encountered, both directly
* and via fragment spreads, are defined by that operation.
*/
export function NoUndefinedVariablesRule(context) {
var variableNameDefined = Object.create(null);
return {
OperationDefinition: {
enter: function enter() {
variableNameDefined = Object.create(null);
},
leave: function leave(operation) {
var usages = context.getRecursiveVariableUsages(operation);
for (var _i2 = 0; _i2 < usages.length; _i2++) {
var _ref2 = usages[_i2];
var node = _ref2.node;
var varName = node.name.value;
if (variableNameDefined[varName] !== true) {
context.reportError(new GraphQLError(operation.name ? "Variable \"$".concat(varName, "\" is not defined by operation \"").concat(operation.name.value, "\".") : "Variable \"$".concat(varName, "\" is not defined."), [node, operation]));
}
}
}
},
VariableDefinition: function VariableDefinition(node) {
variableNameDefined[node.variable.name.value] = true;
}
};
}

View File

@@ -0,0 +1,10 @@
import { ASTVisitor } from '../../language/visitor';
import { ValidationContext } from '../ValidationContext';
/**
* No unused fragments
*
* A GraphQL document is only valid if all fragment definitions are spread
* within operations, or spread within other fragments spread within operations.
*/
export function NoUnusedFragmentsRule(context: ValidationContext): ASTVisitor;

View File

@@ -0,0 +1,52 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.NoUnusedFragmentsRule = NoUnusedFragmentsRule;
var _GraphQLError = require("../../error/GraphQLError.js");
/**
* No unused fragments
*
* A GraphQL document is only valid if all fragment definitions are spread
* within operations, or spread within other fragments spread within operations.
*/
function NoUnusedFragmentsRule(context) {
var operationDefs = [];
var fragmentDefs = [];
return {
OperationDefinition: function OperationDefinition(node) {
operationDefs.push(node);
return false;
},
FragmentDefinition: function FragmentDefinition(node) {
fragmentDefs.push(node);
return false;
},
Document: {
leave: function leave() {
var fragmentNameUsed = Object.create(null);
for (var _i2 = 0; _i2 < operationDefs.length; _i2++) {
var operation = operationDefs[_i2];
for (var _i4 = 0, _context$getRecursive2 = context.getRecursivelyReferencedFragments(operation); _i4 < _context$getRecursive2.length; _i4++) {
var fragment = _context$getRecursive2[_i4];
fragmentNameUsed[fragment.name.value] = true;
}
}
for (var _i6 = 0; _i6 < fragmentDefs.length; _i6++) {
var fragmentDef = fragmentDefs[_i6];
var fragName = fragmentDef.name.value;
if (fragmentNameUsed[fragName] !== true) {
context.reportError(new _GraphQLError.GraphQLError("Fragment \"".concat(fragName, "\" is never used."), fragmentDef));
}
}
}
}
};
}

View File

@@ -0,0 +1,54 @@
// @flow strict
import { GraphQLError } from '../../error/GraphQLError';
import type { ASTVisitor } from '../../language/visitor';
import type { ASTValidationContext } from '../ValidationContext';
/**
* No unused fragments
*
* A GraphQL document is only valid if all fragment definitions are spread
* within operations, or spread within other fragments spread within operations.
*/
export function NoUnusedFragmentsRule(
context: ASTValidationContext,
): ASTVisitor {
const operationDefs = [];
const fragmentDefs = [];
return {
OperationDefinition(node) {
operationDefs.push(node);
return false;
},
FragmentDefinition(node) {
fragmentDefs.push(node);
return false;
},
Document: {
leave() {
const fragmentNameUsed = Object.create(null);
for (const operation of operationDefs) {
for (const fragment of context.getRecursivelyReferencedFragments(
operation,
)) {
fragmentNameUsed[fragment.name.value] = true;
}
}
for (const fragmentDef of fragmentDefs) {
const fragName = fragmentDef.name.value;
if (fragmentNameUsed[fragName] !== true) {
context.reportError(
new GraphQLError(
`Fragment "${fragName}" is never used.`,
fragmentDef,
),
);
}
}
},
},
};
}

View File

@@ -0,0 +1,45 @@
import { GraphQLError } from "../../error/GraphQLError.mjs";
/**
* No unused fragments
*
* A GraphQL document is only valid if all fragment definitions are spread
* within operations, or spread within other fragments spread within operations.
*/
export function NoUnusedFragmentsRule(context) {
var operationDefs = [];
var fragmentDefs = [];
return {
OperationDefinition: function OperationDefinition(node) {
operationDefs.push(node);
return false;
},
FragmentDefinition: function FragmentDefinition(node) {
fragmentDefs.push(node);
return false;
},
Document: {
leave: function leave() {
var fragmentNameUsed = Object.create(null);
for (var _i2 = 0; _i2 < operationDefs.length; _i2++) {
var operation = operationDefs[_i2];
for (var _i4 = 0, _context$getRecursive2 = context.getRecursivelyReferencedFragments(operation); _i4 < _context$getRecursive2.length; _i4++) {
var fragment = _context$getRecursive2[_i4];
fragmentNameUsed[fragment.name.value] = true;
}
}
for (var _i6 = 0; _i6 < fragmentDefs.length; _i6++) {
var fragmentDef = fragmentDefs[_i6];
var fragName = fragmentDef.name.value;
if (fragmentNameUsed[fragName] !== true) {
context.reportError(new GraphQLError("Fragment \"".concat(fragName, "\" is never used."), fragmentDef));
}
}
}
}
};
}

View File

@@ -0,0 +1,10 @@
import { ASTVisitor } from '../../language/visitor';
import { ValidationContext } from '../ValidationContext';
/**
* No unused variables
*
* A GraphQL operation is only valid if all variables defined by an operation
* are used, either directly or within a spread fragment.
*/
export function NoUnusedVariablesRule(context: ValidationContext): ASTVisitor;

View File

@@ -0,0 +1,47 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.NoUnusedVariablesRule = NoUnusedVariablesRule;
var _GraphQLError = require("../../error/GraphQLError.js");
/**
* No unused variables
*
* A GraphQL operation is only valid if all variables defined by an operation
* are used, either directly or within a spread fragment.
*/
function NoUnusedVariablesRule(context) {
var variableDefs = [];
return {
OperationDefinition: {
enter: function enter() {
variableDefs = [];
},
leave: function leave(operation) {
var variableNameUsed = Object.create(null);
var usages = context.getRecursiveVariableUsages(operation);
for (var _i2 = 0; _i2 < usages.length; _i2++) {
var _ref2 = usages[_i2];
var node = _ref2.node;
variableNameUsed[node.name.value] = true;
}
for (var _i4 = 0, _variableDefs2 = variableDefs; _i4 < _variableDefs2.length; _i4++) {
var variableDef = _variableDefs2[_i4];
var variableName = variableDef.variable.name.value;
if (variableNameUsed[variableName] !== true) {
context.reportError(new _GraphQLError.GraphQLError(operation.name ? "Variable \"$".concat(variableName, "\" is never used in operation \"").concat(operation.name.value, "\".") : "Variable \"$".concat(variableName, "\" is never used."), variableDef));
}
}
}
},
VariableDefinition: function VariableDefinition(def) {
variableDefs.push(def);
}
};
}

View File

@@ -0,0 +1,49 @@
// @flow strict
import { GraphQLError } from '../../error/GraphQLError';
import type { ASTVisitor } from '../../language/visitor';
import type { ValidationContext } from '../ValidationContext';
/**
* No unused variables
*
* A GraphQL operation is only valid if all variables defined by an operation
* are used, either directly or within a spread fragment.
*/
export function NoUnusedVariablesRule(context: ValidationContext): ASTVisitor {
let variableDefs = [];
return {
OperationDefinition: {
enter() {
variableDefs = [];
},
leave(operation) {
const variableNameUsed = Object.create(null);
const usages = context.getRecursiveVariableUsages(operation);
for (const { node } of usages) {
variableNameUsed[node.name.value] = true;
}
for (const variableDef of variableDefs) {
const variableName = variableDef.variable.name.value;
if (variableNameUsed[variableName] !== true) {
context.reportError(
new GraphQLError(
operation.name
? `Variable "$${variableName}" is never used in operation "${operation.name.value}".`
: `Variable "$${variableName}" is never used.`,
variableDef,
),
);
}
}
},
},
VariableDefinition(def) {
variableDefs.push(def);
},
};
}

View File

@@ -0,0 +1,40 @@
import { GraphQLError } from "../../error/GraphQLError.mjs";
/**
* No unused variables
*
* A GraphQL operation is only valid if all variables defined by an operation
* are used, either directly or within a spread fragment.
*/
export function NoUnusedVariablesRule(context) {
var variableDefs = [];
return {
OperationDefinition: {
enter: function enter() {
variableDefs = [];
},
leave: function leave(operation) {
var variableNameUsed = Object.create(null);
var usages = context.getRecursiveVariableUsages(operation);
for (var _i2 = 0; _i2 < usages.length; _i2++) {
var _ref2 = usages[_i2];
var node = _ref2.node;
variableNameUsed[node.name.value] = true;
}
for (var _i4 = 0, _variableDefs2 = variableDefs; _i4 < _variableDefs2.length; _i4++) {
var variableDef = _variableDefs2[_i4];
var variableName = variableDef.variable.name.value;
if (variableNameUsed[variableName] !== true) {
context.reportError(new GraphQLError(operation.name ? "Variable \"$".concat(variableName, "\" is never used in operation \"").concat(operation.name.value, "\".") : "Variable \"$".concat(variableName, "\" is never used."), variableDef));
}
}
}
},
VariableDefinition: function VariableDefinition(def) {
variableDefs.push(def);
}
};
}

View File

@@ -0,0 +1,13 @@
import { ASTVisitor } from '../../language/visitor';
import { ValidationContext } from '../ValidationContext';
/**
* Overlapping fields can be merged
*
* A selection set is only valid if all fields (including spreading any
* fragments) either correspond to distinct response names or can be merged
* without ambiguity.
*/
export function OverlappingFieldsCanBeMergedRule(
context: ValidationContext,
): ASTVisitor;

View File

@@ -0,0 +1,584 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.OverlappingFieldsCanBeMergedRule = OverlappingFieldsCanBeMergedRule;
var _find = _interopRequireDefault(require("../../polyfills/find.js"));
var _objectEntries3 = _interopRequireDefault(require("../../polyfills/objectEntries.js"));
var _inspect = _interopRequireDefault(require("../../jsutils/inspect.js"));
var _GraphQLError = require("../../error/GraphQLError.js");
var _kinds = require("../../language/kinds.js");
var _printer = require("../../language/printer.js");
var _definition = require("../../type/definition.js");
var _typeFromAST = require("../../utilities/typeFromAST.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function reasonMessage(reason) {
if (Array.isArray(reason)) {
return reason.map(function (_ref) {
var responseName = _ref[0],
subReason = _ref[1];
return "subfields \"".concat(responseName, "\" conflict because ") + reasonMessage(subReason);
}).join(' and ');
}
return reason;
}
/**
* Overlapping fields can be merged
*
* A selection set is only valid if all fields (including spreading any
* fragments) either correspond to distinct response names or can be merged
* without ambiguity.
*/
function OverlappingFieldsCanBeMergedRule(context) {
// A memoization for when two fragments are compared "between" each other for
// conflicts. Two fragments may be compared many times, so memoizing this can
// dramatically improve the performance of this validator.
var comparedFragmentPairs = new PairSet(); // A cache for the "field map" and list of fragment names found in any given
// selection set. Selection sets may be asked for this information multiple
// times, so this improves the performance of this validator.
var cachedFieldsAndFragmentNames = new Map();
return {
SelectionSet: function SelectionSet(selectionSet) {
var conflicts = findConflictsWithinSelectionSet(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, context.getParentType(), selectionSet);
for (var _i2 = 0; _i2 < conflicts.length; _i2++) {
var _ref3 = conflicts[_i2];
var _ref2$ = _ref3[0];
var responseName = _ref2$[0];
var reason = _ref2$[1];
var fields1 = _ref3[1];
var fields2 = _ref3[2];
var reasonMsg = reasonMessage(reason);
context.reportError(new _GraphQLError.GraphQLError("Fields \"".concat(responseName, "\" conflict because ").concat(reasonMsg, ". Use different aliases on the fields to fetch both if this was intentional."), fields1.concat(fields2)));
}
}
};
}
/**
* Algorithm:
*
* Conflicts occur when two fields exist in a query which will produce the same
* response name, but represent differing values, thus creating a conflict.
* The algorithm below finds all conflicts via making a series of comparisons
* between fields. In order to compare as few fields as possible, this makes
* a series of comparisons "within" sets of fields and "between" sets of fields.
*
* Given any selection set, a collection produces both a set of fields by
* also including all inline fragments, as well as a list of fragments
* referenced by fragment spreads.
*
* A) Each selection set represented in the document first compares "within" its
* collected set of fields, finding any conflicts between every pair of
* overlapping fields.
* Note: This is the *only time* that a the fields "within" a set are compared
* to each other. After this only fields "between" sets are compared.
*
* B) Also, if any fragment is referenced in a selection set, then a
* comparison is made "between" the original set of fields and the
* referenced fragment.
*
* C) Also, if multiple fragments are referenced, then comparisons
* are made "between" each referenced fragment.
*
* D) When comparing "between" a set of fields and a referenced fragment, first
* a comparison is made between each field in the original set of fields and
* each field in the the referenced set of fields.
*
* E) Also, if any fragment is referenced in the referenced selection set,
* then a comparison is made "between" the original set of fields and the
* referenced fragment (recursively referring to step D).
*
* F) When comparing "between" two fragments, first a comparison is made between
* each field in the first referenced set of fields and each field in the the
* second referenced set of fields.
*
* G) Also, any fragments referenced by the first must be compared to the
* second, and any fragments referenced by the second must be compared to the
* first (recursively referring to step F).
*
* H) When comparing two fields, if both have selection sets, then a comparison
* is made "between" both selection sets, first comparing the set of fields in
* the first selection set with the set of fields in the second.
*
* I) Also, if any fragment is referenced in either selection set, then a
* comparison is made "between" the other set of fields and the
* referenced fragment.
*
* J) Also, if two fragments are referenced in both selection sets, then a
* comparison is made "between" the two fragments.
*
*/
// Find all conflicts found "within" a selection set, including those found
// via spreading in fragments. Called when visiting each SelectionSet in the
// GraphQL Document.
function findConflictsWithinSelectionSet(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, parentType, selectionSet) {
var conflicts = [];
var _getFieldsAndFragment = getFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, parentType, selectionSet),
fieldMap = _getFieldsAndFragment[0],
fragmentNames = _getFieldsAndFragment[1]; // (A) Find find all conflicts "within" the fields of this selection set.
// Note: this is the *only place* `collectConflictsWithin` is called.
collectConflictsWithin(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, fieldMap);
if (fragmentNames.length !== 0) {
// (B) Then collect conflicts between these fields and those represented by
// each spread fragment name found.
for (var i = 0; i < fragmentNames.length; i++) {
collectConflictsBetweenFieldsAndFragment(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, false, fieldMap, fragmentNames[i]); // (C) Then compare this fragment with all other fragments found in this
// selection set to collect conflicts between fragments spread together.
// This compares each item in the list of fragment names to every other
// item in that same list (except for itself).
for (var j = i + 1; j < fragmentNames.length; j++) {
collectConflictsBetweenFragments(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, false, fragmentNames[i], fragmentNames[j]);
}
}
}
return conflicts;
} // Collect all conflicts found between a set of fields and a fragment reference
// including via spreading in any nested fragments.
function collectConflictsBetweenFieldsAndFragment(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap, fragmentName) {
var fragment = context.getFragment(fragmentName);
if (!fragment) {
return;
}
var _getReferencedFieldsA = getReferencedFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, fragment),
fieldMap2 = _getReferencedFieldsA[0],
fragmentNames2 = _getReferencedFieldsA[1]; // Do not compare a fragment's fieldMap to itself.
if (fieldMap === fieldMap2) {
return;
} // (D) First collect any conflicts between the provided collection of fields
// and the collection of fields represented by the given fragment.
collectConflictsBetween(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap, fieldMap2); // (E) Then collect any conflicts between the provided collection of fields
// and any fragment names found in the given fragment.
for (var i = 0; i < fragmentNames2.length; i++) {
collectConflictsBetweenFieldsAndFragment(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap, fragmentNames2[i]);
}
} // Collect all conflicts found between two fragments, including via spreading in
// any nested fragments.
function collectConflictsBetweenFragments(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fragmentName1, fragmentName2) {
// No need to compare a fragment to itself.
if (fragmentName1 === fragmentName2) {
return;
} // Memoize so two fragments are not compared for conflicts more than once.
if (comparedFragmentPairs.has(fragmentName1, fragmentName2, areMutuallyExclusive)) {
return;
}
comparedFragmentPairs.add(fragmentName1, fragmentName2, areMutuallyExclusive);
var fragment1 = context.getFragment(fragmentName1);
var fragment2 = context.getFragment(fragmentName2);
if (!fragment1 || !fragment2) {
return;
}
var _getReferencedFieldsA2 = getReferencedFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, fragment1),
fieldMap1 = _getReferencedFieldsA2[0],
fragmentNames1 = _getReferencedFieldsA2[1];
var _getReferencedFieldsA3 = getReferencedFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, fragment2),
fieldMap2 = _getReferencedFieldsA3[0],
fragmentNames2 = _getReferencedFieldsA3[1]; // (F) First, collect all conflicts between these two collections of fields
// (not including any nested fragments).
collectConflictsBetween(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap1, fieldMap2); // (G) Then collect conflicts between the first fragment and any nested
// fragments spread in the second fragment.
for (var j = 0; j < fragmentNames2.length; j++) {
collectConflictsBetweenFragments(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fragmentName1, fragmentNames2[j]);
} // (G) Then collect conflicts between the second fragment and any nested
// fragments spread in the first fragment.
for (var i = 0; i < fragmentNames1.length; i++) {
collectConflictsBetweenFragments(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fragmentNames1[i], fragmentName2);
}
} // Find all conflicts found between two selection sets, including those found
// via spreading in fragments. Called when determining if conflicts exist
// between the sub-fields of two overlapping fields.
function findConflictsBetweenSubSelectionSets(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, parentType1, selectionSet1, parentType2, selectionSet2) {
var conflicts = [];
var _getFieldsAndFragment2 = getFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, parentType1, selectionSet1),
fieldMap1 = _getFieldsAndFragment2[0],
fragmentNames1 = _getFieldsAndFragment2[1];
var _getFieldsAndFragment3 = getFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, parentType2, selectionSet2),
fieldMap2 = _getFieldsAndFragment3[0],
fragmentNames2 = _getFieldsAndFragment3[1]; // (H) First, collect all conflicts between these two collections of field.
collectConflictsBetween(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap1, fieldMap2); // (I) Then collect conflicts between the first collection of fields and
// those referenced by each fragment name associated with the second.
if (fragmentNames2.length !== 0) {
for (var j = 0; j < fragmentNames2.length; j++) {
collectConflictsBetweenFieldsAndFragment(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap1, fragmentNames2[j]);
}
} // (I) Then collect conflicts between the second collection of fields and
// those referenced by each fragment name associated with the first.
if (fragmentNames1.length !== 0) {
for (var i = 0; i < fragmentNames1.length; i++) {
collectConflictsBetweenFieldsAndFragment(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap2, fragmentNames1[i]);
}
} // (J) Also collect conflicts between any fragment names by the first and
// fragment names by the second. This compares each item in the first set of
// names to each item in the second set of names.
for (var _i3 = 0; _i3 < fragmentNames1.length; _i3++) {
for (var _j = 0; _j < fragmentNames2.length; _j++) {
collectConflictsBetweenFragments(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fragmentNames1[_i3], fragmentNames2[_j]);
}
}
return conflicts;
} // Collect all Conflicts "within" one collection of fields.
function collectConflictsWithin(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, fieldMap) {
// A field map is a keyed collection, where each key represents a response
// name and the value at that key is a list of all fields which provide that
// response name. For every response name, if there are multiple fields, they
// must be compared to find a potential conflict.
for (var _i5 = 0, _objectEntries2 = (0, _objectEntries3.default)(fieldMap); _i5 < _objectEntries2.length; _i5++) {
var _ref5 = _objectEntries2[_i5];
var responseName = _ref5[0];
var fields = _ref5[1];
// This compares every field in the list to every other field in this list
// (except to itself). If the list only has one item, nothing needs to
// be compared.
if (fields.length > 1) {
for (var i = 0; i < fields.length; i++) {
for (var j = i + 1; j < fields.length; j++) {
var conflict = findConflict(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, false, // within one collection is never mutually exclusive
responseName, fields[i], fields[j]);
if (conflict) {
conflicts.push(conflict);
}
}
}
}
}
} // Collect all Conflicts between two collections of fields. This is similar to,
// but different from the `collectConflictsWithin` function above. This check
// assumes that `collectConflictsWithin` has already been called on each
// provided collection of fields. This is true because this validator traverses
// each individual selection set.
function collectConflictsBetween(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, parentFieldsAreMutuallyExclusive, fieldMap1, fieldMap2) {
// A field map is a keyed collection, where each key represents a response
// name and the value at that key is a list of all fields which provide that
// response name. For any response name which appears in both provided field
// maps, each field from the first field map must be compared to every field
// in the second field map to find potential conflicts.
for (var _i7 = 0, _Object$keys2 = Object.keys(fieldMap1); _i7 < _Object$keys2.length; _i7++) {
var responseName = _Object$keys2[_i7];
var fields2 = fieldMap2[responseName];
if (fields2) {
var fields1 = fieldMap1[responseName];
for (var i = 0; i < fields1.length; i++) {
for (var j = 0; j < fields2.length; j++) {
var conflict = findConflict(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, parentFieldsAreMutuallyExclusive, responseName, fields1[i], fields2[j]);
if (conflict) {
conflicts.push(conflict);
}
}
}
}
}
} // Determines if there is a conflict between two particular fields, including
// comparing their sub-fields.
function findConflict(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, parentFieldsAreMutuallyExclusive, responseName, field1, field2) {
var parentType1 = field1[0],
node1 = field1[1],
def1 = field1[2];
var parentType2 = field2[0],
node2 = field2[1],
def2 = field2[2]; // If it is known that two fields could not possibly apply at the same
// time, due to the parent types, then it is safe to permit them to diverge
// in aliased field or arguments used as they will not present any ambiguity
// by differing.
// It is known that two parent types could never overlap if they are
// different Object types. Interface or Union types might overlap - if not
// in the current state of the schema, then perhaps in some future version,
// thus may not safely diverge.
var areMutuallyExclusive = parentFieldsAreMutuallyExclusive || parentType1 !== parentType2 && (0, _definition.isObjectType)(parentType1) && (0, _definition.isObjectType)(parentType2);
if (!areMutuallyExclusive) {
var _node1$arguments, _node2$arguments;
// Two aliases must refer to the same field.
var name1 = node1.name.value;
var name2 = node2.name.value;
if (name1 !== name2) {
return [[responseName, "\"".concat(name1, "\" and \"").concat(name2, "\" are different fields")], [node1], [node2]];
} // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var args1 = (_node1$arguments = node1.arguments) !== null && _node1$arguments !== void 0 ? _node1$arguments : []; // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var args2 = (_node2$arguments = node2.arguments) !== null && _node2$arguments !== void 0 ? _node2$arguments : []; // Two field calls must have the same arguments.
if (!sameArguments(args1, args2)) {
return [[responseName, 'they have differing arguments'], [node1], [node2]];
}
} // The return type for each field.
var type1 = def1 === null || def1 === void 0 ? void 0 : def1.type;
var type2 = def2 === null || def2 === void 0 ? void 0 : def2.type;
if (type1 && type2 && doTypesConflict(type1, type2)) {
return [[responseName, "they return conflicting types \"".concat((0, _inspect.default)(type1), "\" and \"").concat((0, _inspect.default)(type2), "\"")], [node1], [node2]];
} // Collect and compare sub-fields. Use the same "visited fragment names" list
// for both collections so fields in a fragment reference are never
// compared to themselves.
var selectionSet1 = node1.selectionSet;
var selectionSet2 = node2.selectionSet;
if (selectionSet1 && selectionSet2) {
var conflicts = findConflictsBetweenSubSelectionSets(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, (0, _definition.getNamedType)(type1), selectionSet1, (0, _definition.getNamedType)(type2), selectionSet2);
return subfieldConflicts(conflicts, responseName, node1, node2);
}
}
function sameArguments(arguments1, arguments2) {
if (arguments1.length !== arguments2.length) {
return false;
}
return arguments1.every(function (argument1) {
var argument2 = (0, _find.default)(arguments2, function (argument) {
return argument.name.value === argument1.name.value;
});
if (!argument2) {
return false;
}
return sameValue(argument1.value, argument2.value);
});
}
function sameValue(value1, value2) {
return (0, _printer.print)(value1) === (0, _printer.print)(value2);
} // Two types conflict if both types could not apply to a value simultaneously.
// Composite types are ignored as their individual field types will be compared
// later recursively. However List and Non-Null types must match.
function doTypesConflict(type1, type2) {
if ((0, _definition.isListType)(type1)) {
return (0, _definition.isListType)(type2) ? doTypesConflict(type1.ofType, type2.ofType) : true;
}
if ((0, _definition.isListType)(type2)) {
return true;
}
if ((0, _definition.isNonNullType)(type1)) {
return (0, _definition.isNonNullType)(type2) ? doTypesConflict(type1.ofType, type2.ofType) : true;
}
if ((0, _definition.isNonNullType)(type2)) {
return true;
}
if ((0, _definition.isLeafType)(type1) || (0, _definition.isLeafType)(type2)) {
return type1 !== type2;
}
return false;
} // Given a selection set, return the collection of fields (a mapping of response
// name to field nodes and definitions) as well as a list of fragment names
// referenced via fragment spreads.
function getFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, parentType, selectionSet) {
var cached = cachedFieldsAndFragmentNames.get(selectionSet);
if (!cached) {
var nodeAndDefs = Object.create(null);
var fragmentNames = Object.create(null);
_collectFieldsAndFragmentNames(context, parentType, selectionSet, nodeAndDefs, fragmentNames);
cached = [nodeAndDefs, Object.keys(fragmentNames)];
cachedFieldsAndFragmentNames.set(selectionSet, cached);
}
return cached;
} // Given a reference to a fragment, return the represented collection of fields
// as well as a list of nested fragment names referenced via fragment spreads.
function getReferencedFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, fragment) {
// Short-circuit building a type from the node if possible.
var cached = cachedFieldsAndFragmentNames.get(fragment.selectionSet);
if (cached) {
return cached;
}
var fragmentType = (0, _typeFromAST.typeFromAST)(context.getSchema(), fragment.typeCondition);
return getFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, fragmentType, fragment.selectionSet);
}
function _collectFieldsAndFragmentNames(context, parentType, selectionSet, nodeAndDefs, fragmentNames) {
for (var _i9 = 0, _selectionSet$selecti2 = selectionSet.selections; _i9 < _selectionSet$selecti2.length; _i9++) {
var selection = _selectionSet$selecti2[_i9];
switch (selection.kind) {
case _kinds.Kind.FIELD:
{
var fieldName = selection.name.value;
var fieldDef = void 0;
if ((0, _definition.isObjectType)(parentType) || (0, _definition.isInterfaceType)(parentType)) {
fieldDef = parentType.getFields()[fieldName];
}
var responseName = selection.alias ? selection.alias.value : fieldName;
if (!nodeAndDefs[responseName]) {
nodeAndDefs[responseName] = [];
}
nodeAndDefs[responseName].push([parentType, selection, fieldDef]);
break;
}
case _kinds.Kind.FRAGMENT_SPREAD:
fragmentNames[selection.name.value] = true;
break;
case _kinds.Kind.INLINE_FRAGMENT:
{
var typeCondition = selection.typeCondition;
var inlineFragmentType = typeCondition ? (0, _typeFromAST.typeFromAST)(context.getSchema(), typeCondition) : parentType;
_collectFieldsAndFragmentNames(context, inlineFragmentType, selection.selectionSet, nodeAndDefs, fragmentNames);
break;
}
}
}
} // Given a series of Conflicts which occurred between two sub-fields, generate
// a single Conflict.
function subfieldConflicts(conflicts, responseName, node1, node2) {
if (conflicts.length > 0) {
return [[responseName, conflicts.map(function (_ref6) {
var reason = _ref6[0];
return reason;
})], conflicts.reduce(function (allFields, _ref7) {
var fields1 = _ref7[1];
return allFields.concat(fields1);
}, [node1]), conflicts.reduce(function (allFields, _ref8) {
var fields2 = _ref8[2];
return allFields.concat(fields2);
}, [node2])];
}
}
/**
* A way to keep track of pairs of things when the ordering of the pair does
* not matter. We do this by maintaining a sort of double adjacency sets.
*/
var PairSet = /*#__PURE__*/function () {
function PairSet() {
this._data = Object.create(null);
}
var _proto = PairSet.prototype;
_proto.has = function has(a, b, areMutuallyExclusive) {
var first = this._data[a];
var result = first && first[b];
if (result === undefined) {
return false;
} // areMutuallyExclusive being false is a superset of being true,
// hence if we want to know if this PairSet "has" these two with no
// exclusivity, we have to ensure it was added as such.
if (areMutuallyExclusive === false) {
return result === false;
}
return true;
};
_proto.add = function add(a, b, areMutuallyExclusive) {
this._pairSetAdd(a, b, areMutuallyExclusive);
this._pairSetAdd(b, a, areMutuallyExclusive);
};
_proto._pairSetAdd = function _pairSetAdd(a, b, areMutuallyExclusive) {
var map = this._data[a];
if (!map) {
map = Object.create(null);
this._data[a] = map;
}
map[b] = areMutuallyExclusive;
};
return PairSet;
}();

View File

@@ -0,0 +1,833 @@
// @flow strict
import find from '../../polyfills/find';
import objectEntries from '../../polyfills/objectEntries';
import type { ObjMap } from '../../jsutils/ObjMap';
import inspect from '../../jsutils/inspect';
import { GraphQLError } from '../../error/GraphQLError';
import type { ASTVisitor } from '../../language/visitor';
import type {
SelectionSetNode,
ValueNode,
FieldNode,
ArgumentNode,
FragmentDefinitionNode,
} from '../../language/ast';
import { Kind } from '../../language/kinds';
import { print } from '../../language/printer';
import type {
GraphQLNamedType,
GraphQLOutputType,
GraphQLCompositeType,
GraphQLField,
} from '../../type/definition';
import {
getNamedType,
isNonNullType,
isLeafType,
isObjectType,
isListType,
isInterfaceType,
} from '../../type/definition';
import { typeFromAST } from '../../utilities/typeFromAST';
import type { ValidationContext } from '../ValidationContext';
function reasonMessage(reason: ConflictReasonMessage): string {
if (Array.isArray(reason)) {
return reason
.map(
([responseName, subReason]) =>
`subfields "${responseName}" conflict because ` +
reasonMessage(subReason),
)
.join(' and ');
}
return reason;
}
/**
* Overlapping fields can be merged
*
* A selection set is only valid if all fields (including spreading any
* fragments) either correspond to distinct response names or can be merged
* without ambiguity.
*/
export function OverlappingFieldsCanBeMergedRule(
context: ValidationContext,
): ASTVisitor {
// A memoization for when two fragments are compared "between" each other for
// conflicts. Two fragments may be compared many times, so memoizing this can
// dramatically improve the performance of this validator.
const comparedFragmentPairs = new PairSet();
// A cache for the "field map" and list of fragment names found in any given
// selection set. Selection sets may be asked for this information multiple
// times, so this improves the performance of this validator.
const cachedFieldsAndFragmentNames = new Map();
return {
SelectionSet(selectionSet) {
const conflicts = findConflictsWithinSelectionSet(
context,
cachedFieldsAndFragmentNames,
comparedFragmentPairs,
context.getParentType(),
selectionSet,
);
for (const [[responseName, reason], fields1, fields2] of conflicts) {
const reasonMsg = reasonMessage(reason);
context.reportError(
new GraphQLError(
`Fields "${responseName}" conflict because ${reasonMsg}. Use different aliases on the fields to fetch both if this was intentional.`,
fields1.concat(fields2),
),
);
}
},
};
}
type Conflict = [ConflictReason, Array<FieldNode>, Array<FieldNode>];
// Field name and reason.
type ConflictReason = [string, ConflictReasonMessage];
// Reason is a string, or a nested list of conflicts.
type ConflictReasonMessage = string | Array<ConflictReason>;
// Tuple defining a field node in a context.
type NodeAndDef = [
GraphQLCompositeType,
FieldNode,
?GraphQLField<mixed, mixed>,
];
// Map of array of those.
type NodeAndDefCollection = ObjMap<Array<NodeAndDef>>;
/**
* Algorithm:
*
* Conflicts occur when two fields exist in a query which will produce the same
* response name, but represent differing values, thus creating a conflict.
* The algorithm below finds all conflicts via making a series of comparisons
* between fields. In order to compare as few fields as possible, this makes
* a series of comparisons "within" sets of fields and "between" sets of fields.
*
* Given any selection set, a collection produces both a set of fields by
* also including all inline fragments, as well as a list of fragments
* referenced by fragment spreads.
*
* A) Each selection set represented in the document first compares "within" its
* collected set of fields, finding any conflicts between every pair of
* overlapping fields.
* Note: This is the *only time* that a the fields "within" a set are compared
* to each other. After this only fields "between" sets are compared.
*
* B) Also, if any fragment is referenced in a selection set, then a
* comparison is made "between" the original set of fields and the
* referenced fragment.
*
* C) Also, if multiple fragments are referenced, then comparisons
* are made "between" each referenced fragment.
*
* D) When comparing "between" a set of fields and a referenced fragment, first
* a comparison is made between each field in the original set of fields and
* each field in the the referenced set of fields.
*
* E) Also, if any fragment is referenced in the referenced selection set,
* then a comparison is made "between" the original set of fields and the
* referenced fragment (recursively referring to step D).
*
* F) When comparing "between" two fragments, first a comparison is made between
* each field in the first referenced set of fields and each field in the the
* second referenced set of fields.
*
* G) Also, any fragments referenced by the first must be compared to the
* second, and any fragments referenced by the second must be compared to the
* first (recursively referring to step F).
*
* H) When comparing two fields, if both have selection sets, then a comparison
* is made "between" both selection sets, first comparing the set of fields in
* the first selection set with the set of fields in the second.
*
* I) Also, if any fragment is referenced in either selection set, then a
* comparison is made "between" the other set of fields and the
* referenced fragment.
*
* J) Also, if two fragments are referenced in both selection sets, then a
* comparison is made "between" the two fragments.
*
*/
// Find all conflicts found "within" a selection set, including those found
// via spreading in fragments. Called when visiting each SelectionSet in the
// GraphQL Document.
function findConflictsWithinSelectionSet(
context: ValidationContext,
cachedFieldsAndFragmentNames,
comparedFragmentPairs: PairSet,
parentType: ?GraphQLNamedType,
selectionSet: SelectionSetNode,
): Array<Conflict> {
const conflicts = [];
const [fieldMap, fragmentNames] = getFieldsAndFragmentNames(
context,
cachedFieldsAndFragmentNames,
parentType,
selectionSet,
);
// (A) Find find all conflicts "within" the fields of this selection set.
// Note: this is the *only place* `collectConflictsWithin` is called.
collectConflictsWithin(
context,
conflicts,
cachedFieldsAndFragmentNames,
comparedFragmentPairs,
fieldMap,
);
if (fragmentNames.length !== 0) {
// (B) Then collect conflicts between these fields and those represented by
// each spread fragment name found.
for (let i = 0; i < fragmentNames.length; i++) {
collectConflictsBetweenFieldsAndFragment(
context,
conflicts,
cachedFieldsAndFragmentNames,
comparedFragmentPairs,
false,
fieldMap,
fragmentNames[i],
);
// (C) Then compare this fragment with all other fragments found in this
// selection set to collect conflicts between fragments spread together.
// This compares each item in the list of fragment names to every other
// item in that same list (except for itself).
for (let j = i + 1; j < fragmentNames.length; j++) {
collectConflictsBetweenFragments(
context,
conflicts,
cachedFieldsAndFragmentNames,
comparedFragmentPairs,
false,
fragmentNames[i],
fragmentNames[j],
);
}
}
}
return conflicts;
}
// Collect all conflicts found between a set of fields and a fragment reference
// including via spreading in any nested fragments.
function collectConflictsBetweenFieldsAndFragment(
context: ValidationContext,
conflicts: Array<Conflict>,
cachedFieldsAndFragmentNames,
comparedFragmentPairs: PairSet,
areMutuallyExclusive: boolean,
fieldMap: NodeAndDefCollection,
fragmentName: string,
): void {
const fragment = context.getFragment(fragmentName);
if (!fragment) {
return;
}
const [fieldMap2, fragmentNames2] = getReferencedFieldsAndFragmentNames(
context,
cachedFieldsAndFragmentNames,
fragment,
);
// Do not compare a fragment's fieldMap to itself.
if (fieldMap === fieldMap2) {
return;
}
// (D) First collect any conflicts between the provided collection of fields
// and the collection of fields represented by the given fragment.
collectConflictsBetween(
context,
conflicts,
cachedFieldsAndFragmentNames,
comparedFragmentPairs,
areMutuallyExclusive,
fieldMap,
fieldMap2,
);
// (E) Then collect any conflicts between the provided collection of fields
// and any fragment names found in the given fragment.
for (let i = 0; i < fragmentNames2.length; i++) {
collectConflictsBetweenFieldsAndFragment(
context,
conflicts,
cachedFieldsAndFragmentNames,
comparedFragmentPairs,
areMutuallyExclusive,
fieldMap,
fragmentNames2[i],
);
}
}
// Collect all conflicts found between two fragments, including via spreading in
// any nested fragments.
function collectConflictsBetweenFragments(
context: ValidationContext,
conflicts: Array<Conflict>,
cachedFieldsAndFragmentNames,
comparedFragmentPairs: PairSet,
areMutuallyExclusive: boolean,
fragmentName1: string,
fragmentName2: string,
): void {
// No need to compare a fragment to itself.
if (fragmentName1 === fragmentName2) {
return;
}
// Memoize so two fragments are not compared for conflicts more than once.
if (
comparedFragmentPairs.has(
fragmentName1,
fragmentName2,
areMutuallyExclusive,
)
) {
return;
}
comparedFragmentPairs.add(fragmentName1, fragmentName2, areMutuallyExclusive);
const fragment1 = context.getFragment(fragmentName1);
const fragment2 = context.getFragment(fragmentName2);
if (!fragment1 || !fragment2) {
return;
}
const [fieldMap1, fragmentNames1] = getReferencedFieldsAndFragmentNames(
context,
cachedFieldsAndFragmentNames,
fragment1,
);
const [fieldMap2, fragmentNames2] = getReferencedFieldsAndFragmentNames(
context,
cachedFieldsAndFragmentNames,
fragment2,
);
// (F) First, collect all conflicts between these two collections of fields
// (not including any nested fragments).
collectConflictsBetween(
context,
conflicts,
cachedFieldsAndFragmentNames,
comparedFragmentPairs,
areMutuallyExclusive,
fieldMap1,
fieldMap2,
);
// (G) Then collect conflicts between the first fragment and any nested
// fragments spread in the second fragment.
for (let j = 0; j < fragmentNames2.length; j++) {
collectConflictsBetweenFragments(
context,
conflicts,
cachedFieldsAndFragmentNames,
comparedFragmentPairs,
areMutuallyExclusive,
fragmentName1,
fragmentNames2[j],
);
}
// (G) Then collect conflicts between the second fragment and any nested
// fragments spread in the first fragment.
for (let i = 0; i < fragmentNames1.length; i++) {
collectConflictsBetweenFragments(
context,
conflicts,
cachedFieldsAndFragmentNames,
comparedFragmentPairs,
areMutuallyExclusive,
fragmentNames1[i],
fragmentName2,
);
}
}
// Find all conflicts found between two selection sets, including those found
// via spreading in fragments. Called when determining if conflicts exist
// between the sub-fields of two overlapping fields.
function findConflictsBetweenSubSelectionSets(
context: ValidationContext,
cachedFieldsAndFragmentNames,
comparedFragmentPairs: PairSet,
areMutuallyExclusive: boolean,
parentType1: ?GraphQLNamedType,
selectionSet1: SelectionSetNode,
parentType2: ?GraphQLNamedType,
selectionSet2: SelectionSetNode,
): Array<Conflict> {
const conflicts = [];
const [fieldMap1, fragmentNames1] = getFieldsAndFragmentNames(
context,
cachedFieldsAndFragmentNames,
parentType1,
selectionSet1,
);
const [fieldMap2, fragmentNames2] = getFieldsAndFragmentNames(
context,
cachedFieldsAndFragmentNames,
parentType2,
selectionSet2,
);
// (H) First, collect all conflicts between these two collections of field.
collectConflictsBetween(
context,
conflicts,
cachedFieldsAndFragmentNames,
comparedFragmentPairs,
areMutuallyExclusive,
fieldMap1,
fieldMap2,
);
// (I) Then collect conflicts between the first collection of fields and
// those referenced by each fragment name associated with the second.
if (fragmentNames2.length !== 0) {
for (let j = 0; j < fragmentNames2.length; j++) {
collectConflictsBetweenFieldsAndFragment(
context,
conflicts,
cachedFieldsAndFragmentNames,
comparedFragmentPairs,
areMutuallyExclusive,
fieldMap1,
fragmentNames2[j],
);
}
}
// (I) Then collect conflicts between the second collection of fields and
// those referenced by each fragment name associated with the first.
if (fragmentNames1.length !== 0) {
for (let i = 0; i < fragmentNames1.length; i++) {
collectConflictsBetweenFieldsAndFragment(
context,
conflicts,
cachedFieldsAndFragmentNames,
comparedFragmentPairs,
areMutuallyExclusive,
fieldMap2,
fragmentNames1[i],
);
}
}
// (J) Also collect conflicts between any fragment names by the first and
// fragment names by the second. This compares each item in the first set of
// names to each item in the second set of names.
for (let i = 0; i < fragmentNames1.length; i++) {
for (let j = 0; j < fragmentNames2.length; j++) {
collectConflictsBetweenFragments(
context,
conflicts,
cachedFieldsAndFragmentNames,
comparedFragmentPairs,
areMutuallyExclusive,
fragmentNames1[i],
fragmentNames2[j],
);
}
}
return conflicts;
}
// Collect all Conflicts "within" one collection of fields.
function collectConflictsWithin(
context: ValidationContext,
conflicts: Array<Conflict>,
cachedFieldsAndFragmentNames,
comparedFragmentPairs: PairSet,
fieldMap: NodeAndDefCollection,
): void {
// A field map is a keyed collection, where each key represents a response
// name and the value at that key is a list of all fields which provide that
// response name. For every response name, if there are multiple fields, they
// must be compared to find a potential conflict.
for (const [responseName, fields] of objectEntries(fieldMap)) {
// This compares every field in the list to every other field in this list
// (except to itself). If the list only has one item, nothing needs to
// be compared.
if (fields.length > 1) {
for (let i = 0; i < fields.length; i++) {
for (let j = i + 1; j < fields.length; j++) {
const conflict = findConflict(
context,
cachedFieldsAndFragmentNames,
comparedFragmentPairs,
false, // within one collection is never mutually exclusive
responseName,
fields[i],
fields[j],
);
if (conflict) {
conflicts.push(conflict);
}
}
}
}
}
}
// Collect all Conflicts between two collections of fields. This is similar to,
// but different from the `collectConflictsWithin` function above. This check
// assumes that `collectConflictsWithin` has already been called on each
// provided collection of fields. This is true because this validator traverses
// each individual selection set.
function collectConflictsBetween(
context: ValidationContext,
conflicts: Array<Conflict>,
cachedFieldsAndFragmentNames,
comparedFragmentPairs: PairSet,
parentFieldsAreMutuallyExclusive: boolean,
fieldMap1: NodeAndDefCollection,
fieldMap2: NodeAndDefCollection,
): void {
// A field map is a keyed collection, where each key represents a response
// name and the value at that key is a list of all fields which provide that
// response name. For any response name which appears in both provided field
// maps, each field from the first field map must be compared to every field
// in the second field map to find potential conflicts.
for (const responseName of Object.keys(fieldMap1)) {
const fields2 = fieldMap2[responseName];
if (fields2) {
const fields1 = fieldMap1[responseName];
for (let i = 0; i < fields1.length; i++) {
for (let j = 0; j < fields2.length; j++) {
const conflict = findConflict(
context,
cachedFieldsAndFragmentNames,
comparedFragmentPairs,
parentFieldsAreMutuallyExclusive,
responseName,
fields1[i],
fields2[j],
);
if (conflict) {
conflicts.push(conflict);
}
}
}
}
}
}
// Determines if there is a conflict between two particular fields, including
// comparing their sub-fields.
function findConflict(
context: ValidationContext,
cachedFieldsAndFragmentNames,
comparedFragmentPairs: PairSet,
parentFieldsAreMutuallyExclusive: boolean,
responseName: string,
field1: NodeAndDef,
field2: NodeAndDef,
): ?Conflict {
const [parentType1, node1, def1] = field1;
const [parentType2, node2, def2] = field2;
// If it is known that two fields could not possibly apply at the same
// time, due to the parent types, then it is safe to permit them to diverge
// in aliased field or arguments used as they will not present any ambiguity
// by differing.
// It is known that two parent types could never overlap if they are
// different Object types. Interface or Union types might overlap - if not
// in the current state of the schema, then perhaps in some future version,
// thus may not safely diverge.
const areMutuallyExclusive =
parentFieldsAreMutuallyExclusive ||
(parentType1 !== parentType2 &&
isObjectType(parentType1) &&
isObjectType(parentType2));
if (!areMutuallyExclusive) {
// Two aliases must refer to the same field.
const name1 = node1.name.value;
const name2 = node2.name.value;
if (name1 !== name2) {
return [
[responseName, `"${name1}" and "${name2}" are different fields`],
[node1],
[node2],
];
}
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
const args1 = node1.arguments ?? [];
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
const args2 = node2.arguments ?? [];
// Two field calls must have the same arguments.
if (!sameArguments(args1, args2)) {
return [
[responseName, 'they have differing arguments'],
[node1],
[node2],
];
}
}
// The return type for each field.
const type1 = def1?.type;
const type2 = def2?.type;
if (type1 && type2 && doTypesConflict(type1, type2)) {
return [
[
responseName,
`they return conflicting types "${inspect(type1)}" and "${inspect(
type2,
)}"`,
],
[node1],
[node2],
];
}
// Collect and compare sub-fields. Use the same "visited fragment names" list
// for both collections so fields in a fragment reference are never
// compared to themselves.
const selectionSet1 = node1.selectionSet;
const selectionSet2 = node2.selectionSet;
if (selectionSet1 && selectionSet2) {
const conflicts = findConflictsBetweenSubSelectionSets(
context,
cachedFieldsAndFragmentNames,
comparedFragmentPairs,
areMutuallyExclusive,
getNamedType(type1),
selectionSet1,
getNamedType(type2),
selectionSet2,
);
return subfieldConflicts(conflicts, responseName, node1, node2);
}
}
function sameArguments(
arguments1: $ReadOnlyArray<ArgumentNode>,
arguments2: $ReadOnlyArray<ArgumentNode>,
): boolean {
if (arguments1.length !== arguments2.length) {
return false;
}
return arguments1.every((argument1) => {
const argument2 = find(
arguments2,
(argument) => argument.name.value === argument1.name.value,
);
if (!argument2) {
return false;
}
return sameValue(argument1.value, argument2.value);
});
}
function sameValue(value1: ValueNode, value2: ValueNode): boolean {
return print(value1) === print(value2);
}
// Two types conflict if both types could not apply to a value simultaneously.
// Composite types are ignored as their individual field types will be compared
// later recursively. However List and Non-Null types must match.
function doTypesConflict(
type1: GraphQLOutputType,
type2: GraphQLOutputType,
): boolean {
if (isListType(type1)) {
return isListType(type2)
? doTypesConflict(type1.ofType, type2.ofType)
: true;
}
if (isListType(type2)) {
return true;
}
if (isNonNullType(type1)) {
return isNonNullType(type2)
? doTypesConflict(type1.ofType, type2.ofType)
: true;
}
if (isNonNullType(type2)) {
return true;
}
if (isLeafType(type1) || isLeafType(type2)) {
return type1 !== type2;
}
return false;
}
// Given a selection set, return the collection of fields (a mapping of response
// name to field nodes and definitions) as well as a list of fragment names
// referenced via fragment spreads.
function getFieldsAndFragmentNames(
context: ValidationContext,
cachedFieldsAndFragmentNames,
parentType: ?GraphQLNamedType,
selectionSet: SelectionSetNode,
): [NodeAndDefCollection, Array<string>] {
let cached = cachedFieldsAndFragmentNames.get(selectionSet);
if (!cached) {
const nodeAndDefs = Object.create(null);
const fragmentNames = Object.create(null);
_collectFieldsAndFragmentNames(
context,
parentType,
selectionSet,
nodeAndDefs,
fragmentNames,
);
cached = [nodeAndDefs, Object.keys(fragmentNames)];
cachedFieldsAndFragmentNames.set(selectionSet, cached);
}
return cached;
}
// Given a reference to a fragment, return the represented collection of fields
// as well as a list of nested fragment names referenced via fragment spreads.
function getReferencedFieldsAndFragmentNames(
context: ValidationContext,
cachedFieldsAndFragmentNames,
fragment: FragmentDefinitionNode,
) {
// Short-circuit building a type from the node if possible.
const cached = cachedFieldsAndFragmentNames.get(fragment.selectionSet);
if (cached) {
return cached;
}
const fragmentType = typeFromAST(context.getSchema(), fragment.typeCondition);
return getFieldsAndFragmentNames(
context,
cachedFieldsAndFragmentNames,
fragmentType,
fragment.selectionSet,
);
}
function _collectFieldsAndFragmentNames(
context: ValidationContext,
parentType: ?GraphQLNamedType,
selectionSet: SelectionSetNode,
nodeAndDefs,
fragmentNames,
): void {
for (const selection of selectionSet.selections) {
switch (selection.kind) {
case Kind.FIELD: {
const fieldName = selection.name.value;
let fieldDef;
if (isObjectType(parentType) || isInterfaceType(parentType)) {
fieldDef = parentType.getFields()[fieldName];
}
const responseName = selection.alias
? selection.alias.value
: fieldName;
if (!nodeAndDefs[responseName]) {
nodeAndDefs[responseName] = [];
}
nodeAndDefs[responseName].push([parentType, selection, fieldDef]);
break;
}
case Kind.FRAGMENT_SPREAD:
fragmentNames[selection.name.value] = true;
break;
case Kind.INLINE_FRAGMENT: {
const typeCondition = selection.typeCondition;
const inlineFragmentType = typeCondition
? typeFromAST(context.getSchema(), typeCondition)
: parentType;
_collectFieldsAndFragmentNames(
context,
inlineFragmentType,
selection.selectionSet,
nodeAndDefs,
fragmentNames,
);
break;
}
}
}
}
// Given a series of Conflicts which occurred between two sub-fields, generate
// a single Conflict.
function subfieldConflicts(
conflicts: $ReadOnlyArray<Conflict>,
responseName: string,
node1: FieldNode,
node2: FieldNode,
): ?Conflict {
if (conflicts.length > 0) {
return [
[responseName, conflicts.map(([reason]) => reason)],
conflicts.reduce((allFields, [, fields1]) => allFields.concat(fields1), [
node1,
]),
conflicts.reduce(
(allFields, [, , fields2]) => allFields.concat(fields2),
[node2],
),
];
}
}
/**
* A way to keep track of pairs of things when the ordering of the pair does
* not matter. We do this by maintaining a sort of double adjacency sets.
*/
class PairSet {
_data: ObjMap<ObjMap<boolean>>;
constructor() {
this._data = Object.create(null);
}
has(a: string, b: string, areMutuallyExclusive: boolean): boolean {
const first = this._data[a];
const result = first && first[b];
if (result === undefined) {
return false;
}
// areMutuallyExclusive being false is a superset of being true,
// hence if we want to know if this PairSet "has" these two with no
// exclusivity, we have to ensure it was added as such.
if (areMutuallyExclusive === false) {
return result === false;
}
return true;
}
add(a: string, b: string, areMutuallyExclusive: boolean): void {
this._pairSetAdd(a, b, areMutuallyExclusive);
this._pairSetAdd(b, a, areMutuallyExclusive);
}
_pairSetAdd(a: string, b: string, areMutuallyExclusive: boolean): void {
let map = this._data[a];
if (!map) {
map = Object.create(null);
this._data[a] = map;
}
map[b] = areMutuallyExclusive;
}
}

View File

@@ -0,0 +1,568 @@
import find from "../../polyfills/find.mjs";
import objectEntries from "../../polyfills/objectEntries.mjs";
import inspect from "../../jsutils/inspect.mjs";
import { GraphQLError } from "../../error/GraphQLError.mjs";
import { Kind } from "../../language/kinds.mjs";
import { print } from "../../language/printer.mjs";
import { getNamedType, isNonNullType, isLeafType, isObjectType, isListType, isInterfaceType } from "../../type/definition.mjs";
import { typeFromAST } from "../../utilities/typeFromAST.mjs";
function reasonMessage(reason) {
if (Array.isArray(reason)) {
return reason.map(function (_ref) {
var responseName = _ref[0],
subReason = _ref[1];
return "subfields \"".concat(responseName, "\" conflict because ") + reasonMessage(subReason);
}).join(' and ');
}
return reason;
}
/**
* Overlapping fields can be merged
*
* A selection set is only valid if all fields (including spreading any
* fragments) either correspond to distinct response names or can be merged
* without ambiguity.
*/
export function OverlappingFieldsCanBeMergedRule(context) {
// A memoization for when two fragments are compared "between" each other for
// conflicts. Two fragments may be compared many times, so memoizing this can
// dramatically improve the performance of this validator.
var comparedFragmentPairs = new PairSet(); // A cache for the "field map" and list of fragment names found in any given
// selection set. Selection sets may be asked for this information multiple
// times, so this improves the performance of this validator.
var cachedFieldsAndFragmentNames = new Map();
return {
SelectionSet: function SelectionSet(selectionSet) {
var conflicts = findConflictsWithinSelectionSet(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, context.getParentType(), selectionSet);
for (var _i2 = 0; _i2 < conflicts.length; _i2++) {
var _ref3 = conflicts[_i2];
var _ref2$ = _ref3[0];
var responseName = _ref2$[0];
var reason = _ref2$[1];
var fields1 = _ref3[1];
var fields2 = _ref3[2];
var reasonMsg = reasonMessage(reason);
context.reportError(new GraphQLError("Fields \"".concat(responseName, "\" conflict because ").concat(reasonMsg, ". Use different aliases on the fields to fetch both if this was intentional."), fields1.concat(fields2)));
}
}
};
}
/**
* Algorithm:
*
* Conflicts occur when two fields exist in a query which will produce the same
* response name, but represent differing values, thus creating a conflict.
* The algorithm below finds all conflicts via making a series of comparisons
* between fields. In order to compare as few fields as possible, this makes
* a series of comparisons "within" sets of fields and "between" sets of fields.
*
* Given any selection set, a collection produces both a set of fields by
* also including all inline fragments, as well as a list of fragments
* referenced by fragment spreads.
*
* A) Each selection set represented in the document first compares "within" its
* collected set of fields, finding any conflicts between every pair of
* overlapping fields.
* Note: This is the *only time* that a the fields "within" a set are compared
* to each other. After this only fields "between" sets are compared.
*
* B) Also, if any fragment is referenced in a selection set, then a
* comparison is made "between" the original set of fields and the
* referenced fragment.
*
* C) Also, if multiple fragments are referenced, then comparisons
* are made "between" each referenced fragment.
*
* D) When comparing "between" a set of fields and a referenced fragment, first
* a comparison is made between each field in the original set of fields and
* each field in the the referenced set of fields.
*
* E) Also, if any fragment is referenced in the referenced selection set,
* then a comparison is made "between" the original set of fields and the
* referenced fragment (recursively referring to step D).
*
* F) When comparing "between" two fragments, first a comparison is made between
* each field in the first referenced set of fields and each field in the the
* second referenced set of fields.
*
* G) Also, any fragments referenced by the first must be compared to the
* second, and any fragments referenced by the second must be compared to the
* first (recursively referring to step F).
*
* H) When comparing two fields, if both have selection sets, then a comparison
* is made "between" both selection sets, first comparing the set of fields in
* the first selection set with the set of fields in the second.
*
* I) Also, if any fragment is referenced in either selection set, then a
* comparison is made "between" the other set of fields and the
* referenced fragment.
*
* J) Also, if two fragments are referenced in both selection sets, then a
* comparison is made "between" the two fragments.
*
*/
// Find all conflicts found "within" a selection set, including those found
// via spreading in fragments. Called when visiting each SelectionSet in the
// GraphQL Document.
function findConflictsWithinSelectionSet(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, parentType, selectionSet) {
var conflicts = [];
var _getFieldsAndFragment = getFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, parentType, selectionSet),
fieldMap = _getFieldsAndFragment[0],
fragmentNames = _getFieldsAndFragment[1]; // (A) Find find all conflicts "within" the fields of this selection set.
// Note: this is the *only place* `collectConflictsWithin` is called.
collectConflictsWithin(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, fieldMap);
if (fragmentNames.length !== 0) {
// (B) Then collect conflicts between these fields and those represented by
// each spread fragment name found.
for (var i = 0; i < fragmentNames.length; i++) {
collectConflictsBetweenFieldsAndFragment(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, false, fieldMap, fragmentNames[i]); // (C) Then compare this fragment with all other fragments found in this
// selection set to collect conflicts between fragments spread together.
// This compares each item in the list of fragment names to every other
// item in that same list (except for itself).
for (var j = i + 1; j < fragmentNames.length; j++) {
collectConflictsBetweenFragments(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, false, fragmentNames[i], fragmentNames[j]);
}
}
}
return conflicts;
} // Collect all conflicts found between a set of fields and a fragment reference
// including via spreading in any nested fragments.
function collectConflictsBetweenFieldsAndFragment(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap, fragmentName) {
var fragment = context.getFragment(fragmentName);
if (!fragment) {
return;
}
var _getReferencedFieldsA = getReferencedFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, fragment),
fieldMap2 = _getReferencedFieldsA[0],
fragmentNames2 = _getReferencedFieldsA[1]; // Do not compare a fragment's fieldMap to itself.
if (fieldMap === fieldMap2) {
return;
} // (D) First collect any conflicts between the provided collection of fields
// and the collection of fields represented by the given fragment.
collectConflictsBetween(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap, fieldMap2); // (E) Then collect any conflicts between the provided collection of fields
// and any fragment names found in the given fragment.
for (var i = 0; i < fragmentNames2.length; i++) {
collectConflictsBetweenFieldsAndFragment(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap, fragmentNames2[i]);
}
} // Collect all conflicts found between two fragments, including via spreading in
// any nested fragments.
function collectConflictsBetweenFragments(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fragmentName1, fragmentName2) {
// No need to compare a fragment to itself.
if (fragmentName1 === fragmentName2) {
return;
} // Memoize so two fragments are not compared for conflicts more than once.
if (comparedFragmentPairs.has(fragmentName1, fragmentName2, areMutuallyExclusive)) {
return;
}
comparedFragmentPairs.add(fragmentName1, fragmentName2, areMutuallyExclusive);
var fragment1 = context.getFragment(fragmentName1);
var fragment2 = context.getFragment(fragmentName2);
if (!fragment1 || !fragment2) {
return;
}
var _getReferencedFieldsA2 = getReferencedFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, fragment1),
fieldMap1 = _getReferencedFieldsA2[0],
fragmentNames1 = _getReferencedFieldsA2[1];
var _getReferencedFieldsA3 = getReferencedFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, fragment2),
fieldMap2 = _getReferencedFieldsA3[0],
fragmentNames2 = _getReferencedFieldsA3[1]; // (F) First, collect all conflicts between these two collections of fields
// (not including any nested fragments).
collectConflictsBetween(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap1, fieldMap2); // (G) Then collect conflicts between the first fragment and any nested
// fragments spread in the second fragment.
for (var j = 0; j < fragmentNames2.length; j++) {
collectConflictsBetweenFragments(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fragmentName1, fragmentNames2[j]);
} // (G) Then collect conflicts between the second fragment and any nested
// fragments spread in the first fragment.
for (var i = 0; i < fragmentNames1.length; i++) {
collectConflictsBetweenFragments(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fragmentNames1[i], fragmentName2);
}
} // Find all conflicts found between two selection sets, including those found
// via spreading in fragments. Called when determining if conflicts exist
// between the sub-fields of two overlapping fields.
function findConflictsBetweenSubSelectionSets(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, parentType1, selectionSet1, parentType2, selectionSet2) {
var conflicts = [];
var _getFieldsAndFragment2 = getFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, parentType1, selectionSet1),
fieldMap1 = _getFieldsAndFragment2[0],
fragmentNames1 = _getFieldsAndFragment2[1];
var _getFieldsAndFragment3 = getFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, parentType2, selectionSet2),
fieldMap2 = _getFieldsAndFragment3[0],
fragmentNames2 = _getFieldsAndFragment3[1]; // (H) First, collect all conflicts between these two collections of field.
collectConflictsBetween(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap1, fieldMap2); // (I) Then collect conflicts between the first collection of fields and
// those referenced by each fragment name associated with the second.
if (fragmentNames2.length !== 0) {
for (var j = 0; j < fragmentNames2.length; j++) {
collectConflictsBetweenFieldsAndFragment(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap1, fragmentNames2[j]);
}
} // (I) Then collect conflicts between the second collection of fields and
// those referenced by each fragment name associated with the first.
if (fragmentNames1.length !== 0) {
for (var i = 0; i < fragmentNames1.length; i++) {
collectConflictsBetweenFieldsAndFragment(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fieldMap2, fragmentNames1[i]);
}
} // (J) Also collect conflicts between any fragment names by the first and
// fragment names by the second. This compares each item in the first set of
// names to each item in the second set of names.
for (var _i3 = 0; _i3 < fragmentNames1.length; _i3++) {
for (var _j = 0; _j < fragmentNames2.length; _j++) {
collectConflictsBetweenFragments(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, fragmentNames1[_i3], fragmentNames2[_j]);
}
}
return conflicts;
} // Collect all Conflicts "within" one collection of fields.
function collectConflictsWithin(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, fieldMap) {
// A field map is a keyed collection, where each key represents a response
// name and the value at that key is a list of all fields which provide that
// response name. For every response name, if there are multiple fields, they
// must be compared to find a potential conflict.
for (var _i5 = 0, _objectEntries2 = objectEntries(fieldMap); _i5 < _objectEntries2.length; _i5++) {
var _ref5 = _objectEntries2[_i5];
var responseName = _ref5[0];
var fields = _ref5[1];
// This compares every field in the list to every other field in this list
// (except to itself). If the list only has one item, nothing needs to
// be compared.
if (fields.length > 1) {
for (var i = 0; i < fields.length; i++) {
for (var j = i + 1; j < fields.length; j++) {
var conflict = findConflict(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, false, // within one collection is never mutually exclusive
responseName, fields[i], fields[j]);
if (conflict) {
conflicts.push(conflict);
}
}
}
}
}
} // Collect all Conflicts between two collections of fields. This is similar to,
// but different from the `collectConflictsWithin` function above. This check
// assumes that `collectConflictsWithin` has already been called on each
// provided collection of fields. This is true because this validator traverses
// each individual selection set.
function collectConflictsBetween(context, conflicts, cachedFieldsAndFragmentNames, comparedFragmentPairs, parentFieldsAreMutuallyExclusive, fieldMap1, fieldMap2) {
// A field map is a keyed collection, where each key represents a response
// name and the value at that key is a list of all fields which provide that
// response name. For any response name which appears in both provided field
// maps, each field from the first field map must be compared to every field
// in the second field map to find potential conflicts.
for (var _i7 = 0, _Object$keys2 = Object.keys(fieldMap1); _i7 < _Object$keys2.length; _i7++) {
var responseName = _Object$keys2[_i7];
var fields2 = fieldMap2[responseName];
if (fields2) {
var fields1 = fieldMap1[responseName];
for (var i = 0; i < fields1.length; i++) {
for (var j = 0; j < fields2.length; j++) {
var conflict = findConflict(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, parentFieldsAreMutuallyExclusive, responseName, fields1[i], fields2[j]);
if (conflict) {
conflicts.push(conflict);
}
}
}
}
}
} // Determines if there is a conflict between two particular fields, including
// comparing their sub-fields.
function findConflict(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, parentFieldsAreMutuallyExclusive, responseName, field1, field2) {
var parentType1 = field1[0],
node1 = field1[1],
def1 = field1[2];
var parentType2 = field2[0],
node2 = field2[1],
def2 = field2[2]; // If it is known that two fields could not possibly apply at the same
// time, due to the parent types, then it is safe to permit them to diverge
// in aliased field or arguments used as they will not present any ambiguity
// by differing.
// It is known that two parent types could never overlap if they are
// different Object types. Interface or Union types might overlap - if not
// in the current state of the schema, then perhaps in some future version,
// thus may not safely diverge.
var areMutuallyExclusive = parentFieldsAreMutuallyExclusive || parentType1 !== parentType2 && isObjectType(parentType1) && isObjectType(parentType2);
if (!areMutuallyExclusive) {
var _node1$arguments, _node2$arguments;
// Two aliases must refer to the same field.
var name1 = node1.name.value;
var name2 = node2.name.value;
if (name1 !== name2) {
return [[responseName, "\"".concat(name1, "\" and \"").concat(name2, "\" are different fields")], [node1], [node2]];
} // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var args1 = (_node1$arguments = node1.arguments) !== null && _node1$arguments !== void 0 ? _node1$arguments : []; // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var args2 = (_node2$arguments = node2.arguments) !== null && _node2$arguments !== void 0 ? _node2$arguments : []; // Two field calls must have the same arguments.
if (!sameArguments(args1, args2)) {
return [[responseName, 'they have differing arguments'], [node1], [node2]];
}
} // The return type for each field.
var type1 = def1 === null || def1 === void 0 ? void 0 : def1.type;
var type2 = def2 === null || def2 === void 0 ? void 0 : def2.type;
if (type1 && type2 && doTypesConflict(type1, type2)) {
return [[responseName, "they return conflicting types \"".concat(inspect(type1), "\" and \"").concat(inspect(type2), "\"")], [node1], [node2]];
} // Collect and compare sub-fields. Use the same "visited fragment names" list
// for both collections so fields in a fragment reference are never
// compared to themselves.
var selectionSet1 = node1.selectionSet;
var selectionSet2 = node2.selectionSet;
if (selectionSet1 && selectionSet2) {
var conflicts = findConflictsBetweenSubSelectionSets(context, cachedFieldsAndFragmentNames, comparedFragmentPairs, areMutuallyExclusive, getNamedType(type1), selectionSet1, getNamedType(type2), selectionSet2);
return subfieldConflicts(conflicts, responseName, node1, node2);
}
}
function sameArguments(arguments1, arguments2) {
if (arguments1.length !== arguments2.length) {
return false;
}
return arguments1.every(function (argument1) {
var argument2 = find(arguments2, function (argument) {
return argument.name.value === argument1.name.value;
});
if (!argument2) {
return false;
}
return sameValue(argument1.value, argument2.value);
});
}
function sameValue(value1, value2) {
return print(value1) === print(value2);
} // Two types conflict if both types could not apply to a value simultaneously.
// Composite types are ignored as their individual field types will be compared
// later recursively. However List and Non-Null types must match.
function doTypesConflict(type1, type2) {
if (isListType(type1)) {
return isListType(type2) ? doTypesConflict(type1.ofType, type2.ofType) : true;
}
if (isListType(type2)) {
return true;
}
if (isNonNullType(type1)) {
return isNonNullType(type2) ? doTypesConflict(type1.ofType, type2.ofType) : true;
}
if (isNonNullType(type2)) {
return true;
}
if (isLeafType(type1) || isLeafType(type2)) {
return type1 !== type2;
}
return false;
} // Given a selection set, return the collection of fields (a mapping of response
// name to field nodes and definitions) as well as a list of fragment names
// referenced via fragment spreads.
function getFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, parentType, selectionSet) {
var cached = cachedFieldsAndFragmentNames.get(selectionSet);
if (!cached) {
var nodeAndDefs = Object.create(null);
var fragmentNames = Object.create(null);
_collectFieldsAndFragmentNames(context, parentType, selectionSet, nodeAndDefs, fragmentNames);
cached = [nodeAndDefs, Object.keys(fragmentNames)];
cachedFieldsAndFragmentNames.set(selectionSet, cached);
}
return cached;
} // Given a reference to a fragment, return the represented collection of fields
// as well as a list of nested fragment names referenced via fragment spreads.
function getReferencedFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, fragment) {
// Short-circuit building a type from the node if possible.
var cached = cachedFieldsAndFragmentNames.get(fragment.selectionSet);
if (cached) {
return cached;
}
var fragmentType = typeFromAST(context.getSchema(), fragment.typeCondition);
return getFieldsAndFragmentNames(context, cachedFieldsAndFragmentNames, fragmentType, fragment.selectionSet);
}
function _collectFieldsAndFragmentNames(context, parentType, selectionSet, nodeAndDefs, fragmentNames) {
for (var _i9 = 0, _selectionSet$selecti2 = selectionSet.selections; _i9 < _selectionSet$selecti2.length; _i9++) {
var selection = _selectionSet$selecti2[_i9];
switch (selection.kind) {
case Kind.FIELD:
{
var fieldName = selection.name.value;
var fieldDef = void 0;
if (isObjectType(parentType) || isInterfaceType(parentType)) {
fieldDef = parentType.getFields()[fieldName];
}
var responseName = selection.alias ? selection.alias.value : fieldName;
if (!nodeAndDefs[responseName]) {
nodeAndDefs[responseName] = [];
}
nodeAndDefs[responseName].push([parentType, selection, fieldDef]);
break;
}
case Kind.FRAGMENT_SPREAD:
fragmentNames[selection.name.value] = true;
break;
case Kind.INLINE_FRAGMENT:
{
var typeCondition = selection.typeCondition;
var inlineFragmentType = typeCondition ? typeFromAST(context.getSchema(), typeCondition) : parentType;
_collectFieldsAndFragmentNames(context, inlineFragmentType, selection.selectionSet, nodeAndDefs, fragmentNames);
break;
}
}
}
} // Given a series of Conflicts which occurred between two sub-fields, generate
// a single Conflict.
function subfieldConflicts(conflicts, responseName, node1, node2) {
if (conflicts.length > 0) {
return [[responseName, conflicts.map(function (_ref6) {
var reason = _ref6[0];
return reason;
})], conflicts.reduce(function (allFields, _ref7) {
var fields1 = _ref7[1];
return allFields.concat(fields1);
}, [node1]), conflicts.reduce(function (allFields, _ref8) {
var fields2 = _ref8[2];
return allFields.concat(fields2);
}, [node2])];
}
}
/**
* A way to keep track of pairs of things when the ordering of the pair does
* not matter. We do this by maintaining a sort of double adjacency sets.
*/
var PairSet = /*#__PURE__*/function () {
function PairSet() {
this._data = Object.create(null);
}
var _proto = PairSet.prototype;
_proto.has = function has(a, b, areMutuallyExclusive) {
var first = this._data[a];
var result = first && first[b];
if (result === undefined) {
return false;
} // areMutuallyExclusive being false is a superset of being true,
// hence if we want to know if this PairSet "has" these two with no
// exclusivity, we have to ensure it was added as such.
if (areMutuallyExclusive === false) {
return result === false;
}
return true;
};
_proto.add = function add(a, b, areMutuallyExclusive) {
this._pairSetAdd(a, b, areMutuallyExclusive);
this._pairSetAdd(b, a, areMutuallyExclusive);
};
_proto._pairSetAdd = function _pairSetAdd(a, b, areMutuallyExclusive) {
var map = this._data[a];
if (!map) {
map = Object.create(null);
this._data[a] = map;
}
map[b] = areMutuallyExclusive;
};
return PairSet;
}();

View File

@@ -0,0 +1,13 @@
import { ASTVisitor } from '../../language/visitor';
import { ValidationContext } from '../ValidationContext';
/**
* Possible fragment spread
*
* A fragment spread is only valid if the type condition could ever possibly
* be true: if there is a non-empty intersection of the possible parent types,
* and possible types which pass the type condition.
*/
export function PossibleFragmentSpreadsRule(
context: ValidationContext,
): ASTVisitor;

View File

@@ -0,0 +1,63 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PossibleFragmentSpreadsRule = PossibleFragmentSpreadsRule;
var _inspect = _interopRequireDefault(require("../../jsutils/inspect.js"));
var _GraphQLError = require("../../error/GraphQLError.js");
var _definition = require("../../type/definition.js");
var _typeFromAST = require("../../utilities/typeFromAST.js");
var _typeComparators = require("../../utilities/typeComparators.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Possible fragment spread
*
* A fragment spread is only valid if the type condition could ever possibly
* be true: if there is a non-empty intersection of the possible parent types,
* and possible types which pass the type condition.
*/
function PossibleFragmentSpreadsRule(context) {
return {
InlineFragment: function InlineFragment(node) {
var fragType = context.getType();
var parentType = context.getParentType();
if ((0, _definition.isCompositeType)(fragType) && (0, _definition.isCompositeType)(parentType) && !(0, _typeComparators.doTypesOverlap)(context.getSchema(), fragType, parentType)) {
var parentTypeStr = (0, _inspect.default)(parentType);
var fragTypeStr = (0, _inspect.default)(fragType);
context.reportError(new _GraphQLError.GraphQLError("Fragment cannot be spread here as objects of type \"".concat(parentTypeStr, "\" can never be of type \"").concat(fragTypeStr, "\"."), node));
}
},
FragmentSpread: function FragmentSpread(node) {
var fragName = node.name.value;
var fragType = getFragmentType(context, fragName);
var parentType = context.getParentType();
if (fragType && parentType && !(0, _typeComparators.doTypesOverlap)(context.getSchema(), fragType, parentType)) {
var parentTypeStr = (0, _inspect.default)(parentType);
var fragTypeStr = (0, _inspect.default)(fragType);
context.reportError(new _GraphQLError.GraphQLError("Fragment \"".concat(fragName, "\" cannot be spread here as objects of type \"").concat(parentTypeStr, "\" can never be of type \"").concat(fragTypeStr, "\"."), node));
}
}
};
}
function getFragmentType(context, name) {
var frag = context.getFragment(name);
if (frag) {
var type = (0, _typeFromAST.typeFromAST)(context.getSchema(), frag.typeCondition);
if ((0, _definition.isCompositeType)(type)) {
return type;
}
}
}

View File

@@ -0,0 +1,78 @@
// @flow strict
import inspect from '../../jsutils/inspect';
import { GraphQLError } from '../../error/GraphQLError';
import type { ASTVisitor } from '../../language/visitor';
import type { GraphQLCompositeType } from '../../type/definition';
import { isCompositeType } from '../../type/definition';
import { typeFromAST } from '../../utilities/typeFromAST';
import { doTypesOverlap } from '../../utilities/typeComparators';
import type { ValidationContext } from '../ValidationContext';
/**
* Possible fragment spread
*
* A fragment spread is only valid if the type condition could ever possibly
* be true: if there is a non-empty intersection of the possible parent types,
* and possible types which pass the type condition.
*/
export function PossibleFragmentSpreadsRule(
context: ValidationContext,
): ASTVisitor {
return {
InlineFragment(node) {
const fragType = context.getType();
const parentType = context.getParentType();
if (
isCompositeType(fragType) &&
isCompositeType(parentType) &&
!doTypesOverlap(context.getSchema(), fragType, parentType)
) {
const parentTypeStr = inspect(parentType);
const fragTypeStr = inspect(fragType);
context.reportError(
new GraphQLError(
`Fragment cannot be spread here as objects of type "${parentTypeStr}" can never be of type "${fragTypeStr}".`,
node,
),
);
}
},
FragmentSpread(node) {
const fragName = node.name.value;
const fragType = getFragmentType(context, fragName);
const parentType = context.getParentType();
if (
fragType &&
parentType &&
!doTypesOverlap(context.getSchema(), fragType, parentType)
) {
const parentTypeStr = inspect(parentType);
const fragTypeStr = inspect(fragType);
context.reportError(
new GraphQLError(
`Fragment "${fragName}" cannot be spread here as objects of type "${parentTypeStr}" can never be of type "${fragTypeStr}".`,
node,
),
);
}
},
};
}
function getFragmentType(
context: ValidationContext,
name: string,
): ?GraphQLCompositeType {
const frag = context.getFragment(name);
if (frag) {
const type = typeFromAST(context.getSchema(), frag.typeCondition);
if (isCompositeType(type)) {
return type;
}
}
}

View File

@@ -0,0 +1,50 @@
import inspect from "../../jsutils/inspect.mjs";
import { GraphQLError } from "../../error/GraphQLError.mjs";
import { isCompositeType } from "../../type/definition.mjs";
import { typeFromAST } from "../../utilities/typeFromAST.mjs";
import { doTypesOverlap } from "../../utilities/typeComparators.mjs";
/**
* Possible fragment spread
*
* A fragment spread is only valid if the type condition could ever possibly
* be true: if there is a non-empty intersection of the possible parent types,
* and possible types which pass the type condition.
*/
export function PossibleFragmentSpreadsRule(context) {
return {
InlineFragment: function InlineFragment(node) {
var fragType = context.getType();
var parentType = context.getParentType();
if (isCompositeType(fragType) && isCompositeType(parentType) && !doTypesOverlap(context.getSchema(), fragType, parentType)) {
var parentTypeStr = inspect(parentType);
var fragTypeStr = inspect(fragType);
context.reportError(new GraphQLError("Fragment cannot be spread here as objects of type \"".concat(parentTypeStr, "\" can never be of type \"").concat(fragTypeStr, "\"."), node));
}
},
FragmentSpread: function FragmentSpread(node) {
var fragName = node.name.value;
var fragType = getFragmentType(context, fragName);
var parentType = context.getParentType();
if (fragType && parentType && !doTypesOverlap(context.getSchema(), fragType, parentType)) {
var parentTypeStr = inspect(parentType);
var fragTypeStr = inspect(fragType);
context.reportError(new GraphQLError("Fragment \"".concat(fragName, "\" cannot be spread here as objects of type \"").concat(parentTypeStr, "\" can never be of type \"").concat(fragTypeStr, "\"."), node));
}
}
};
}
function getFragmentType(context, name) {
var frag = context.getFragment(name);
if (frag) {
var type = typeFromAST(context.getSchema(), frag.typeCondition);
if (isCompositeType(type)) {
return type;
}
}
}

View File

@@ -0,0 +1,8 @@
/**
* @deprecated and will be removed in v16
* Please use either:
* import { PossibleTypeExtensionsRule } from 'graphql'
* or
* import { PossibleTypeExtensionsRule } from 'graphql/validation'
*/
export { PossibleTypeExtensionsRule as PossibleTypeExtensions } from './PossibleTypeExtensionsRule';

View File

@@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "PossibleTypeExtensions", {
enumerable: true,
get: function get() {
return _PossibleTypeExtensionsRule.PossibleTypeExtensionsRule;
}
});
var _PossibleTypeExtensionsRule = require("./PossibleTypeExtensionsRule.js");

View File

@@ -0,0 +1,9 @@
// @flow strict
/**
* @deprecated and will be removed in v16
* Please use either:
* import { PossibleTypeExtensionsRule } from 'graphql'
* or
* import { PossibleTypeExtensionsRule } from 'graphql/validation'
*/
export { PossibleTypeExtensionsRule as PossibleTypeExtensions } from './PossibleTypeExtensionsRule';

View File

@@ -0,0 +1,8 @@
/**
* @deprecated and will be removed in v16
* Please use either:
* import { PossibleTypeExtensionsRule } from 'graphql'
* or
* import { PossibleTypeExtensionsRule } from 'graphql/validation'
*/
export { PossibleTypeExtensionsRule as PossibleTypeExtensions } from "./PossibleTypeExtensionsRule.mjs";

View File

@@ -0,0 +1,11 @@
import { ASTVisitor } from '../../language/visitor';
import { SDLValidationContext } from '../ValidationContext';
/**
* Possible type extension
*
* A type extension is only valid if the type is defined and has the same kind.
*/
export function PossibleTypeExtensionsRule(
context: SDLValidationContext,
): ASTVisitor;

View File

@@ -0,0 +1,141 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PossibleTypeExtensionsRule = PossibleTypeExtensionsRule;
var _inspect = _interopRequireDefault(require("../../jsutils/inspect.js"));
var _invariant = _interopRequireDefault(require("../../jsutils/invariant.js"));
var _didYouMean = _interopRequireDefault(require("../../jsutils/didYouMean.js"));
var _suggestionList = _interopRequireDefault(require("../../jsutils/suggestionList.js"));
var _GraphQLError = require("../../error/GraphQLError.js");
var _kinds = require("../../language/kinds.js");
var _predicates = require("../../language/predicates.js");
var _definition = require("../../type/definition.js");
var _defKindToExtKind;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
/**
* Possible type extension
*
* A type extension is only valid if the type is defined and has the same kind.
*/
function PossibleTypeExtensionsRule(context) {
var schema = context.getSchema();
var definedTypes = Object.create(null);
for (var _i2 = 0, _context$getDocument$2 = context.getDocument().definitions; _i2 < _context$getDocument$2.length; _i2++) {
var def = _context$getDocument$2[_i2];
if ((0, _predicates.isTypeDefinitionNode)(def)) {
definedTypes[def.name.value] = def;
}
}
return {
ScalarTypeExtension: checkExtension,
ObjectTypeExtension: checkExtension,
InterfaceTypeExtension: checkExtension,
UnionTypeExtension: checkExtension,
EnumTypeExtension: checkExtension,
InputObjectTypeExtension: checkExtension
};
function checkExtension(node) {
var typeName = node.name.value;
var defNode = definedTypes[typeName];
var existingType = schema === null || schema === void 0 ? void 0 : schema.getType(typeName);
var expectedKind;
if (defNode) {
expectedKind = defKindToExtKind[defNode.kind];
} else if (existingType) {
expectedKind = typeToExtKind(existingType);
}
if (expectedKind) {
if (expectedKind !== node.kind) {
var kindStr = extensionKindToTypeName(node.kind);
context.reportError(new _GraphQLError.GraphQLError("Cannot extend non-".concat(kindStr, " type \"").concat(typeName, "\"."), defNode ? [defNode, node] : node));
}
} else {
var allTypeNames = Object.keys(definedTypes);
if (schema) {
allTypeNames = allTypeNames.concat(Object.keys(schema.getTypeMap()));
}
var suggestedTypes = (0, _suggestionList.default)(typeName, allTypeNames);
context.reportError(new _GraphQLError.GraphQLError("Cannot extend type \"".concat(typeName, "\" because it is not defined.") + (0, _didYouMean.default)(suggestedTypes), node.name));
}
}
}
var defKindToExtKind = (_defKindToExtKind = {}, _defineProperty(_defKindToExtKind, _kinds.Kind.SCALAR_TYPE_DEFINITION, _kinds.Kind.SCALAR_TYPE_EXTENSION), _defineProperty(_defKindToExtKind, _kinds.Kind.OBJECT_TYPE_DEFINITION, _kinds.Kind.OBJECT_TYPE_EXTENSION), _defineProperty(_defKindToExtKind, _kinds.Kind.INTERFACE_TYPE_DEFINITION, _kinds.Kind.INTERFACE_TYPE_EXTENSION), _defineProperty(_defKindToExtKind, _kinds.Kind.UNION_TYPE_DEFINITION, _kinds.Kind.UNION_TYPE_EXTENSION), _defineProperty(_defKindToExtKind, _kinds.Kind.ENUM_TYPE_DEFINITION, _kinds.Kind.ENUM_TYPE_EXTENSION), _defineProperty(_defKindToExtKind, _kinds.Kind.INPUT_OBJECT_TYPE_DEFINITION, _kinds.Kind.INPUT_OBJECT_TYPE_EXTENSION), _defKindToExtKind);
function typeToExtKind(type) {
if ((0, _definition.isScalarType)(type)) {
return _kinds.Kind.SCALAR_TYPE_EXTENSION;
}
if ((0, _definition.isObjectType)(type)) {
return _kinds.Kind.OBJECT_TYPE_EXTENSION;
}
if ((0, _definition.isInterfaceType)(type)) {
return _kinds.Kind.INTERFACE_TYPE_EXTENSION;
}
if ((0, _definition.isUnionType)(type)) {
return _kinds.Kind.UNION_TYPE_EXTENSION;
}
if ((0, _definition.isEnumType)(type)) {
return _kinds.Kind.ENUM_TYPE_EXTENSION;
} // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if ((0, _definition.isInputObjectType)(type)) {
return _kinds.Kind.INPUT_OBJECT_TYPE_EXTENSION;
} // istanbul ignore next (Not reachable. All possible types have been considered)
false || (0, _invariant.default)(0, 'Unexpected type: ' + (0, _inspect.default)(type));
}
function extensionKindToTypeName(kind) {
switch (kind) {
case _kinds.Kind.SCALAR_TYPE_EXTENSION:
return 'scalar';
case _kinds.Kind.OBJECT_TYPE_EXTENSION:
return 'object';
case _kinds.Kind.INTERFACE_TYPE_EXTENSION:
return 'interface';
case _kinds.Kind.UNION_TYPE_EXTENSION:
return 'union';
case _kinds.Kind.ENUM_TYPE_EXTENSION:
return 'enum';
case _kinds.Kind.INPUT_OBJECT_TYPE_EXTENSION:
return 'input object';
} // istanbul ignore next (Not reachable. All possible types have been considered)
false || (0, _invariant.default)(0, 'Unexpected kind: ' + (0, _inspect.default)(kind));
}

View File

@@ -0,0 +1,145 @@
// @flow strict
import inspect from '../../jsutils/inspect';
import invariant from '../../jsutils/invariant';
import didYouMean from '../../jsutils/didYouMean';
import suggestionList from '../../jsutils/suggestionList';
import { GraphQLError } from '../../error/GraphQLError';
import type { KindEnum } from '../../language/kinds';
import type { ASTVisitor } from '../../language/visitor';
import type { TypeExtensionNode } from '../../language/ast';
import { Kind } from '../../language/kinds';
import { isTypeDefinitionNode } from '../../language/predicates';
import type { GraphQLNamedType } from '../../type/definition';
import {
isScalarType,
isObjectType,
isInterfaceType,
isUnionType,
isEnumType,
isInputObjectType,
} from '../../type/definition';
import type { SDLValidationContext } from '../ValidationContext';
/**
* Possible type extension
*
* A type extension is only valid if the type is defined and has the same kind.
*/
export function PossibleTypeExtensionsRule(
context: SDLValidationContext,
): ASTVisitor {
const schema = context.getSchema();
const definedTypes = Object.create(null);
for (const def of context.getDocument().definitions) {
if (isTypeDefinitionNode(def)) {
definedTypes[def.name.value] = def;
}
}
return {
ScalarTypeExtension: checkExtension,
ObjectTypeExtension: checkExtension,
InterfaceTypeExtension: checkExtension,
UnionTypeExtension: checkExtension,
EnumTypeExtension: checkExtension,
InputObjectTypeExtension: checkExtension,
};
function checkExtension(node: TypeExtensionNode): void {
const typeName = node.name.value;
const defNode = definedTypes[typeName];
const existingType = schema?.getType(typeName);
let expectedKind;
if (defNode) {
expectedKind = defKindToExtKind[defNode.kind];
} else if (existingType) {
expectedKind = typeToExtKind(existingType);
}
if (expectedKind) {
if (expectedKind !== node.kind) {
const kindStr = extensionKindToTypeName(node.kind);
context.reportError(
new GraphQLError(
`Cannot extend non-${kindStr} type "${typeName}".`,
defNode ? [defNode, node] : node,
),
);
}
} else {
let allTypeNames = Object.keys(definedTypes);
if (schema) {
allTypeNames = allTypeNames.concat(Object.keys(schema.getTypeMap()));
}
const suggestedTypes = suggestionList(typeName, allTypeNames);
context.reportError(
new GraphQLError(
`Cannot extend type "${typeName}" because it is not defined.` +
didYouMean(suggestedTypes),
node.name,
),
);
}
}
}
const defKindToExtKind = {
[Kind.SCALAR_TYPE_DEFINITION]: Kind.SCALAR_TYPE_EXTENSION,
[Kind.OBJECT_TYPE_DEFINITION]: Kind.OBJECT_TYPE_EXTENSION,
[Kind.INTERFACE_TYPE_DEFINITION]: Kind.INTERFACE_TYPE_EXTENSION,
[Kind.UNION_TYPE_DEFINITION]: Kind.UNION_TYPE_EXTENSION,
[Kind.ENUM_TYPE_DEFINITION]: Kind.ENUM_TYPE_EXTENSION,
[Kind.INPUT_OBJECT_TYPE_DEFINITION]: Kind.INPUT_OBJECT_TYPE_EXTENSION,
};
function typeToExtKind(type: GraphQLNamedType): KindEnum {
if (isScalarType(type)) {
return Kind.SCALAR_TYPE_EXTENSION;
}
if (isObjectType(type)) {
return Kind.OBJECT_TYPE_EXTENSION;
}
if (isInterfaceType(type)) {
return Kind.INTERFACE_TYPE_EXTENSION;
}
if (isUnionType(type)) {
return Kind.UNION_TYPE_EXTENSION;
}
if (isEnumType(type)) {
return Kind.ENUM_TYPE_EXTENSION;
}
// istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if (isInputObjectType(type)) {
return Kind.INPUT_OBJECT_TYPE_EXTENSION;
}
// istanbul ignore next (Not reachable. All possible types have been considered)
invariant(false, 'Unexpected type: ' + inspect((type: empty)));
}
function extensionKindToTypeName(kind: KindEnum): string {
switch (kind) {
case Kind.SCALAR_TYPE_EXTENSION:
return 'scalar';
case Kind.OBJECT_TYPE_EXTENSION:
return 'object';
case Kind.INTERFACE_TYPE_EXTENSION:
return 'interface';
case Kind.UNION_TYPE_EXTENSION:
return 'union';
case Kind.ENUM_TYPE_EXTENSION:
return 'enum';
case Kind.INPUT_OBJECT_TYPE_EXTENSION:
return 'input object';
}
// istanbul ignore next (Not reachable. All possible types have been considered)
invariant(false, 'Unexpected kind: ' + inspect(kind));
}

View File

@@ -0,0 +1,124 @@
var _defKindToExtKind;
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import inspect from "../../jsutils/inspect.mjs";
import invariant from "../../jsutils/invariant.mjs";
import didYouMean from "../../jsutils/didYouMean.mjs";
import suggestionList from "../../jsutils/suggestionList.mjs";
import { GraphQLError } from "../../error/GraphQLError.mjs";
import { Kind } from "../../language/kinds.mjs";
import { isTypeDefinitionNode } from "../../language/predicates.mjs";
import { isScalarType, isObjectType, isInterfaceType, isUnionType, isEnumType, isInputObjectType } from "../../type/definition.mjs";
/**
* Possible type extension
*
* A type extension is only valid if the type is defined and has the same kind.
*/
export function PossibleTypeExtensionsRule(context) {
var schema = context.getSchema();
var definedTypes = Object.create(null);
for (var _i2 = 0, _context$getDocument$2 = context.getDocument().definitions; _i2 < _context$getDocument$2.length; _i2++) {
var def = _context$getDocument$2[_i2];
if (isTypeDefinitionNode(def)) {
definedTypes[def.name.value] = def;
}
}
return {
ScalarTypeExtension: checkExtension,
ObjectTypeExtension: checkExtension,
InterfaceTypeExtension: checkExtension,
UnionTypeExtension: checkExtension,
EnumTypeExtension: checkExtension,
InputObjectTypeExtension: checkExtension
};
function checkExtension(node) {
var typeName = node.name.value;
var defNode = definedTypes[typeName];
var existingType = schema === null || schema === void 0 ? void 0 : schema.getType(typeName);
var expectedKind;
if (defNode) {
expectedKind = defKindToExtKind[defNode.kind];
} else if (existingType) {
expectedKind = typeToExtKind(existingType);
}
if (expectedKind) {
if (expectedKind !== node.kind) {
var kindStr = extensionKindToTypeName(node.kind);
context.reportError(new GraphQLError("Cannot extend non-".concat(kindStr, " type \"").concat(typeName, "\"."), defNode ? [defNode, node] : node));
}
} else {
var allTypeNames = Object.keys(definedTypes);
if (schema) {
allTypeNames = allTypeNames.concat(Object.keys(schema.getTypeMap()));
}
var suggestedTypes = suggestionList(typeName, allTypeNames);
context.reportError(new GraphQLError("Cannot extend type \"".concat(typeName, "\" because it is not defined.") + didYouMean(suggestedTypes), node.name));
}
}
}
var defKindToExtKind = (_defKindToExtKind = {}, _defineProperty(_defKindToExtKind, Kind.SCALAR_TYPE_DEFINITION, Kind.SCALAR_TYPE_EXTENSION), _defineProperty(_defKindToExtKind, Kind.OBJECT_TYPE_DEFINITION, Kind.OBJECT_TYPE_EXTENSION), _defineProperty(_defKindToExtKind, Kind.INTERFACE_TYPE_DEFINITION, Kind.INTERFACE_TYPE_EXTENSION), _defineProperty(_defKindToExtKind, Kind.UNION_TYPE_DEFINITION, Kind.UNION_TYPE_EXTENSION), _defineProperty(_defKindToExtKind, Kind.ENUM_TYPE_DEFINITION, Kind.ENUM_TYPE_EXTENSION), _defineProperty(_defKindToExtKind, Kind.INPUT_OBJECT_TYPE_DEFINITION, Kind.INPUT_OBJECT_TYPE_EXTENSION), _defKindToExtKind);
function typeToExtKind(type) {
if (isScalarType(type)) {
return Kind.SCALAR_TYPE_EXTENSION;
}
if (isObjectType(type)) {
return Kind.OBJECT_TYPE_EXTENSION;
}
if (isInterfaceType(type)) {
return Kind.INTERFACE_TYPE_EXTENSION;
}
if (isUnionType(type)) {
return Kind.UNION_TYPE_EXTENSION;
}
if (isEnumType(type)) {
return Kind.ENUM_TYPE_EXTENSION;
} // istanbul ignore else (See: 'https://github.com/graphql/graphql-js/issues/2618')
if (isInputObjectType(type)) {
return Kind.INPUT_OBJECT_TYPE_EXTENSION;
} // istanbul ignore next (Not reachable. All possible types have been considered)
false || invariant(0, 'Unexpected type: ' + inspect(type));
}
function extensionKindToTypeName(kind) {
switch (kind) {
case Kind.SCALAR_TYPE_EXTENSION:
return 'scalar';
case Kind.OBJECT_TYPE_EXTENSION:
return 'object';
case Kind.INTERFACE_TYPE_EXTENSION:
return 'interface';
case Kind.UNION_TYPE_EXTENSION:
return 'union';
case Kind.ENUM_TYPE_EXTENSION:
return 'enum';
case Kind.INPUT_OBJECT_TYPE_EXTENSION:
return 'input object';
} // istanbul ignore next (Not reachable. All possible types have been considered)
false || invariant(0, 'Unexpected kind: ' + inspect(kind));
}

View File

@@ -0,0 +1,19 @@
import { ASTVisitor } from '../../language/visitor';
import { ValidationContext, SDLValidationContext } from '../ValidationContext';
/**
* Provided required arguments
*
* A field or directive is only valid if all required (non-null without a
* default value) field arguments have been provided.
*/
export function ProvidedRequiredArgumentsRule(
context: ValidationContext,
): ASTVisitor;
/**
* @internal
*/
export function ProvidedRequiredArgumentsOnDirectivesRule(
context: ValidationContext | SDLValidationContext,
): ASTVisitor;

View File

@@ -0,0 +1,136 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ProvidedRequiredArgumentsRule = ProvidedRequiredArgumentsRule;
exports.ProvidedRequiredArgumentsOnDirectivesRule = ProvidedRequiredArgumentsOnDirectivesRule;
var _inspect = _interopRequireDefault(require("../../jsutils/inspect.js"));
var _keyMap = _interopRequireDefault(require("../../jsutils/keyMap.js"));
var _GraphQLError = require("../../error/GraphQLError.js");
var _kinds = require("../../language/kinds.js");
var _printer = require("../../language/printer.js");
var _directives = require("../../type/directives.js");
var _definition = require("../../type/definition.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
/**
* Provided required arguments
*
* A field or directive is only valid if all required (non-null without a
* default value) field arguments have been provided.
*/
function ProvidedRequiredArgumentsRule(context) {
return _objectSpread(_objectSpread({}, ProvidedRequiredArgumentsOnDirectivesRule(context)), {}, {
Field: {
// Validate on leave to allow for deeper errors to appear first.
leave: function leave(fieldNode) {
var _fieldNode$arguments;
var fieldDef = context.getFieldDef();
if (!fieldDef) {
return false;
} // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var argNodes = (_fieldNode$arguments = fieldNode.arguments) !== null && _fieldNode$arguments !== void 0 ? _fieldNode$arguments : [];
var argNodeMap = (0, _keyMap.default)(argNodes, function (arg) {
return arg.name.value;
});
for (var _i2 = 0, _fieldDef$args2 = fieldDef.args; _i2 < _fieldDef$args2.length; _i2++) {
var argDef = _fieldDef$args2[_i2];
var argNode = argNodeMap[argDef.name];
if (!argNode && (0, _definition.isRequiredArgument)(argDef)) {
var argTypeStr = (0, _inspect.default)(argDef.type);
context.reportError(new _GraphQLError.GraphQLError("Field \"".concat(fieldDef.name, "\" argument \"").concat(argDef.name, "\" of type \"").concat(argTypeStr, "\" is required, but it was not provided."), fieldNode));
}
}
}
}
});
}
/**
* @internal
*/
function ProvidedRequiredArgumentsOnDirectivesRule(context) {
var requiredArgsMap = Object.create(null);
var schema = context.getSchema();
var definedDirectives = schema ? schema.getDirectives() : _directives.specifiedDirectives;
for (var _i4 = 0; _i4 < definedDirectives.length; _i4++) {
var directive = definedDirectives[_i4];
requiredArgsMap[directive.name] = (0, _keyMap.default)(directive.args.filter(_definition.isRequiredArgument), function (arg) {
return arg.name;
});
}
var astDefinitions = context.getDocument().definitions;
for (var _i6 = 0; _i6 < astDefinitions.length; _i6++) {
var def = astDefinitions[_i6];
if (def.kind === _kinds.Kind.DIRECTIVE_DEFINITION) {
var _def$arguments;
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var argNodes = (_def$arguments = def.arguments) !== null && _def$arguments !== void 0 ? _def$arguments : [];
requiredArgsMap[def.name.value] = (0, _keyMap.default)(argNodes.filter(isRequiredArgumentNode), function (arg) {
return arg.name.value;
});
}
}
return {
Directive: {
// Validate on leave to allow for deeper errors to appear first.
leave: function leave(directiveNode) {
var directiveName = directiveNode.name.value;
var requiredArgs = requiredArgsMap[directiveName];
if (requiredArgs) {
var _directiveNode$argume;
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var _argNodes = (_directiveNode$argume = directiveNode.arguments) !== null && _directiveNode$argume !== void 0 ? _directiveNode$argume : [];
var argNodeMap = (0, _keyMap.default)(_argNodes, function (arg) {
return arg.name.value;
});
for (var _i8 = 0, _Object$keys2 = Object.keys(requiredArgs); _i8 < _Object$keys2.length; _i8++) {
var argName = _Object$keys2[_i8];
if (!argNodeMap[argName]) {
var argType = requiredArgs[argName].type;
var argTypeStr = (0, _definition.isType)(argType) ? (0, _inspect.default)(argType) : (0, _printer.print)(argType);
context.reportError(new _GraphQLError.GraphQLError("Directive \"@".concat(directiveName, "\" argument \"").concat(argName, "\" of type \"").concat(argTypeStr, "\" is required, but it was not provided."), directiveNode));
}
}
}
}
}
};
}
function isRequiredArgumentNode(arg) {
return arg.type.kind === _kinds.Kind.NON_NULL_TYPE && arg.defaultValue == null;
}

View File

@@ -0,0 +1,125 @@
// @flow strict
import inspect from '../../jsutils/inspect';
import keyMap from '../../jsutils/keyMap';
import { GraphQLError } from '../../error/GraphQLError';
import type { ASTVisitor } from '../../language/visitor';
import type { InputValueDefinitionNode } from '../../language/ast';
import { Kind } from '../../language/kinds';
import { print } from '../../language/printer';
import { specifiedDirectives } from '../../type/directives';
import { isType, isRequiredArgument } from '../../type/definition';
import type {
ValidationContext,
SDLValidationContext,
} from '../ValidationContext';
/**
* Provided required arguments
*
* A field or directive is only valid if all required (non-null without a
* default value) field arguments have been provided.
*/
export function ProvidedRequiredArgumentsRule(
context: ValidationContext,
): ASTVisitor {
return {
// eslint-disable-next-line new-cap
...ProvidedRequiredArgumentsOnDirectivesRule(context),
Field: {
// Validate on leave to allow for deeper errors to appear first.
leave(fieldNode) {
const fieldDef = context.getFieldDef();
if (!fieldDef) {
return false;
}
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
const argNodes = fieldNode.arguments ?? [];
const argNodeMap = keyMap(argNodes, (arg) => arg.name.value);
for (const argDef of fieldDef.args) {
const argNode = argNodeMap[argDef.name];
if (!argNode && isRequiredArgument(argDef)) {
const argTypeStr = inspect(argDef.type);
context.reportError(
new GraphQLError(
`Field "${fieldDef.name}" argument "${argDef.name}" of type "${argTypeStr}" is required, but it was not provided.`,
fieldNode,
),
);
}
}
},
},
};
}
/**
* @internal
*/
export function ProvidedRequiredArgumentsOnDirectivesRule(
context: ValidationContext | SDLValidationContext,
): ASTVisitor {
const requiredArgsMap = Object.create(null);
const schema = context.getSchema();
const definedDirectives = schema
? schema.getDirectives()
: specifiedDirectives;
for (const directive of definedDirectives) {
requiredArgsMap[directive.name] = keyMap(
directive.args.filter(isRequiredArgument),
(arg) => arg.name,
);
}
const astDefinitions = context.getDocument().definitions;
for (const def of astDefinitions) {
if (def.kind === Kind.DIRECTIVE_DEFINITION) {
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
const argNodes = def.arguments ?? [];
requiredArgsMap[def.name.value] = keyMap(
argNodes.filter(isRequiredArgumentNode),
(arg) => arg.name.value,
);
}
}
return {
Directive: {
// Validate on leave to allow for deeper errors to appear first.
leave(directiveNode) {
const directiveName = directiveNode.name.value;
const requiredArgs = requiredArgsMap[directiveName];
if (requiredArgs) {
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
const argNodes = directiveNode.arguments ?? [];
const argNodeMap = keyMap(argNodes, (arg) => arg.name.value);
for (const argName of Object.keys(requiredArgs)) {
if (!argNodeMap[argName]) {
const argType = requiredArgs[argName].type;
const argTypeStr = isType(argType)
? inspect(argType)
: print(argType);
context.reportError(
new GraphQLError(
`Directive "@${directiveName}" argument "${argName}" of type "${argTypeStr}" is required, but it was not provided.`,
directiveNode,
),
);
}
}
}
},
},
};
}
function isRequiredArgumentNode(arg: InputValueDefinitionNode): boolean {
return arg.type.kind === Kind.NON_NULL_TYPE && arg.defaultValue == null;
}

View File

@@ -0,0 +1,119 @@
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import inspect from "../../jsutils/inspect.mjs";
import keyMap from "../../jsutils/keyMap.mjs";
import { GraphQLError } from "../../error/GraphQLError.mjs";
import { Kind } from "../../language/kinds.mjs";
import { print } from "../../language/printer.mjs";
import { specifiedDirectives } from "../../type/directives.mjs";
import { isType, isRequiredArgument } from "../../type/definition.mjs";
/**
* Provided required arguments
*
* A field or directive is only valid if all required (non-null without a
* default value) field arguments have been provided.
*/
export function ProvidedRequiredArgumentsRule(context) {
return _objectSpread(_objectSpread({}, ProvidedRequiredArgumentsOnDirectivesRule(context)), {}, {
Field: {
// Validate on leave to allow for deeper errors to appear first.
leave: function leave(fieldNode) {
var _fieldNode$arguments;
var fieldDef = context.getFieldDef();
if (!fieldDef) {
return false;
} // istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var argNodes = (_fieldNode$arguments = fieldNode.arguments) !== null && _fieldNode$arguments !== void 0 ? _fieldNode$arguments : [];
var argNodeMap = keyMap(argNodes, function (arg) {
return arg.name.value;
});
for (var _i2 = 0, _fieldDef$args2 = fieldDef.args; _i2 < _fieldDef$args2.length; _i2++) {
var argDef = _fieldDef$args2[_i2];
var argNode = argNodeMap[argDef.name];
if (!argNode && isRequiredArgument(argDef)) {
var argTypeStr = inspect(argDef.type);
context.reportError(new GraphQLError("Field \"".concat(fieldDef.name, "\" argument \"").concat(argDef.name, "\" of type \"").concat(argTypeStr, "\" is required, but it was not provided."), fieldNode));
}
}
}
}
});
}
/**
* @internal
*/
export function ProvidedRequiredArgumentsOnDirectivesRule(context) {
var requiredArgsMap = Object.create(null);
var schema = context.getSchema();
var definedDirectives = schema ? schema.getDirectives() : specifiedDirectives;
for (var _i4 = 0; _i4 < definedDirectives.length; _i4++) {
var directive = definedDirectives[_i4];
requiredArgsMap[directive.name] = keyMap(directive.args.filter(isRequiredArgument), function (arg) {
return arg.name;
});
}
var astDefinitions = context.getDocument().definitions;
for (var _i6 = 0; _i6 < astDefinitions.length; _i6++) {
var def = astDefinitions[_i6];
if (def.kind === Kind.DIRECTIVE_DEFINITION) {
var _def$arguments;
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var argNodes = (_def$arguments = def.arguments) !== null && _def$arguments !== void 0 ? _def$arguments : [];
requiredArgsMap[def.name.value] = keyMap(argNodes.filter(isRequiredArgumentNode), function (arg) {
return arg.name.value;
});
}
}
return {
Directive: {
// Validate on leave to allow for deeper errors to appear first.
leave: function leave(directiveNode) {
var directiveName = directiveNode.name.value;
var requiredArgs = requiredArgsMap[directiveName];
if (requiredArgs) {
var _directiveNode$argume;
// istanbul ignore next (See: 'https://github.com/graphql/graphql-js/issues/2203')
var _argNodes = (_directiveNode$argume = directiveNode.arguments) !== null && _directiveNode$argume !== void 0 ? _directiveNode$argume : [];
var argNodeMap = keyMap(_argNodes, function (arg) {
return arg.name.value;
});
for (var _i8 = 0, _Object$keys2 = Object.keys(requiredArgs); _i8 < _Object$keys2.length; _i8++) {
var argName = _Object$keys2[_i8];
if (!argNodeMap[argName]) {
var argType = requiredArgs[argName].type;
var argTypeStr = isType(argType) ? inspect(argType) : print(argType);
context.reportError(new GraphQLError("Directive \"@".concat(directiveName, "\" argument \"").concat(argName, "\" of type \"").concat(argTypeStr, "\" is required, but it was not provided."), directiveNode));
}
}
}
}
}
};
}
function isRequiredArgumentNode(arg) {
return arg.type.kind === Kind.NON_NULL_TYPE && arg.defaultValue == null;
}

View File

@@ -0,0 +1,10 @@
import { ASTVisitor } from '../../language/visitor';
import { ValidationContext } from '../ValidationContext';
/**
* Scalar leafs
*
* A GraphQL document is valid only if all leaf fields (fields without
* sub selections) are of scalar or enum types.
*/
export function ScalarLeafsRule(context: ValidationContext): ASTVisitor;

View File

@@ -0,0 +1,45 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ScalarLeafsRule = ScalarLeafsRule;
var _inspect = _interopRequireDefault(require("../../jsutils/inspect.js"));
var _GraphQLError = require("../../error/GraphQLError.js");
var _definition = require("../../type/definition.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Scalar leafs
*
* A GraphQL document is valid only if all leaf fields (fields without
* sub selections) are of scalar or enum types.
*/
function ScalarLeafsRule(context) {
return {
Field: function Field(node) {
var type = context.getType();
var selectionSet = node.selectionSet;
if (type) {
if ((0, _definition.isLeafType)((0, _definition.getNamedType)(type))) {
if (selectionSet) {
var fieldName = node.name.value;
var typeStr = (0, _inspect.default)(type);
context.reportError(new _GraphQLError.GraphQLError("Field \"".concat(fieldName, "\" must not have a selection since type \"").concat(typeStr, "\" has no subfields."), selectionSet));
}
} else if (!selectionSet) {
var _fieldName = node.name.value;
var _typeStr = (0, _inspect.default)(type);
context.reportError(new _GraphQLError.GraphQLError("Field \"".concat(_fieldName, "\" of type \"").concat(_typeStr, "\" must have a selection of subfields. Did you mean \"").concat(_fieldName, " { ... }\"?"), node));
}
}
}
};
}

View File

@@ -0,0 +1,49 @@
// @flow strict
import inspect from '../../jsutils/inspect';
import { GraphQLError } from '../../error/GraphQLError';
import type { FieldNode } from '../../language/ast';
import type { ASTVisitor } from '../../language/visitor';
import { getNamedType, isLeafType } from '../../type/definition';
import type { ValidationContext } from '../ValidationContext';
/**
* Scalar leafs
*
* A GraphQL document is valid only if all leaf fields (fields without
* sub selections) are of scalar or enum types.
*/
export function ScalarLeafsRule(context: ValidationContext): ASTVisitor {
return {
Field(node: FieldNode) {
const type = context.getType();
const selectionSet = node.selectionSet;
if (type) {
if (isLeafType(getNamedType(type))) {
if (selectionSet) {
const fieldName = node.name.value;
const typeStr = inspect(type);
context.reportError(
new GraphQLError(
`Field "${fieldName}" must not have a selection since type "${typeStr}" has no subfields.`,
selectionSet,
),
);
}
} else if (!selectionSet) {
const fieldName = node.name.value;
const typeStr = inspect(type);
context.reportError(
new GraphQLError(
`Field "${fieldName}" of type "${typeStr}" must have a selection of subfields. Did you mean "${fieldName} { ... }"?`,
node,
),
);
}
}
},
};
}

View File

@@ -0,0 +1,34 @@
import inspect from "../../jsutils/inspect.mjs";
import { GraphQLError } from "../../error/GraphQLError.mjs";
import { getNamedType, isLeafType } from "../../type/definition.mjs";
/**
* Scalar leafs
*
* A GraphQL document is valid only if all leaf fields (fields without
* sub selections) are of scalar or enum types.
*/
export function ScalarLeafsRule(context) {
return {
Field: function Field(node) {
var type = context.getType();
var selectionSet = node.selectionSet;
if (type) {
if (isLeafType(getNamedType(type))) {
if (selectionSet) {
var fieldName = node.name.value;
var typeStr = inspect(type);
context.reportError(new GraphQLError("Field \"".concat(fieldName, "\" must not have a selection since type \"").concat(typeStr, "\" has no subfields."), selectionSet));
}
} else if (!selectionSet) {
var _fieldName = node.name.value;
var _typeStr = inspect(type);
context.reportError(new GraphQLError("Field \"".concat(_fieldName, "\" of type \"").concat(_typeStr, "\" must have a selection of subfields. Did you mean \"").concat(_fieldName, " { ... }\"?"), node));
}
}
}
};
}

View File

@@ -0,0 +1,11 @@
import { ASTVisitor } from '../../language/visitor';
import { ASTValidationContext } from '../ValidationContext';
/**
* Subscriptions must only include one field.
*
* A GraphQL subscription is valid only if it contains a single root field.
*/
export function SingleFieldSubscriptionsRule(
context: ASTValidationContext,
): ASTVisitor;

View File

@@ -0,0 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SingleFieldSubscriptionsRule = SingleFieldSubscriptionsRule;
var _GraphQLError = require("../../error/GraphQLError.js");
/**
* Subscriptions must only include one field.
*
* A GraphQL subscription is valid only if it contains a single root field.
*/
function SingleFieldSubscriptionsRule(context) {
return {
OperationDefinition: function OperationDefinition(node) {
if (node.operation === 'subscription') {
if (node.selectionSet.selections.length !== 1) {
context.reportError(new _GraphQLError.GraphQLError(node.name ? "Subscription \"".concat(node.name.value, "\" must select only one top level field.") : 'Anonymous Subscription must select only one top level field.', node.selectionSet.selections.slice(1)));
}
}
}
};
}

View File

@@ -0,0 +1,33 @@
// @flow strict
import { GraphQLError } from '../../error/GraphQLError';
import type { ASTVisitor } from '../../language/visitor';
import type { OperationDefinitionNode } from '../../language/ast';
import type { ASTValidationContext } from '../ValidationContext';
/**
* Subscriptions must only include one field.
*
* A GraphQL subscription is valid only if it contains a single root field.
*/
export function SingleFieldSubscriptionsRule(
context: ASTValidationContext,
): ASTVisitor {
return {
OperationDefinition(node: OperationDefinitionNode) {
if (node.operation === 'subscription') {
if (node.selectionSet.selections.length !== 1) {
context.reportError(
new GraphQLError(
node.name
? `Subscription "${node.name.value}" must select only one top level field.`
: 'Anonymous Subscription must select only one top level field.',
node.selectionSet.selections.slice(1),
),
);
}
}
},
};
}

View File

@@ -0,0 +1,18 @@
import { GraphQLError } from "../../error/GraphQLError.mjs";
/**
* Subscriptions must only include one field.
*
* A GraphQL subscription is valid only if it contains a single root field.
*/
export function SingleFieldSubscriptionsRule(context) {
return {
OperationDefinition: function OperationDefinition(node) {
if (node.operation === 'subscription') {
if (node.selectionSet.selections.length !== 1) {
context.reportError(new GraphQLError(node.name ? "Subscription \"".concat(node.name.value, "\" must select only one top level field.") : 'Anonymous Subscription must select only one top level field.', node.selectionSet.selections.slice(1)));
}
}
}
};
}

View File

@@ -0,0 +1,12 @@
import { ASTVisitor } from '../../language/visitor';
import { ASTValidationContext } from '../ValidationContext';
/**
* Unique argument names
*
* A GraphQL field or directive is only valid if all supplied arguments are
* uniquely named.
*/
export function UniqueArgumentNamesRule(
context: ASTValidationContext,
): ASTVisitor;

View File

@@ -0,0 +1,37 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.UniqueArgumentNamesRule = UniqueArgumentNamesRule;
var _GraphQLError = require("../../error/GraphQLError.js");
/**
* Unique argument names
*
* A GraphQL field or directive is only valid if all supplied arguments are
* uniquely named.
*/
function UniqueArgumentNamesRule(context) {
var knownArgNames = Object.create(null);
return {
Field: function Field() {
knownArgNames = Object.create(null);
},
Directive: function Directive() {
knownArgNames = Object.create(null);
},
Argument: function Argument(node) {
var argName = node.name.value;
if (knownArgNames[argName]) {
context.reportError(new _GraphQLError.GraphQLError("There can be only one argument named \"".concat(argName, "\"."), [knownArgNames[argName], node.name]));
} else {
knownArgNames[argName] = node.name;
}
return false;
}
};
}

View File

@@ -0,0 +1,39 @@
// @flow strict
import { GraphQLError } from '../../error/GraphQLError';
import type { ASTVisitor } from '../../language/visitor';
import type { ASTValidationContext } from '../ValidationContext';
/**
* Unique argument names
*
* A GraphQL field or directive is only valid if all supplied arguments are
* uniquely named.
*/
export function UniqueArgumentNamesRule(
context: ASTValidationContext,
): ASTVisitor {
let knownArgNames = Object.create(null);
return {
Field() {
knownArgNames = Object.create(null);
},
Directive() {
knownArgNames = Object.create(null);
},
Argument(node) {
const argName = node.name.value;
if (knownArgNames[argName]) {
context.reportError(
new GraphQLError(
`There can be only one argument named "${argName}".`,
[knownArgNames[argName], node.name],
),
);
} else {
knownArgNames[argName] = node.name;
}
return false;
},
};
}

View File

@@ -0,0 +1,30 @@
import { GraphQLError } from "../../error/GraphQLError.mjs";
/**
* Unique argument names
*
* A GraphQL field or directive is only valid if all supplied arguments are
* uniquely named.
*/
export function UniqueArgumentNamesRule(context) {
var knownArgNames = Object.create(null);
return {
Field: function Field() {
knownArgNames = Object.create(null);
},
Directive: function Directive() {
knownArgNames = Object.create(null);
},
Argument: function Argument(node) {
var argName = node.name.value;
if (knownArgNames[argName]) {
context.reportError(new GraphQLError("There can be only one argument named \"".concat(argName, "\"."), [knownArgNames[argName], node.name]));
} else {
knownArgNames[argName] = node.name;
}
return false;
}
};
}

Some files were not shown because too many files have changed in this diff Show More