UNPKG

eslint-plugin-stylistic-compat

Version:

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

301 lines (296 loc) 12.1 kB
'use strict'; var _Object$values = require('@babel/runtime-corejs3/core-js/object/values'); var _someInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/some'); var _filterInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/filter'); 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/object/entries'); require('@babel/runtime-corejs3/core-js/set'); 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/instance/concat'); require('@babel/runtime-corejs3/core-js/object/keys'); 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/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('@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/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'); 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'); const ClassMemberTypes = { "*": { test: () => true }, "field": { test: node => node.type === "PropertyDefinition" }, "method": { test: node => node.type === "MethodDefinition" } }; var _baseRule = utils.createRule({ name: "lines-between-class-members", package: "js", meta: { type: "layout", docs: { description: "Require or disallow an empty line between class members" }, fixable: "whitespace", schema: [{ anyOf: [{ type: "object", properties: { enforce: { type: "array", items: { type: "object", properties: { blankLine: { type: "string", enum: ["always", "never"] }, prev: { type: "string", enum: ["method", "field", "*"] }, next: { type: "string", enum: ["method", "field", "*"] } }, additionalProperties: false, required: ["blankLine", "prev", "next"] }, minItems: 1 } }, additionalProperties: false, required: ["enforce"] }, { type: "string", enum: ["always", "never"] }] }, { type: "object", properties: { exceptAfterSingleLine: { type: "boolean", default: false } }, additionalProperties: false }], messages: { never: "Unexpected blank line between class members.", always: "Expected blank line between class members." } }, create(context) { const options = []; options[0] = context.options[0] || "always"; options[1] = context.options[1] || { exceptAfterSingleLine: false }; const configureList = typeof options[0] === "object" ? options[0].enforce : [{ blankLine: options[0], prev: "*", next: "*" }]; const sourceCode = context.sourceCode; function getBoundaryTokens(curNode, nextNode) { const lastToken = sourceCode.getLastToken(curNode); const prevToken = sourceCode.getTokenBefore(lastToken); const nextToken = sourceCode.getFirstToken(nextNode); const isSemicolonLessStyle = utils.isSemicolonToken(lastToken) && !utils.isTokenOnSameLine(prevToken, lastToken) && utils.isTokenOnSameLine(lastToken, nextToken); return isSemicolonLessStyle ? { curLast: prevToken, nextFirst: lastToken } : { curLast: lastToken, nextFirst: nextToken }; } function findLastConsecutiveTokenAfter(prevLastToken, nextFirstToken, maxLine) { const after = sourceCode.getTokenAfter(prevLastToken, { includeComments: true }); if (after !== nextFirstToken && after.loc.start.line - prevLastToken.loc.end.line <= maxLine) return findLastConsecutiveTokenAfter(after, nextFirstToken, maxLine); return prevLastToken; } function findFirstConsecutiveTokenBefore(nextFirstToken, prevLastToken, maxLine) { const before = sourceCode.getTokenBefore(nextFirstToken, { includeComments: true }); if (before !== prevLastToken && nextFirstToken.loc.start.line - before.loc.end.line <= maxLine) return findFirstConsecutiveTokenBefore(before, prevLastToken, maxLine); return nextFirstToken; } function hasTokenOrCommentBetween(before, after) { return sourceCode.getTokensBetween(before, after, { includeComments: true }).length !== 0; } function match(node, type) { return ClassMemberTypes[type].test(node); } function getPaddingType(prevNode, nextNode) { for (let i = configureList.length - 1; i >= 0; --i) { const configure = configureList[i]; const matched = match(prevNode, configure.prev) && match(nextNode, configure.next); if (matched) return configure.blankLine; } return null; } return { ClassBody(node) { const body = node.body; for (let i = 0; i < body.length - 1; i++) { const curFirst = sourceCode.getFirstToken(body[i]); const { curLast, nextFirst } = getBoundaryTokens(body[i], body[i + 1]); const isMulti = !utils.isTokenOnSameLine(curFirst, curLast); const skip = !isMulti && options[1].exceptAfterSingleLine; const beforePadding = findLastConsecutiveTokenAfter(curLast, nextFirst, 1); const afterPadding = findFirstConsecutiveTokenBefore(nextFirst, curLast, 1); const isPadded = afterPadding.loc.start.line - beforePadding.loc.end.line > 1; const hasTokenInPadding = hasTokenOrCommentBetween(beforePadding, afterPadding); const curLineLastToken = findLastConsecutiveTokenAfter(curLast, nextFirst, 0); const paddingType = getPaddingType(body[i], body[i + 1]); if (paddingType === "never" && isPadded) { context.report({ node: body[i + 1], messageId: "never", fix(fixer) { if (hasTokenInPadding) return null; return fixer.replaceTextRange([beforePadding.range[1], afterPadding.range[0]], "\n"); } }); } else if (paddingType === "always" && !skip && !isPadded) { context.report({ node: body[i + 1], messageId: "always", fix(fixer) { if (hasTokenInPadding) return null; return fixer.insertTextAfter(curLineLastToken, "\n"); } }); } } } }; } }); const baseRule = /* @__PURE__ */utils.castRuleModule(_baseRule); const schema = _Object$values(utils.deepMerge({ ...baseRule.meta.schema }, { 1: { properties: { exceptAfterOverload: { type: "boolean", default: true } } } })); var linesBetweenClassMembers = utils.createRule({ name: "lines-between-class-members", package: "ts", meta: { type: "layout", docs: { description: "Require or disallow an empty line between class members" }, fixable: "whitespace", hasSuggestions: baseRule.meta.hasSuggestions, schema, messages: baseRule.meta.messages }, defaultOptions: ["always", { exceptAfterOverload: true, exceptAfterSingleLine: false }], create(context, [firstOption, secondOption]) { var _context; const rules = baseRule.create(context); const exceptAfterOverload = (secondOption == null ? undefined : secondOption.exceptAfterOverload) && (firstOption === "always" || typeof firstOption !== "string" && (firstOption == null ? undefined : _someInstanceProperty(_context = firstOption.enforce).call(_context, ({ blankLine, prev, next }) => blankLine === "always" && prev !== "field" && next !== "field"))); function isOverload(node) { return (node.type === vendor.distExports.AST_NODE_TYPES.TSAbstractMethodDefinition || node.type === vendor.distExports.AST_NODE_TYPES.MethodDefinition) && node.value.type === vendor.distExports.AST_NODE_TYPES.TSEmptyBodyFunctionExpression; } return { ClassBody(node) { var _context2; const body = exceptAfterOverload ? _filterInstanceProperty(_context2 = node.body).call(_context2, node2 => !isOverload(node2)) : node.body; rules.ClassBody({ ...node, body }); } }; } }); module.exports = linesBetweenClassMembers;