A line-by-line indentation formatter is conceptually simple: track a indentLevel counter, increment it when you see an opening bracket or block start, decrement it when you see a closing bracket or block end, and prefix each line with indentLevel × indentSize spaces.
The first edge case that breaks this simple model: block comments.
The problem
Consider this CSS:
.container {
display: flex;
/*
* This is a multi-line
* block comment
*/
flex-direction: column;
}On the line .container {, indent level goes from 0 to 1. Every subsequent line should be at indent level 1. But the comment lines don't contain brackets — they should just be printed at the current indent level without being processed for bracket changes.
If your formatter processes * at the start of a line as a closing bracket candidate (some grammars use * in patterns), or if the closing */ is accidentally counted as two characters that change indent — you get misformatted output.
The solution: stateful tracking
mkhCodeFormatter maintains two variables across the entire forEach line loop:
inBlockComment: boolean— whether the current line is inside an open block commentblockCommentType: 'css' | 'html' | null— to know which closing delimiter to watch for
For each line, before any bracket or directive logic runs:
if (inBlockComment) {
isThisLineAComment = true;
if (blockCommentType === 'html' && trimmedLine.includes('-->')) {
inBlockComment = false;
} else if (blockCommentType === 'css' && trimmedLine.includes('*/')) {
inBlockComment = false;
}
} else {
if (trimmedLine.startsWith('/*') || trimmedLine.startsWith('/**')) {
isThisLineAComment = true;
if (!trimmedLine.includes('*/')) { // multi-line block, not self-closing
inBlockComment = true;
blockCommentType = 'css';
}
} else if (trimmedLine.startsWith('<!--')) {
isThisLineAComment = true;
if (!trimmedLine.includes('-->')) {
inBlockComment = true;
blockCommentType = 'html';
}
} else if (trimmedLine.startsWith('//') || trimmedLine.startsWith('#') || trimmedLine.startsWith('*')) {
isThisLineAComment = true;
}
}If isThisLineAComment is true, the line is indented at the current level (with a special +1 space offset for JSDoc * continuation lines) and the loop continues to the next line — no bracket counting, no directive detection.
The JSDoc +1 offset
JSDoc * continuation lines inside a /** */ block conventionally align with the * of the opening /** — which is one character after the indent:
/** ← indent level 1 (2 spaces) * text ← indent level 1 + 1 space = 3 spaces */ ← indent level 1 + 1 space = 3 spaces
This is handled by adding 1 to the space count when the trimmed line starts with * but not with /*:
if (trimmedLine.startsWith('*') && !trimmedLine.startsWith('/*')) {
indentSpaceCount += 1;
}---
