diff options
| author | Fuwn <[email protected]> | 2026-02-03 19:56:15 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-02-03 19:56:15 -0800 |
| commit | 0dc7d010110038e50cf18c686f6de6dbf4e0cfea (patch) | |
| tree | 78d5c6518f5836d13ff912808fc66f2f36cf0b05 /packages/iku | |
| parent | feat(iku): Add comment detection with --allow-comments flag (diff) | |
| download | archived-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.ts | 41 |
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); |