« get me outta code hell

okay so like, hear me out here - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/upd8-util.js
diff options
context:
space:
mode:
author(quasar) nebula <towerofnix@gmail.com>2021-01-08 00:15:37 -0400
committer(quasar) nebula <towerofnix@gmail.com>2021-01-08 00:15:37 -0400
commit8a7cb1edff25ba3e612d7c24b07cc776ff8738d6 (patch)
tree3a0fd54a103d340fd2d39f67620daea85eca2682 /upd8-util.js
parent8aa973e5b4c22b34dfa6256f716ff872d8dad042 (diff)
okay so like, hear me out here
this commit isnt QUITE done but its in a working state, and i just had
the scariest vision of accidentally discarding all my work via git
mishap, yknow? even though im not doing anything funky with git! so yall
get this commit early and its goin on line but im not pushing it to the
site til its done. no spoilering yourself (even though ive already
posted most of the cool things in the discord) <3
Diffstat (limited to 'upd8-util.js')
-rw-r--r--upd8-util.js143
1 files changed, 142 insertions, 1 deletions
diff --git a/upd8-util.js b/upd8-util.js
index b24b3b7f..28504eaf 100644
--- a/upd8-util.js
+++ b/upd8-util.js
@@ -62,7 +62,11 @@ module.exports.progressPromiseAll = function (msg, array) {
     })));
 };
 
-module.exports.queue = function (array, max = 10) {
+module.exports.queue = function (array, max = 50) {
+    if (max === 0) {
+        return array.map(fn => fn());
+    }
+
     const begin = [];
     let current = 0;
     const ret = array.map(fn => new Promise((resolve, reject) => {
@@ -155,3 +159,140 @@ decorateTime.displayTime = function() {
 };
 
 module.exports.decorateTime = decorateTime;
+
+// Stolen as #@CK from mtui!
+const parseOptions = async function(options, optionDescriptorMap) {
+    // This function is sorely lacking in comments, but the basic usage is
+    // as such:
+    //
+    // options is the array of options you want to process;
+    // optionDescriptorMap is a mapping of option names to objects that describe
+    // the expected value for their corresponding options.
+    // Returned is a mapping of any specified option names to their values, or
+    // a process.exit(1) and error message if there were any issues.
+    //
+    // Here are examples of optionDescriptorMap to cover all the things you can
+    // do with it:
+    //
+    // optionDescriptorMap: {
+    //   'telnet-server': {type: 'flag'},
+    //   't': {alias: 'telnet-server'}
+    // }
+    //
+    // options: ['t'] -> result: {'telnet-server': true}
+    //
+    // optionDescriptorMap: {
+    //   'directory': {
+    //     type: 'value',
+    //     validate(name) {
+    //       // const whitelistedDirectories = ['apple', 'banana']
+    //       if (whitelistedDirectories.includes(name)) {
+    //         return true
+    //       } else {
+    //         return 'a whitelisted directory'
+    //       }
+    //     }
+    //   },
+    //   'files': {type: 'series'}
+    // }
+    //
+    // ['--directory', 'apple'] -> {'directory': 'apple'}
+    // ['--directory', 'artichoke'] -> (error)
+    // ['--files', 'a', 'b', 'c', ';'] -> {'files': ['a', 'b', 'c']}
+    //
+    // TODO: Be able to validate the values in a series option.
+
+    const handleDashless = optionDescriptorMap[parseOptions.handleDashless];
+    const handleUnknown = optionDescriptorMap[parseOptions.handleUnknown];
+    const result = Object.create(null);
+    for (let i = 0; i < options.length; i++) {
+        const option = options[i];
+        if (option.startsWith('--')) {
+            // --x can be a flag or expect a value or series of values
+            let name = option.slice(2).split('=')[0]; // '--x'.split('=') = ['--x']
+            let descriptor = optionDescriptorMap[name];
+            if (!descriptor) {
+                if (handleUnknown) {
+                    handleUnknown(option);
+                } else {
+                    console.error(`Unknown option name: ${name}`);
+                    process.exit(1);
+                }
+                continue;
+            }
+            if (descriptor.alias) {
+                name = descriptor.alias;
+                descriptor = optionDescriptorMap[name];
+            }
+            if (descriptor.type === 'flag') {
+                result[name] = true;
+            } else if (descriptor.type === 'value') {
+                let value = option.slice(2).split('=')[1];
+                if (!value) {
+                    value = options[++i];
+                    if (!value || value.startsWith('-')) {
+                        value = null;
+                    }
+                }
+                if (!value) {
+                    console.error(`Expected a value for --${name}`);
+                    process.exit(1);
+                }
+                result[name] = value;
+            } else if (descriptor.type === 'series') {
+                if (!options.slice(i).includes(';')) {
+                    console.error(`Expected a series of values concluding with ; (\\;) for --${name}`);
+                    process.exit(1);
+                }
+                const endIndex = i + options.slice(i).indexOf(';');
+                result[name] = options.slice(i + 1, endIndex);
+                i = endIndex;
+            }
+            if (descriptor.validate) {
+                const validation = await descriptor.validate(result[name]);
+                if (validation !== true) {
+                    console.error(`Expected ${validation} for --${name}`);
+                    process.exit(1);
+                }
+            }
+        } else if (option.startsWith('-')) {
+            // mtui doesn't use any -x=y or -x y format optionuments
+            // -x will always just be a flag
+            let name = option.slice(1);
+            let descriptor = optionDescriptorMap[name];
+            if (!descriptor) {
+                if (handleUnknown) {
+                    handleUnknown(option);
+                } else {
+                    console.error(`Unknown option name: ${name}`);
+                    process.exit(1);
+                }
+                continue;
+            }
+            if (descriptor.alias) {
+                name = descriptor.alias;
+                descriptor = optionDescriptorMap[name];
+            }
+            if (descriptor.type === 'flag') {
+                result[name] = true;
+            } else {
+                console.error(`Use --${name} (value) to specify ${name}`);
+                process.exit(1);
+            }
+        } else if (handleDashless) {
+            handleDashless(option);
+        }
+    }
+    return result;
+}
+
+parseOptions.handleDashless = Symbol();
+parseOptions.handleUnknown = Symbol();
+
+module.exports.parseOptions = parseOptions;
+
+// Cheap FP for a cheap dyke!
+// I have no idea if this is what curry actually means.
+module.exports.curry = f => x => (...args) => f(x, ...args);
+
+module.exports.mapInPlace = (array, fn) => array.splice(0, array.length, ...array.map(fn));