eslint-plugin-arrow-return-style
Version:
Enforce arrow function return style and automatically fix it
310 lines (298 loc) • 12.6 kB
JavaScript
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;
}
;