aboutsummaryrefslogtreecommitdiff
path: root/packages/iku
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-02-03 19:56:15 -0800
committerFuwn <[email protected]>2026-02-03 19:56:15 -0800
commit0dc7d010110038e50cf18c686f6de6dbf4e0cfea (patch)
tree78d5c6518f5836d13ff912808fc66f2f36cf0b05 /packages/iku
parentfeat(iku): Add comment detection with --allow-comments flag (diff)
downloadarchived-imemio-0dc7d010110038e50cf18c686f6de6dbf4e0cfea.tar.xz
archived-imemio-0dc7d010110038e50cf18c686f6de6dbf4e0cfea.zip
feat(iku): Support comment-aware whitespace checking
Diffstat (limited to 'packages/iku')
-rw-r--r--packages/iku/src/checker.ts41
1 files changed, 34 insertions, 7 deletions
diff --git a/packages/iku/src/checker.ts b/packages/iku/src/checker.ts
index 93781ec..a69a232 100644
--- a/packages/iku/src/checker.ts
+++ b/packages/iku/src/checker.ts
@@ -124,10 +124,34 @@ function countBlankLinesBetween(
return blankCount;
}
+function hasCommentBetween(
+ previousEndLine: number,
+ currentStartLine: number,
+ sourceFile: typescript.SourceFile,
+): boolean {
+ const text = sourceFile.getFullText();
+ const lines = text.split("\n");
+
+ for (let lineIndex = previousEndLine; lineIndex < currentStartLine - 1; lineIndex++) {
+ const line = lines[lineIndex];
+
+ if (line !== undefined) {
+ const trimmed = line.trim();
+
+ if (trimmed.startsWith("//") || trimmed.startsWith("/*") || trimmed.startsWith("*") || trimmed.endsWith("*/")) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
function checkStatementSpacing(
statements: StatementInfo[],
sourceFile: typescript.SourceFile,
filePath: string,
+ allowComments: boolean,
): string[] {
const errors: string[] = [];
@@ -145,9 +169,10 @@ function checkStatementSpacing(
const blankLines = countBlankLinesBetween(previous.endLine, current.startLine, sourceFile);
const sameCategory = previous.category === current.category;
+ const hasComment = hasCommentBetween(previous.endLine, current.startLine, sourceFile);
if (previous.category === "import" && current.category === "import") {
- if (blankLines > 0) {
+ if (blankLines > 0 && !(allowComments && hasComment)) {
errors.push(`${filePath}:${current.startLine}: Blank line between imports`);
}
@@ -156,7 +181,7 @@ function checkStatementSpacing(
const bothHaveBlocks = previous.hasBlock && current.hasBlock;
- if (sameCategory && !bothHaveBlocks && blankLines > 0) {
+ if (sameCategory && !bothHaveBlocks && blankLines > 0 && !(allowComments && hasComment)) {
errors.push(
`${filePath}:${current.startLine}: Unnecessary blank line between same statement types (${current.category})`,
);
@@ -168,7 +193,7 @@ function checkStatementSpacing(
);
}
- if (!sameCategory && blankLines === 0) {
+ if (!sameCategory && blankLines === 0 && !hasComment) {
errors.push(
`${filePath}:${current.startLine}: Missing blank line between different statement types (${previous.category} -> ${current.category})`,
);
@@ -183,16 +208,17 @@ function visitBlocks(
sourceFile: typescript.SourceFile,
filePath: string,
errors: string[],
+ allowComments: boolean,
): void {
if (typescript.isBlock(node)) {
const statements = getStatementsFromBlock(node, sourceFile);
- const blockErrors = checkStatementSpacing(statements, sourceFile, filePath);
+ const blockErrors = checkStatementSpacing(statements, sourceFile, filePath, allowComments);
errors.push(...blockErrors);
}
typescript.forEachChild(node, (child) => {
- visitBlocks(child, sourceFile, filePath, errors);
+ visitBlocks(child, sourceFile, filePath, errors, allowComments);
});
}
@@ -245,12 +271,13 @@ export function checkFile(filePath: string, options: CheckerOptions = defaultOpt
return [];
}
+ const allowComments = !options.noComments;
const errors: string[] = [];
const topLevelStatements = getStatementsFromBlock(sourceFile, sourceFile);
- const topLevelErrors = checkStatementSpacing(topLevelStatements, sourceFile, filePath);
+ const topLevelErrors = checkStatementSpacing(topLevelStatements, sourceFile, filePath, allowComments);
errors.push(...topLevelErrors);
- visitBlocks(sourceFile, sourceFile, filePath, errors);
+ visitBlocks(sourceFile, sourceFile, filePath, errors, allowComments);
if (options.noComments) {
const commentErrors = checkForComments(sourceFile, filePath);