1 #!/usr/bin
/env
-S deno run
--allow
-read
--allow
-write
3 // Copyright © 2023 Lady [@ Lady’s Computer].
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/>.
9 import hljs
from "npm:highlight.js@11.8.0";
11 const contentLinks
= new WeakMap();
13 const processContent = function (content
) {
14 if (content
== null || Object(content
) instanceof String
) {
15 // The provided content is nullish or a string.
17 } else if (Array
.isArray(content
)) {
18 // The provided content is an array.
19 content
.forEach(processContent
.bind(this));
21 // The provided content is a NodeList.
22 for (const child
of Array
.from(content
)) {
23 applyTransforms
.call(this, child
);
28 const applyTransforms = function (node
) {
29 const document
= node
.ownerDocument
;
30 const LMN
= Lemon
.bind(document
);
32 node
.localName
== "pre" && node
.childNodes
.length
== 1 &&
33 node
.firstChild
.localName
== "code"
35 // This is a code block and should be highlighted.
36 const code
= node
.firstChild
;
37 const language
= /language-(.*)/u.exec(code
.getAttribute("class"))
41 const { value
: highlight
} = hljs
.highlight(
42 node
.firstChild
.textContent
,
45 const nodes
= new DOMParser().parseFromString(
46 `<!DOCTYPE html><html><body>${highlight}</body></html>`,
48 ).documentElement
.lastChild
.childNodes
;
51 `hljs ${code.getAttribute("class")}`,
53 code
.textContent
= "";
54 for (const node
of Array
.from(nodes
)) {
55 code
.appendChild(code
.ownerDocument
.importNode(node
, true));
57 return; // don’t continue processing this node
62 } else if (node
.localName
== "a") {
63 const href
= node
.getAttribute("href");
64 const title
= node
.getAttribute("title");
66 contentLinks
.get(this)[title
] = href
;
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
);
85 prev
.parentNode
.replaceChild(
86 document
.createTextNode(
87 prevText
.substring(0, prevText
.length
- prevWrap
.length
),
92 document
.createTextNode(
93 prevText
.substring(prevText
.length
- prevWrap
.length
),
97 span
.appendChild(node
);
100 document
.createTextNode(
101 nextText
.substring(0, nextWrap
.length
),
103 document
.createTextNode(
104 nextText
.substring(nextWrap
.length
),
107 span
.appendChild(nexts
[0]);
108 next
.parentNode
.replaceChild(nexts
[1], next
);
109 for (const nextNode
of nexts
) {
110 applyTransforms
.call(this, nextNode
);
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—");
122 globalThis
.bj
ørnTransformMetadata
= (metadata
, _type
) => {
123 contentLinks
.set(metadata
, {});
124 processContent
.call(metadata
, metadata
.content
);
125 processContent
.call(metadata
, metadata
.summary
);
128 globalThis
.bj
ørnTransformFeedHTML
= (document
, _metadata
) => {
129 const LMN
= Lemon
.bind({ document
});
130 const h1
= document
.getElementsByTagNameNS(
131 "http://www.w3.org/1999/xhtml",
134 const link
= LMN
.a
.href("/")``;
135 for (const child
of Array
.from(h1
.childNodes
)) {
136 link
.appendChild(child
);
138 h1
.appendChild(link
);
141 globalThis
.bj
ørnTransformEntryHTML
= (document
, metadata
) => {
142 const LMN
= Lemon
.bind({ document
});
143 const links
= Object
.entries(contentLinks
.get(metadata
));
145 document
.getElementById("entry.content").appendChild(
146 LMN
.footer
`${LMN.nav`${[
147 LMN
.h2
`This post contains links.`,
149 links.map(([name, href]) =>
150 LMN.li`${LMN.a.href(href)`${name}
`}`
159 "https://git.ladys.computer/Beorn/blob_plain/0.2.4:/build.js"