UNPKG

eslint-plugin-stylistic-compat

Version:

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

480 lines (476 loc) 22.2 kB
'use strict'; var _Array$from = require('@babel/runtime-corejs3/core-js/array/from'); var _Set = require('@babel/runtime-corejs3/core-js/set'); var _String$raw = require('@babel/runtime-corejs3/core-js/string/raw'); var _Array$isArray = require('@babel/runtime-corejs3/core-js/array/is-array'); var _includesInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/includes'); var _sliceInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/slice'); var _Object$keys = require('@babel/runtime-corejs3/core-js/object/keys'); var _someInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/some'); var _bindInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/bind'); var utils = require('../utils.js'); var vendor = require('../vendor.js'); require('@babel/runtime-corejs3/core-js/object/from-entries'); require('@babel/runtime-corejs3/core-js/instance/map'); require('@babel/runtime-corejs3/core-js/instance/filter'); require('@babel/runtime-corejs3/core-js/object/entries'); require('@babel/runtime-corejs3/core-js/instance/flags'); require('@babel/runtime-corejs3/core-js/instance/starts-with'); require('@babel/runtime-corejs3/core-js/instance/concat'); require('@babel/runtime-corejs3/core-js/instance/reduce'); require('@babel/runtime-corejs3/core-js/object/assign'); 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/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('@babel/runtime-corejs3/core-js/instance/for-each'); 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/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/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'); 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/splice'); require('@babel/runtime-corejs3/core-js/instance/repeat'); const CJS_EXPORT = /^(?:module\s*\.\s*)?exports(?:\s*\.|\s*\[|$)/u; const CJS_IMPORT = /^require\(/u; const LT = `[${_Array$from(/* @__PURE__ */new _Set(["\r\n", "\r", "\n", "\u2028", "\u2029"])).join("")}]`; const PADDING_LINE_SEQUENCE = new RegExp(_String$raw`^(\s*?${LT})\s*${LT}(\s*;?)$`, "u"); function newKeywordTester(type, keyword) { return { test(node, sourceCode) { var _sourceCode$getFirstT; const isSameKeyword = ((_sourceCode$getFirstT = sourceCode.getFirstToken(node)) == null ? undefined : _sourceCode$getFirstT.value) === keyword; const isSameType = _Array$isArray(type) ? _includesInstanceProperty(type).call(type, node.type) : type === node.type; return isSameKeyword && isSameType; } }; } function newSinglelineKeywordTester(keyword) { return { test(node, sourceCode) { return node.loc.start.line === node.loc.end.line && sourceCode.getFirstToken(node).value === keyword; } }; } function newMultilineKeywordTester(keyword) { return { test(node, sourceCode) { return node.loc.start.line !== node.loc.end.line && sourceCode.getFirstToken(node).value === keyword; } }; } function newNodeTypeTester(type) { return { test: node => node.type === type }; } function skipChainExpression(node) { return node && node.type === vendor.distExports.AST_NODE_TYPES.ChainExpression ? node.expression : node; } function isIIFEStatement(node) { if (node.type === vendor.distExports.AST_NODE_TYPES.ExpressionStatement) { let expression = skipChainExpression(node.expression); if (expression.type === vendor.distExports.AST_NODE_TYPES.UnaryExpression) expression = skipChainExpression(expression.argument); if (expression.type === vendor.distExports.AST_NODE_TYPES.CallExpression) { let node2 = expression.callee; while (node2.type === vendor.distExports.AST_NODE_TYPES.SequenceExpression) node2 = node2.expressions[node2.expressions.length - 1]; return vendor.astUtilsExports.isFunction(node2); } } return false; } function isCJSRequire(node) { if (node.type === vendor.distExports.AST_NODE_TYPES.VariableDeclaration) { const declaration = node.declarations[0]; if (declaration != null && declaration.init) { let call = declaration == null ? undefined : declaration.init; while (call.type === vendor.distExports.AST_NODE_TYPES.MemberExpression) call = call.object; if (call.type === vendor.distExports.AST_NODE_TYPES.CallExpression && call.callee.type === vendor.distExports.AST_NODE_TYPES.Identifier) { return call.callee.name === "require"; } } } return false; } function isBlockLikeStatement(node, sourceCode) { if (node.type === vendor.distExports.AST_NODE_TYPES.DoWhileStatement && node.body.type === vendor.distExports.AST_NODE_TYPES.BlockStatement) { return true; } if (isIIFEStatement(node)) return true; const lastToken = sourceCode.getLastToken(node, vendor.astUtilsExports.isNotSemicolonToken); const belongingNode = lastToken && vendor.astUtilsExports.isClosingBraceToken(lastToken) ? sourceCode.getNodeByRangeIndex(lastToken.range[0]) : null; return !!belongingNode && (belongingNode.type === vendor.distExports.AST_NODE_TYPES.BlockStatement || belongingNode.type === vendor.distExports.AST_NODE_TYPES.SwitchStatement); } function isDirective(node, sourceCode) { var _node$parent, _node$parent2; return node.type === vendor.distExports.AST_NODE_TYPES.ExpressionStatement && (((_node$parent = node.parent) == null ? undefined : _node$parent.type) === vendor.distExports.AST_NODE_TYPES.Program || ((_node$parent2 = node.parent) == null ? undefined : _node$parent2.type) === vendor.distExports.AST_NODE_TYPES.BlockStatement && vendor.astUtilsExports.isFunction(node.parent.parent)) && node.expression.type === vendor.distExports.AST_NODE_TYPES.Literal && typeof node.expression.value === "string" && !vendor.astUtilsExports.isParenthesized(node.expression, sourceCode); } function isDirectivePrologue(node, sourceCode) { if (isDirective(node, sourceCode) && node.parent && "body" in node.parent && _Array$isArray(node.parent.body)) { for (const sibling of node.parent.body) { if (sibling === node) break; if (!isDirective(sibling, sourceCode)) return false; } return true; } return false; } function isCJSExport(node) { if (node.type === vendor.distExports.AST_NODE_TYPES.ExpressionStatement) { const expression = node.expression; if (expression.type === vendor.distExports.AST_NODE_TYPES.AssignmentExpression) { let left = expression.left; if (left.type === vendor.distExports.AST_NODE_TYPES.MemberExpression) { while (left.object.type === vendor.distExports.AST_NODE_TYPES.MemberExpression) left = left.object; return left.object.type === vendor.distExports.AST_NODE_TYPES.Identifier && (left.object.name === "exports" || left.object.name === "module" && left.property.type === vendor.distExports.AST_NODE_TYPES.Identifier && left.property.name === "exports"); } } } return false; } function isExpression(node, sourceCode) { return node.type === vendor.distExports.AST_NODE_TYPES.ExpressionStatement && !isDirectivePrologue(node, sourceCode); } function getActualLastToken(node, sourceCode) { const semiToken = sourceCode.getLastToken(node); const prevToken = sourceCode.getTokenBefore(semiToken); const nextToken = sourceCode.getTokenAfter(semiToken); const isSemicolonLessStyle = prevToken && nextToken && prevToken.range[0] >= node.range[0] && vendor.astUtilsExports.isSemicolonToken(semiToken) && semiToken.loc.start.line !== prevToken.loc.end.line && semiToken.loc.end.line === nextToken.loc.start.line; return isSemicolonLessStyle ? prevToken : semiToken; } function replacerToRemovePaddingLines(_, trailingSpaces, indentSpaces) { return trailingSpaces + indentSpaces; } function verifyForAny() {} function verifyForNever(context, _, nextNode, paddingLines) { if (paddingLines.length === 0) return; context.report({ node: nextNode, messageId: "unexpectedBlankLine", fix(fixer) { var _context; if (paddingLines.length >= 2) return null; const prevToken = paddingLines[0][0]; const nextToken = paddingLines[0][1]; const start = prevToken.range[1]; const end = nextToken.range[0]; const text = _sliceInstanceProperty(_context = context.getSourceCode().text).call(_context, start, end).replace(PADDING_LINE_SEQUENCE, replacerToRemovePaddingLines); return fixer.replaceTextRange([start, end], text); } }); } function verifyForAlways(context, prevNode, nextNode, paddingLines) { if (paddingLines.length > 0) return; context.report({ node: nextNode, messageId: "expectedBlankLine", fix(fixer) { const sourceCode = context.sourceCode; let prevToken = getActualLastToken(prevNode, sourceCode); const nextToken = sourceCode.getFirstTokenBetween(prevToken, nextNode, { includeComments: true, /** * Skip the trailing comments of the previous node. * This inserts a blank line after the last trailing comment. * * For example: * * foo(); // trailing comment. * // comment. * bar(); * * Get fixed to: * * foo(); // trailing comment. * * // comment. * bar(); * @param token The token to check. * @returns `true` if the token is not a trailing comment. * @private */ filter(token) { if (vendor.astUtilsExports.isTokenOnSameLine(prevToken, token)) { prevToken = token; return false; } return true; } }) || nextNode; const insertText = vendor.astUtilsExports.isTokenOnSameLine(prevToken, nextToken) ? "\n\n" : "\n"; return fixer.insertTextAfter(prevToken, insertText); } }); } const PaddingTypes = { any: { verify: verifyForAny }, never: { verify: verifyForNever }, always: { verify: verifyForAlways } }; const StatementTypes = { "*": { test: () => true }, "block-like": { test: isBlockLikeStatement }, "exports": { test: isCJSExport }, "require": { test: isCJSRequire }, "directive": { test: isDirectivePrologue }, "expression": { test: isExpression }, "iife": { test: isIIFEStatement }, "multiline-block-like": { test: (node, sourceCode) => node.loc.start.line !== node.loc.end.line && isBlockLikeStatement(node, sourceCode) }, "multiline-expression": { test: (node, sourceCode) => node.loc.start.line !== node.loc.end.line && node.type === vendor.distExports.AST_NODE_TYPES.ExpressionStatement && !isDirectivePrologue(node, sourceCode) }, "multiline-const": newMultilineKeywordTester("const"), "multiline-export": newMultilineKeywordTester("export"), "multiline-let": newMultilineKeywordTester("let"), "multiline-var": newMultilineKeywordTester("var"), "singleline-const": newSinglelineKeywordTester("const"), "singleline-export": newSinglelineKeywordTester("export"), "singleline-let": newSinglelineKeywordTester("let"), "singleline-var": newSinglelineKeywordTester("var"), "block": newNodeTypeTester(vendor.distExports.AST_NODE_TYPES.BlockStatement), "empty": newNodeTypeTester(vendor.distExports.AST_NODE_TYPES.EmptyStatement), "function": newNodeTypeTester(vendor.distExports.AST_NODE_TYPES.FunctionDeclaration), "ts-method": newNodeTypeTester(vendor.distExports.AST_NODE_TYPES.TSMethodSignature), "break": newKeywordTester(vendor.distExports.AST_NODE_TYPES.BreakStatement, "break"), "case": newKeywordTester(vendor.distExports.AST_NODE_TYPES.SwitchCase, "case"), "class": newKeywordTester(vendor.distExports.AST_NODE_TYPES.ClassDeclaration, "class"), "const": newKeywordTester(vendor.distExports.AST_NODE_TYPES.VariableDeclaration, "const"), "continue": newKeywordTester(vendor.distExports.AST_NODE_TYPES.ContinueStatement, "continue"), "debugger": newKeywordTester(vendor.distExports.AST_NODE_TYPES.DebuggerStatement, "debugger"), "default": newKeywordTester([vendor.distExports.AST_NODE_TYPES.SwitchCase, vendor.distExports.AST_NODE_TYPES.ExportDefaultDeclaration], "default"), "do": newKeywordTester(vendor.distExports.AST_NODE_TYPES.DoWhileStatement, "do"), "export": newKeywordTester([vendor.distExports.AST_NODE_TYPES.ExportAllDeclaration, vendor.distExports.AST_NODE_TYPES.ExportDefaultDeclaration, vendor.distExports.AST_NODE_TYPES.ExportNamedDeclaration], "export"), "for": newKeywordTester([vendor.distExports.AST_NODE_TYPES.ForStatement, vendor.distExports.AST_NODE_TYPES.ForInStatement, vendor.distExports.AST_NODE_TYPES.ForOfStatement], "for"), "if": newKeywordTester(vendor.distExports.AST_NODE_TYPES.IfStatement, "if"), "import": newKeywordTester(vendor.distExports.AST_NODE_TYPES.ImportDeclaration, "import"), "let": newKeywordTester(vendor.distExports.AST_NODE_TYPES.VariableDeclaration, "let"), "return": newKeywordTester(vendor.distExports.AST_NODE_TYPES.ReturnStatement, "return"), "switch": newKeywordTester(vendor.distExports.AST_NODE_TYPES.SwitchStatement, "switch"), "throw": newKeywordTester(vendor.distExports.AST_NODE_TYPES.ThrowStatement, "throw"), "try": newKeywordTester(vendor.distExports.AST_NODE_TYPES.TryStatement, "try"), "var": newKeywordTester(vendor.distExports.AST_NODE_TYPES.VariableDeclaration, "var"), "while": newKeywordTester([vendor.distExports.AST_NODE_TYPES.WhileStatement, vendor.distExports.AST_NODE_TYPES.DoWhileStatement], "while"), "with": newKeywordTester(vendor.distExports.AST_NODE_TYPES.WithStatement, "with"), "cjs-export": { test: (node, sourceCode) => node.type === "ExpressionStatement" && node.expression.type === "AssignmentExpression" && CJS_EXPORT.test(sourceCode.getText(node.expression.left)) }, "cjs-import": { test: (node, sourceCode) => node.type === "VariableDeclaration" && node.declarations.length > 0 && Boolean(node.declarations[0].init) && CJS_IMPORT.test(sourceCode.getText(node.declarations[0].init)) }, // Additional Typescript constructs "enum": newKeywordTester(vendor.distExports.AST_NODE_TYPES.TSEnumDeclaration, "enum"), "interface": newKeywordTester(vendor.distExports.AST_NODE_TYPES.TSInterfaceDeclaration, "interface"), "type": newKeywordTester(vendor.distExports.AST_NODE_TYPES.TSTypeAliasDeclaration, "type"), "function-overload": { test: node => node.type === "TSDeclareFunction" } }; var paddingLineBetweenStatements = utils.createRule({ name: "padding-line-between-statements", package: "ts", meta: { type: "layout", docs: { description: "Require or disallow padding lines between statements" }, fixable: "whitespace", hasSuggestions: false, // This is intentionally an array schema as you can pass 0..n config objects schema: { $defs: { paddingType: { type: "string", enum: _Object$keys(PaddingTypes) }, statementType: { anyOf: [{ type: "string", enum: _Object$keys(StatementTypes) }, { type: "array", items: { type: "string", enum: _Object$keys(StatementTypes) }, minItems: 1, uniqueItems: true, additionalItems: false }] } }, type: "array", additionalItems: false, items: { type: "object", properties: { blankLine: { $ref: "#/$defs/paddingType" }, prev: { $ref: "#/$defs/statementType" }, next: { $ref: "#/$defs/statementType" } }, additionalProperties: false, required: ["blankLine", "prev", "next"] } }, messages: { unexpectedBlankLine: "Unexpected blank line before this statement.", expectedBlankLine: "Expected blank line before this statement." } }, defaultOptions: [], create(context) { const sourceCode = context.sourceCode; const configureList = context.options || []; let scopeInfo = null; function enterScope() { scopeInfo = { upper: scopeInfo, prevNode: null }; } function exitScope() { if (scopeInfo) scopeInfo = scopeInfo.upper; } function match(node, type) { let innerStatementNode = node; while (innerStatementNode.type === vendor.distExports.AST_NODE_TYPES.LabeledStatement) innerStatementNode = innerStatementNode.body; if (_Array$isArray(type)) return _someInstanceProperty(type).call(type, _bindInstanceProperty(match).call(match, null, innerStatementNode)); return StatementTypes[type].test(innerStatementNode, sourceCode); } function getPaddingType(prevNode, nextNode) { for (let i = configureList.length - 1; i >= 0; --i) { const configure = configureList[i]; if (match(prevNode, configure.prev) && match(nextNode, configure.next)) { return PaddingTypes[configure.blankLine]; } } return PaddingTypes.any; } function getPaddingLineSequences(prevNode, nextNode) { const pairs = []; let prevToken = getActualLastToken(prevNode, sourceCode); if (nextNode.loc.start.line - prevToken.loc.end.line >= 2) { do { const token = sourceCode.getTokenAfter(prevToken, { includeComments: true }); if (token.loc.start.line - prevToken.loc.end.line >= 2) pairs.push([prevToken, token]); prevToken = token; } while (prevToken.range[0] < nextNode.range[0]); } return pairs; } function verify(node) { var _context2; if (!node.parent || !_includesInstanceProperty(_context2 = [vendor.distExports.AST_NODE_TYPES.BlockStatement, vendor.distExports.AST_NODE_TYPES.Program, vendor.distExports.AST_NODE_TYPES.StaticBlock, vendor.distExports.AST_NODE_TYPES.SwitchCase, vendor.distExports.AST_NODE_TYPES.SwitchStatement, vendor.distExports.AST_NODE_TYPES.TSInterfaceBody, vendor.distExports.AST_NODE_TYPES.TSModuleBlock, vendor.distExports.AST_NODE_TYPES.TSTypeLiteral]).call(_context2, node.parent.type)) { return; } const prevNode = scopeInfo.prevNode; if (prevNode) { const type = getPaddingType(prevNode, node); const paddingLines = getPaddingLineSequences(prevNode, node); type.verify(context, prevNode, node, paddingLines); } scopeInfo.prevNode = node; } function verifyThenEnterScope(node) { verify(node); enterScope(); } return { "Program": enterScope, "BlockStatement": enterScope, "SwitchStatement": enterScope, "StaticBlock": enterScope, "TSInterfaceBody": enterScope, "TSModuleBlock": enterScope, "TSTypeLiteral": enterScope, "Program:exit": exitScope, "BlockStatement:exit": exitScope, "SwitchStatement:exit": exitScope, "StaticBlock:exit": exitScope, "TSInterfaceBody:exit": exitScope, "TSModuleBlock:exit": exitScope, "TSTypeLiteral:exit": exitScope, ":statement": verify, "SwitchCase": verifyThenEnterScope, "TSDeclareFunction": verifyThenEnterScope, "TSMethodSignature": verifyThenEnterScope, "SwitchCase:exit": exitScope, "TSDeclareFunction:exit": exitScope, "TSMethodSignature:exit": exitScope }; } }); module.exports = paddingLineBetweenStatements;