This repository has been archived by the owner on Jun 7, 2024. It is now read-only.
forked from speced/respec
-
Notifications
You must be signed in to change notification settings - Fork 4
/
highlight.js
100 lines (95 loc) · 2.68 KB
/
highlight.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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// @ts-check
/**
* Module core/highlight
*
* Performs syntax highlighting to all pre and code elements.
*/
import css from "../styles/highlight.css.js";
import { html } from "./import-maps.js";
import { msgIdGenerator } from "./utils.js";
import { workerPromise } from "./worker.js";
export const name = "core/highlight";
const nextMsgId = msgIdGenerator("highlight");
function getLanguageHint(classList) {
return Array.from(classList)
.filter(item => item !== "highlight" && item !== "nolinks")
.map(item => item.toLowerCase());
}
async function highlightElement(elem) {
elem.setAttribute("aria-busy", "true");
const languages = getLanguageHint(elem.classList);
let response;
try {
response = await sendHighlightRequest(elem.innerText, languages);
} catch (err) {
console.error(err);
return;
}
const { language, value } = response;
switch (elem.localName) {
case "pre":
elem.classList.remove(language);
elem.innerHTML = `<code class="hljs${
language ? ` ${language}` : ""
}">${value}</code>`;
if (!elem.classList.length) elem.removeAttribute("class");
break;
case "code":
elem.innerHTML = value;
elem.classList.add("hljs");
if (language) elem.classList.add(language);
break;
}
elem.setAttribute("aria-busy", "false");
}
async function sendHighlightRequest(code, languages) {
const msg = {
action: "highlight",
code,
id: nextMsgId(),
languages,
};
const worker = await workerPromise;
worker.postMessage(msg);
return new Promise((resolve, reject) => {
const timeoutId = setTimeout(() => {
reject(new Error("Timed out waiting for highlight."));
}, 4000);
worker.addEventListener("message", function listener(ev) {
const {
data: { id, language, value },
} = ev;
if (id !== msg.id) return; // not for us!
worker.removeEventListener("message", listener);
clearTimeout(timeoutId);
resolve({ language, value });
});
});
}
export async function run(conf) {
// Nothing to highlight
if (conf.noHighlightCSS) return;
const highlightables = [
...document.querySelectorAll(`
pre:not(.idl):not(.nohighlight) > code:not(.nohighlight),
pre:not(.idl):not(.nohighlight),
code.highlight
`),
].filter(
// Filter pre's that contain code
elem => elem.localName !== "pre" || !elem.querySelector("code")
);
// Nothing to highlight
if (!highlightables.length) {
return;
}
const promisesToHighlight = highlightables
.filter(elem => elem.textContent.trim())
.map(highlightElement);
document.head.appendChild(
html`<style>
${css}
</style>`
);
await Promise.all(promisesToHighlight);
}