@tanstack/highlight
Version:
Tiny class-based syntax highlighting for documentation.
69 lines (68 loc) • 2.65 kB
JavaScript
import { renderTokenOutput } from './internal/render.js';
import { renderNodesToHtml, renderTokens, } from './core.js';
import { parseCodeDiffNotation, prepareCodeFence, tokenizeCodeFence, } from './internal/code-fence.js';
export { getCodeFenceTitle, parseCodeDiffNotation, parseCodeFenceMeta, } from './internal/code-fence.js';
export function renderCodeFence(input, highlighter) {
const prepared = prepareCodeFence(input);
return {
...highlighter.renderCodeBlockData(prepared),
decorations: prepared.decorations,
lineNumbers: prepared.lineNumbers,
};
}
export function codeFenceToHast(input, highlighter) {
const rendered = tokenizeCodeFence(input, highlighter);
return tokensToHast(rendered.tokens, rendered.lang, rendered);
}
export function createTanStackMarkdownHighlighter(highlighter) {
return (code, lang = 'plaintext', options = {}) => {
const annotated = parseCodeDiffNotation(code);
const result = highlighter.tokenize(annotated.code, { lang });
for (const lines of options.highlightLines || []) {
annotated.decorations.push({ className: 'th-line--highlighted', lines });
}
return renderNodesToHtml(renderTokens(result.tokens, {
lineNumbers: options.lineNumbers,
decorations: annotated.decorations,
}));
};
}
export function tokensToHast(tokens, lang, options = {}) {
return {
type: 'element',
tagName: 'pre',
properties: {
className: [
'th-code',
`th-code--${lang}`,
...(options.lineNumbers ? ['th-code--line-numbers'] : []),
],
dataLanguage: lang,
...(options.title ? { dataTitle: options.title } : {}),
},
children: [
{
type: 'element',
tagName: 'code',
properties: {},
children: renderTokenOutput(tokens, options, hastRenderer),
},
],
};
}
const hastRenderer = {
text: value => ({ type: 'text', value }),
token: (className, child) => ({
type: 'element', tagName: 'span',
properties: { className: ['th-token', `th-${className}`] }, children: [child],
}),
element(classNames, data, children) {
const properties = { className: classNames };
if (data) {
for (const [key, value] of Object.entries(data)) {
properties[`data${key[0]?.toUpperCase() || ''}${key.slice(1)}`] = value;
}
}
return { type: 'element', tagName: 'span', properties, children };
},
};