]> Lady’s Gitweb - GitWikiWeb/blobdiff - build.js
Support arbitrary use of @as
[GitWikiWeb] / build.js
index 8eab7f426f0b6922e5839785e01108141e9b470e..b50fe3d4c2c83da96c1eb154d806443e8a7a1d16 100644 (file)
--- a/build.js
+++ b/build.js
@@ -20,7 +20,7 @@
 //     export GITWIKIWEB=/srv/git/GitWikiWeb
 //     git archive --remote=$GITWIKIWEB HEAD build.js \
 //       | tar -xO \
-//       | deno run -A - ~/public/wiki $GITWIKIWEB
+//       | deno run -A - ~/public/wiki $GITWIKIWEB current
 //
 // The directory `~/public/wiki` (or whatever you specify as the first
 // argument to `deno run -A -`) **will be deleted** and a new static
 import {
   emptyDir,
   ensureDir,
-} from "https://deno.land/std@0.195.0/fs/mod.ts";
+} from "https://deno.land/std@0.196.0/fs/mod.ts";
+import {
+  JSON_SCHEMA,
+  parse as parseYaml,
+} from "https://deno.land/std@0.196.0/yaml/mod.ts";
 import djot from "npm:@djot/djot@0.2.3";
 import { Parser } from "npm:htmlparser2@9.0.0";
 import { DomHandler, Element, Text } from "npm:domhandler@5.0.3";
@@ -46,6 +50,7 @@ import domSerializer from "npm:dom-serializer@2.0.0";
 
 const DESTINATION = Deno.args[0] ?? "~/public/wiki";
 const REMOTE = Deno.args[1] ?? "/srv/git/GitWikiWeb";
+const REV = Deno.args[2] ?? "HEAD";
 
 const READ_ONLY = {
   configurable: false,
@@ -53,6 +58,8 @@ const READ_ONLY = {
   writable: false,
 };
 
+const NIL = Object.preventExtensions(Object.create(null));
+
 const rawBlock = (strings, ...substitutions) => ({
   tag: "raw_block",
   format: "html",
@@ -87,7 +94,7 @@ const getDOM = (source) => {
 
 const getRemoteContent = async (pathName) => {
   const getArchive = new Deno.Command("git", {
-    args: ["archive", `--remote=${REMOTE}`, "HEAD", pathName],
+    args: ["archive", `--remote=${REMOTE}`, REV, pathName],
     stdout: "piped",
     stderr: "piped",
   }).spawn();
@@ -171,7 +178,7 @@ const listOfInternalLinks = (references, wrapper = ($) => $) => ({
   ),
 });
 
-const diffReferences = async (hash) => {
+const diffReferences = async (hash, againstHead = false) => {
   const diff = new Deno.Command("git", {
     args: [
       "diff-tree",
@@ -180,7 +187,7 @@ const diffReferences = async (hash) => {
       "--name-only",
       "--no-renames",
       "--diff-filter=AM",
-      hash,
+      ...(againstHead ? [hash, "HEAD"] : [hash]),
     ],
     stdout: "piped",
     stderr: "piped",
@@ -215,7 +222,7 @@ class GitWikiWebPage {
   #internalLinks = new Set();
   #externalLinks = new Map();
 
-  constructor(namespace, name, ast, source) {
+  constructor(namespace, name, ast, source, config) {
     const internalLinks = this.#internalLinks;
     const externalLinks = this.#externalLinks;
     const sections = Object.create(null);
@@ -446,6 +453,20 @@ class GitWikiWebPage {
           },
           exit: (_) => {},
         },
+        symb: {
+          enter: (e) => {
+            const { alias } = e;
+            const codepoint = /^U\+([0-9A-Fa-f]+)$/u.exec(alias)?.[1];
+            if (codepoint) {
+              return str`${
+                String.fromCodePoint(parseInt(codepoint, 16))
+              }`;
+            } else {
+              const resolved = config.symbols?.[alias];
+              return resolved != null ? str`${resolved}` : e;
+            }
+          },
+        },
       };
     });
     Object.defineProperties(this, {
@@ -470,8 +491,43 @@ class GitWikiWebPage {
 }
 
 {
+  // Patches for Djot HTML renderer.
+  const { HTMLRenderer: { prototype: htmlRendererPrototype } } = djot;
+  const { inTags: upstreamInTags } = htmlRendererPrototype;
+  htmlRendererPrototype.inTags = function (
+    tag,
+    node,
+    newlines,
+    extraAttrs = undefined,
+  ) {
+    const attributes = node.attributes ?? NIL;
+    if ("as" in attributes) {
+      const newTag = attributes.as;
+      delete attributes.as;
+      return upstreamInTags.call(
+        this,
+        newTag,
+        node,
+        newlines,
+        extraAttrs,
+      );
+    } else {
+      return upstreamInTags.call(
+        this,
+        tag,
+        node,
+        newlines,
+        extraAttrs,
+      );
+    }
+  };
+}
+{
+  const config = await getRemoteContent("config.yaml").then((yaml) =>
+    parseYaml(yaml, { schema: JSON_SCHEMA })
+  );
   const ls = new Deno.Command("git", {
-    args: ["ls-tree", "-rz", "live"],
+    args: ["ls-tree", "-rz", "HEAD"],
     stdout: "piped",
     stderr: "piped",
   }).spawn();
@@ -543,6 +599,7 @@ class GitWikiWebPage {
                     console.warn(`Djot(${reference}): ${$.render()}`),
                 }),
                 source,
+                config,
               );
               const reference = `${namespace}:${pageName}`;
               pages.set(reference, page);
@@ -564,6 +621,7 @@ class GitWikiWebPage {
             console.warn(`Djot(${reference}): ${$.render()}`),
         }),
         source,
+        config,
       );
       pages.set(reference, page);
     }
@@ -615,7 +673,8 @@ class GitWikiWebPage {
         }
         const results = new Array(6);
         const seen = new Set();
-        let recency = 5;
+        const maxRecency = Math.max(config.max_recency | 0, 0);
+        let recency = maxRecency;
         let current;
         do {
           const show = new Deno.Command("git", {
@@ -623,7 +682,7 @@ class GitWikiWebPage {
               "show",
               "-s",
               "--format=%H%x00%cI%x00%cD",
-              recency ? `HEAD~${5 - recency}` : commit,
+              recency ? `HEAD~${maxRecency - recency}` : commit,
             ],
             stdout: "piped",
             stderr: "piped",
@@ -638,7 +697,9 @@ class GitWikiWebPage {
           ]).then(logErrorsAndCollectResults);
           const refs = [];
           current = hash;
-          for (const ref of (await diffReferences(current))) {
+          for (
+            const ref of (await diffReferences(current, !recency))
+          ) {
             if (seen.has(ref)) {
               /* do nothing */
             } else {
@@ -646,7 +707,7 @@ class GitWikiWebPage {
               seen.add(ref);
             }
           }
-          results[recency] = { dateTime, humanReadable, refs };
+          results[recency] = { dateTime, hash, humanReadable, refs };
         } while (recency-- > 0 && current && current != commit);
         return results;
       })(),
@@ -707,14 +768,16 @@ class GitWikiWebPage {
                             refs,
                           } = result;
                           yield* listOfInternalLinks(refs, (link) => ({
-                            tag: index ? "strong" : "span",
+                            tag: index == 0 ? "span" : "strong",
                             attributes: { "data-recency": `${index}` },
                             children: [
                               link,
-                              str` `,
-                              rawInline`<small>(<time dateTime="${dateTime}">`,
-                              str`${humanReadable}`,
-                              rawInline`</time>)</small>`,
+                              ...(index == 0 ? [] : [
+                                str` `,
+                                rawInline`<small>(<time dateTime="${dateTime}">`,
+                                str`${humanReadable}`,
+                                rawInline`</time>)</small>`,
+                              ]),
                             ],
                           })).children;
                         } else {
@@ -763,7 +826,7 @@ class GitWikiWebPage {
           },
           heading: {
             enter: (e) => {
-              const attributes = e.attributes ?? Object.create(null);
+              const attributes = e.attributes ?? NIL;
               if (
                 isNavigationPage && e.level == 1 &&
                 attributes?.class == "main"
@@ -806,8 +869,7 @@ class GitWikiWebPage {
                 }
                 if (children.length == 0) {
                   const section =
-                    pages.get(reference)?.sections?.main ??
-                      Object.create(null);
+                    pages.get(reference)?.sections?.main ?? NIL;
                   const { v } = attributes;
                   if (v == null) {
                     children.push(
This page took 0.035165 seconds and 4 git commands to generate.