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) Canceled after 0s
268 lines
8.3 KiB
Plaintext
268 lines
8.3 KiB
Plaintext
import { K as isSingleLine, M as getTokenBeforeClosingBracket, f as createRule, g as import_ast_utils } from "../utils.js";
|
|
function validateClosingSlash(context, node, option) {
|
|
const sourceCode = context.sourceCode;
|
|
let adjacent;
|
|
if ("selfClosing" in node && node.selfClosing) {
|
|
const lastTokens = sourceCode.getLastTokens(node, 2);
|
|
adjacent = !sourceCode.isSpaceBetween(lastTokens[0], lastTokens[1]);
|
|
if (option === "never") {
|
|
if (!adjacent) context.report({
|
|
node,
|
|
messageId: "selfCloseSlashNoSpace",
|
|
loc: {
|
|
start: lastTokens[0].loc.start,
|
|
end: lastTokens[1].loc.end
|
|
},
|
|
fix(fixer) {
|
|
return fixer.removeRange([lastTokens[0].range[1], lastTokens[1].range[0]]);
|
|
}
|
|
});
|
|
} else if (option === "always" && adjacent) context.report({
|
|
node,
|
|
messageId: "selfCloseSlashNeedSpace",
|
|
loc: {
|
|
start: lastTokens[0].loc.start,
|
|
end: lastTokens[1].loc.end
|
|
},
|
|
fix(fixer) {
|
|
return fixer.insertTextBefore(lastTokens[1], " ");
|
|
}
|
|
});
|
|
} else {
|
|
const firstTokens = sourceCode.getFirstTokens(node, 2);
|
|
adjacent = !sourceCode.isSpaceBetween(firstTokens[0], firstTokens[1]);
|
|
if (option === "never") {
|
|
if (!adjacent) context.report({
|
|
node,
|
|
messageId: "closeSlashNoSpace",
|
|
loc: {
|
|
start: firstTokens[0].loc.start,
|
|
end: firstTokens[1].loc.end
|
|
},
|
|
fix(fixer) {
|
|
return fixer.removeRange([firstTokens[0].range[1], firstTokens[1].range[0]]);
|
|
}
|
|
});
|
|
} else if (option === "always" && adjacent) context.report({
|
|
node,
|
|
messageId: "closeSlashNeedSpace",
|
|
loc: {
|
|
start: firstTokens[0].loc.start,
|
|
end: firstTokens[1].loc.end
|
|
},
|
|
fix(fixer) {
|
|
return fixer.insertTextBefore(firstTokens[1], " ");
|
|
}
|
|
});
|
|
}
|
|
}
|
|
function validateBeforeSelfClosing(context, node, option) {
|
|
const sourceCode = context.sourceCode;
|
|
const leftToken = getTokenBeforeClosingBracket(node);
|
|
const closingSlash = sourceCode.getTokenAfter(leftToken);
|
|
if (!isSingleLine(node) && option === "proportional-always") {
|
|
if ((0, import_ast_utils.isTokenOnSameLine)(leftToken, closingSlash)) {
|
|
context.report({
|
|
node,
|
|
messageId: "beforeSelfCloseNeedNewline",
|
|
loc: leftToken.loc.end,
|
|
fix(fixer) {
|
|
return fixer.insertTextBefore(closingSlash, "\n");
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
}
|
|
if (!(0, import_ast_utils.isTokenOnSameLine)(leftToken, closingSlash)) return;
|
|
const adjacent = !sourceCode.isSpaceBetween(leftToken, closingSlash);
|
|
if ((option === "always" || option === "proportional-always") && adjacent) context.report({
|
|
node,
|
|
messageId: "beforeSelfCloseNeedSpace",
|
|
loc: closingSlash.loc.start,
|
|
fix(fixer) {
|
|
return fixer.insertTextBefore(closingSlash, " ");
|
|
}
|
|
});
|
|
else if (option === "never" && !adjacent) context.report({
|
|
node,
|
|
messageId: "beforeSelfCloseNoSpace",
|
|
loc: closingSlash.loc.start,
|
|
fix(fixer) {
|
|
const previousToken = sourceCode.getTokenBefore(closingSlash);
|
|
return fixer.removeRange([previousToken.range[1], closingSlash.range[0]]);
|
|
}
|
|
});
|
|
}
|
|
function validateAfterOpening(context, node, option) {
|
|
const sourceCode = context.sourceCode;
|
|
const openingToken = sourceCode.getTokenBefore(node.name);
|
|
if (option === "allow-multiline") {
|
|
if (openingToken.loc.start.line !== node.name.loc.start.line) return;
|
|
}
|
|
const adjacent = !sourceCode.isSpaceBetween(openingToken, node.name);
|
|
if (option === "never" || option === "allow-multiline") {
|
|
if (!adjacent) context.report({
|
|
node,
|
|
messageId: "afterOpenNoSpace",
|
|
loc: {
|
|
start: openingToken.loc.start,
|
|
end: node.name.loc.start
|
|
},
|
|
fix(fixer) {
|
|
return fixer.removeRange([openingToken.range[1], node.name.range[0]]);
|
|
}
|
|
});
|
|
} else if (option === "always" && adjacent) context.report({
|
|
node,
|
|
messageId: "afterOpenNeedSpace",
|
|
loc: {
|
|
start: openingToken.loc.start,
|
|
end: node.name.loc.start
|
|
},
|
|
fix(fixer) {
|
|
return fixer.insertTextBefore(node.name, " ");
|
|
}
|
|
});
|
|
}
|
|
function validateBeforeClosing(context, node, option) {
|
|
if (!("selfClosing" in node && node.selfClosing)) {
|
|
const sourceCode = context.sourceCode;
|
|
const leftToken = option === "proportional-always" ? getTokenBeforeClosingBracket(node) : sourceCode.getLastTokens(node, 2)[0];
|
|
const closingToken = sourceCode.getTokenAfter(leftToken);
|
|
if (!isSingleLine(node) && option === "proportional-always") {
|
|
if ((0, import_ast_utils.isTokenOnSameLine)(leftToken, closingToken)) {
|
|
context.report({
|
|
node,
|
|
messageId: "beforeCloseNeedNewline",
|
|
loc: leftToken.loc.end,
|
|
fix(fixer) {
|
|
return fixer.insertTextBefore(closingToken, "\n");
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
}
|
|
if (leftToken.loc.start.line !== closingToken.loc.start.line) return;
|
|
const adjacent = !sourceCode.isSpaceBetween(leftToken, closingToken);
|
|
if (option === "never" && !adjacent) context.report({
|
|
node,
|
|
messageId: "beforeCloseNoSpace",
|
|
loc: {
|
|
start: leftToken.loc.end,
|
|
end: closingToken.loc.start
|
|
},
|
|
fix(fixer) {
|
|
return fixer.removeRange([leftToken.range[1], closingToken.range[0]]);
|
|
}
|
|
});
|
|
else if (option === "always" && adjacent) context.report({
|
|
node,
|
|
loc: {
|
|
start: leftToken.loc.end,
|
|
end: closingToken.loc.start
|
|
},
|
|
messageId: "beforeCloseNeedSpace",
|
|
fix(fixer) {
|
|
return fixer.insertTextBefore(closingToken, " ");
|
|
}
|
|
});
|
|
else if (option === "proportional-always" && node.type === "JSXOpeningElement" && adjacent !== isSingleLine(node)) context.report({
|
|
node,
|
|
messageId: "beforeCloseNeedSpace",
|
|
loc: {
|
|
start: leftToken.loc.end,
|
|
end: closingToken.loc.start
|
|
},
|
|
fix(fixer) {
|
|
return fixer.insertTextBefore(closingToken, " ");
|
|
}
|
|
});
|
|
}
|
|
}
|
|
var jsx_tag_spacing_default = createRule({
|
|
name: "jsx-tag-spacing",
|
|
meta: {
|
|
type: "layout",
|
|
docs: { description: "Enforce whitespace in and around the JSX opening and closing brackets" },
|
|
fixable: "whitespace",
|
|
schema: [{
|
|
type: "object",
|
|
properties: {
|
|
closingSlash: {
|
|
type: "string",
|
|
enum: [
|
|
"always",
|
|
"never",
|
|
"allow"
|
|
]
|
|
},
|
|
beforeSelfClosing: {
|
|
type: "string",
|
|
enum: [
|
|
"always",
|
|
"proportional-always",
|
|
"never",
|
|
"allow"
|
|
]
|
|
},
|
|
afterOpening: {
|
|
type: "string",
|
|
enum: [
|
|
"always",
|
|
"allow-multiline",
|
|
"never",
|
|
"allow"
|
|
]
|
|
},
|
|
beforeClosing: {
|
|
type: "string",
|
|
enum: [
|
|
"always",
|
|
"proportional-always",
|
|
"never",
|
|
"allow"
|
|
]
|
|
}
|
|
},
|
|
additionalProperties: false
|
|
}],
|
|
defaultOptions: [{
|
|
closingSlash: "never",
|
|
beforeSelfClosing: "always",
|
|
afterOpening: "never",
|
|
beforeClosing: "allow"
|
|
}],
|
|
messages: {
|
|
selfCloseSlashNoSpace: "Whitespace is forbidden between `/` and `>`; write `/>`",
|
|
selfCloseSlashNeedSpace: "Whitespace is required between `/` and `>`; write `/ >`",
|
|
closeSlashNoSpace: "Whitespace is forbidden between `<` and `/`; write `</`",
|
|
closeSlashNeedSpace: "Whitespace is required between `<` and `/`; write `< /`",
|
|
beforeSelfCloseNoSpace: "A space is forbidden before closing bracket",
|
|
beforeSelfCloseNeedSpace: "A space is required before closing bracket",
|
|
beforeSelfCloseNeedNewline: "A newline is required before closing bracket",
|
|
afterOpenNoSpace: "A space is forbidden after opening bracket",
|
|
afterOpenNeedSpace: "A space is required after opening bracket",
|
|
beforeCloseNoSpace: "A space is forbidden before closing bracket",
|
|
beforeCloseNeedSpace: "Whitespace is required before closing bracket",
|
|
beforeCloseNeedNewline: "A newline is required before closing bracket"
|
|
}
|
|
},
|
|
create(context, [options]) {
|
|
const { closingSlash, beforeSelfClosing, afterOpening, beforeClosing } = options;
|
|
return {
|
|
JSXOpeningElement(node) {
|
|
if (closingSlash !== "allow" && node.selfClosing) validateClosingSlash(context, node, closingSlash);
|
|
if (afterOpening !== "allow") validateAfterOpening(context, node, afterOpening);
|
|
if (beforeSelfClosing !== "allow" && node.selfClosing) validateBeforeSelfClosing(context, node, beforeSelfClosing);
|
|
if (beforeClosing !== "allow") validateBeforeClosing(context, node, beforeClosing);
|
|
},
|
|
JSXClosingElement(node) {
|
|
if (afterOpening !== "allow") validateAfterOpening(context, node, afterOpening);
|
|
if (closingSlash !== "allow") validateClosingSlash(context, node, closingSlash);
|
|
if (beforeClosing !== "allow") validateBeforeClosing(context, node, beforeClosing);
|
|
}
|
|
};
|
|
}
|
|
});
|
|
export { jsx_tag_spacing_default as t };
|