UNPKG

eslint-plugin-stylistic-compat

Version:

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

505 lines (500 loc) 22.3 kB
'use strict'; var _Array$isArray = require('@babel/runtime-corejs3/core-js/array/is-array'); var utils = require('../utils.js'); var vendor = require('../vendor.js'); var _concatInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/concat'); var _sortInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/sort'); var _reduceInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/reduce'); var _WeakSet = require('@babel/runtime-corejs3/core-js/weak-set'); var _Object$create = require('@babel/runtime-corejs3/core-js/object/create'); 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/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/object/keys'); 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/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/some'); require('@babel/runtime-corejs3/core-js/instance/every'); 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'); 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 PREV_TOKEN = /^[)\]}>]$/u; const NEXT_TOKEN = /^(?:[([{<~!]|\+\+?|--?)$/u; const PREV_TOKEN_M = /^[)\]}>*]$/u; const NEXT_TOKEN_M = /^[{*]$/u; const TEMPLATE_OPEN_PAREN = /\$\{$/u; const TEMPLATE_CLOSE_PAREN = /^\}/u; const CHECK_TYPE = /^(?:JSXElement|RegularExpression|String|Template|PrivateIdentifier)$/u; const KEYS = _concatInstanceProperty(utils.KEYWORDS_JS).call(utils.KEYWORDS_JS, ["as", "async", "await", "from", "get", "let", "of", "satisfies", "set", "yield"]); (function () { _sortInstanceProperty(KEYS).call(KEYS); for (let i = 1; i < KEYS.length; ++i) { if (KEYS[i] === KEYS[i - 1]) throw new Error(`Duplication was found in the keyword list: ${KEYS[i]}`); } })(); function isOpenParenOfTemplate(token) { return token.type === "Template" && TEMPLATE_OPEN_PAREN.test(token.value); } function isCloseParenOfTemplate(token) { return token.type === "Template" && TEMPLATE_CLOSE_PAREN.test(token.value); } var _baseRule = utils.createRule({ name: "keyword-spacing", package: "js", meta: { type: "layout", docs: { description: "Enforce consistent spacing before and after keywords" }, fixable: "whitespace", schema: [{ type: "object", properties: { before: { type: "boolean", default: true }, after: { type: "boolean", default: true }, overrides: { type: "object", properties: _reduceInstanceProperty(KEYS).call(KEYS, (retv, key) => { retv[key] = { type: "object", properties: { before: { type: "boolean" }, after: { type: "boolean" } }, additionalProperties: false }; return retv; }, {}), additionalProperties: false } }, additionalProperties: false }], messages: { expectedBefore: 'Expected space(s) before "{{value}}".', expectedAfter: 'Expected space(s) after "{{value}}".', unexpectedBefore: 'Unexpected space(s) before "{{value}}".', unexpectedAfter: 'Unexpected space(s) after "{{value}}".' } }, create(context) { const sourceCode = context.sourceCode; const tokensToIgnore = /* @__PURE__ */new _WeakSet(); function expectSpaceBefore(token, pattern) { const prevToken = sourceCode.getTokenBefore(token); if (prevToken && (CHECK_TYPE.test(prevToken.type) || pattern.test(prevToken.value)) && !isOpenParenOfTemplate(prevToken) && !tokensToIgnore.has(prevToken) && utils.isTokenOnSameLine(prevToken, token) && !sourceCode.isSpaceBetween(prevToken, token)) { context.report({ loc: token.loc, messageId: "expectedBefore", // @ts-expect-error index signature for string is missing data: token, fix(fixer) { return fixer.insertTextBefore(token, " "); } }); } } function unexpectSpaceBefore(token, pattern) { const prevToken = sourceCode.getTokenBefore(token); if (prevToken && (CHECK_TYPE.test(prevToken.type) || pattern.test(prevToken.value)) && !isOpenParenOfTemplate(prevToken) && !tokensToIgnore.has(prevToken) && utils.isTokenOnSameLine(prevToken, token) && sourceCode.isSpaceBetween(prevToken, token)) { context.report({ loc: { start: prevToken.loc.end, end: token.loc.start }, messageId: "unexpectedBefore", // @ts-expect-error index signature for string is missing data: token, fix(fixer) { return fixer.removeRange([prevToken.range[1], token.range[0]]); } }); } } function expectSpaceAfter(token, pattern) { const nextToken = sourceCode.getTokenAfter(token); if (nextToken && (CHECK_TYPE.test(nextToken.type) || pattern.test(nextToken.value)) && !isCloseParenOfTemplate(nextToken) && !tokensToIgnore.has(nextToken) && utils.isTokenOnSameLine(token, nextToken) && !sourceCode.isSpaceBetween(token, nextToken)) { context.report({ loc: token.loc, messageId: "expectedAfter", // @ts-expect-error index signature for string is missing data: token, fix(fixer) { return fixer.insertTextAfter(token, " "); } }); } } function unexpectSpaceAfter(token, pattern) { const nextToken = sourceCode.getTokenAfter(token); if (nextToken && (CHECK_TYPE.test(nextToken.type) || pattern.test(nextToken.value)) && !isCloseParenOfTemplate(nextToken) && !tokensToIgnore.has(nextToken) && utils.isTokenOnSameLine(token, nextToken) && sourceCode.isSpaceBetween(token, nextToken)) { context.report({ loc: { start: token.loc.end, end: nextToken.loc.start }, messageId: "unexpectedAfter", // @ts-expect-error index signature for string is missing data: token, fix(fixer) { return fixer.removeRange([token.range[1], nextToken.range[0]]); } }); } } function parseOptions(options = {}) { const before = options.before !== false; const after = options.after !== false; const defaultValue = { before: before ? expectSpaceBefore : unexpectSpaceBefore, after: after ? expectSpaceAfter : unexpectSpaceAfter }; const overrides = options && options.overrides || {}; const retv = /* @__PURE__ */_Object$create(null); for (let i = 0; i < KEYS.length; ++i) { const key = KEYS[i]; const override = overrides[key]; if (override) { const thisBefore = "before" in override ? override.before : before; const thisAfter = "after" in override ? override.after : after; retv[key] = { before: thisBefore ? expectSpaceBefore : unexpectSpaceBefore, after: thisAfter ? expectSpaceAfter : unexpectSpaceAfter }; } else { retv[key] = defaultValue; } } return retv; } const checkMethodMap = parseOptions(context.options[0]); function checkSpacingBefore(token, pattern) { checkMethodMap[token.value].before(token, pattern || PREV_TOKEN); } function checkSpacingAfter(token, pattern) { checkMethodMap[token.value].after(token, pattern || NEXT_TOKEN); } function checkSpacingAround(token) { checkSpacingBefore(token); checkSpacingAfter(token); } function checkSpacingAroundFirstToken(node) { const firstToken = node && sourceCode.getFirstToken(node); if (firstToken && firstToken.type === "Keyword") checkSpacingAround(firstToken); } function checkSpacingBeforeFirstToken(node) { const firstToken = node && sourceCode.getFirstToken(node); if (firstToken && firstToken.type === "Keyword") checkSpacingBefore(firstToken); } function checkSpacingAroundTokenBefore(node) { if (node) { const token = sourceCode.getTokenBefore(node, utils.isKeywordToken); if (token) checkSpacingAround(token); } } function checkSpacingForFunction(node) { const firstToken = node && sourceCode.getFirstToken(node); if (firstToken && (firstToken.type === "Keyword" && firstToken.value === "function" || firstToken.value === "async")) { checkSpacingBefore(firstToken); } } function checkSpacingForClass(node) { checkSpacingAroundFirstToken(node); checkSpacingAroundTokenBefore(node.superClass); } function checkSpacingForIfStatement(node) { checkSpacingAroundFirstToken(node); checkSpacingAroundTokenBefore(node.alternate); } function checkSpacingForTryStatement(node) { checkSpacingAroundFirstToken(node); checkSpacingAroundFirstToken(node.handler); checkSpacingAroundTokenBefore(node.finalizer); } function checkSpacingForDoWhileStatement(node) { checkSpacingAroundFirstToken(node); checkSpacingAroundTokenBefore(node.test); } function checkSpacingForForInStatement(node) { checkSpacingAroundFirstToken(node); const inToken = sourceCode.getTokenBefore(node.right, utils.isNotOpeningParenToken); const previousToken = sourceCode.getTokenBefore(inToken); if (previousToken.type !== "PrivateIdentifier") checkSpacingBefore(inToken); checkSpacingAfter(inToken); } function checkSpacingForForOfStatement(node) { if (node.await) { checkSpacingBefore(sourceCode.getFirstToken(node, 0)); checkSpacingAfter(sourceCode.getFirstToken(node, 1)); } else { checkSpacingAroundFirstToken(node); } const ofToken = sourceCode.getTokenBefore(node.right, utils.isNotOpeningParenToken); const previousToken = sourceCode.getTokenBefore(ofToken); if (previousToken.type !== "PrivateIdentifier") checkSpacingBefore(ofToken); checkSpacingAfter(ofToken); } function checkSpacingForModuleDeclaration(node) { const firstToken = sourceCode.getFirstToken(node); checkSpacingBefore(firstToken, PREV_TOKEN_M); checkSpacingAfter(firstToken, NEXT_TOKEN_M); if (node.type === "ExportDefaultDeclaration") checkSpacingAround(sourceCode.getTokenAfter(firstToken)); if (node.type === "ExportAllDeclaration" && node.exported) { const asToken = sourceCode.getTokenBefore(node.exported); checkSpacingBefore(asToken, PREV_TOKEN_M); checkSpacingAfter(asToken, NEXT_TOKEN_M); } if ("source" in node && node.source) { const fromToken = sourceCode.getTokenBefore(node.source); checkSpacingBefore(fromToken, PREV_TOKEN_M); checkSpacingAfter(fromToken, NEXT_TOKEN_M); } } function checkSpacingForImportSpecifier(node) { if (node.imported.range[0] !== node.local.range[0]) { const asToken = sourceCode.getTokenBefore(node.local); checkSpacingBefore(asToken, PREV_TOKEN_M); } } function checkSpacingForExportSpecifier(node) { if (node.local.range[0] !== node.exported.range[0]) { const asToken = sourceCode.getTokenBefore(node.exported); checkSpacingBefore(asToken, PREV_TOKEN_M); checkSpacingAfter(asToken, NEXT_TOKEN_M); } } function checkSpacingForImportNamespaceSpecifier(node) { const asToken = sourceCode.getFirstToken(node, 1); checkSpacingBefore(asToken, PREV_TOKEN_M); } function checkSpacingForProperty(node) { if ("static" in node && node.static) checkSpacingAroundFirstToken(node); if (node.kind === "get" || node.kind === "set" || ("method" in node && node.method || node.type === "MethodDefinition") && "async" in node.value && node.value.async) { const token = sourceCode.getTokenBefore(node.key, tok => { switch (tok.value) { case "get": case "set": case "async": return true; default: return false; } }); if (!token) throw new Error("Failed to find token get, set, or async beside method name"); checkSpacingAround(token); } } function checkSpacingForAwaitExpression(node) { checkSpacingBefore(sourceCode.getFirstToken(node)); } return { // Statements "DebuggerStatement": checkSpacingAroundFirstToken, "WithStatement": checkSpacingAroundFirstToken, // Statements - Control flow "BreakStatement": checkSpacingAroundFirstToken, "ContinueStatement": checkSpacingAroundFirstToken, "ReturnStatement": checkSpacingAroundFirstToken, "ThrowStatement": checkSpacingAroundFirstToken, "TryStatement": checkSpacingForTryStatement, // Statements - Choice "IfStatement": checkSpacingForIfStatement, "SwitchStatement": checkSpacingAroundFirstToken, "SwitchCase": checkSpacingAroundFirstToken, // Statements - Loops "DoWhileStatement": checkSpacingForDoWhileStatement, "ForInStatement": checkSpacingForForInStatement, "ForOfStatement": checkSpacingForForOfStatement, "ForStatement": checkSpacingAroundFirstToken, "WhileStatement": checkSpacingAroundFirstToken, // Statements - Declarations "ClassDeclaration": checkSpacingForClass, "ExportNamedDeclaration": checkSpacingForModuleDeclaration, "ExportDefaultDeclaration": checkSpacingForModuleDeclaration, "ExportAllDeclaration": checkSpacingForModuleDeclaration, "FunctionDeclaration": checkSpacingForFunction, "ImportDeclaration": checkSpacingForModuleDeclaration, "VariableDeclaration": checkSpacingAroundFirstToken, // Expressions "ArrowFunctionExpression": checkSpacingForFunction, "AwaitExpression": checkSpacingForAwaitExpression, "ClassExpression": checkSpacingForClass, "FunctionExpression": checkSpacingForFunction, "NewExpression": checkSpacingBeforeFirstToken, "Super": checkSpacingBeforeFirstToken, "ThisExpression": checkSpacingBeforeFirstToken, "UnaryExpression": checkSpacingBeforeFirstToken, "YieldExpression": checkSpacingBeforeFirstToken, // Others "ImportSpecifier": checkSpacingForImportSpecifier, "ExportSpecifier": checkSpacingForExportSpecifier, "ImportNamespaceSpecifier": checkSpacingForImportNamespaceSpecifier, "MethodDefinition": checkSpacingForProperty, "PropertyDefinition": checkSpacingForProperty, "StaticBlock": checkSpacingAroundFirstToken, "Property": checkSpacingForProperty, // To avoid conflicts with `space-infix-ops`, e.g. `a > this.b` "BinaryExpression[operator='>']": function (node) { const operatorToken = sourceCode.getTokenBefore(node.right, utils.isNotOpeningParenToken); tokensToIgnore.add(operatorToken); } }; } }); const baseRule = /* @__PURE__ */utils.castRuleModule(_baseRule); const baseSchema = _Array$isArray(baseRule.meta.schema) ? baseRule.meta.schema[0] : baseRule.meta.schema; const schema = utils.deepMerge(baseSchema, { properties: { overrides: { properties: { type: baseSchema.properties.overrides.properties.import } } } }); var keywordSpacing = utils.createRule({ name: "keyword-spacing", package: "ts", meta: { type: "layout", docs: { description: "Enforce consistent spacing before and after keywords" }, fixable: "whitespace", hasSuggestions: baseRule.meta.hasSuggestions, schema: [schema], messages: baseRule.meta.messages }, defaultOptions: [{}], create(context, [options]) { const { after, overrides } = options != null ? options : {}; const sourceCode = context.sourceCode; const baseRules = baseRule.create(context); return { ...baseRules, TSAsExpression(node) { const asToken = utils.nullThrows(sourceCode.getTokenAfter(node.expression, token => token.value === "as"), utils.NullThrowsReasons.MissingToken("as", node.type)); const oldTokenType = asToken.type; asToken.type = vendor.distExports.AST_TOKEN_TYPES.Keyword; baseRules.DebuggerStatement(asToken); asToken.type = oldTokenType; }, // TODO: Stage3: copy from `TSAsExpression`, just call `checkSpacingAroundFirstToken` when refactor TSSatisfiesExpression(node) { const satisfiesToken = utils.nullThrows(sourceCode.getTokenAfter(node.expression, token => token.value === "satisfies"), utils.NullThrowsReasons.MissingToken("satisfies", node.type)); const oldTokenType = satisfiesToken.type; satisfiesToken.type = vendor.distExports.AST_TOKEN_TYPES.Keyword; baseRules.DebuggerStatement(satisfiesToken); satisfiesToken.type = oldTokenType; }, "ImportDeclaration[importKind=type]": function (node) { var _node$specifiers, _typeOptionOverride$a, _typeOptionOverride$a2; const { type: typeOptionOverride = {} } = overrides != null ? overrides : {}; const typeToken = sourceCode.getFirstToken(node, { skip: 1 }); const punctuatorToken = sourceCode.getTokenAfter(typeToken); if (((_node$specifiers = node.specifiers) == null || (_node$specifiers = _node$specifiers[0]) == null ? undefined : _node$specifiers.type) === vendor.distExports.AST_NODE_TYPES.ImportDefaultSpecifier) return; const spacesBetweenTypeAndPunctuator = punctuatorToken.range[0] - typeToken.range[1]; if (((_typeOptionOverride$a = typeOptionOverride.after) != null ? _typeOptionOverride$a : after) === true && spacesBetweenTypeAndPunctuator === 0) { context.report({ loc: typeToken.loc, messageId: "expectedAfter", data: { value: "type" }, fix(fixer) { return fixer.insertTextAfter(typeToken, " "); } }); } if (((_typeOptionOverride$a2 = typeOptionOverride.after) != null ? _typeOptionOverride$a2 : after) === false && spacesBetweenTypeAndPunctuator > 0) { context.report({ loc: typeToken.loc, messageId: "unexpectedAfter", data: { value: "type" }, fix(fixer) { return fixer.removeRange([typeToken.range[1], typeToken.range[1] + spacesBetweenTypeAndPunctuator]); } }); } } }; } }); module.exports = keywordSpacing;