187 lines
7.7 KiB
Plaintext
187 lines
7.7 KiB
Plaintext
import { L as isHashbangComment, f as createRule, g as import_ast_utils, h as AST_TOKEN_TYPES, m as AST_NODE_TYPES, v as COMMENTS_IGNORE_PATTERN } from "../utils.js";
|
|
function getEmptyLineNums(lines) {
|
|
const emptyLines = [];
|
|
lines.forEach((line, i) => {
|
|
if (!line.trim()) emptyLines.push(i + 1);
|
|
});
|
|
return emptyLines;
|
|
}
|
|
function getCommentLineNums(comments) {
|
|
const lines = [];
|
|
comments.forEach((token) => {
|
|
const start = token.loc.start.line;
|
|
const end = token.loc.end.line;
|
|
lines.push(start, end);
|
|
});
|
|
return lines;
|
|
}
|
|
const ALLOW_TARGETS = [
|
|
"Block",
|
|
"Class",
|
|
"Object",
|
|
"Array",
|
|
"Interface",
|
|
"Type",
|
|
"Enum",
|
|
"Module"
|
|
];
|
|
const ALLOW_NODE_TYPES = {
|
|
Block: [
|
|
AST_NODE_TYPES.ClassBody,
|
|
AST_NODE_TYPES.BlockStatement,
|
|
AST_NODE_TYPES.StaticBlock,
|
|
AST_NODE_TYPES.SwitchCase,
|
|
AST_NODE_TYPES.SwitchStatement
|
|
],
|
|
Class: [AST_NODE_TYPES.ClassBody],
|
|
Object: [AST_NODE_TYPES.ObjectExpression, AST_NODE_TYPES.ObjectPattern],
|
|
Array: [AST_NODE_TYPES.ArrayExpression, AST_NODE_TYPES.ArrayPattern],
|
|
Interface: [AST_NODE_TYPES.TSInterfaceBody],
|
|
Type: [AST_NODE_TYPES.TSTypeLiteral],
|
|
Enum: [AST_NODE_TYPES.TSEnumBody, AST_NODE_TYPES.TSEnumDeclaration],
|
|
Module: [AST_NODE_TYPES.TSModuleBlock]
|
|
};
|
|
function getAllowOptionName(target, boundary) {
|
|
return `allow${target}${boundary}`;
|
|
}
|
|
var lines_around_comment_default = createRule({
|
|
name: "lines-around-comment",
|
|
meta: {
|
|
type: "layout",
|
|
docs: { description: "Require empty lines around comments" },
|
|
fixable: "whitespace",
|
|
schema: [{
|
|
type: "object",
|
|
properties: {
|
|
beforeBlockComment: { type: "boolean" },
|
|
afterBlockComment: { type: "boolean" },
|
|
beforeLineComment: { type: "boolean" },
|
|
afterLineComment: { type: "boolean" },
|
|
...Object.fromEntries(ALLOW_TARGETS.flatMap((target) => [[getAllowOptionName(target, "Start"), { type: "boolean" }], [getAllowOptionName(target, "End"), { type: "boolean" }]])),
|
|
ignorePattern: { type: "string" },
|
|
applyDefaultIgnorePatterns: { type: "boolean" },
|
|
afterHashbangComment: { type: "boolean" }
|
|
},
|
|
additionalProperties: false
|
|
}],
|
|
defaultOptions: [{ beforeBlockComment: true }],
|
|
messages: {
|
|
after: "Expected line after comment.",
|
|
before: "Expected line before comment."
|
|
}
|
|
},
|
|
create(context, [options]) {
|
|
const normalizedOptions = options;
|
|
const defaultIgnoreRegExp = COMMENTS_IGNORE_PATTERN;
|
|
const { beforeBlockComment, afterBlockComment, beforeLineComment, afterLineComment, afterHashbangComment, applyDefaultIgnorePatterns, ignorePattern = "" } = normalizedOptions;
|
|
const customIgnoreRegExp = ignorePattern ? new RegExp(ignorePattern, "u") : null;
|
|
const sourceCode = context.sourceCode;
|
|
const comments = sourceCode.getAllComments();
|
|
const lines = sourceCode.lines;
|
|
const numLines = lines.length + 1;
|
|
const commentLines = getCommentLineNums(comments);
|
|
const emptyLines = getEmptyLineNums(lines);
|
|
const commentAndEmptyLines = new Set(commentLines.concat(emptyLines));
|
|
function codeAroundComment(token) {
|
|
let currentToken = token;
|
|
do
|
|
currentToken = sourceCode.getTokenBefore(currentToken, { includeComments: true });
|
|
while (currentToken && (0, import_ast_utils.isCommentToken)(currentToken));
|
|
if (currentToken && (0, import_ast_utils.isTokenOnSameLine)(currentToken, token)) return true;
|
|
currentToken = token;
|
|
do
|
|
currentToken = sourceCode.getTokenAfter(currentToken, { includeComments: true });
|
|
while (currentToken && (0, import_ast_utils.isCommentToken)(currentToken));
|
|
if (currentToken && (0, import_ast_utils.isTokenOnSameLine)(token, currentToken)) return true;
|
|
return false;
|
|
}
|
|
function getParentNodeOfToken(token) {
|
|
const node = sourceCode.getNodeByRangeIndex(token.range[0]);
|
|
if (node && node.type === "StaticBlock") {
|
|
const openingBrace = sourceCode.getFirstToken(node, { skip: 1 });
|
|
return openingBrace && token.range[0] >= openingBrace.range[0] ? node : null;
|
|
}
|
|
return node;
|
|
}
|
|
function isCommentAtParentStart(token, nodeTypes) {
|
|
const parent = getParentNodeOfToken(token);
|
|
if (parent && (0, import_ast_utils.isNodeOfTypes)(nodeTypes)(parent)) {
|
|
let parentStartNodeOrToken = parent;
|
|
if (parent.type === "StaticBlock") parentStartNodeOrToken = sourceCode.getFirstToken(parent, { skip: 1 });
|
|
else if (parent.type === "SwitchStatement") parentStartNodeOrToken = sourceCode.getTokenAfter(parent.discriminant, { filter: import_ast_utils.isOpeningBraceToken });
|
|
return !!parentStartNodeOrToken && token.loc.start.line - parentStartNodeOrToken.loc.start.line === 1;
|
|
}
|
|
return false;
|
|
}
|
|
function isCommentAtParentEnd(token, nodeTypes) {
|
|
const parent = getParentNodeOfToken(token);
|
|
return !!parent && (0, import_ast_utils.isNodeOfTypes)(nodeTypes)(parent) && parent.loc.end.line - token.loc.end.line === 1;
|
|
}
|
|
function isCommentAtBoundary(token, target, boundary) {
|
|
return (boundary === "Start" ? isCommentAtParentStart : isCommentAtParentEnd)(token, ALLOW_NODE_TYPES[target]);
|
|
}
|
|
function isExceptionAllowed(token, boundary) {
|
|
const blockOptionName = getAllowOptionName("Block", boundary);
|
|
const classOptionName = getAllowOptionName("Class", boundary);
|
|
if (normalizedOptions[blockOptionName] && isCommentAtBoundary(token, "Block", boundary) && !(normalizedOptions[classOptionName] === false && isCommentAtBoundary(token, "Class", boundary))) return true;
|
|
return ALLOW_TARGETS.some((target) => {
|
|
if (target === "Block") return false;
|
|
const optionName = getAllowOptionName(target, boundary);
|
|
return Boolean(normalizedOptions[optionName]) && isCommentAtBoundary(token, target, boundary);
|
|
});
|
|
}
|
|
function checkForEmptyLine(token, { before, after }) {
|
|
if (applyDefaultIgnorePatterns !== false && defaultIgnoreRegExp.test(token.value)) return;
|
|
if (customIgnoreRegExp?.test(token.value)) return;
|
|
const prevLineNum = token.loc.start.line - 1;
|
|
const nextLineNum = token.loc.end.line + 1;
|
|
if (prevLineNum < 1) before = false;
|
|
if (nextLineNum >= numLines) after = false;
|
|
if (codeAroundComment(token)) return;
|
|
const exceptionStartAllowed = isExceptionAllowed(token, "Start");
|
|
const exceptionEndAllowed = isExceptionAllowed(token, "End");
|
|
const previousTokenOrComment = sourceCode.getTokenBefore(token, { includeComments: true });
|
|
const nextTokenOrComment = sourceCode.getTokenAfter(token, { includeComments: true });
|
|
if (!exceptionStartAllowed && before && !commentAndEmptyLines.has(prevLineNum) && !((0, import_ast_utils.isCommentToken)(previousTokenOrComment) && (0, import_ast_utils.isTokenOnSameLine)(previousTokenOrComment, token))) {
|
|
const lineStart = token.range[0] - token.loc.start.column;
|
|
const range = [lineStart, lineStart];
|
|
context.report({
|
|
node: token,
|
|
messageId: "before",
|
|
fix(fixer) {
|
|
return fixer.insertTextBeforeRange(range, "\n");
|
|
}
|
|
});
|
|
}
|
|
if (!exceptionEndAllowed && after && !commentAndEmptyLines.has(nextLineNum) && !((0, import_ast_utils.isCommentToken)(nextTokenOrComment) && (0, import_ast_utils.isTokenOnSameLine)(token, nextTokenOrComment))) context.report({
|
|
node: token,
|
|
messageId: "after",
|
|
fix(fixer) {
|
|
return fixer.insertTextAfter(token, "\n");
|
|
}
|
|
});
|
|
}
|
|
return { Program() {
|
|
comments.forEach((token) => {
|
|
if (token.type === AST_TOKEN_TYPES.Line) {
|
|
if (beforeLineComment || afterLineComment) checkForEmptyLine(token, {
|
|
after: afterLineComment,
|
|
before: beforeLineComment
|
|
});
|
|
} else if (token.type === AST_TOKEN_TYPES.Block) {
|
|
if (beforeBlockComment || afterBlockComment) checkForEmptyLine(token, {
|
|
after: afterBlockComment,
|
|
before: beforeBlockComment
|
|
});
|
|
} else if (isHashbangComment(token)) {
|
|
if (afterHashbangComment) checkForEmptyLine(token, {
|
|
after: afterHashbangComment,
|
|
before: false
|
|
});
|
|
}
|
|
});
|
|
} };
|
|
}
|
|
});
|
|
export { lines_around_comment_default as t };
|