UNPKG

eslint-plugin-stylistic-compat

Version:

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

325 lines (321 loc) 16.6 kB
'use strict'; var _Object$assign = require('@babel/runtime-corejs3/core-js/object/assign'); var _includesInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/includes'); var _trimInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/trim'); var _mapInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/map'); var _JSON$stringify = require('@babel/runtime-corejs3/core-js/json/stringify'); var _reduceInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/reduce'); var _sliceInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/slice'); var _filterInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/filter'); var _someInstanceProperty = require('@babel/runtime-corejs3/core-js/instance/some'); var utils = require('../utils.js'); require('@babel/runtime-corejs3/core-js/object/from-entries'); 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/starts-with'); require('../vendor.js'); require('@babel/runtime-corejs3/core-js/object/create'); require('@babel/runtime-corejs3/core-js/object/freeze'); require('@babel/runtime-corejs3/core-js/array/is-array'); 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/object/keys'); 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/object/define-property'); require('@babel/runtime-corejs3/core-js/global-this'); require('@babel/runtime-corejs3/core-js/instance/for-each'); require('@babel/runtime-corejs3/core-js/array/from'); 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/find'); 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/concat'); 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/keys'); 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'); require('@babel/runtime-corejs3/core-js/instance/reverse'); const OPTION_ALWAYS = "always"; const OPTION_NEVER = "never"; const OPTION_IGNORE = "ignore"; const OPTION_VALUES = [OPTION_ALWAYS, OPTION_NEVER, OPTION_IGNORE]; const DEFAULT_CONFIG = { props: OPTION_NEVER, children: OPTION_NEVER, propElementValues: OPTION_IGNORE }; const messages = { unnecessaryCurly: "Curly braces are unnecessary here.", missingCurly: "Need to wrap this literal in a JSX expression." }; var jsxCurlyBracePresence = utils.createRule({ name: "jsx-curly-brace-presence", package: "jsx", meta: { type: "layout", docs: { description: "Disallow unnecessary JSX expressions when literals alone are sufficient or enforce JSX expressions on literals in JSX children or attributes" }, fixable: "code", messages, schema: [{ anyOf: [{ type: "object", properties: { props: { type: "string", enum: OPTION_VALUES }, children: { type: "string", enum: OPTION_VALUES }, propElementValues: { type: "string", enum: OPTION_VALUES } }, additionalProperties: false }, { type: "string", enum: OPTION_VALUES }] }] }, create(context) { const HTML_ENTITY_REGEX = () => /&[A-Z\d#]+;/gi; const ruleOptions = context.options[0]; const userConfig = typeof ruleOptions === "string" ? { props: ruleOptions, children: ruleOptions, propElementValues: OPTION_IGNORE } : _Object$assign({}, DEFAULT_CONFIG, ruleOptions); function containsLineTerminators(rawStringValue) { return /[\n\r\u2028\u2029]/.test(rawStringValue); } function containsBackslash(rawStringValue) { return _includesInstanceProperty(rawStringValue).call(rawStringValue, "\\"); } function containsHTMLEntity(rawStringValue) { return HTML_ENTITY_REGEX().test(rawStringValue); } function containsOnlyHtmlEntities(rawStringValue) { var _context; return _trimInstanceProperty(_context = rawStringValue.replace(HTML_ENTITY_REGEX(), "")).call(_context) === ""; } function containsDisallowedJSXTextChars(rawStringValue) { return /[{<>}]/.test(rawStringValue); } function containsQuoteCharacters(value) { return /['"]/.test(value); } function containsMultilineComment(value) { return /\/\*/.test(value); } function escapeDoubleQuotes(rawStringValue) { return rawStringValue.replace(/\\"/g, '"').replace(/"/g, '\\"'); } function escapeBackslashes(rawStringValue) { return rawStringValue.replace(/\\/g, "\\\\"); } function needToEscapeCharacterForJSX(raw, node) { return containsBackslash(raw) || containsHTMLEntity(raw) || node.parent.type !== "JSXAttribute" && containsDisallowedJSXTextChars(raw); } function containsWhitespaceExpression(child) { if (child.type === "JSXExpressionContainer") { const value = child.expression.value; return value ? utils.isWhiteSpaces(value) : false; } return false; } function isLineBreak(text) { return containsLineTerminators(text) && _trimInstanceProperty(text).call(text) === ""; } function wrapNonHTMLEntities(text) { var _context2; const HTML_ENTITY = "<HTML_ENTITY>"; const withCurlyBraces = _mapInstanceProperty(_context2 = text.split(HTML_ENTITY_REGEX())).call(_context2, word => word === "" ? "" : `{${_JSON$stringify(word)}}`).join(HTML_ENTITY); const htmlEntities = text.match(HTML_ENTITY_REGEX()); return _reduceInstanceProperty(htmlEntities).call(htmlEntities, (acc, htmlEntity) => acc.replace(HTML_ENTITY, htmlEntity), withCurlyBraces); } function wrapWithCurlyBraces(rawText) { var _context3; if (!containsLineTerminators(rawText)) return `{${_JSON$stringify(rawText)}}`; return _mapInstanceProperty(_context3 = rawText.split("\n")).call(_context3, line => { if (_trimInstanceProperty(line).call(line) === "") return line; const firstCharIndex = line.search(/\S/); const leftWhitespace = _sliceInstanceProperty(line).call(line, 0, firstCharIndex); const text = _sliceInstanceProperty(line).call(line, firstCharIndex); if (containsHTMLEntity(line)) return `${leftWhitespace}${wrapNonHTMLEntities(text)}`; return `${leftWhitespace}{${_JSON$stringify(text)}}`; }).join("\n"); } function reportUnnecessaryCurly(JSXExpressionNode) { context.report({ messageId: "unnecessaryCurly", node: JSXExpressionNode, fix(fixer) { const expression = JSXExpressionNode.expression; let textToReplace; if (utils.isJSX(expression)) { const sourceCode = context.sourceCode; textToReplace = sourceCode.getText(expression); } else { const parentType = JSXExpressionNode.parent.type; if (parentType === "JSXAttribute") { var _context4; textToReplace = `"${expression.type === "TemplateLiteral" ? expression.quasis[0].value.raw : _sliceInstanceProperty(_context4 = expression.raw).call(_context4, 1, -1)}"`; } else if (utils.isJSX(expression)) { const sourceCode = context.sourceCode; textToReplace = sourceCode.getText(expression); } else { textToReplace = expression.type === "TemplateLiteral" ? expression.quasis[0].value.cooked : expression.value; } } return fixer.replaceText(JSXExpressionNode, textToReplace); } }); } function reportMissingCurly(literalNode) { context.report({ messageId: "missingCurly", node: literalNode, fix(fixer) { var _context5; if (utils.isJSX(literalNode)) return fixer.replaceText(literalNode, `{${context.sourceCode.getText(literalNode)}}`); if (containsOnlyHtmlEntities(literalNode.raw) || literalNode.parent.type === "JSXAttribute" && containsLineTerminators(literalNode.raw) || isLineBreak(literalNode.raw)) { return null; } const expression = literalNode.parent.type === "JSXAttribute" ? `{"${escapeDoubleQuotes(escapeBackslashes(_sliceInstanceProperty(_context5 = literalNode.raw).call(_context5, 1, -1)))}"}` : wrapWithCurlyBraces(literalNode.raw); return fixer.replaceText(literalNode, expression); } }); } function isWhiteSpaceLiteral(node) { return node.type && node.type === "Literal" && node.value && utils.isWhiteSpaces(node.value); } function isStringWithTrailingWhiteSpaces(value) { return /^\s|\s$/.test(value); } function isLiteralWithTrailingWhiteSpaces(node) { return node.type && node.type === "Literal" && node.value && isStringWithTrailingWhiteSpaces(node.value); } function lintUnnecessaryCurly(JSXExpressionNode) { var _context6; const expression = JSXExpressionNode.expression; const expressionType = expression.type; const sourceCode = context.sourceCode; if (sourceCode.getCommentsInside && sourceCode.getCommentsInside(JSXExpressionNode).length > 0) return; if ((expressionType === "Literal" || expressionType === "JSXText") && typeof expression.value === "string" && (JSXExpressionNode.parent.type === "JSXAttribute" && !isWhiteSpaceLiteral(expression) || !isLiteralWithTrailingWhiteSpaces(expression)) && !containsMultilineComment(expression.value) && !needToEscapeCharacterForJSX(expression.raw, JSXExpressionNode) && (utils.isJSX(JSXExpressionNode.parent) || !containsQuoteCharacters(expression.value))) { reportUnnecessaryCurly(JSXExpressionNode); } else if (expressionType === "TemplateLiteral" && expression.expressions.length === 0 && !_includesInstanceProperty(_context6 = expression.quasis[0].value.raw).call(_context6, "\n") && !isStringWithTrailingWhiteSpaces(expression.quasis[0].value.raw) && !needToEscapeCharacterForJSX(expression.quasis[0].value.raw, JSXExpressionNode) && !containsQuoteCharacters(expression.quasis[0].value.cooked)) { reportUnnecessaryCurly(JSXExpressionNode); } else if (utils.isJSX(expression)) { reportUnnecessaryCurly(JSXExpressionNode); } } function areRuleConditionsSatisfied(parent, config, ruleCondition) { return parent.type === "JSXAttribute" && typeof config.props === "string" && config.props === ruleCondition || utils.isJSX(parent) && typeof config.children === "string" && config.children === ruleCondition; } function getAdjacentSiblings(node, children) { for (let i = 1; i < children.length - 1; i++) { const child = children[i]; if (node === child) return [children[i - 1], children[i + 1]]; } if (node === children[0] && children[1]) return [children[1]]; if (node === children[children.length - 1] && children[children.length - 2]) return [children[children.length - 2]]; return []; } function hasAdjacentJsxExpressionContainers(node, children) { if (!children) return false; const childrenExcludingWhitespaceLiteral = _filterInstanceProperty(children).call(children, child => !isWhiteSpaceLiteral(child)); const adjSiblings = getAdjacentSiblings(node, childrenExcludingWhitespaceLiteral); return _someInstanceProperty(adjSiblings).call(adjSiblings, x => x.type && x.type === "JSXExpressionContainer"); } function hasAdjacentJsx(node, children) { if (!children) return false; const childrenExcludingWhitespaceLiteral = _filterInstanceProperty(children).call(children, child => !isWhiteSpaceLiteral(child)); const adjSiblings = getAdjacentSiblings(node, childrenExcludingWhitespaceLiteral); return _someInstanceProperty(adjSiblings).call(adjSiblings, x => { var _context7; return x.type && _includesInstanceProperty(_context7 = ["JSXExpressionContainer", "JSXElement"]).call(_context7, x.type); }); } function shouldCheckForUnnecessaryCurly(node, config) { const parent = node.parent; if (parent.type && parent.type === "JSXAttribute" && node.expression && node.expression.type && node.expression.type !== "Literal" && node.expression.type !== "StringLiteral" && node.expression.type !== "TemplateLiteral") { return false; } if (utils.isJSX(parent) && hasAdjacentJsxExpressionContainers(node, parent.children)) return false; if (containsWhitespaceExpression(node) && hasAdjacentJsx(node, parent.children)) return false; if (parent.children && parent.children.length === 1 && containsWhitespaceExpression(node)) { return false; } return areRuleConditionsSatisfied(parent, config, OPTION_NEVER); } function shouldCheckForMissingCurly(node, config) { if (utils.isJSX(node)) return config.propElementValues !== OPTION_IGNORE; if (isLineBreak(node.raw) || containsOnlyHtmlEntities(node.raw)) { return false; } const parent = node.parent; if (parent.children && parent.children.length === 1 && containsWhitespaceExpression(parent.children[0])) { return false; } return areRuleConditionsSatisfied(parent, config, OPTION_ALWAYS); } return { "JSXAttribute > JSXExpressionContainer > JSXElement": function (node) { if (userConfig.propElementValues === OPTION_NEVER) reportUnnecessaryCurly(node.parent); }, JSXExpressionContainer(node) { if (shouldCheckForUnnecessaryCurly(node, userConfig)) lintUnnecessaryCurly(node); }, "JSXAttribute > JSXElement, Literal, JSXText": function (node) { if (shouldCheckForMissingCurly(node, userConfig)) reportMissingCurly(node); } }; } }); module.exports = jsxCurlyBracePresence;