#!/usr/bin/env node const test = require('node:test'); // WIP // Example /* let cpuArguments = { help: '', // TODO args: [ { flags: { short: 'f' }, name: 'Filename', requiresValue: true, }, { name: 'Clock speed', flags: { short: 'c', long: 'clock' }, requiresValue: true, optional: true }, { name: 'Pretty-print display', flags: { short: 'p', long: 'pretty' }, optional: true, }, { name: 'Single-step', flags: { short: 's', long: 'step' }, optional: true, }, { 'name': 'Debug', flags: { short: 'd', long: 'debug' }, optional: true, } ] }; */ // Constructors function Arguments(argumentsObject=[], helpText='') { this.help = helpText; this.args = argumentsObject; Arguments.prototype.add = (...a) => a.forEach((x) => argumentsObject.push(x)); }; function Arg({ name = 'Flag', shortFlag = null, longFlag = null, requiresValue=false, optional=false }) { this.name = name; this.flags = { short: shortFlag, long: longFlag }; this.requiresValue = requiresValue; this.optional = optional; }; // Test constructors let cpuArguments = new Arguments(); cpuArguments.add( new Arg({name: 'Filename', shortFlag: 'f', requiresValue: true}), new Arg({name: 'Clock speed', shortFlag: 'c', longFlag: 'clock', requiresValue: true, optional: true}), new Arg({name: 'Debug', shortFlag: 'd', longFlag: 'debug', optional: true}), new Arg({name: 'Pretty-print display', shortFlag: 'p', longFlag: 'pretty', optional: true}), new Arg({name: 'Single-step', shortFlag: 's', longFlag: 'step', optional: true})); ///console.log(cpuArguments); ///console.log('flags', cpuArguments.args[0].flags); // MODULE: // TODO: // - building a structured output // - testing // - exporting as object const argsRequiringValues = cpuArguments.args.filter((a) => a.requiresValue); const requiredArgs = cpuArguments.args.filter((a) => !a.optional); let argv = process.argv.slice(2); // Split up grouped short flags let argvSplit = [].concat(...argv.map((x) => { if (x.startsWith('-') && !x.startsWith('--')) { // short flags let arr = x.substring(1).split(''); arr = arr.map((y) => '-' + y); return arr; } return x; })); // Check if all the required flags have been included requiredArgs.forEach((a) => { if (!argvSplit.includes('-'+a.flags.short) && !argvSplit.includes('-'+a.flags.long)) { let long = (a.flags.long) ? `--${a.flags.long}, ` : ''; throw new Error(`${a.name} flag (-${a.flags.short}${long}) is required`); } }); // Validate... argvSplit.forEach((currentArg, index) => { console.log('checking', currentArg); // Check for attempts to use --flags that don't exist if (currentArg.startsWith('--')) { console.log('--'); let valid = cpuArguments.args.filter((a) => { return A.flags.long === currentArg.substring(2)}).length > 0; console.log('valid', valid); if (!valid) { throw new Error(`There is no ${currentArg} option`); } } else if (currentArg.startsWith('-')) { console.log(currentArg.substring(1)); let valid = cpuArguments.args.filter((a) => { console.log(a); return a.flags.short === currentArg.substring(1)}).length > 0; if (!valid) { throw new Error(`There is no ${currentArg} option`); } } ///console.log(' it\'s a valid argument'); ///console.log(' argsrequiringvalues', argsRequiringValues); ///console.log(' currentarg', currentArg); // Check if it requires a value... // and if it does, do a cursory check to see if one is likely to be there let shouldCheckValue = argsRequiringValues.filter((a) => { /// console.log('a', a); let noDash = currentArg.substring(1); return (a.flags.short === noDash || a.flags.long === noDash); }).length > 0; /// console.log(' requires a value?', shouldCheckValue); /// console.log(' split', argvSplit); if (shouldCheckValue) { ///console.log(currentArg); let errorMessage = `Value required for ${currentArg}`; // If there's nothing after this flag, error; // Or if the next item is a flag... error: /// console.log('idx', index, argvSplit[index]); if (typeof argvSplit[index + 1] === 'undefined') { throw new Error(errorMessage); } else if (argvSplit[index + 1].startsWith('-')) { throw new Error(errorMessage); }; } });