« get me outta code hell

stub --help option - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
diff options
context:
space:
mode:
author(quasar) nebula <qznebula@protonmail.com>2023-01-16 19:44:33 -0400
committer(quasar) nebula <qznebula@protonmail.com>2023-01-16 19:44:58 -0400
commit8fa238e49bf4db2ddd72de4960bbaec7f4a72824 (patch)
tree7ad7450bc235816a3e14974e9bbf4a834892c3dd
parentda564121c31235f9000f09dd6f9d922b5623249e (diff)
stub --help option
-rw-r--r--package-lock.json7
-rw-r--r--package.json3
-rwxr-xr-xsrc/upd8.js101
3 files changed, 93 insertions, 18 deletions
diff --git a/package-lock.json b/package-lock.json
index 65e8bcac..fcccac83 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,7 +12,8 @@
                 "chroma-js": "^2.4.2",
                 "command-exists": "^1.2.9",
                 "he": "^1.2.0",
-                "js-yaml": "^4.1.0"
+                "js-yaml": "^4.1.0",
+                "word-wrap": "^1.2.3"
             },
             "bin": {
                 "hsmusic": "src/upd8.js"
@@ -1895,7 +1896,6 @@
             "version": "1.2.3",
             "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
             "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
-            "dev": true,
             "engines": {
                 "node": ">=0.10.0"
             }
@@ -3289,8 +3289,7 @@
         "word-wrap": {
             "version": "1.2.3",
             "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
-            "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
-            "dev": true
+            "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
         },
         "wrappy": {
             "version": "1.0.2",
diff --git a/package.json b/package.json
index c9f0c1d7..348ca896 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,8 @@
         "chroma-js": "^2.4.2",
         "command-exists": "^1.2.9",
         "he": "^1.2.0",
-        "js-yaml": "^4.1.0"
+        "js-yaml": "^4.1.0",
+        "word-wrap": "^1.2.3"
     },
     "license": "GPL-3.0",
     "devDependencies": {
diff --git a/src/upd8.js b/src/upd8.js
index cb6c559a..5668542c 100755
--- a/src/upd8.js
+++ b/src/upd8.js
@@ -34,6 +34,7 @@
 import {execSync} from 'child_process';
 import * as path from 'path';
 import {fileURLToPath} from 'url';
+import wrap from 'word-wrap';
 
 import genThumbs from './gen-thumbs.js';
 import {listingSpec, listingTargetSpec} from './listing-spec.js';
@@ -60,6 +61,7 @@ import {validateReplacerSpec} from './util/replacer.js';
 import {empty, showAggregate} from './util/sugar.js';
 import {replacerSpec} from './util/transform-content.js';
 import {generateURLs} from './util/urls.js';
+import {sortByName} from './util/wiki-data.js';
 
 import {generateDevelopersCommentHTML} from './write/page-template.js';
 import * as buildModes from './write/build-modes/index.js';
@@ -99,14 +101,15 @@ if (!validateReplacerSpec(replacerSpec, {find, link})) {
 async function main() {
   Error.stackTraceLimit = Infinity;
 
+  const buildModeFlagOptions = (
+    Object.fromEntries(
+      Object.keys(buildModes)
+        .map(key => [key, {type: 'flag'}])));
+
   const selectedBuildModeFlags = Object.keys(
     await parseOptions(process.argv.slice(2), {
-      // Ignore unknown options for now - we'll handle and error them later.
       [parseOptions.handleUnknown]: () => {},
-
-      ...Object.fromEntries(
-        Object.keys(buildModes)
-          .map((key) => [key, {type: 'flag'}])),
+      ...buildModeFlagOptions,
     }));
 
   let selectedBuildModeFlag;
@@ -131,15 +134,12 @@ async function main() {
     listingTargetSpec,
   };
 
-  const cliOptions = await parseOptions(process.argv.slice(2), {
-    // We don't want to error when we receive these options, so specify them
-    // here, even though we won't be doing anything with them later.
-    // (This is a bit of a hack.)
-    ...Object.fromEntries(
-      Object.keys(buildModes)
-        .map((key) => [key, {type: 'flag'}])),
+  const buildOptions = selectedBuildMode.getCLIOptions();
 
-    ...selectedBuildMode.getCLIOptions(),
+  const commonOptions = {
+    'help': {
+      type: 'flag',
+    },
 
     // Data files for the site, including flash, artist, and al8um data,
     // and like a jillion other things too. Pretty much everything which
@@ -226,8 +226,83 @@ async function main() {
     'precache-data': {
       type: 'flag',
     },
+  };
+
+  const cliOptions = await parseOptions(process.argv.slice(2), {
+    // We don't want to error when we receive these options, so specify them
+    // here, even though we won't be doing anything with them later.
+    // (This is a bit of a hack.)
+    ...buildModeFlagOptions,
+
+    ...commonOptions,
+    ...buildOptions,
   });
 
+  if (cliOptions['help']) {
+    const indentWrap = (spaces, str) => wrap(str, {width: 60 - spaces, indent: ' '.repeat(spaces)});
+
+    const showOptions = (msg, options) => {
+      console.log(color.bright(msg));
+
+      const entries = Object.entries(options);
+      const sortedOptions = sortByName(entries
+        .map(([name, descriptor]) => ({name, descriptor})));
+
+      if (!sortedOptions.length) {
+        console.log(`(No options available)`)
+      }
+
+      for (const {name, descriptor} of sortedOptions) {
+        if (descriptor.alias) {
+          continue;
+        }
+
+        const aliases = entries
+          .filter(([_name, {alias}]) => alias === name)
+          .map(([name]) => name);
+
+        console.log(color.bright(` --` + name) +
+          (aliases.length
+            ? ` (or: ${aliases.map(alias => color.bright(`--` + alias)).join(', ')})`
+            : '') +
+          (descriptor.help
+            ? ''
+            : color.dim('  (no help provided)')));
+
+        if (descriptor.help) {
+          console.log(indentWrap(4, descriptor.help));
+        }
+      }
+
+      console.log(``);
+    };
+
+    console.log(
+      color.bright(`hsmusic (aka. Homestuck Music Wiki)\n`) +
+      `static wiki software cataloguing collaborative creation\n`);
+
+    console.log(indentWrap(0,
+      `The \`hsmusic\` command provides basic control over all parts of generating user-visible HTML pages and website content/structure from provided data, media, and language directories.\n` +
+      `\n` +
+      `CLI options are divided into three groups:\n`));
+    console.log(` 1) ` + indentWrap(4,
+      `Common options: These are shared by all build modes and always have the same essential behavior`).trim());
+    console.log(` 2) ` + indentWrap(4,
+      `Build mode selection: One build mode may be selected (or else the default, --static-build, is used), and it decides which entire set of behavior to use for providing site content to the user`).trim());
+    console.log(` 3) ` + indentWrap(4,
+      `Build options: Each build mode has a set of unique options which customize behavior for that build mode`).trim());
+    console.log(``);
+
+    showOptions(`Common options`, commonOptions);
+    showOptions(`Build mode selection`, buildModeFlagOptions);
+
+    if (buildOptions) {
+      showOptions(`Build options for --${selectedBuildModeFlag}`, buildOptions);
+    }
+
+    return;
+  }
+
   const dataPath = cliOptions['data-path'] || process.env.HSMUSIC_DATA;
   const mediaPath = cliOptions['media-path'] || process.env.HSMUSIC_MEDIA;
   const langPath = cliOptions['lang-path'] || process.env.HSMUSIC_LANG; // Can 8e left unset!