Files
2026-08-20 14:36:47 +00:00

122 lines
3.9 KiB
TypeScript

import assert from "node:assert";
import type { Comment, Plugin, Rule } from "#oxlint/plugins";
function formatComments(comments: Comment[]): string {
let text = `${comments.length} comment${comments.length === 1 ? "" : "s"}`;
if (comments.length > 0) {
text += "\n";
text += comments
.map(
(c, i) =>
` [${i}] ${c.type}: ${JSON.stringify(c.value)} at [${c.range[0]}, ${c.range[1]}]`,
)
.join("\n");
}
return text;
}
const testCommentsRule: Rule = {
create(context) {
const { sourceCode } = context;
const { ast } = sourceCode;
const comments = sourceCode.getAllComments();
for (const comment of comments) {
// Check getting `range` / `loc` properties twice results in same objects
const { range, loc } = comment;
assert(comment.range === range);
assert(comment.loc === loc);
// Cloning comment with spread should include `loc` and it should be the same object
const clone = { ...comment };
assert(Object.hasOwn(clone, "loc"));
assert(clone.loc === loc);
// Check `getRange` and `getLoc` return the same objects too
assert(sourceCode.getRange(comment) === range);
assert(sourceCode.getLoc(comment) === loc);
// Check comment can be converted to a string without an error
// oxlint-disable-next-line typescript/no-base-to-string, typescript/restrict-template-expressions
assert.equal(`${comment}`, "[object Object]");
}
context.report({
message: `getAllComments: ${formatComments(comments)}`,
node: ast,
});
// Check `JSON.stringify` on comments includes `loc`
const firstComment = comments[0];
if (firstComment) {
context.report({
message: `Comment JSON.stringify:\n${JSON.stringify(firstComment, null, 2)}`,
node: firstComment,
});
}
const [, topLevelVariable2, topLevelFunctionExport] = ast.body;
assert(topLevelFunctionExport.type === "ExportNamedDeclaration");
const topLevelFunction = topLevelFunctionExport.declaration;
assert(topLevelFunction?.type === "FunctionDeclaration");
context.report({
message:
"commentsExistBetween(topLevelVariable2, topLevelFunction): "
+ sourceCode.commentsExistBetween(topLevelVariable2, topLevelFunction),
node: topLevelVariable2,
});
// Test `commentsExistBetween` returns `false` when start node is after end node
context.report({
message:
"commentsExistBetween(topLevelFunction, topLevelVariable2): "
+ sourceCode.commentsExistBetween(topLevelFunction, topLevelVariable2),
node: topLevelFunction,
});
return {
VariableDeclaration(node) {
const { declarations } = node;
assert(declarations.length >= 1);
const { id, init } = declarations[0];
assert(id.type === "Identifier");
assert(init !== null);
context.report({
message:
`VariableDeclaration(${id.name}):\n`
+ `getCommentsBefore: ${formatComments(sourceCode.getCommentsBefore(node))}\n`
+ `getCommentsInside: ${formatComments(sourceCode.getCommentsInside(node))}\n`
+ `getCommentsAfter: ${formatComments(sourceCode.getCommentsAfter(node))}\n`
+ `commentsExistBetween(id, init): ${sourceCode.commentsExistBetween(id, init)}`,
node,
});
},
FunctionDeclaration(node) {
context.report({
message:
`FunctionDeclaration(${node.id?.name}):\n`
+ `getCommentsBefore: ${formatComments(sourceCode.getCommentsBefore(node))}\n`
+ `getCommentsInside: ${formatComments(sourceCode.getCommentsInside(node))}\n`
+ `getCommentsAfter: ${formatComments(sourceCode.getCommentsAfter(node))}`,
node,
});
},
};
},
};
const plugin: Plugin = {
meta: {
name: "test-comments",
},
rules: {
"test-comments": testCommentsRule,
},
};
export default plugin;