Dev Build / cleanup (push) Canceled after 0s
Dev Build / typecheck (push) Canceled after 0s
Dev Build / build (linux-arm64, ubuntu-24.04-arm, linux-arm64) (push) Canceled after 0s
Dev Build / build (linux-x64, ubuntu-latest, linux-x64) (push) Canceled after 0s
Dev Build / build (win-x64, windows-latest, win32-x64) (push) Canceled after 0s
Dev Build / dispatch-dev-docker (push) Skipped
229 lines
6.6 KiB
Plaintext
229 lines
6.6 KiB
Plaintext
import { K as isSingleLine, f as createRule, g as import_ast_utils, o as isJSX } from "../utils.js";
|
|
var jsx_wrap_multilines_default = createRule({
|
|
name: "jsx-wrap-multilines",
|
|
meta: {
|
|
type: "layout",
|
|
docs: { description: "Disallow missing parentheses around multiline JSX" },
|
|
fixable: "code",
|
|
schema: [{
|
|
type: "object",
|
|
properties: {
|
|
declaration: {
|
|
type: ["string", "boolean"],
|
|
enum: [
|
|
true,
|
|
false,
|
|
"ignore",
|
|
"parens",
|
|
"parens-new-line"
|
|
]
|
|
},
|
|
assignment: {
|
|
type: ["string", "boolean"],
|
|
enum: [
|
|
true,
|
|
false,
|
|
"ignore",
|
|
"parens",
|
|
"parens-new-line"
|
|
]
|
|
},
|
|
return: {
|
|
type: ["string", "boolean"],
|
|
enum: [
|
|
true,
|
|
false,
|
|
"ignore",
|
|
"parens",
|
|
"parens-new-line"
|
|
]
|
|
},
|
|
arrow: {
|
|
type: ["string", "boolean"],
|
|
enum: [
|
|
true,
|
|
false,
|
|
"ignore",
|
|
"parens",
|
|
"parens-new-line"
|
|
]
|
|
},
|
|
condition: {
|
|
type: ["string", "boolean"],
|
|
enum: [
|
|
true,
|
|
false,
|
|
"ignore",
|
|
"parens",
|
|
"parens-new-line"
|
|
]
|
|
},
|
|
logical: {
|
|
type: ["string", "boolean"],
|
|
enum: [
|
|
true,
|
|
false,
|
|
"ignore",
|
|
"parens",
|
|
"parens-new-line"
|
|
]
|
|
},
|
|
prop: {
|
|
type: ["string", "boolean"],
|
|
enum: [
|
|
true,
|
|
false,
|
|
"ignore",
|
|
"parens",
|
|
"parens-new-line"
|
|
]
|
|
},
|
|
propertyValue: {
|
|
type: ["string", "boolean"],
|
|
enum: [
|
|
true,
|
|
false,
|
|
"ignore",
|
|
"parens",
|
|
"parens-new-line"
|
|
]
|
|
}
|
|
},
|
|
additionalProperties: false
|
|
}],
|
|
defaultOptions: [{
|
|
declaration: "parens",
|
|
assignment: "parens",
|
|
return: "parens",
|
|
arrow: "parens",
|
|
condition: "ignore",
|
|
logical: "ignore",
|
|
prop: "ignore",
|
|
propertyValue: "ignore"
|
|
}],
|
|
messages: {
|
|
missingParens: "Missing parentheses around multilines JSX",
|
|
parensOnNewLines: "Parentheses around JSX should be on separate lines"
|
|
}
|
|
},
|
|
create(context, [options]) {
|
|
function isEnabled(type) {
|
|
const option = options[type];
|
|
return option && option !== "ignore";
|
|
}
|
|
const { sourceCode } = context;
|
|
function needsOpeningNewLine(node) {
|
|
const previousToken = sourceCode.getTokenBefore(node);
|
|
if (!(0, import_ast_utils.isParenthesized)(node, sourceCode)) return false;
|
|
if ((0, import_ast_utils.isTokenOnSameLine)(previousToken, node)) return true;
|
|
return false;
|
|
}
|
|
function needsClosingNewLine(node) {
|
|
const nextToken = sourceCode.getTokenAfter(node);
|
|
if (!(0, import_ast_utils.isParenthesized)(node, sourceCode)) return false;
|
|
if ((0, import_ast_utils.isTokenOnSameLine)(node, nextToken)) return true;
|
|
return false;
|
|
}
|
|
function trimTokenBeforeNewline(tokenBefore) {
|
|
const isBracket = tokenBefore.value === "{" || tokenBefore.value === "[";
|
|
return `${tokenBefore.value.trim()}${isBracket ? "" : " "}`;
|
|
}
|
|
function check(node, type) {
|
|
if (!node || !isJSX(node)) return;
|
|
const option = options[type];
|
|
if ((option === true || option === "parens") && !(0, import_ast_utils.isParenthesized)(node, sourceCode) && !isSingleLine(node)) context.report({
|
|
node,
|
|
messageId: "missingParens",
|
|
fix: (fixer) => fixer.replaceText(node, `(${sourceCode.getText(node)})`)
|
|
});
|
|
if (option === "parens-new-line" && !isSingleLine(node)) if (!(0, import_ast_utils.isParenthesized)(node, sourceCode)) {
|
|
const tokenBefore = sourceCode.getTokenBefore(node);
|
|
const tokenAfter = sourceCode.getTokenAfter(node);
|
|
const start = node.loc.start;
|
|
if (tokenBefore.loc.end.line < start.line) {
|
|
const textBefore = sourceCode.getText().slice(tokenBefore.range[1], node.range[0]).trim();
|
|
const isTab = /^\t/.test(sourceCode.lines[start.line - 1]);
|
|
const INDENT = isTab ? " " : " ";
|
|
const indentBefore = INDENT.repeat(start.column);
|
|
const indentAfter = INDENT.repeat(Math.max(0, start.column - (isTab ? 1 : 2)));
|
|
context.report({
|
|
node,
|
|
messageId: "missingParens",
|
|
fix: (fixer) => fixer.replaceTextRange([tokenBefore.range[0], tokenAfter && (tokenAfter.value === ";" || tokenAfter.value === "}") ? tokenAfter.range[0] : node.range[1]], `${trimTokenBeforeNewline(tokenBefore)}(\n${indentBefore}${textBefore}${textBefore.length > 0 ? `\n${indentBefore}` : ""}${sourceCode.getText(node)}\n${indentAfter})`)
|
|
});
|
|
} else context.report({
|
|
node,
|
|
messageId: "missingParens",
|
|
fix: (fixer) => fixer.replaceText(node, `(\n${sourceCode.getText(node)}\n)`)
|
|
});
|
|
} else {
|
|
const needsOpening = needsOpeningNewLine(node);
|
|
const needsClosing = needsClosingNewLine(node);
|
|
if (needsOpening || needsClosing) context.report({
|
|
node,
|
|
messageId: "parensOnNewLines",
|
|
fix: (fixer) => {
|
|
let fixed = sourceCode.getText(node);
|
|
if (needsOpening) fixed = `\n${fixed}`;
|
|
if (needsClosing) fixed = `${fixed}\n`;
|
|
return fixer.replaceText(node, fixed);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
return {
|
|
VariableDeclarator(node) {
|
|
const type = "declaration";
|
|
if (!isEnabled(type)) return;
|
|
if (!isEnabled("condition") && node.init?.type === "ConditionalExpression") {
|
|
check(node.init.consequent, type);
|
|
check(node.init.alternate, type);
|
|
return;
|
|
}
|
|
check(node.init, type);
|
|
},
|
|
AssignmentExpression(node) {
|
|
const type = "assignment";
|
|
if (!isEnabled(type)) return;
|
|
if (!isEnabled("condition") && node.right.type === "ConditionalExpression") {
|
|
check(node.right.consequent, type);
|
|
check(node.right.alternate, type);
|
|
return;
|
|
}
|
|
check(node.right, type);
|
|
},
|
|
ReturnStatement(node) {
|
|
const type = "return";
|
|
if (isEnabled(type)) check(node.argument, type);
|
|
},
|
|
"ArrowFunctionExpression:exit": (node) => {
|
|
const arrowBody = node.body;
|
|
const type = "arrow";
|
|
if (isEnabled(type) && arrowBody.type !== "BlockStatement") check(arrowBody, type);
|
|
},
|
|
ConditionalExpression(node) {
|
|
const type = "condition";
|
|
if (isEnabled(type)) {
|
|
check(node.consequent, type);
|
|
check(node.alternate, type);
|
|
}
|
|
},
|
|
LogicalExpression(node) {
|
|
const type = "logical";
|
|
if (isEnabled(type)) check(node.right, type);
|
|
},
|
|
JSXAttribute(node) {
|
|
const type = "prop";
|
|
if (isEnabled(type) && node.value?.type === "JSXExpressionContainer") check(node.value.expression, type);
|
|
},
|
|
ObjectExpression(node) {
|
|
const type = "propertyValue";
|
|
if (isEnabled(type)) node.properties.forEach((property) => {
|
|
if (property.type === "Property" && property.value.type === "JSXElement") check(property.value, type);
|
|
});
|
|
}
|
|
};
|
|
}
|
|
});
|
|
export { jsx_wrap_multilines_default as t };
|