UNPKG

eslint-plugin-arrow-return-style

Version:

Enforce arrow function return style and automatically fix it

310 lines (298 loc) 12.6 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name2 in all) __defProp(target, name2, { get: all[name2], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { default: () => src_default }); module.exports = __toCommonJS(src_exports); // package.json var name = "eslint-plugin-arrow-return-style"; var version = "1.3.1"; // src/utils/create-rule.ts var import_utils = require("@typescript-eslint/utils"); var createRule = import_utils.ESLintUtils.RuleCreator((rule) => { return `https://github.com/u3u/eslint-plugin-arrow-return-style/tree/v${version}/docs/rules/${rule}.md`; }); // src/utils/define-config.ts var defineConfig = (config) => { return config; }; // src/utils/define-plugin.ts var definePlugin = (plugin) => { return plugin; }; // src/configs/recommended.ts var recommended_default = defineConfig({ plugins: ["arrow-return-style"], rules: { "arrow-body-style": "off", "arrow-return-style/arrow-return-style": "warn", "arrow-return-style/no-export-default-arrow": "warn" } }); // src/rules/arrow-return-style.ts var import_utils3 = require("@typescript-eslint/utils"); var RULE_NAME = "arrow-return-style"; var arrowReturnStyleRule = createRule({ create: (context) => { const sourceCode = context.getSourceCode(); return { ArrowFunctionExpression: (arrowFunction) => { const { body: arrowBody, parent: arrowFunctionParent } = arrowFunction; const { jsxAlwaysUseExplicitReturn, maxLen = 80, namedExportsAlwaysUseExplicitReturn = true } = context.options?.[0] || {}; const isMaxLen = (node = getArrowRoot()) => getTokensLength(node) > maxLen; const isMultiline = (node = arrowBody) => { return node.loc.start.line !== node.loc.end.line; }; const isObjectLiteral = (node = arrowBody) => { return node.type === import_utils3.AST_NODE_TYPES.ObjectExpression; }; const isJsxElement = (node = arrowBody) => { return node.type === import_utils3.AST_NODE_TYPES.JSXElement || node.type === import_utils3.AST_NODE_TYPES.JSXFragment; }; const isNamedExport = () => { return arrowFunctionParent.parent?.parent?.type === import_utils3.AST_NODE_TYPES.ExportNamedDeclaration; }; const isCallExpression = (node) => { return node?.type === import_utils3.AST_NODE_TYPES.CallExpression; }; const isVariableDeclaration = (node) => { return node?.type === import_utils3.AST_NODE_TYPES.VariableDeclaration; }; const getArrowVariableDeclaration = () => { return isVariableDeclaration(arrowFunctionParent.parent) ? arrowFunctionParent.parent : void 0; }; const getArrowRoot = () => { return isCallExpression(arrowFunctionParent) ? arrowFunction : getArrowVariableDeclaration() || arrowFunctionParent; }; const getLength = (node) => { return node.loc.end.column - node.loc.start.column; }; const getTokensLength = (node = getArrowRoot()) => { const tokens = sourceCode.getTokens(node); const implicitReturnTokens = tokens.filter(import_utils3.ASTUtils.isNotOpeningBraceToken).filter((x) => !(x.type === import_utils3.AST_TOKEN_TYPES.Keyword && x.value === "return")).filter(import_utils3.ASTUtils.isNotClosingBraceToken).filter(import_utils3.ASTUtils.isNotSemicolonToken); const length = implicitReturnTokens.reduce((acc, token) => acc + getLength(token), 0); return length; }; const getArrowToken = () => { const tokens = sourceCode.getTokens(arrowFunction); const arrowToken = tokens.find(import_utils3.ASTUtils.isArrowToken); return arrowToken; }; const commentsExistBetweenArrowTokenAndArrowBody = () => { const arrowToken = getArrowToken(); return arrowToken && sourceCode.commentsExistBetween(arrowToken, arrowBody); }; if (arrowBody.type === import_utils3.AST_NODE_TYPES.BlockStatement) { const blockBody = arrowBody.body; if (blockBody.length === 1 && blockBody[0].type === import_utils3.AST_NODE_TYPES.ReturnStatement) { const returnStatement = blockBody[0]; const returnValue = returnStatement.argument; if (!returnValue) return; if (isMaxLen()) return; if (isMaxLen(returnValue)) return; if (isMultiline(returnValue)) return; if (jsxAlwaysUseExplicitReturn && isJsxElement(returnValue)) return; if (namedExportsAlwaysUseExplicitReturn && isNamedExport()) return; const openingBrace = sourceCode.getFirstToken(arrowBody); const closingBrace = sourceCode.getLastToken(arrowBody); const firstToken = sourceCode.getFirstToken(returnStatement, 1); const lastToken = sourceCode.getLastToken(returnStatement); const commentsExist = sourceCode.commentsExistBetween(openingBrace, firstToken) || sourceCode.commentsExistBetween(lastToken, closingBrace); if (commentsExist) return; context.report({ fix: (fixer) => { const fixes = []; const returnText = sourceCode.getText(returnValue); fixes.push( fixer.remove(openingBrace), fixer.remove(closingBrace), fixer.replaceText(returnStatement, isObjectLiteral(returnValue) ? `(${returnText})` : returnText) ); return fixes; }, messageId: "useImplicitReturn", node: arrowFunction }); } } else { const commentsExist = commentsExistBetweenArrowTokenAndArrowBody(); if ( // commentsExist || isMaxLen() || isMultiline() || jsxAlwaysUseExplicitReturn && isJsxElement() || namedExportsAlwaysUseExplicitReturn && isNamedExport() ) { context.report({ fix: (fixer) => { const fixes = []; const firstToken = sourceCode.getTokenBefore(arrowBody); const lastToken = sourceCode.getTokenAfter(arrowBody); if (firstToken && lastToken && import_utils3.ASTUtils.isOpeningParenToken(firstToken) && import_utils3.ASTUtils.isClosingParenToken(lastToken)) fixes.push(fixer.remove(firstToken), fixer.remove(lastToken)); if (commentsExist) { const arrowToken = getArrowToken(); fixes.push( fixer.insertTextAfter(arrowToken, " {"), fixer.insertTextBefore(arrowBody, "return "), fixer.insertTextAfter(arrowBody, "\n}") ); } else { fixes.push(fixer.replaceText(arrowBody, `{ return ${sourceCode.getText(arrowBody)} }`)); } return fixes; }, messageId: "useExplicitReturn", node: arrowFunction }); } } } }; }, defaultOptions: [ { jsxAlwaysUseExplicitReturn: false, maxLen: 80, namedExportsAlwaysUseExplicitReturn: true } ], meta: { docs: { description: "Enforce arrow function return style" }, fixable: "code", messages: { useExplicitReturn: "Use explicit return for multiline arrow function bodies.", useImplicitReturn: "Use implicit return for single-line arrow function bodies." }, schema: [ { additionalProperties: true, properties: { jsxAlwaysUseExplicitReturn: { default: false, type: "boolean" }, maxLen: { default: 80, type: "number" }, namedExportsAlwaysUseExplicitReturn: { default: true, type: "boolean" } }, type: "object" } ], type: "suggestion" }, name: RULE_NAME }); // src/rules/no-export-default-arrow.ts var import_node_path = __toESM(require("path")); var import_utils4 = require("@typescript-eslint/utils"); var import_scule = require("scule"); var RULE_NAME2 = "no-export-default-arrow"; var noExportDefaultArrowRule = createRule({ create: (context) => { const sourceCode = context.getSourceCode(); let program; return { ArrowFunctionExpression: (arrowFunction) => { const { body: arrowBody, parent: arrowFunctionParent } = arrowFunction; const isJsxElement = (node) => { return node.type === import_utils4.AST_NODE_TYPES.JSXElement || node.type === import_utils4.AST_NODE_TYPES.JSXFragment; }; const getArrowReturnValues = () => { if (arrowBody.type === import_utils4.AST_NODE_TYPES.BlockStatement) { const blockBody = arrowBody.body; const returnValues = blockBody.filter((node) => { return node.type === import_utils4.AST_NODE_TYPES.ReturnStatement; }).map((node) => node.argument).filter(Boolean); return returnValues; } return [arrowBody]; }; const arrowReturnIsJsxElement = () => { const returnValues = getArrowReturnValues(); return returnValues.some((node) => isJsxElement(node)); }; if (arrowFunctionParent.type === import_utils4.AST_NODE_TYPES.ExportDefaultDeclaration) { context.report({ fix: (fixer) => { const fixes = []; const lastToken = sourceCode.getLastToken(program, { includeComments: true }) || arrowFunctionParent; const fileName = context.getPhysicalFilename?.() || context.getFilename() || "namedFunction"; const { name: fileNameWithoutExtension } = import_node_path.default.parse(fileName); const funcName = arrowReturnIsJsxElement() ? (0, import_scule.pascalCase)(fileNameWithoutExtension) : (0, import_scule.camelCase)(fileNameWithoutExtension); fixes.push( fixer.replaceText(arrowFunctionParent, `const ${funcName} = ${sourceCode.getText(arrowFunction)}`), fixer.insertTextAfter(lastToken, ` export default ${funcName}`) ); return fixes; }, messageId: "disallowExportDefaultArrow", node: arrowFunction }); } }, Program: (node) => program = node }; }, defaultOptions: [], meta: { docs: { description: "Disallow export default anonymous arrow function<br/>_**Automatically fix using the current file name.**_" }, fixable: "code", messages: { disallowExportDefaultArrow: "Disallow export default anonymous arrow function" }, schema: [], type: "suggestion" }, name: RULE_NAME2 }); // src/index.ts var src_default = definePlugin({ configs: { recommended: recommended_default }, meta: { name, version }, rules: { [RULE_NAME]: arrowReturnStyleRule, [RULE_NAME2]: noExportDefaultArrowRule } }); // fix-cjs-exports if (module.exports.default) { Object.assign(module.exports.default, module.exports); module.exports = module.exports.default; delete module.exports.default; }