]> Lady’s Gitweb - Beorn/blobdiff - build.js
Support hooks for transforming build script output
[Beorn] / build.js
index 785b86f94b9db7e39c28ffd0f381725e15ae1d81..4c26518b85d4a2597126c582d50d305fd4ccd38c 100755 (executable)
--- a/build.js
+++ b/build.js
@@ -2,7 +2,7 @@
 // 🧸📔 Bjørn ∷ build.js
 // ====================================================================
 //
-// Copyright © 2022 Lady [@ Lady’s Computer].
+// Copyright © 2022‐2023 Lady [@ Lady’s Computer].
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -344,6 +344,7 @@ const applyMetadata = (node, metadata) => {
         // There is no content placeholder.
         /* do nothing */
       }
+      globalThis.bjørnTransformEntryHTML?.(document, metadata);
     } else {
       // This is not an XHTML template.
       /* do nothing */
@@ -403,13 +404,19 @@ const applyMetadata = (node, metadata) => {
       // This entry does not have a publication date.
       /* do nothing */
     }
-    addContent(contentElement, "\n");
-    addContent(
-      contentElement.appendChild(
-        LMN.div.property(`${DC11}abstract`)``,
-      ),
-      summary,
-    );
+    if (summary) {
+      // This entry has a summary.
+      addContent(contentElement, "\n");
+      addContent(
+        contentElement.appendChild(
+          LMN.div.property(`${DC11}abstract`)``,
+        ),
+        summary,
+      );
+    } else {
+      // This entry does not have a summary.
+      /* do nothing */
+    }
     addContent(contentElement, "\n");
     addContent(node, "\n");
   } else {
@@ -633,6 +640,7 @@ const fillOutHead = (document, metadata, type) => {
         .href("./feed.atom")``,
     );
   }
+  globalThis.bjørnTransformHead?.(head, metadata, type);
 };
 
 /**
@@ -860,6 +868,7 @@ const metadataFromDocument = (
       /* do nothing */
     }
   }
+  globalThis.bjørnTransformMetadata?.(result, documentType);
   return validateMetadata(result, documentType);
 };
 
@@ -900,16 +909,40 @@ const validateMetadata = (metadata, type) => {
   }
 };
 
+{ // Set up global variables for use in hooks.
+  //
+  // Bjørn is principally built to be run from the command line (as a
+  // shell script) rather than conforming to typical Ecmascript module
+  // patterns. However, it recognizes hooks through various
+  // specially‐named properties on `globalThis`. After defining these
+  // hooks, a script can use a *dynamic* `import("./path/to/build.js")`
+  // to run the Bjørn build steps.
+  //
+  // To make writing scripts which make use of these hooks easier,
+  // infrastructural dependencies and useful functions are provided on
+  // `globalThis` so that wrapping scripts don’t have to attempt to
+  // manage the dependencies themselves.
+  //
+  // Note that the `Lemon/window` polyfill will already have
+  // established some D·O·M‐related global properties by the time this
+  // runs, so they don’t need to be redeclared here.
+  globalThis.Lemon = Lemon;
+  globalThis.Bjørn = {
+    addContent,
+    getLanguage,
+    setLanguage,
+  };
+}
+
 await (async () => { // this is the run script
   const writes = [];
 
   // Set up the feed metadata and Atom feed document.
-  const feedMetadata = metadataFromDocument(
-    parser.parseFromString(
-      await Deno.readTextFile(`${basePath}/#feed.rdf`),
-      "application/xml",
-    ),
+  const feedDocument = parser.parseFromString(
+    await Deno.readTextFile(`${basePath}/#feed.rdf`),
+    "application/xml",
   );
+  const feedMetadata = metadataFromDocument(feedDocument);
   const feedURI = new URL(feedMetadata.id);
   const document = parser.parseFromString(
     `<?xml version="1.0" encoding="utf-8"?>
@@ -920,10 +953,28 @@ await (async () => { // this is the run script
     "application/xml",
   );
   const { documentElement: feed } = document;
+  const feedLanguage = getLanguage(feedDocument);
+  if (feedLanguage) {
+    // The feed element has a language.
+    setLanguage(feed, feedLanguage);
+  } else {
+    // There is no language for the feed.
+    /* do nothing */
+  }
   applyMetadata(feed, feedMetadata);
 
   // Set up the index page.
   const feedTemplate = await documentFromTemplate("feed");
+  const { documentElement: feedTemplateRoot } = feedTemplate;
+  if (feedLanguage && !getLanguage(feedTemplateRoot)) {
+    // The root element of the template does not have an
+    // assigned language, but the feed does.
+    setLanguage(feedTemplateRoot, feedLanguage);
+  } else {
+    // Either the template root already has a language, or the
+    // entry doesn’t either.
+    /* do nothing */
+  }
   const feedEntries = feedTemplate.createDocumentFragment();
 
   // Process entries and save the resulting index files.
@@ -1016,8 +1067,7 @@ await (async () => { // this is the run script
 
   // Apply the feed metadata to the feed template and save the
   // resulting index file.
-  const { documentElement: feedRoot } = feedTemplate;
-  if (hasExpandedName(feedRoot, XHTML, "html")) {
+  if (hasExpandedName(feedTemplateRoot, XHTML, "html")) {
     // This is an XHTML template.
     const LMN = Lemon.bind({ document: feedTemplate });
     const {
@@ -1092,6 +1142,7 @@ await (async () => { // this is the run script
       /* do nothing */
     }
   }
+  globalThis.bjørnTransformFeedHTML?.(feedTemplate, feedMetadata);
   writes.push(
     Deno.writeTextFile(
       "index.xhtml",
@@ -1100,6 +1151,7 @@ await (async () => { // this is the run script
   );
 
   // Save the feed Atom file.
+  globalThis.bjørnTransformFeedAtom?.(document, feedMetadata);
   writes.push(
     Deno.writeTextFile(
       "feed.atom",
This page took 0.02896 seconds and 4 git commands to generate.