UNPKG

@graphql-eslint/eslint-plugin

Version:
142 lines (139 loc) 4.6 kB
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }var _graphql = require('graphql'); var _graphqldepthlimit = require('graphql-depth-limit'); var _graphqldepthlimit2 = _interopRequireDefault(_graphqldepthlimit); var _utilsjs = 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: _utilsjs.ARRAY_DEFAULT_OPTIONS } } }; const 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 = _utilsjs.requireGraphQLOperations.call(void 0, RULE_ID, context); } catch (e2) { _utilsjs.logger.warn( `Rule "${RULE_ID}" works best with siblings operations loaded. See https://the-guild.dev/graphql/eslint/docs/usage#providing-operations for more info` ); } const { maxDepth, ignore = [] } = context.options[0]; const checkFn = _graphqldepthlimit2.default.call(void 0, maxDepth, { ignore }); return { "OperationDefinition, FragmentDefinition"(node) { try { const rawNode = node.rawNode(); const fragmentsInUse = siblings ? siblings.getFragmentsInUse(rawNode) : []; const document = { kind: _graphql.Kind.DOCUMENT, definitions: [rawNode, ...fragmentsInUse] }; checkFn({ getDocument: () => document, reportError(error) { const { line, column } = error.locations[0]; const ancestors = context.sourceCode.getAncestors(node); const token = ancestors[0].tokens.find( (token2) => token2.loc.start.line === line && token2.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) { _utilsjs.logger.warn( `Rule "${RULE_ID}" check failed due to a missing siblings operations. See https://the-guild.dev/graphql/eslint/docs/usage#providing-operations for more info`, e ); } } }; } }; exports.rule = rule;