UNPKG

eslint-plugin-stylistic-compat

Version:

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

308 lines (304 loc) 11.4 kB
'use strict'; var _forEachInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/for-each'); 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/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('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'); 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 isLastTokenEndOfLine(token, line) { const positionInLine = token.loc.start.column; return positionInLine === line.length - 1; } function isCommentsEndOfLine(token, comments, line) { if (!comments) return false; if (comments.loc.end.line > token.loc.end.line) return true; const positionInLine = comments.loc.end.column; return positionInLine === line.length; } function makeFixFunction({ optsNone, optsSemi, lastToken, commentsAfterLastToken, missingDelimiter, lastTokenLine, isSingleLine }) { if (optsNone && !isLastTokenEndOfLine(lastToken, lastTokenLine) && !isCommentsEndOfLine(lastToken, commentsAfterLastToken, lastTokenLine) && !isSingleLine) { return null; } return fixer => { if (optsNone) { return fixer.remove(lastToken); } const token = optsSemi ? ";" : ","; if (missingDelimiter) { return fixer.insertTextAfter(lastToken, token); } return fixer.replaceText(lastToken, token); }; } const BASE_SCHEMA = { type: "object", properties: { multiline: { type: "object", properties: { delimiter: { $ref: "#/items/0/$defs/multiLineOption" }, requireLast: { type: "boolean" } }, additionalProperties: false }, singleline: { type: "object", properties: { delimiter: { $ref: "#/items/0/$defs/singleLineOption" }, requireLast: { type: "boolean" } }, additionalProperties: false } }, additionalProperties: false }; var memberDelimiterStyle = utils.createRule({ name: "member-delimiter-style", package: "ts", meta: { type: "layout", docs: { description: "Require a specific member delimiter style for interfaces and type literals" }, fixable: "whitespace", messages: { unexpectedComma: "Unexpected separator (,).", unexpectedSemi: "Unexpected separator (;).", expectedComma: "Expected a comma.", expectedSemi: "Expected a semicolon." }, schema: [{ $defs: { multiLineOption: { type: "string", enum: ["none", "semi", "comma"] }, // note can't have "none" for single line delimiter as it's invalid syntax singleLineOption: { type: "string", enum: ["semi", "comma"] }, // note - need to define this last as it references the enums delimiterConfig: BASE_SCHEMA }, type: "object", properties: { ...BASE_SCHEMA.properties, overrides: { type: "object", properties: { interface: { $ref: "#/items/0/$defs/delimiterConfig" }, typeLiteral: { $ref: "#/items/0/$defs/delimiterConfig" } }, additionalProperties: false }, multilineDetection: { type: "string", enum: ["brackets", "last-member"] } }, additionalProperties: false }] }, defaultOptions: [{ multiline: { delimiter: "semi", requireLast: true }, singleline: { delimiter: "semi", requireLast: false }, multilineDetection: "brackets" }], create(context, [options]) { var _baseOptions$override; const sourceCode = context.sourceCode; const baseOptions = options; const overrides = (_baseOptions$override = baseOptions.overrides) != null ? _baseOptions$override : {}; const interfaceOptions = utils.deepMerge(baseOptions, overrides.interface); const typeLiteralOptions = utils.deepMerge(baseOptions, overrides.typeLiteral); function checkLastToken(member, opts, isLast) { function getOption(type) { if (isLast && !opts.requireLast) { return type === "none"; } return opts.delimiter === type; } let messageId = null; let missingDelimiter = false; const lastToken = sourceCode.getLastToken(member, { includeComments: false }); if (!lastToken) return; const commentsAfterLastToken = sourceCode.getCommentsAfter(lastToken).pop(); const sourceCodeLines = sourceCode.getLines(); const lastTokenLine = sourceCodeLines[(lastToken == null ? undefined : lastToken.loc.start.line) - 1]; const optsSemi = getOption("semi"); const optsComma = getOption("comma"); const optsNone = getOption("none"); if (lastToken.value === ";") { if (optsComma) { messageId = "expectedComma"; } else if (optsNone) { missingDelimiter = true; messageId = "unexpectedSemi"; } } else if (lastToken.value === ",") { if (optsSemi) { messageId = "expectedSemi"; } else if (optsNone) { missingDelimiter = true; messageId = "unexpectedComma"; } } else { if (optsSemi) { missingDelimiter = true; messageId = "expectedSemi"; } else if (optsComma) { missingDelimiter = true; messageId = "expectedComma"; } } if (messageId) { context.report({ node: lastToken, loc: { start: { line: lastToken.loc.end.line, column: lastToken.loc.end.column }, end: { line: lastToken.loc.end.line, column: lastToken.loc.end.column } }, messageId, fix: makeFixFunction({ optsNone, optsSemi, lastToken, commentsAfterLastToken, missingDelimiter, lastTokenLine, isSingleLine: opts.type === "single-line" }) }); } } function checkMemberSeparatorStyle(node) { const members = node.type === vendor.distExports.AST_NODE_TYPES.TSInterfaceBody ? node.body : node.members; let isSingleLine = node.loc.start.line === node.loc.end.line; if (options.multilineDetection === "last-member" && !isSingleLine && members.length > 0) { const lastMember = members[members.length - 1]; if (lastMember.loc.end.line === node.loc.end.line) isSingleLine = true; } const typeOpts = node.type === vendor.distExports.AST_NODE_TYPES.TSInterfaceBody ? interfaceOptions : typeLiteralOptions; const opts = isSingleLine ? { ...typeOpts.singleline, type: "single-line" } : { ...typeOpts.multiline, type: "multi-line" }; _forEachInstanceProperty(members).call(members, (member, index) => { checkLastToken(member, opts != null ? opts : {}, index === members.length - 1); }); } return { TSInterfaceBody: checkMemberSeparatorStyle, TSTypeLiteral: checkMemberSeparatorStyle }; } }); module.exports = memberDelimiterStyle;