94 lines
2.8 KiB
Plaintext
94 lines
2.8 KiB
Plaintext
'use strict';
|
|
|
|
var utils = require('../utils.js');
|
|
require('eslint-visitor-keys');
|
|
require('espree');
|
|
require('estraverse');
|
|
|
|
const messages = {
|
|
onOwnLine: "Closing tag of a multiline JSX expression must be on its own line.",
|
|
matchIndent: "Expected closing tag to match indentation of opening.",
|
|
alignWithOpening: "Expected closing tag to be aligned with the line containing the opening tag"
|
|
};
|
|
const DEFAULT_LOCATION = "tag-aligned";
|
|
const MESSAGE_LOCATION = {
|
|
"tag-aligned": "matchIndent",
|
|
"line-aligned": "alignWithOpening"
|
|
};
|
|
var jsxClosingTagLocation = utils.createRule({
|
|
name: "jsx-closing-tag-location",
|
|
package: "jsx",
|
|
meta: {
|
|
type: "layout",
|
|
docs: {
|
|
description: "Enforce closing tag location for multiline JSX"
|
|
},
|
|
fixable: "whitespace",
|
|
messages,
|
|
schema: [{
|
|
anyOf: [
|
|
{
|
|
type: "string",
|
|
enum: ["tag-aligned", "line-aligned"],
|
|
default: DEFAULT_LOCATION
|
|
}
|
|
]
|
|
}]
|
|
},
|
|
defaultOptions: [
|
|
DEFAULT_LOCATION
|
|
],
|
|
create(context) {
|
|
const option = context.options[0] || DEFAULT_LOCATION;
|
|
function getIndentation(openingStartOfLine, opening) {
|
|
if (option === "line-aligned")
|
|
return openingStartOfLine.column;
|
|
else
|
|
return opening.loc.start.column;
|
|
}
|
|
function handleClosingElement(node) {
|
|
if (!node.parent)
|
|
return;
|
|
const sourceCode = context.sourceCode;
|
|
const opening = "openingFragment" in node.parent ? node.parent.openingFragment : node.parent.openingElement;
|
|
const openingLoc = sourceCode.getFirstToken(opening).loc.start;
|
|
const openingLine = sourceCode.lines[openingLoc.line - 1];
|
|
const openingStartOfLine = {
|
|
column: /^\s*/.exec(openingLine)?.[0].length,
|
|
line: openingLoc.line
|
|
};
|
|
if (opening.loc.start.line === node.loc.start.line)
|
|
return;
|
|
if (opening.loc.start.column === node.loc.start.column && option === "tag-aligned") {
|
|
return;
|
|
}
|
|
if (openingStartOfLine.column === node.loc.start.column && option === "line-aligned") {
|
|
return;
|
|
}
|
|
const messageId = utils.isNodeFirstInLine(context, node) ? MESSAGE_LOCATION[option] : "onOwnLine";
|
|
context.report({
|
|
node,
|
|
messageId,
|
|
loc: node.loc,
|
|
fix(fixer) {
|
|
const indent = new Array((getIndentation(openingStartOfLine, opening) || 0) + 1).join(" ");
|
|
if (utils.isNodeFirstInLine(context, node)) {
|
|
return fixer.replaceTextRange(
|
|
[node.range[0] - node.loc.start.column, node.range[0]],
|
|
indent
|
|
);
|
|
}
|
|
return fixer.insertTextBefore(node, `
|
|
${indent}`);
|
|
}
|
|
});
|
|
}
|
|
return {
|
|
JSXClosingElement: handleClosingElement,
|
|
JSXClosingFragment: handleClosingElement
|
|
};
|
|
}
|
|
});
|
|
|
|
module.exports = jsxClosingTagLocation;
|