aboutsummaryrefslogtreecommitdiffhomepage
path: root/services/blog/nuldoc-src/renderers/xml.ts
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2025-11-02 17:49:34 +0900
committernsfisis <nsfisis@gmail.com>2025-11-02 17:49:34 +0900
commit57315c52be96d2a2c013f0cfb0de5429980e301a (patch)
tree5d691497772fddfe401cd970ead4e9a74b34ef38 /services/blog/nuldoc-src/renderers/xml.ts
parentcf4091a93ed831456e8b30e2a9e1fc2650dcae02 (diff)
downloadnsfisis.dev-57315c52be96d2a2c013f0cfb0de5429980e301a.tar.gz
nsfisis.dev-57315c52be96d2a2c013f0cfb0de5429980e301a.tar.zst
nsfisis.dev-57315c52be96d2a2c013f0cfb0de5429980e301a.zip
refactor(blog): rename directory, services/{blog => nuldoc}/
Diffstat (limited to 'services/blog/nuldoc-src/renderers/xml.ts')
-rw-r--r--services/blog/nuldoc-src/renderers/xml.ts128
1 files changed, 0 insertions, 128 deletions
diff --git a/services/blog/nuldoc-src/renderers/xml.ts b/services/blog/nuldoc-src/renderers/xml.ts
deleted file mode 100644
index 523567a..0000000
--- a/services/blog/nuldoc-src/renderers/xml.ts
+++ /dev/null
@@ -1,128 +0,0 @@
-import { Element, forEachChild, Node, Text } from "../dom.ts";
-
-export function renderXml(root: Node): string {
- return `<?xml version="1.0" encoding="utf-8"?>\n` + nodeToXmlText(root, {
- indentLevel: 0,
- });
-}
-
-type Context = {
- indentLevel: number;
-};
-
-type Dtd = { type: "block" | "inline" };
-
-function getDtd(name: string): Dtd {
- switch (name) {
- case "feed":
- case "entry":
- case "author":
- return { type: "block" };
- default:
- return { type: "inline" };
- }
-}
-
-function isInlineNode(n: Node): boolean {
- if (n.kind === "text" || n.kind === "raw") {
- return true;
- }
- return getDtd(n.name).type === "inline";
-}
-
-function isBlockNode(n: Node): boolean {
- return !isInlineNode(n);
-}
-
-function nodeToXmlText(n: Node, ctx: Context): string {
- if (n.kind === "text") {
- return textNodeToXmlText(n);
- } else if (n.kind === "raw") {
- return n.html;
- } else {
- return elementNodeToXmlText(n, ctx);
- }
-}
-
-function textNodeToXmlText(t: Text): string {
- const s = encodeSpecialCharacters(t.content);
-
- // TODO: 日本語で改行するときはスペースを入れない
- return s.replaceAll(/\n */g, " ");
-}
-
-function encodeSpecialCharacters(s: string): string {
- return s.replaceAll(/&(?!\w+;)/g, "&amp;")
- .replaceAll(/</g, "&lt;")
- .replaceAll(/>/g, "&gt;")
- .replaceAll(/'/g, "&apos;")
- .replaceAll(/"/g, "&quot;");
-}
-
-function elementNodeToXmlText(e: Element, ctx: Context): string {
- let s = "";
-
- s += indent(ctx);
- s += `<${e.name}`;
- const attributes = getElementAttributes(e);
- if (attributes.length > 0) {
- s += " ";
- for (let i = 0; i < attributes.length; i++) {
- const [name, value] = attributes[i];
- s += `${name}="${encodeSpecialCharacters(value)}"`;
- if (i !== attributes.length - 1) {
- s += " ";
- }
- }
- }
- s += ">";
- if (isBlockNode(e)) {
- s += "\n";
- }
- ctx.indentLevel += 1;
-
- forEachChild(e, (c) => {
- s += nodeToXmlText(c, ctx);
- });
-
- ctx.indentLevel -= 1;
- if (isBlockNode(e)) {
- s += indent(ctx);
- }
- s += `</${e.name}>`;
- s += "\n";
-
- return s;
-}
-
-function indent(ctx: Context): string {
- return " ".repeat(ctx.indentLevel);
-}
-
-function getElementAttributes(e: Element): [string, string][] {
- return [...Object.entries(e.attributes)]
- .filter((a) => !a[0].startsWith("__"))
- .sort(
- (a, b) => {
- // Special rules:
- if (e.name === "link") {
- if (a[0] === "href" && b[0] === "rel") {
- return 1;
- }
- if (a[0] === "rel" && b[0] === "href") {
- return -1;
- }
- if (a[0] === "href" && b[0] === "type") {
- return 1;
- }
- if (a[0] === "type" && b[0] === "href") {
- return -1;
- }
- }
- // General rules:
- if (a[0] > b[0]) return 1;
- else if (a[0] < b[0]) return -1;
- else return 0;
- },
- );
-}