-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsvasciidoc.js
84 lines (72 loc) · 2.37 KB
/
svasciidoc.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import Processor from '@asciidoctor/core';
import matter from 'gray-matter';
import { JSDOM } from 'jsdom';
import { all, createStarryNight } from '@wooorm/starry-night';
import { toHtml } from 'hast-util-to-html';
/** @type (content: string) => {markdown: string, meta: string} */
function frontmatter(content) {
const { content: markdown, data } = matter(content);
const meta = `
<script context="module">
export const metadata = ${JSON.stringify(data)};
</script>
`;
return { markdown, meta };
}
/** @type (content: string) => Promise<string> */
async function parseAdoc(content) {
const processor = Processor();
let html = processor
.convert(content, {
standalone: false,
safe: 'unsafe',
attributes: {
icons: 'font',
'allow-uri-read': '',
sectanchors: true,
'skip-front-matter': true
}
})
.toString();
const dom = new JSDOM(html);
const document = dom.window.document;
/** @type {NodeListOf<HTMLElement>} */
const codes = document.querySelectorAll('pre.highlight > code');
for (const code of codes) {
code.innerHTML = code.innerHTML.replace(/</g, '<').replace(/>/g, '>');
const lang = code.dataset.lang;
if (!lang) continue;
const starryNight = await createStarryNight(all);
const scope = starryNight.flagToScope(lang);
if (!scope) continue;
code.innerHTML = toHtml(starryNight.highlight(code.innerHTML, scope));
}
return document.body.innerHTML;
}
/**
* Replace characters with HTML entities.
* @param {string} content
*/
function escapeHtml(content) {
content = content.replace(/{/g, '{').replace(/}/g, '}');
const componentRegex = /<[A-Z].*/g;
const components = content.match(componentRegex);
components?.forEach((component) => {
const replaced = component.replace('{', '{').replace('}', '}');
content = content.replace(component, replaced);
});
return content;
}
/** @type () => {markup: (file: {content: string, filename: string}) => Promise<{code: string} | undefined>} */
export default function svasciidoc() {
return {
markup: async ({ content, filename }) => {
if (filename.endsWith('.adoc')) {
const { markdown, meta } = frontmatter(content);
const document = await parseAdoc(markdown);
const html = escapeHtml(document);
return { code: meta + html };
}
}
};
}