refactoring

This commit is contained in:
2026-09-02 08:38:03 +02:00
parent 649ff0d7c5
commit 38f255c1a4
48 changed files with 6998 additions and 5577 deletions
+64
View File
@@ -0,0 +1,64 @@
/*
* Markdown page-outline calculations.
*
* This module recognizes source headings and assigns stable HTML identifiers.
* It has no application state and does not inspect or modify the DOM.
*/
/**
* goal : Produce a unique HTML identifier for a rendered heading.
* pre : usedIds contains identifiers already assigned within the document.
* post : The returned identifier is added to usedIds.
* result : A readable normalized identifier, with a numeric suffix if needed.
*/
function headingId(text, usedIds) {
const base = String(text || "")
.trim()
.toLocaleLowerCase()
.normalize("NFKD")
.replace(/[\u0300-\u036f]/g, "")
.replace(/[^\p{L}\p{N}]+/gu, "-")
.replace(/^-+|-+$/g, "") || "section";
let id = base;
let number = 2;
while (usedIds.has(id)) {
id = `${base}-${number}`;
number += 1;
}
usedIds.add(id);
return id;
}
/**
* goal : Extract ATX headings and their source locations from Markdown.
* pre : markdown is source text and may contain fenced code blocks.
* post : The source is not changed; headings inside fences are ignored.
* result : Ordered level/text/line records for the document outline.
*/
function markdownHeadings(markdown) {
const headings = [];
const lines = String(markdown || "").replace(/\r\n/g, "\n").split("\n");
const fencePattern = /^\s*(```|~~~)/;
let inFence = false;
for (let lineNumber = 0; lineNumber < lines.length; lineNumber += 1) {
const line = lines[lineNumber];
if (fencePattern.test(line)) {
inFence = !inFence;
continue;
}
if (inFence) continue;
const match = line.match(/^\s{0,3}(#{1,6})\s+(.+?)\s*#*\s*$/);
if (!match) continue;
headings.push({
level: match[1].length,
text: match[2].trim(),
line: lineNumber
});
}
return headings;
}
export { headingId, markdownHeadings };