@mdfriday/foundry
Version:
The core engine of MDFriday. Convert Markdown and shortcodes into fully themed static sites – Hugo-style, powered by TypeScript.
234 lines • 6.69 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AutoIDGenerator = exports.TOCBuilder = exports.ParagraphImpl = exports.LinkImpl = exports.HeaderImpl = exports.TableOfContentsImpl = void 0;
/**
* TableOfContentsImpl implements TocFragments
*/
class TableOfContentsImpl {
constructor(fragments = []) {
this.fragments = fragments;
}
toHTML(startLevel, stopLevel, ordered) {
if (this.fragments.length === 0) {
return '';
}
const filtered = this.filterByLevel(this.fragments, startLevel, stopLevel);
if (filtered.length === 0) {
return '';
}
const tag = ordered ? 'ol' : 'ul';
return `<${tag}>\n${this.renderFragments(filtered, ordered)}</${tag}>\n`;
}
filterByLevel(fragments, startLevel, stopLevel) {
return fragments
.filter(f => f.level >= startLevel && f.level <= stopLevel)
.map(f => {
const filtered = {
id: f.id,
text: f.text,
level: f.level,
};
if (f.children) {
filtered.children = this.filterByLevel(f.children, startLevel, stopLevel);
}
return filtered;
});
}
renderFragments(fragments, ordered) {
const tag = ordered ? 'ol' : 'ul';
return fragments
.map(f => {
let html = ` <li><a href="#${f.id}">${this.escapeHTML(f.text)}</a>`;
if (f.children && f.children.length > 0) {
html += `\n <${tag}>\n${this.renderFragments(f.children, ordered)} </${tag}>`;
}
html += '</li>';
return html;
})
.join('\n');
}
escapeHTML(text) {
return text
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
addFragment(fragment) {
this.fragments.push(fragment);
}
getFragments() {
return [...this.fragments];
}
}
exports.TableOfContentsImpl = TableOfContentsImpl;
/**
* HeaderImpl implements Header interface
*/
class HeaderImpl {
constructor(_name, _level, _links = [], _paragraphs = [], _listParagraphs = []) {
this._name = _name;
this._level = _level;
this._links = _links;
this._paragraphs = _paragraphs;
this._listParagraphs = _listParagraphs;
}
name() {
return this._name;
}
level() {
return this._level;
}
links() {
return [...this._links];
}
paragraphs() {
return [...this._paragraphs];
}
listParagraphs() {
return [...this._listParagraphs];
}
addLink(link) {
this._links.push(link);
}
addParagraph(paragraph) {
this._paragraphs.push(paragraph);
}
addListParagraph(paragraph) {
this._listParagraphs.push(paragraph);
}
}
exports.HeaderImpl = HeaderImpl;
/**
* LinkImpl implements Link interface
*/
class LinkImpl {
constructor(_text, _url) {
this._text = _text;
this._url = _url;
}
text() {
return this._text;
}
url() {
return this._url;
}
}
exports.LinkImpl = LinkImpl;
/**
* ParagraphImpl implements Paragraph interface
*/
class ParagraphImpl {
constructor(_text) {
this._text = _text;
}
text() {
return this._text;
}
}
exports.ParagraphImpl = ParagraphImpl;
/**
* TOC Builder utility class
*/
class TOCBuilder {
constructor() {
this.fragments = [];
this.stack = [];
}
addHeading(text, level, id) {
// Remove any fragments from stack that are at same or deeper level
while (this.stack.length > 0 && this.stack[this.stack.length - 1].level >= level) {
this.stack.pop();
}
const fragment = {
id,
text,
level,
children: [],
};
if (this.stack.length === 0) {
// Top level fragment
this.fragments.push(fragment);
}
else {
// Child fragment
const parent = this.stack[this.stack.length - 1];
if (!parent.children) {
parent.children = [];
}
parent.children.push(fragment);
}
this.stack.push(fragment);
}
build() {
return new TableOfContentsImpl(this.fragments);
}
reset() {
this.fragments = [];
this.stack = [];
}
}
exports.TOCBuilder = TOCBuilder;
/**
* Auto ID generation utilities
*/
class AutoIDGenerator {
constructor() {
this.usedIds = new Set();
}
generateID(text, type = 'github') {
let id;
switch (type) {
case 'github':
id = this.githubStyle(text);
break;
case 'github-ascii':
id = this.githubAsciiStyle(text);
break;
case 'blackfriday':
id = this.blackfridayStyle(text);
break;
default:
id = this.githubStyle(text);
}
// Ensure uniqueness
if (this.usedIds.has(id)) {
let counter = 1;
let uniqueId = `${id}-${counter}`;
while (this.usedIds.has(uniqueId)) {
counter++;
uniqueId = `${id}-${counter}`;
}
id = uniqueId;
}
this.usedIds.add(id);
return id;
}
githubStyle(text) {
return text
.toLowerCase()
.replace(/[^\w\u4e00-\u9fff\s-]/g, '') // Keep word chars, CJK, spaces, and hyphens
.replace(/\s+/g, '-') // Replace spaces with hyphens
.replace(/^-+|-+$/g, ''); // Remove leading/trailing hyphens
}
githubAsciiStyle(text) {
return text
.toLowerCase()
.replace(/[^\w\s-]/g, '') // Keep only ASCII word chars, spaces, and hyphens
.replace(/\s+/g, '-') // Replace spaces with hyphens
.replace(/^-+|-+$/g, ''); // Remove leading/trailing hyphens
}
blackfridayStyle(text) {
return text
.toLowerCase()
.replace(/[^a-z0-9\s-]/g, '') // Keep only lowercase letters, digits, spaces, and hyphens
.replace(/\s+/g, '-') // Replace spaces with hyphens
.replace(/^-+|-+$/g, ''); // Remove leading/trailing hyphens
}
reset() {
this.usedIds.clear();
}
}
exports.AutoIDGenerator = AutoIDGenerator;
//# sourceMappingURL=tableofcontents.js.map