@tanstack/markdown
Version:
A tiny, fast, deterministic Markdown renderer for blogs and documentation.
69 lines (68 loc) • 2.2 kB
JavaScript
export function commentComponentsExtension(options = {}) {
return {
name: 'comment-components',
parseBlock: context => parseCommentComponentBlock(context, options),
};
}
export function parseCommentComponentBlock(context, options = {}) {
const line = context.lines[context.index] ?? '';
const start = parseComponentComment(line);
if (!start)
return undefined;
if (!start.block) {
context.consume(1);
return transform({
type: 'component',
name: start.name,
attributes: start.attributes,
children: [],
}, options);
}
const body = [];
let cursor = context.index + 1;
let foundEnd = false;
while (cursor < context.lines.length) {
const candidate = context.lines[cursor] ?? '';
if (isEndComment(candidate, start.name)) {
foundEnd = true;
cursor++;
break;
}
body.push(candidate);
cursor++;
}
context.consume(foundEnd ? cursor - context.index : 1);
return transform({
type: 'component',
name: start.name,
attributes: start.attributes,
children: foundEnd ? context.parseBlocks(body.join('\n')) : [],
}, options);
}
export function parseComponentComment(line) {
const match = line.match(/^ {0,3}<!--\s*::(start:)?([A-Za-z][\w-]*)(.*?)\s*-->\s*$/);
if (!match)
return undefined;
return {
block: Boolean(match[1]),
name: match[2].toLowerCase(),
attributes: parseAttributes(match[3] ?? ''),
};
}
export function parseAttributes(value) {
const attrs = {};
const regex = /([A-Za-z_][\w:-]*)(?:=(?:"([^"]*)"|'([^']*)'|([^\s"']+)))?/g;
for (const match of value.matchAll(regex)) {
attrs[match[1]] = match[2] ?? match[3] ?? match[4] ?? 'true';
}
return attrs;
}
function transform(node, options) {
return options.transformComponent?.(node) ?? node;
}
function isEndComment(line, name) {
return new RegExp(`^ {0,3}<!--\\s*::end:${escapeRegex(name)}\\s*-->\\s*$`, 'i').test(line);
}
function escapeRegex(value) {
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}