Initial commit
Some checks failed
Node.js build / build (20.x) (push) Failing after 5m57s
Node.js build / build (22.x) (push) Failing after 5m52s

This commit is contained in:
2026-02-19 16:35:20 -08:00
parent dc2fa22c4d
commit 2936f7d359
18 changed files with 2727 additions and 93 deletions

View File

@@ -0,0 +1,98 @@
/**
* Regex pattern for markdown todo checkboxes (for toggling).
*/
const TODO_PATTERN = /^(\s*[-*+]\s+\[)([xX ]?)(\].*)$/;
/**
* Toggle the checkbox state at the specified line number.
* Returns the modified content.
*/
export function toggleTodo(content: string, lineNumber: number): string {
const lines = content.split('\n');
if (lineNumber < 0 || lineNumber >= lines.length) {
return content;
}
const line = lines[lineNumber];
if (line === undefined) {
return content;
}
const match = line.match(TODO_PATTERN);
if (!match) {
return content;
}
const checkboxContent = match[2];
const isChecked = checkboxContent === 'x' || checkboxContent === 'X';
const newCheckbox = isChecked ? ' ' : 'x';
lines[lineNumber] = `${match[1]}${newCheckbox}${match[3]}`;
return lines.join('\n');
}
/**
* Remove the line at the specified line number.
* Returns the modified content.
*/
export function removeTodoLine(content: string, lineNumber: number): string {
const lines = content.split('\n');
if (lineNumber < 0 || lineNumber >= lines.length) {
return content;
}
lines.splice(lineNumber, 1);
return lines.join('\n');
}
/**
* Insert a todo line at the end of the content.
* Handles files with/without trailing newlines.
*/
export function insertTodoAtEnd(content: string, todoLine: string): string {
if (!content) {
return todoLine;
}
// If content ends with newline(s), append directly
if (content.endsWith('\n')) {
return content + todoLine;
}
// Otherwise add a newline before the todo
return content + '\n' + todoLine;
}
/**
* Insert a todo line under a specific heading.
* @param content - The file content
* @param headingLineNumber - The line number of the heading (0-based)
* @param todoLine - The todo line to insert
* @param nextHeadingLineNumber - Optional line number of the next heading (for section boundary)
*/
export function insertTodoUnderHeading(
content: string,
headingLineNumber: number,
todoLine: string,
nextHeadingLineNumber?: number
): string {
const lines = content.split('\n');
// Determine where to insert
let insertPosition: number;
if (nextHeadingLineNumber !== undefined) {
// Insert just before the next heading (at the end of this section)
insertPosition = nextHeadingLineNumber;
} else {
// No next heading - insert right after the heading line
insertPosition = headingLineNumber + 1;
}
// Insert the todo line
lines.splice(insertPosition, 0, todoLine);
return lines.join('\n');
}