UNPKG

eslint-plugin-stylistic-compat

Version:

Compatibility version of @stylistic/eslint-plugin for Node.js >= 12 and ESLint v8

616 lines (611 loc) 25.9 kB
'use strict'; var _mapInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/map'); var _filterInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/filter'); var _trimInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/trim'); var _forEachInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/for-each'); var _Set = require('@babel/runtime-corejs3/core-js/set'); var _concatInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/concat'); var _Reflect$get = require('@babel/runtime-corejs3/core-js/reflect/get'); var utils = require('../utils.js'); var vendor = require('../vendor.js'); var _Object$assign = require('@babel/runtime-corejs3/core-js/object/assign'); require('@babel/runtime-corejs3/core-js/object/from-entries'); require('@babel/runtime-corejs3/core-js/object/entries'); require('@babel/runtime-corejs3/core-js/instance/flags'); require('@babel/runtime-corejs3/core-js/instance/includes'); require('@babel/runtime-corejs3/core-js/instance/starts-with'); require('@babel/runtime-corejs3/core-js/array/from'); require('@babel/runtime-corejs3/core-js/array/is-array'); require('@babel/runtime-corejs3/core-js/object/keys'); require('@babel/runtime-corejs3/core-js/instance/reduce'); require('@babel/runtime-corejs3/core-js/instance/keys'); require('@babel/runtime-corejs3/core-js/instance/find'); require('@babel/runtime-corejs3/core-js/instance/reverse'); require('@babel/runtime-corejs3/core-js/object/define-property'); require('@babel/runtime-corejs3/core-js/instance/slice'); require('@babel/runtime-corejs3/core-js/object/create'); require('@babel/runtime-corejs3/core-js/object/freeze'); require('@babel/runtime-corejs3/core-js/instance/last-index-of'); require('@babel/runtime-corejs3/core-js/object/define-properties'); require('@babel/runtime-corejs3/core-js/instance/index-of'); require('@babel/runtime-corejs3/core-js/instance/at'); require('@babel/runtime-corejs3/core-js/symbol'); require('@babel/runtime-corejs3/core-js/symbol/iterator'); require('@babel/runtime-corejs3/core-js/parse-int'); require('@babel/runtime-corejs3/core-js/parse-float'); require('@babel/runtime-corejs3/core-js/weak-map'); require('@babel/runtime-corejs3/core-js/global-this'); require('eslint/use-at-your-own-risk'); require('eslint'); require('@babel/runtime-corejs3/core-js/object/get-own-property-descriptor'); require('@babel/runtime-corejs3/core-js/map'); require('@babel/runtime-corejs3/core-js/instance/some'); require('@babel/runtime-corejs3/core-js/instance/every'); require('@babel/runtime-corejs3/core-js/instance/sort'); require('@babel/runtime-corejs3/core-js/array/of'); require('@babel/runtime-corejs3/core-js/instance/entries'); require('@babel/runtime-corejs3/core-js/instance/find-index'); require('@babel/runtime-corejs3/core-js/instance/flat'); require('@babel/runtime-corejs3/core-js/instance/values'); require('@babel/runtime-corejs3/core-js/object/get-own-property-names'); require('@babel/runtime-corejs3/core-js/number/is-finite'); require('@babel/runtime-corejs3/core-js/number/is-nan'); require('@babel/runtime-corejs3/core-js/number/parse-float'); require('@babel/runtime-corejs3/core-js/number/parse-int'); require('@babel/runtime-corejs3/core-js/object/is'); require('@babel/runtime-corejs3/core-js/object/is-extensible'); require('@babel/runtime-corejs3/core-js/object/is-frozen'); require('@babel/runtime-corejs3/core-js/object/is-sealed'); require('@babel/runtime-corejs3/core-js/object/values'); require('@babel/runtime-corejs3/core-js/string/from-code-point'); require('@babel/runtime-corejs3/core-js/string/raw'); require('@babel/runtime-corejs3/core-js/instance/code-point-at'); require('@babel/runtime-corejs3/core-js/instance/ends-with'); require('@babel/runtime-corejs3/core-js/instance/pad-end'); require('@babel/runtime-corejs3/core-js/instance/pad-start'); require('@babel/runtime-corejs3/core-js/instance/trim-end'); require('@babel/runtime-corejs3/core-js/instance/trim-left'); require('@babel/runtime-corejs3/core-js/instance/trim-right'); require('@babel/runtime-corejs3/core-js/instance/trim-start'); require('@babel/runtime-corejs3/core-js/symbol/for'); require('@babel/runtime-corejs3/core-js/symbol/key-for'); require('@babel/runtime-corejs3/core-js/object/prevent-extensions'); require('@babel/runtime-corejs3/core-js/object/seal'); require('@babel/runtime-corejs3/core-js/object/get-prototype-of'); require('@babel/runtime-corejs3/core-js/symbol/replace'); require('@babel/runtime-corejs3/core-js/instance/bind'); require('@babel/runtime-corejs3/core-js/instance/splice'); require('@babel/runtime-corejs3/core-js/instance/repeat'); function getEmptyLineNums$1(lines) { var _context, _context2; const emptyLines = _mapInstanceProperty(_context = _filterInstanceProperty(_context2 = _mapInstanceProperty(lines).call(lines, (line, i) => ({ code: _trimInstanceProperty(line).call(line), num: i + 1 }))).call(_context2, line => !line.code)).call(_context, line => line.num); return emptyLines; } function getCommentLineNums$1(comments) { const lines = []; _forEachInstanceProperty(comments).call(comments, token => { const start = token.loc.start.line; const end = token.loc.end.line; lines.push(start, end); }); return lines; } var _baseRule = utils.createRule({ name: "lines-around-comment", package: "js", meta: { type: "layout", docs: { description: "Require empty lines around comments" }, fixable: "whitespace", schema: [{ type: "object", properties: { beforeBlockComment: { type: "boolean", default: true }, afterBlockComment: { type: "boolean", default: false }, beforeLineComment: { type: "boolean", default: false }, afterLineComment: { type: "boolean", default: false }, allowBlockStart: { type: "boolean", default: false }, allowBlockEnd: { type: "boolean", default: false }, allowClassStart: { type: "boolean" }, allowClassEnd: { type: "boolean" }, allowObjectStart: { type: "boolean" }, allowObjectEnd: { type: "boolean" }, allowArrayStart: { type: "boolean" }, allowArrayEnd: { type: "boolean" }, ignorePattern: { type: "string" }, applyDefaultIgnorePatterns: { type: "boolean" }, afterHashbangComment: { type: "boolean", default: false } }, additionalProperties: false }], messages: { after: "Expected line after comment.", before: "Expected line before comment." } }, create(context) { const options = _Object$assign({}, context.options[0]); const ignorePattern = options.ignorePattern; const defaultIgnoreRegExp = utils.COMMENTS_IGNORE_PATTERN; const customIgnoreRegExp = ignorePattern && new RegExp(ignorePattern, "u"); const applyDefaultIgnorePatterns = options.applyDefaultIgnorePatterns !== false; options.beforeBlockComment = typeof options.beforeBlockComment !== "undefined" ? options.beforeBlockComment : true; const sourceCode = context.sourceCode; const lines = sourceCode.lines; const numLines = lines.length + 1; const comments = sourceCode.getAllComments(); const commentLines = getCommentLineNums$1(comments); const emptyLines = getEmptyLineNums$1(lines); const commentAndEmptyLines = new _Set(_concatInstanceProperty(commentLines).call(commentLines, emptyLines)); function codeAroundComment(token) { let currentToken = token; do currentToken = sourceCode.getTokenBefore(currentToken, { includeComments: true }); while (currentToken && utils.isCommentToken(currentToken)); if (currentToken && utils.isTokenOnSameLine(currentToken, token)) return true; currentToken = token; do currentToken = sourceCode.getTokenAfter(currentToken, { includeComments: true }); while (currentToken && utils.isCommentToken(currentToken)); if (currentToken && utils.isTokenOnSameLine(token, currentToken)) return true; return false; } function isParentNodeType(parent, nodeType) { return parent.type === nodeType; } function getParentNodeOfToken(token) { const node = sourceCode.getNodeByRangeIndex(token.range[0]); if (node && node.type === "StaticBlock") { const openingBrace = sourceCode.getFirstToken(node, { skip: 1 }); return openingBrace && token.range[0] >= openingBrace.range[0] ? node : null; } return node; } function isCommentAtParentStart(token, nodeType) { const parent = getParentNodeOfToken(token); if (parent && isParentNodeType(parent, nodeType)) { let parentStartNodeOrToken = parent; if (parent.type === "StaticBlock") { parentStartNodeOrToken = sourceCode.getFirstToken(parent, { skip: 1 }); } else if (parent.type === "SwitchStatement") { parentStartNodeOrToken = sourceCode.getTokenAfter(parent.discriminant, { filter: utils.isOpeningBraceToken }); } return !!parentStartNodeOrToken && token.loc.start.line - parentStartNodeOrToken.loc.start.line === 1; } return false; } function isCommentAtParentEnd(token, nodeType) { const parent = getParentNodeOfToken(token); return !!parent && isParentNodeType(parent, nodeType) && parent.loc.end.line - token.loc.end.line === 1; } function isCommentAtBlockStart(token) { return isCommentAtParentStart(token, "ClassBody") || isCommentAtParentStart(token, "BlockStatement") || isCommentAtParentStart(token, "StaticBlock") || isCommentAtParentStart(token, "SwitchCase") || isCommentAtParentStart(token, "SwitchStatement"); } function isCommentAtBlockEnd(token) { return isCommentAtParentEnd(token, "ClassBody") || isCommentAtParentEnd(token, "BlockStatement") || isCommentAtParentEnd(token, "StaticBlock") || isCommentAtParentEnd(token, "SwitchCase") || isCommentAtParentEnd(token, "SwitchStatement"); } function isCommentAtClassStart(token) { return isCommentAtParentStart(token, "ClassBody"); } function isCommentAtClassEnd(token) { return isCommentAtParentEnd(token, "ClassBody"); } function isCommentAtObjectStart(token) { return isCommentAtParentStart(token, "ObjectExpression") || isCommentAtParentStart(token, "ObjectPattern"); } function isCommentAtObjectEnd(token) { return isCommentAtParentEnd(token, "ObjectExpression") || isCommentAtParentEnd(token, "ObjectPattern"); } function isCommentAtArrayStart(token) { return isCommentAtParentStart(token, "ArrayExpression") || isCommentAtParentStart(token, "ArrayPattern"); } function isCommentAtArrayEnd(token) { return isCommentAtParentEnd(token, "ArrayExpression") || isCommentAtParentEnd(token, "ArrayPattern"); } function checkForEmptyLine(token, opts) { if (applyDefaultIgnorePatterns && defaultIgnoreRegExp.test(token.value)) return; if (customIgnoreRegExp && customIgnoreRegExp.test(token.value)) return; let after = opts.after; let before = opts.before; const prevLineNum = token.loc.start.line - 1; const nextLineNum = token.loc.end.line + 1; const commentIsNotAlone = codeAroundComment(token); const blockStartAllowed = options.allowBlockStart && isCommentAtBlockStart(token) && !(options.allowClassStart === false && isCommentAtClassStart(token)); const blockEndAllowed = options.allowBlockEnd && isCommentAtBlockEnd(token) && !(options.allowClassEnd === false && isCommentAtClassEnd(token)); const classStartAllowed = options.allowClassStart && isCommentAtClassStart(token); const classEndAllowed = options.allowClassEnd && isCommentAtClassEnd(token); const objectStartAllowed = options.allowObjectStart && isCommentAtObjectStart(token); const objectEndAllowed = options.allowObjectEnd && isCommentAtObjectEnd(token); const arrayStartAllowed = options.allowArrayStart && isCommentAtArrayStart(token); const arrayEndAllowed = options.allowArrayEnd && isCommentAtArrayEnd(token); const exceptionStartAllowed = blockStartAllowed || classStartAllowed || objectStartAllowed || arrayStartAllowed; const exceptionEndAllowed = blockEndAllowed || classEndAllowed || objectEndAllowed || arrayEndAllowed; if (prevLineNum < 1) before = false; if (nextLineNum >= numLines) after = false; if (commentIsNotAlone) return; const previousTokenOrComment = sourceCode.getTokenBefore(token, { includeComments: true }); const nextTokenOrComment = sourceCode.getTokenAfter(token, { includeComments: true }); if (!exceptionStartAllowed && before && !commentAndEmptyLines.has(prevLineNum) && !(utils.isCommentToken(previousTokenOrComment) && utils.isTokenOnSameLine(previousTokenOrComment, token))) { const lineStart = token.range[0] - token.loc.start.column; const range = [lineStart, lineStart]; context.report({ node: token, messageId: "before", fix(fixer) { return fixer.insertTextBeforeRange(range, "\n"); } }); } if (!exceptionEndAllowed && after && !commentAndEmptyLines.has(nextLineNum) && !(utils.isCommentToken(nextTokenOrComment) && utils.isTokenOnSameLine(token, nextTokenOrComment))) { context.report({ node: token, messageId: "after", fix(fixer) { return fixer.insertTextAfter(token, "\n"); } }); } } return { Program() { _forEachInstanceProperty(comments).call(comments, token => { if (token.type === "Line") { if (options.beforeLineComment || options.afterLineComment) { checkForEmptyLine(token, { after: options.afterLineComment, before: options.beforeLineComment }); } } else if (token.type === "Block") { if (options.beforeBlockComment || options.afterBlockComment) { checkForEmptyLine(token, { after: options.afterBlockComment, before: options.beforeBlockComment }); } } else if (token.type === "Shebang") { if (options.afterHashbangComment) { checkForEmptyLine(token, { after: options.afterHashbangComment, before: false }); } } }); } }; } }); const baseRule = /* @__PURE__ */utils.castRuleModule(_baseRule); const COMMENTS_IGNORE_PATTERN = /^\s*(?:eslint|jshint\s+|jslint\s+|istanbul\s+|globals?\s+|exported\s+|jscs)/u; function getEmptyLineNums(lines) { var _context, _context2; const emptyLines = _mapInstanceProperty(_context = _filterInstanceProperty(_context2 = _mapInstanceProperty(lines).call(lines, (line, i) => ({ code: _trimInstanceProperty(line).call(line), num: i + 1 }))).call(_context2, line => !line.code)).call(_context, line => line.num); return emptyLines; } function getCommentLineNums(comments) { const lines = []; _forEachInstanceProperty(comments).call(comments, token => { const start = token.loc.start.line; const end = token.loc.end.line; lines.push(start, end); }); return lines; } var linesAroundComment = utils.createRule({ name: "lines-around-comment", package: "ts", meta: { type: "layout", docs: { description: "Require empty lines around comments" }, schema: [{ type: "object", properties: { beforeBlockComment: { type: "boolean", default: true }, afterBlockComment: { type: "boolean", default: false }, beforeLineComment: { type: "boolean", default: false }, afterLineComment: { type: "boolean", default: false }, allowBlockStart: { type: "boolean", default: false }, allowBlockEnd: { type: "boolean", default: false }, allowClassStart: { type: "boolean" }, allowClassEnd: { type: "boolean" }, allowObjectStart: { type: "boolean" }, allowObjectEnd: { type: "boolean" }, allowArrayStart: { type: "boolean" }, allowArrayEnd: { type: "boolean" }, allowInterfaceStart: { type: "boolean" }, allowInterfaceEnd: { type: "boolean" }, allowTypeStart: { type: "boolean" }, allowTypeEnd: { type: "boolean" }, allowEnumStart: { type: "boolean" }, allowEnumEnd: { type: "boolean" }, allowModuleStart: { type: "boolean" }, allowModuleEnd: { type: "boolean" }, ignorePattern: { type: "string" }, applyDefaultIgnorePatterns: { type: "boolean" }, afterHashbangComment: { type: "boolean" } }, additionalProperties: false }], fixable: baseRule.meta.fixable, hasSuggestions: baseRule.meta.hasSuggestions, messages: baseRule.meta.messages }, defaultOptions: [{ beforeBlockComment: true }], create(context, [_options]) { var _options$ignorePatter; const options = _options; const defaultIgnoreRegExp = COMMENTS_IGNORE_PATTERN; const customIgnoreRegExp = new RegExp((_options$ignorePatter = options.ignorePattern) != null ? _options$ignorePatter : "", "u"); const sourceCode = context.sourceCode; const comments = sourceCode.getAllComments(); const lines = sourceCode.lines; const commentLines = getCommentLineNums(comments); const emptyLines = getEmptyLineNums(lines); const commentAndEmptyLines = new _Set(_concatInstanceProperty(commentLines).call(commentLines, emptyLines)); function codeAroundComment(token) { let currentToken = token; do { currentToken = sourceCode.getTokenBefore(currentToken, { includeComments: true }); } while (currentToken && vendor.astUtilsExports.isCommentToken(currentToken)); if (currentToken && vendor.astUtilsExports.isTokenOnSameLine(currentToken, token)) return true; currentToken = token; do { currentToken = sourceCode.getTokenAfter(currentToken, { includeComments: true }); } while (currentToken && vendor.astUtilsExports.isCommentToken(currentToken)); if (currentToken && vendor.astUtilsExports.isTokenOnSameLine(token, currentToken)) return true; return false; } function isParentNodeType(parent, nodeType) { return parent.type === nodeType; } function getParentNodeOfToken(token) { const node = sourceCode.getNodeByRangeIndex(token.range[0]); return node; } function isCommentAtParentStart(token, nodeType) { const parent = getParentNodeOfToken(token); if (parent && isParentNodeType(parent, nodeType)) { const parentStartNodeOrToken = parent; return token.loc.start.line - parentStartNodeOrToken.loc.start.line === 1; } return false; } function isCommentAtParentEnd(token, nodeType) { const parent = getParentNodeOfToken(token); return !!parent && isParentNodeType(parent, nodeType) && parent.loc.end.line - token.loc.end.line === 1; } function isCommentAtInterfaceStart(token) { return isCommentAtParentStart(token, vendor.distExports.AST_NODE_TYPES.TSInterfaceBody); } function isCommentAtInterfaceEnd(token) { return isCommentAtParentEnd(token, vendor.distExports.AST_NODE_TYPES.TSInterfaceBody); } function isCommentAtTypeStart(token) { return isCommentAtParentStart(token, vendor.distExports.AST_NODE_TYPES.TSTypeLiteral); } function isCommentAtTypeEnd(token) { return isCommentAtParentEnd(token, vendor.distExports.AST_NODE_TYPES.TSTypeLiteral); } function isCommentAtEnumStart(token) { return isCommentAtParentStart(token, vendor.distExports.AST_NODE_TYPES.TSEnumBody) || isCommentAtParentStart(token, vendor.distExports.AST_NODE_TYPES.TSEnumDeclaration); } function isCommentAtEnumEnd(token) { return isCommentAtParentEnd(token, vendor.distExports.AST_NODE_TYPES.TSEnumBody) || isCommentAtParentEnd(token, vendor.distExports.AST_NODE_TYPES.TSEnumDeclaration); } function isCommentAtModuleStart(token) { return isCommentAtParentStart(token, vendor.distExports.AST_NODE_TYPES.TSModuleBlock); } function isCommentAtModuleEnd(token) { return isCommentAtParentEnd(token, vendor.distExports.AST_NODE_TYPES.TSModuleBlock); } function isCommentNearTSConstruct(token) { return isCommentAtInterfaceStart(token) || isCommentAtInterfaceEnd(token) || isCommentAtTypeStart(token) || isCommentAtTypeEnd(token) || isCommentAtEnumStart(token) || isCommentAtEnumEnd(token) || isCommentAtModuleStart(token) || isCommentAtModuleEnd(token); } function checkForEmptyLine(token, { before, after }) { if (!isCommentNearTSConstruct(token)) return; if (options.applyDefaultIgnorePatterns !== false && defaultIgnoreRegExp.test(token.value)) { return; } if (options.ignorePattern && customIgnoreRegExp.test(token.value)) return; const prevLineNum = token.loc.start.line - 1; const nextLineNum = token.loc.end.line + 1; if (codeAroundComment(token)) return; const interfaceStartAllowed = Boolean(options.allowInterfaceStart) && isCommentAtInterfaceStart(token); const interfaceEndAllowed = Boolean(options.allowInterfaceEnd) && isCommentAtInterfaceEnd(token); const typeStartAllowed = Boolean(options.allowTypeStart) && isCommentAtTypeStart(token); const typeEndAllowed = Boolean(options.allowTypeEnd) && isCommentAtTypeEnd(token); const enumStartAllowed = Boolean(options.allowEnumStart) && isCommentAtEnumStart(token); const enumEndAllowed = Boolean(options.allowEnumEnd) && isCommentAtEnumEnd(token); const moduleStartAllowed = Boolean(options.allowModuleStart) && isCommentAtModuleStart(token); const moduleEndAllowed = Boolean(options.allowModuleEnd) && isCommentAtModuleEnd(token); const exceptionStartAllowed = interfaceStartAllowed || typeStartAllowed || enumStartAllowed || moduleStartAllowed; const exceptionEndAllowed = interfaceEndAllowed || typeEndAllowed || enumEndAllowed || moduleEndAllowed; const previousTokenOrComment = sourceCode.getTokenBefore(token, { includeComments: true }); const nextTokenOrComment = sourceCode.getTokenAfter(token, { includeComments: true }); if (!exceptionStartAllowed && before && !commentAndEmptyLines.has(prevLineNum) && !(vendor.astUtilsExports.isCommentToken(previousTokenOrComment) && vendor.astUtilsExports.isTokenOnSameLine(previousTokenOrComment, token))) { const lineStart = token.range[0] - token.loc.start.column; const range = [lineStart, lineStart]; context.report({ node: token, messageId: "before", fix(fixer) { return fixer.insertTextBeforeRange(range, "\n"); } }); } if (!exceptionEndAllowed && after && !commentAndEmptyLines.has(nextLineNum) && !(vendor.astUtilsExports.isCommentToken(nextTokenOrComment) && vendor.astUtilsExports.isTokenOnSameLine(token, nextTokenOrComment))) { context.report({ node: token, messageId: "after", fix(fixer) { return fixer.insertTextAfter(token, "\n"); } }); } } const customReport = descriptor => { if ("node" in descriptor) { if (descriptor.node.type === vendor.distExports.AST_TOKEN_TYPES.Line || descriptor.node.type === vendor.distExports.AST_TOKEN_TYPES.Block) { if (isCommentNearTSConstruct(descriptor.node)) return; } } return context.report(descriptor); }; const customContext = { report: customReport }; const proxiedContext = new Proxy(customContext, { get(target, path, receiver) { if (path !== "report") return _Reflect$get(context, path, receiver); return _Reflect$get(target, path, receiver); } }); const rules = baseRule.create(proxiedContext); return { Program(node) { rules.Program(node); _forEachInstanceProperty(comments).call(comments, token => { if (token.type === vendor.distExports.AST_TOKEN_TYPES.Line) { if (options.beforeLineComment || options.afterLineComment) { checkForEmptyLine(token, { after: options.afterLineComment, before: options.beforeLineComment }); } } else if (token.type === vendor.distExports.AST_TOKEN_TYPES.Block) { if (options.beforeBlockComment || options.afterBlockComment) { checkForEmptyLine(token, { after: options.afterBlockComment, before: options.beforeBlockComment }); } } }); } }; } }); module.exports = linesAroundComment;