@relay-graphql-js/validation-rules
Version:
shared relay validation rules for graphql-js parser
153 lines (152 loc) • 8.06 kB
JavaScript
;
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
exports.__esModule = true;
exports.RelayKnownArgumentNames = void 0;
var graphql_1 = require("graphql");
var argumentDefinitions_1 = require("./argumentDefinitions");
var utils_1 = require("./utils");
// tslint:disable-next-line: no-shadowed-variable
exports.RelayKnownArgumentNames = function RelayKnownArgumentNames(context) {
var originalRuleVisitor = graphql_1.KnownArgumentNamesRule(context);
return {
Argument: function (argumentNode) {
/**
* Always forward field arguments to the original rule.
*/
graphql_1.visit(argumentNode, originalRuleVisitor);
return false;
},
FragmentSpread: function (fragmentSpreadNode) {
var fragmentDefinitionNode = context.getFragment(fragmentSpreadNode.name.value);
if (fragmentDefinitionNode &&
(!fragmentSpreadNode.directives ||
fragmentSpreadNode.directives.findIndex(function (directive) { return directive.name.value === "arguments"; }) === -1) &&
argumentDefinitions_1.getArgumentDefinitions(fragmentDefinitionNode)) {
validateFragmentArguments(context, fragmentDefinitionNode, fragmentSpreadNode);
}
},
Directive: function (directiveNode, _key, _parent, _nodePath, ancestors) {
if (directiveNode.name.value === "argumentDefinitions") {
validateFragmentArgumentDefinitions(context, directiveNode);
return false;
}
if (directiveNode.name.value === "arguments") {
var fragmentSpreadNode = ancestors[ancestors.length - 1];
var fragmentDefinitionNode = context.getFragment(fragmentSpreadNode.name.value);
if (fragmentDefinitionNode) {
validateFragmentArguments(context, fragmentDefinitionNode, fragmentSpreadNode, directiveNode);
}
return false;
}
/**
* Forward any other directives to original rule.
*/
graphql_1.visit(directiveNode, originalRuleVisitor);
return false;
}
};
};
function validateFragmentArgumentDefinitions(context, directiveNode) {
if (!directiveNode.arguments || directiveNode.arguments.length === 0) {
context.reportError(new graphql_1.GraphQLError("Missing required argument definitions.", directiveNode));
}
else {
directiveNode.arguments.forEach(function (argumentNode) {
var metadataNode = argumentNode.value;
if (metadataNode.kind !== "ObjectValue" || !metadataNode.fields.some(function (field) { return field.name.value === "type"; })) {
context.reportError(new graphql_1.GraphQLError("Metadata of argument definition should be of type \"Object\" with a \"type\" and optional \"defaultValue\" key.", metadataNode));
}
else {
metadataNode.fields.forEach(function (fieldNode) {
var name = fieldNode.name.value;
if (name !== "type" && name !== "defaultValue") {
context.reportError(new graphql_1.GraphQLError("Unknown key \"" + name + "\" in argument definition metadata.", fieldNode.name));
}
var valueNode = fieldNode.value;
if (name === "type") {
if (valueNode.kind !== "StringValue") {
context.reportError(new graphql_1.GraphQLError("Value for \"type\" in argument definition metadata must be specified as string literal.", valueNode));
}
else {
var typeNode = null;
try {
typeNode = graphql_1.parseType(valueNode.value);
}
catch (error) {
context.reportError(new graphql_1.GraphQLError(error.message, valueNode));
}
if (typeNode) {
while (typeNode.kind === "NonNullType" || typeNode.kind === "ListType") {
typeNode = typeNode.type;
}
if (!context.getSchema().getType(typeNode.name.value)) {
context.reportError(new graphql_1.GraphQLError("Unknown type \"" + typeNode.name.value + "\" in argument definition metadata.", valueNode));
}
}
}
}
else if (name === "defaultValue") {
if (utils_1.containsVariableNodes(fieldNode.value)) {
context.reportError(new graphql_1.GraphQLError("defaultValue contains variables for argument " + argumentNode.name.value + " in argument definition metadata.", valueNode));
}
}
});
}
});
}
}
function isNullableArgument(argumentDefinition) {
var typeField = argumentDefinition.fields.find(function (f) { return f.name.value === "type"; });
if (typeField == null) {
return false;
}
if (typeField.value.kind !== "StringValue") {
return false;
}
try {
var type = graphql_1.parseType(typeField.value.value);
return type.kind !== "NonNullType";
}
catch (e) {
return false;
}
}
function validateFragmentArguments(context, fragmentDefinitionNode, fragmentSpreadNode, directiveNode) {
var argumentDefinitionNodes = argumentDefinitions_1.getArgumentDefinitions(fragmentDefinitionNode);
var suggestionList = require("graphql/jsutils/suggestionList")["default"];
var didYouMean = require("graphql/jsutils/didYouMean")["default"];
if (!argumentDefinitionNodes) {
context.reportError(new graphql_1.GraphQLError("No fragment argument definitions exist for fragment \"" + fragmentSpreadNode.name.value + "\".", fragmentSpreadNode));
}
else {
var argumentNodes_1 = __spreadArrays(((directiveNode && directiveNode.arguments) || []));
argumentDefinitionNodes.forEach(function (argumentDef) {
var argumentIndex = argumentNodes_1.findIndex(function (a) { return a.name.value === argumentDef.name.value; });
if (argumentIndex >= 0) {
argumentNodes_1.splice(argumentIndex, 1);
}
else {
var value = argumentDef.value;
if (value.kind === "ObjectValue") {
if (value.fields.findIndex(function (field) { return field.name.value === "defaultValue"; }) === -1 &&
!isNullableArgument(value)) {
context.reportError(new graphql_1.GraphQLError("Missing required fragment argument \"" + argumentDef.name.value + "\".", directiveNode || fragmentSpreadNode));
}
}
else {
console.log("Unexpected fragment argument value kind \"" + value.kind + "\".");
}
}
});
argumentNodes_1.forEach(function (argumentNode) {
var suggestions = suggestionList(argumentNode.name.value, argumentDefinitionNodes.map(function (argDef) { return argDef.name.value; }));
context.reportError(new graphql_1.GraphQLError("Unknown fragment argument \"" + argumentNode.name.value + "\"." + didYouMean(suggestions.map(function (x) { return "\"" + x + "\""; })), directiveNode));
});
}
}