123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- "use strict";
- const astUtils = require("./utils/ast-utils");
- module.exports = {
- meta: {
- deprecated: true,
- replacedBy: [],
- type: "layout",
- docs: {
- description: "Enforce consistent line breaks inside function parentheses",
- recommended: false,
- url: "https://eslint.org/docs/latest/rules/function-paren-newline"
- },
- fixable: "whitespace",
- schema: [
- {
- oneOf: [
- {
- enum: ["always", "never", "consistent", "multiline", "multiline-arguments"]
- },
- {
- type: "object",
- properties: {
- minItems: {
- type: "integer",
- minimum: 0
- }
- },
- additionalProperties: false
- }
- ]
- }
- ],
- messages: {
- expectedBefore: "Expected newline before ')'.",
- expectedAfter: "Expected newline after '('.",
- expectedBetween: "Expected newline between arguments/params.",
- unexpectedBefore: "Unexpected newline before ')'.",
- unexpectedAfter: "Unexpected newline after '('."
- }
- },
- create(context) {
- const sourceCode = context.sourceCode;
- const rawOption = context.options[0] || "multiline";
- const multilineOption = rawOption === "multiline";
- const multilineArgumentsOption = rawOption === "multiline-arguments";
- const consistentOption = rawOption === "consistent";
- let minItems;
- if (typeof rawOption === "object") {
- minItems = rawOption.minItems;
- } else if (rawOption === "always") {
- minItems = 0;
- } else if (rawOption === "never") {
- minItems = Infinity;
- } else {
- minItems = null;
- }
-
-
-
-
- function shouldHaveNewlines(elements, hasLeftNewline) {
- if (multilineArgumentsOption && elements.length === 1) {
- return hasLeftNewline;
- }
- if (multilineOption || multilineArgumentsOption) {
- return elements.some((element, index) => index !== elements.length - 1 && element.loc.end.line !== elements[index + 1].loc.start.line);
- }
- if (consistentOption) {
- return hasLeftNewline;
- }
- return elements.length >= minItems;
- }
-
- function validateParens(parens, elements) {
- const leftParen = parens.leftParen;
- const rightParen = parens.rightParen;
- const tokenAfterLeftParen = sourceCode.getTokenAfter(leftParen);
- const tokenBeforeRightParen = sourceCode.getTokenBefore(rightParen);
- const hasLeftNewline = !astUtils.isTokenOnSameLine(leftParen, tokenAfterLeftParen);
- const hasRightNewline = !astUtils.isTokenOnSameLine(tokenBeforeRightParen, rightParen);
- const needsNewlines = shouldHaveNewlines(elements, hasLeftNewline);
- if (hasLeftNewline && !needsNewlines) {
- context.report({
- node: leftParen,
- messageId: "unexpectedAfter",
- fix(fixer) {
- return sourceCode.getText().slice(leftParen.range[1], tokenAfterLeftParen.range[0]).trim()
-
- ? null
- : fixer.removeRange([leftParen.range[1], tokenAfterLeftParen.range[0]]);
- }
- });
- } else if (!hasLeftNewline && needsNewlines) {
- context.report({
- node: leftParen,
- messageId: "expectedAfter",
- fix: fixer => fixer.insertTextAfter(leftParen, "\n")
- });
- }
- if (hasRightNewline && !needsNewlines) {
- context.report({
- node: rightParen,
- messageId: "unexpectedBefore",
- fix(fixer) {
- return sourceCode.getText().slice(tokenBeforeRightParen.range[1], rightParen.range[0]).trim()
-
- ? null
- : fixer.removeRange([tokenBeforeRightParen.range[1], rightParen.range[0]]);
- }
- });
- } else if (!hasRightNewline && needsNewlines) {
- context.report({
- node: rightParen,
- messageId: "expectedBefore",
- fix: fixer => fixer.insertTextBefore(rightParen, "\n")
- });
- }
- }
-
- function validateArguments(parens, elements) {
- const leftParen = parens.leftParen;
- const tokenAfterLeftParen = sourceCode.getTokenAfter(leftParen);
- const hasLeftNewline = !astUtils.isTokenOnSameLine(leftParen, tokenAfterLeftParen);
- const needsNewlines = shouldHaveNewlines(elements, hasLeftNewline);
- for (let i = 0; i <= elements.length - 2; i++) {
- const currentElement = elements[i];
- const nextElement = elements[i + 1];
- const hasNewLine = currentElement.loc.end.line !== nextElement.loc.start.line;
- if (!hasNewLine && needsNewlines) {
- context.report({
- node: currentElement,
- messageId: "expectedBetween",
- fix: fixer => fixer.insertTextBefore(nextElement, "\n")
- });
- }
- }
- }
-
- function getParenTokens(node) {
- switch (node.type) {
- case "NewExpression":
- if (!node.arguments.length &&
- !(
- astUtils.isOpeningParenToken(sourceCode.getLastToken(node, { skip: 1 })) &&
- astUtils.isClosingParenToken(sourceCode.getLastToken(node)) &&
- node.callee.range[1] < node.range[1]
- )
- ) {
-
- return null;
- }
-
- case "CallExpression":
- return {
- leftParen: sourceCode.getTokenAfter(node.callee, astUtils.isOpeningParenToken),
- rightParen: sourceCode.getLastToken(node)
- };
- case "FunctionDeclaration":
- case "FunctionExpression": {
- const leftParen = sourceCode.getFirstToken(node, astUtils.isOpeningParenToken);
- const rightParen = node.params.length
- ? sourceCode.getTokenAfter(node.params.at(-1), astUtils.isClosingParenToken)
- : sourceCode.getTokenAfter(leftParen);
- return { leftParen, rightParen };
- }
- case "ArrowFunctionExpression": {
- const firstToken = sourceCode.getFirstToken(node, { skip: (node.async ? 1 : 0) });
- if (!astUtils.isOpeningParenToken(firstToken)) {
-
- return null;
- }
- const rightParen = node.params.length
- ? sourceCode.getTokenAfter(node.params.at(-1), astUtils.isClosingParenToken)
- : sourceCode.getTokenAfter(firstToken);
- return {
- leftParen: firstToken,
- rightParen
- };
- }
- case "ImportExpression": {
- const leftParen = sourceCode.getFirstToken(node, 1);
- const rightParen = sourceCode.getLastToken(node);
- return { leftParen, rightParen };
- }
- default:
- throw new TypeError(`unexpected node with type ${node.type}`);
- }
- }
-
-
-
- return {
- [[
- "ArrowFunctionExpression",
- "CallExpression",
- "FunctionDeclaration",
- "FunctionExpression",
- "ImportExpression",
- "NewExpression"
- ]](node) {
- const parens = getParenTokens(node);
- let params;
- if (node.type === "ImportExpression") {
- params = [node.source];
- } else if (astUtils.isFunction(node)) {
- params = node.params;
- } else {
- params = node.arguments;
- }
- if (parens) {
- validateParens(parens, params);
- if (multilineArgumentsOption) {
- validateArguments(parens, params);
- }
- }
- }
- };
- }
- };
|