@graphql-eslint/eslint-plugin
Version:
GraphQL plugin for ESLint
136 lines (135 loc) • 5.25 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.rule = void 0;
const tslib_1 = require("tslib");
const graphql_1 = require("graphql");
const graphql_depth_limit_1 = tslib_1.__importDefault(require("graphql-depth-limit"));
const utils_js_1 = require("../utils.js");
const RULE_ID = 'selection-set-depth';
const schema = {
type: 'array',
minItems: 1,
maxItems: 1,
items: {
type: 'object',
additionalProperties: false,
required: ['maxDepth'],
properties: {
maxDepth: {
type: 'number',
},
ignore: utils_js_1.ARRAY_DEFAULT_OPTIONS,
},
},
};
exports.rule = {
meta: {
type: 'suggestion',
hasSuggestions: true,
docs: {
category: 'Operations',
description: 'Limit the complexity of the GraphQL operations solely by their depth. Based on [graphql-depth-limit](https://npmjs.com/package/graphql-depth-limit).',
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID}`,
requiresSiblings: true,
examples: [
{
title: 'Incorrect',
usage: [{ maxDepth: 1 }],
code: `
query deep2 {
viewer { # Level 0
albums { # Level 1
title # Level 2
}
}
}
`,
},
{
title: 'Correct',
usage: [{ maxDepth: 4 }],
code: `
query deep2 {
viewer { # Level 0
albums { # Level 1
title # Level 2
}
}
}
`,
},
{
title: 'Correct (ignored field)',
usage: [{ maxDepth: 1, ignore: ['albums'] }],
code: `
query deep2 {
viewer { # Level 0
albums { # Level 1
title # Level 2
}
}
}
`,
},
],
recommended: true,
configOptions: [{ maxDepth: 7 }],
},
schema,
},
create(context) {
let siblings = null;
try {
siblings = (0, utils_js_1.requireSiblingsOperations)(RULE_ID, context);
}
catch (_a) {
utils_js_1.logger.warn(`Rule "${RULE_ID}" works best with siblings operations loaded. For more info: https://bit.ly/graphql-eslint-operations`);
}
const { maxDepth, ignore = [] } = context.options[0];
const checkFn = (0, graphql_depth_limit_1.default)(maxDepth, { ignore });
return {
'OperationDefinition, FragmentDefinition'(node) {
try {
const rawNode = node.rawNode();
const fragmentsInUse = siblings ? siblings.getFragmentsInUse(rawNode) : [];
const document = {
kind: graphql_1.Kind.DOCUMENT,
definitions: [rawNode, ...fragmentsInUse],
};
checkFn({
getDocument: () => document,
reportError(error) {
const { line, column } = error.locations[0];
const ancestors = context.getAncestors();
const token = ancestors[0].tokens.find(token => token.loc.start.line === line && token.loc.start.column === column - 1);
context.report({
loc: {
line,
column: column - 1,
},
message: error.message,
// Don't provide suggestions for fragment that can be in a separate file
...(token && {
suggest: [
{
desc: 'Remove selections',
fix(fixer) {
const sourceCode = context.getSourceCode();
const foundNode = sourceCode.getNodeByRangeIndex(token.range[0]);
const parentNode = foundNode.parent.parent;
return fixer.remove(foundNode.kind === 'Name' ? parentNode.parent : parentNode);
},
},
],
}),
});
},
});
}
catch (e) {
utils_js_1.logger.warn(`Rule "${RULE_ID}" check failed due to a missing siblings operations. For more info: https://bit.ly/graphql-eslint-operations`, e);
}
},
};
},
};