@relay-graphql-js/validation-rules
Version:
shared relay validation rules for graphql-js parser
153 lines (152 loc) • 7.03 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.RelayCompatRequiredPageInfoFields = exports.connectionSelectionSetPaginationInfo = void 0;
var graphql_1 = require("graphql");
var utils_1 = require("./utils");
function hasFirstArgument(fieldNode) {
return !!(fieldNode.arguments && fieldNode.arguments.find(function (arg) { return arg.name.value === "first"; }));
}
function hasLastArgument(fieldNode) {
return !!(fieldNode.arguments && fieldNode.arguments.find(function (arg) { return arg.name.value === "last"; }));
}
function hasAfterArgument(fieldNode) {
return !!(fieldNode.arguments && fieldNode.arguments.find(function (arg) { return arg.name.value === "after"; }));
}
function hasBeforeArgument(fieldNode) {
return !!(fieldNode.arguments && fieldNode.arguments.find(function (arg) { return arg.name.value === "before"; }));
}
function rollupFieldsInfo(fieldsInfo) {
return fieldsInfo.reduce(function (carry, el) {
carry.hasNextPage = carry.hasNextPage || el.hasNextPage;
carry.hasPreviousPage = carry.hasPreviousPage || el.hasPreviousPage;
carry.endCursor = carry.endCursor || el.endCursor;
carry.startCursor = carry.startCursor || el.startCursor;
return carry;
}, {
hasNextPage: false,
hasPreviousPage: false,
endCursor: false,
startCursor: false
});
}
function connectionSelectionSetPaginationInfo(getFragment, selectionSetNode) {
var fieldsInfo = [];
graphql_1.visit(selectionSetNode, {
SelectionSet: function (selectionSet) {
if (selectionSet !== selectionSetNode) {
// Don't recurse into other selection sets
return false;
}
},
InlineFragment: function (inlineFragment) {
fieldsInfo.push(connectionSelectionSetPaginationInfo(getFragment, inlineFragment.selectionSet));
return false;
},
Field: function (fieldNode) {
if (fieldNode.name.value === "pageInfo" && fieldNode.selectionSet) {
fieldsInfo.push(pageInfoSelectionSetPaginationInfo(getFragment, fieldNode.selectionSet));
return false;
}
},
FragmentSpread: function (fragmentSpread) {
var fragmentDefinitionNode = getFragment(fragmentSpread.name.value);
if (fragmentDefinitionNode) {
fieldsInfo.push(connectionSelectionSetPaginationInfo(getFragment, fragmentDefinitionNode.selectionSet));
}
return false;
}
});
return rollupFieldsInfo(fieldsInfo);
}
exports.connectionSelectionSetPaginationInfo = connectionSelectionSetPaginationInfo;
function pageInfoSelectionSetPaginationInfo(getFragment, selectionSetNode) {
var fields = {
hasNextPage: false,
hasPreviousPage: false,
startCursor: false,
endCursor: false
};
var nestedFieldsInfo = [];
graphql_1.visit(selectionSetNode, {
SelectionSet: function (selectionSet) {
if (selectionSet !== selectionSetNode) {
// Don't recurse into other selection sets
return false;
}
},
InlineFragment: function (inlineFragment) {
nestedFieldsInfo.push(pageInfoSelectionSetPaginationInfo(getFragment, inlineFragment.selectionSet));
return false;
},
Field: function (fieldNode) {
if (fieldNode.name.value === "startCursor") {
fields.startCursor = true;
}
if (fieldNode.name.value === "endCursor") {
fields.endCursor = true;
}
if (fieldNode.name.value === "hasPreviousPage") {
fields.hasPreviousPage = true;
}
if (fieldNode.name.value === "hasNextPage") {
fields.hasNextPage = true;
}
},
FragmentSpread: function (fragmentSpread) {
var fragmentDefinitionNode = getFragment(fragmentSpread.name.value);
if (fragmentDefinitionNode) {
nestedFieldsInfo.push(pageInfoSelectionSetPaginationInfo(getFragment, fragmentDefinitionNode.selectionSet));
}
return false;
}
});
return rollupFieldsInfo(__spreadArrays([fields], nestedFieldsInfo));
}
// tslint:disable-next-line: no-shadowed-variable
exports.RelayCompatRequiredPageInfoFields = function RelayCompatRequiredPageInfoFields(context) {
return {
Field: {
enter: function (fieldNode) {
if (!fieldNode.selectionSet) {
return;
}
var type = context.getType();
if (!type || !utils_1.isConnectionType(type)) {
return;
}
var connectionDirective = utils_1.getConnectionDirective(fieldNode);
if (!connectionDirective) {
return;
}
var isForwardConnection = hasFirstArgument(fieldNode) && hasAfterArgument(fieldNode);
var isBackwardConnection = hasLastArgument(fieldNode) && hasBeforeArgument(fieldNode);
var selectionName = fieldNode.alias || fieldNode.name;
var paginationFields = connectionSelectionSetPaginationInfo(function (name) { return context.getFragment(name); }, fieldNode.selectionSet);
var connectionName = connectionDirective.key || selectionName;
if (isForwardConnection) {
if (!paginationFields.hasNextPage) {
context.reportError(new graphql_1.GraphQLError("Missing pageInfo.hasNextPage field on connection \"" + connectionName + "\".", connectionDirective.directive));
}
if (!paginationFields.endCursor) {
context.reportError(new graphql_1.GraphQLError("Missing pageInfo.endCursor field on connection \"" + connectionName + "\".", connectionDirective.directive));
}
}
if (isBackwardConnection) {
if (!paginationFields.hasPreviousPage) {
context.reportError(new graphql_1.GraphQLError("Missing pageInfo.hasPreviousPage field on connection \"" + connectionName + "\".", connectionDirective.directive));
}
if (!paginationFields.startCursor) {
context.reportError(new graphql_1.GraphQLError("Missing pageInfo.startCursor field on connection \"" + connectionName + "\".", connectionDirective.directive));
}
}
}
}
};
};