]> Lady’s Gitweb - Blog/blob - build.js
Use data: u·r·i’s for branding
[Blog] / build.js
1 #!/usr/bin/env -S deno run --allow-read --allow-write
2
3 // Copyright © 2023 Lady [@ Lady’s Computer].
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
8
9 import hljs from "npm:highlight.js@11.8.0";
10
11 const contentLinks = new WeakMap();
12
13 const processContent = function (content) {
14 if (content == null || Object(content) instanceof String) {
15 // The provided content is nullish or a string.
16 /* do nothing */
17 } else if (Array.isArray(content)) {
18 // The provided content is an array.
19 content.forEach(processContent.bind(this));
20 } else {
21 // The provided content is a NodeList.
22 for (const child of Array.from(content)) {
23 applyTransforms.call(this, child);
24 }
25 }
26 };
27
28 const applyTransforms = function (node) {
29 const document = node.ownerDocument;
30 const LMN = Lemon.bind(document);
31 if (
32 node.localName == "pre" && node.childNodes.length == 1 &&
33 node.firstChild.localName == "code"
34 ) {
35 // This is a code block and should be highlighted.
36 const code = node.firstChild;
37 const language = /language-(.*)/u.exec(code.getAttribute("class"))
38 ?.[1];
39 if (language) {
40 try {
41 const { value: highlight } = hljs.highlight(
42 node.firstChild.textContent,
43 { language },
44 );
45 const nodes = new DOMParser().parseFromString(
46 `<!DOCTYPE html><html><body>${highlight}</body></html>`,
47 "text/html",
48 ).documentElement.lastChild.childNodes;
49 code.setAttribute(
50 "class",
51 `hljs ${code.getAttribute("class")}`,
52 );
53 code.textContent = "";
54 for (const node of Array.from(nodes)) {
55 code.appendChild(code.ownerDocument.importNode(node, true));
56 }
57 return; // don’t continue processing this node
58 } catch (e) {
59 console.warn(e);
60 }
61 }
62 } else if (node.localName == "a") {
63 const href = node.getAttribute("href");
64 const title = node.getAttribute("title");
65 if (title && href) {
66 contentLinks.get(this)[title] = href;
67 }
68 }
69 if (node.nodeType == 1) {
70 // This is an element; process its children.
71 if (node.localName == "code") {
72 // This is a `<code>` element; wrap it in a `Word-Wrap: Pre` with
73 // any previous/next characters to prevent line‐breaking due to
74 // it being rendered as an inline block.
75 const prev = node.previousSibling;
76 const prevText = prev?.nodeType == 3 ? prev.textContent : "";
77 const prevWrap = prevText.match(/(?:(?!—)\S)*$/u)[0];
78 const next = node.nextSibling;
79 const nextText = next?.nodeType == 3 ? next.textContent : "";
80 const nextWrap = nextText.match(/^(?:(?!—)\S)*/u)[0];
81 if (prevWrap || nextWrap) {
82 const span = LMN.span.style("White-Space: Pre")``;
83 node.parentNode.replaceChild(span, node);
84 if (prevWrap) {
85 prev.parentNode.replaceChild(
86 document.createTextNode(
87 prevText.substring(0, prevText.length - prevWrap.length),
88 ),
89 prev,
90 );
91 span.appendChild(
92 document.createTextNode(
93 prevText.substring(prevText.length - prevWrap.length),
94 ),
95 );
96 }
97 span.appendChild(node);
98 if (nextWrap) {
99 const nexts = [
100 document.createTextNode(
101 nextText.substring(0, nextWrap.length),
102 ),
103 document.createTextNode(
104 nextText.substring(nextWrap.length),
105 ),
106 ];
107 span.appendChild(nexts[0]);
108 next.parentNode.replaceChild(nexts[1], next);
109 for (const nextNode of nexts) {
110 applyTransforms.call(this, nextNode);
111 }
112 }
113 }
114 }
115 Array.from(node.childNodes).forEach(applyTransforms.bind(this));
116 } else if (node.nodeType == 3) {
117 // This is a text node; apply replacements.
118 node.textContent = node.textContent.replaceAll(":—", ":\u2060—");
119 }
120 };
121
122 globalThis.bjørnTransformMetadata = (metadata, _type) => {
123 contentLinks.set(metadata, {});
124 processContent.call(metadata, metadata.content);
125 processContent.call(metadata, metadata.summary);
126 };
127
128 globalThis.bjørnTransformFeedHTML = (document, _metadata) => {
129 const LMN = Lemon.bind({ document });
130 const h1 = document.getElementsByTagNameNS(
131 "http://www.w3.org/1999/xhtml",
132 "h1",
133 )[0];
134 const link = LMN.a.href("/")``;
135 for (const child of Array.from(h1.childNodes)) {
136 link.appendChild(child);
137 }
138 h1.appendChild(link);
139 };
140
141 globalThis.bjørnTransformEntryHTML = (document, metadata) => {
142 const LMN = Lemon.bind({ document });
143 const links = Object.entries(contentLinks.get(metadata));
144 if (links.length) {
145 document.getElementById("entry.content").appendChild(
146 LMN.footer`${LMN.nav`${[
147 LMN.h2`This post contains links.`,
148 LMN.ul`${
149 links.map(([name, href]) =>
150 LMN.li`${LMN.a.href(href)`${name}`}`
151 )
152 }`,
153 ]}`}`,
154 );
155 }
156 };
157
158 await import(
159 "https://git.ladys.computer/Beorn/blob_plain/0.2.4:/build.js"
160 );
This page took 0.111331 seconds and 5 git commands to generate.