« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/write/build-modes
diff options
context:
space:
mode:
Diffstat (limited to 'src/write/build-modes')
-rw-r--r--src/write/build-modes/index.js1
-rw-r--r--src/write/build-modes/live-dev-server.js29
-rw-r--r--src/write/build-modes/sort.js76
-rw-r--r--src/write/build-modes/static-build.js47
4 files changed, 106 insertions, 47 deletions
diff --git a/src/write/build-modes/index.js b/src/write/build-modes/index.js
index 3ae2cfc6..4b61619d 100644
--- a/src/write/build-modes/index.js
+++ b/src/write/build-modes/index.js
@@ -1,3 +1,4 @@
 export * as 'live-dev-server' from './live-dev-server.js';
 export * as 'repl' from './repl.js';
+export * as 'sort' from './sort.js';
 export * as 'static-build' from './static-build.js';
diff --git a/src/write/build-modes/live-dev-server.js b/src/write/build-modes/live-dev-server.js
index 28969de2..5dece8d0 100644
--- a/src/write/build-modes/live-dev-server.js
+++ b/src/write/build-modes/live-dev-server.js
@@ -1,6 +1,7 @@
 import {spawn} from 'node:child_process';
 import * as http from 'node:http';
 import {open, stat} from 'node:fs/promises';
+import * as os from 'node:os';
 import * as path from 'node:path';
 import {pipeline} from 'node:stream/promises';
 import {inspect as nodeInspect} from 'node:util';
@@ -252,7 +253,7 @@ export async function go({
     let url;
     try {
       url = new URL(request.url, `http://${request.headers.host}`);
-    } catch (error) {
+    } catch {
       response.writeHead(500, contentTypePlain);
       response.end('Failed to parse request URL\n');
       return;
@@ -299,7 +300,7 @@ export async function go({
       let filePath;
       try {
         filePath = path.resolve(localDirectory, decodeURI(safePath.split('/').join(path.sep)));
-      } catch (error) {
+      } catch {
         response.writeHead(404, contentTypePlain);
         response.end(`File not found for: ${safePath}`);
         console.log(`${requestHead} [404] ${pathname}`);
@@ -389,7 +390,11 @@ export async function go({
     // URL to page map expects trailing slash but no leading slash.
     const pathnameKey = pathname.replace(/^\//, '') + (pathname.endsWith('/') ? '' : '/');
 
-    if (!Object.hasOwn(urlToPageMap, pathnameKey)) {
+    const is404 =
+      !Object.hasOwn(urlToPageMap, pathnameKey) ||
+      !(urlToPageMap[pathnameKey].page.condition?.() ?? true);
+
+    if (is404) {
       response.writeHead(404, contentTypePlain);
       response.end(`No page found for: ${pathnameKey}\n`);
       if (loudResponses) console.log(`${requestHead} [404] ${pathname} (no page)`);
@@ -488,7 +493,13 @@ export async function go({
     }
   });
 
-  const address = `http://${host}:${port}/`;
+  const addresses =
+    (host === '0.0.0.0'
+      ? [`http://localhost:${port}/`,
+         `http://${os.hostname()}:${port}/`]
+   : host === '127.0.0.1'
+      ? [`http://localhost:${port}/`]
+      : [`http://${host}:${port}/`]);
 
   server.on('error', error => {
     if (error.code === 'EADDRINUSE') {
@@ -505,7 +516,15 @@ export async function go({
   });
 
   server.on('listening', () => {
-    logInfo`${'All done!'} Listening at: ${address}`;
+    if (addresses.length === 1) {
+      logInfo`${'All done!'} Listening at: ${addresses[0]}`;
+    } else {
+      logInfo`${`All done!`} Listening at:`;
+      for (const address of addresses) {
+        logInfo`- ${address}`;
+      }
+    }
+
     logInfo`Press ^C here (control+C) to stop the server and exit.`;
     if (showTimings && loudResponses) {
       logInfo`Printing all HTTP responses, plus page generation timings.`;
diff --git a/src/write/build-modes/sort.js b/src/write/build-modes/sort.js
new file mode 100644
index 00000000..1a738ac8
--- /dev/null
+++ b/src/write/build-modes/sort.js
@@ -0,0 +1,76 @@
+export const description = `Update data files in-place to satisfy custom sorting rules`;
+
+import {logInfo} from '#cli';
+import {empty} from '#sugar';
+import thingConstructors from '#things';
+
+export const config = {
+  fileSizes: {
+    applicable: false,
+  },
+
+  languageReloading: {
+    applicable: false,
+  },
+
+  mediaValidation: {
+    applicable: false,
+  },
+
+  search: {
+    applicable: false,
+  },
+
+  thumbs: {
+    applicable: false,
+  },
+
+  webRoutes: {
+    applicable: false,
+  },
+
+  sort: {
+    applicable: false,
+  },
+};
+
+export function getCLIOptions() {
+  return {};
+}
+
+export async function go({wikiData, dataPath}) {
+  if (empty(wikiData.sortingRules)) {
+    logInfo`There aren't any sorting rules in for this wiki.`;
+    return true;
+  }
+
+  const {SortingRule} = thingConstructors;
+
+  let numUpdated = 0;
+  let numActive = 0;
+
+  for await (const result of SortingRule.go({wikiData, dataPath})) {
+    numActive++;
+
+    const niceMessage = `"${result.rule.message}"`;
+
+    if (result.changed) {
+      numUpdated++;
+      logInfo`Updating to satisfy ${niceMessage}.`;
+    } else {
+      logInfo`Already good: ${niceMessage}`;
+    }
+  }
+
+  if (numUpdated > 1) {
+    logInfo`Updated data files to satisfy ${numUpdated} sorting rules.`;
+  } else if (numUpdated === 1) {
+    logInfo`Updated data files to satisfy ${1} sorting rule.`
+  } else if (numActive >= 1) {
+    logInfo`All sorting rules were already satisfied. Good to go!`;
+  } else {
+    logInfo`No sorting rules are currently active.`;
+  }
+
+  return true;
+}
diff --git a/src/write/build-modes/static-build.js b/src/write/build-modes/static-build.js
index 7eb73474..b5ded04c 100644
--- a/src/write/build-modes/static-build.js
+++ b/src/write/build-modes/static-build.js
@@ -1,15 +1,6 @@
+import {cp, mkdir, stat, symlink, writeFile, unlink} from 'node:fs/promises';
 import * as path from 'node:path';
 
-import {
-  copyFile,
-  cp,
-  mkdir,
-  stat,
-  symlink,
-  writeFile,
-  unlink,
-} from 'node:fs/promises';
-
 import {rimraf} from 'rimraf';
 
 import {quickLoadContentDependencies} from '#content-dependencies';
@@ -115,8 +106,6 @@ export async function go({
 
   universalUtilities,
 
-  mediaPath,
-
   defaultLanguage,
   languages,
   urls,
@@ -166,11 +155,6 @@ export async function go({
   });
 
   if (writeAll) {
-    await writeFavicon({
-      mediaPath,
-      outputPath,
-    });
-
     await writeSharedFilesAndPages({
       outputPath,
       randomLinkDataJSON: generateRandomLinkDataJSON({wikiData}),
@@ -195,7 +179,7 @@ export async function go({
           return null;
         }
 
-        const paths = [];
+        let paths = [];
 
         if (pageSpec.pathsTargetless) {
           const result = pageSpec.pathsTargetless({wikiData});
@@ -225,6 +209,9 @@ export async function go({
           // TODO: Validate each pathsForTargets entry
         }
 
+        paths =
+          paths.filter(path => path.condition?.() ?? true);
+
         return paths;
       })
       .filter(Boolean)
@@ -592,30 +579,6 @@ async function writeWebRouteCopies({
   }
 }
 
-async function writeFavicon({
-  mediaPath,
-  outputPath,
-}) {
-  const faviconFile = 'favicon.ico';
-
-  try {
-    await stat(path.join(mediaPath, faviconFile));
-  } catch (error) {
-    return;
-  }
-
-  try {
-    await copyFile(
-      path.join(mediaPath, faviconFile),
-      path.join(outputPath, faviconFile));
-  } catch (error) {
-    logWarn`Failed to copy favicon! ${error.message}`;
-    return;
-  }
-
-  logInfo`Copied favicon to site root.`;
-}
-
 async function writeSharedFilesAndPages({
   outputPath,
   randomLinkDataJSON,