WIP - Rewrite to better handle multiple option-arguments / operands

This commit is contained in:
n loewen 2023-08-31 23:45:17 -04:00
parent cec7d20a14
commit 1a1b189f7a
1 changed files with 112 additions and 4 deletions

View File

@ -1,12 +1,119 @@
module.exports = parse;
// Inspired a bit by
// https://github.com/eveningkid/args-parser/blob/master/parse.js
// https://unix.stackexchange.com/questions/364383/confusion-about-changing-meaning-of-arguments-and-options-is-there-an-official
// https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/basedefs/V1_chap12.html#tag_12_01
// 'options' are --foo, -f
//
// 'option-arguments' are (non-option) things that follow an option, and that the option expects
// eg. 'filename.txt' in './example --input filename.txt'
//
// 'operands' are (non-option) things that follow an option, but aren't option-arguments
// eg 'filename.txt' in './example --verbose filename.txt'
/**
* @returns [ { string: boolean } | { string: string[] } ]
**/
function parse(argv) {
argv = process.argv.slice(2);
let finalOutput = {};
// Label everything in argv as either
// an 'option' or an 'arg_or_operand'
let mapped = argv.flatMap((a) => {
// A single long option
if (a.startsWith('--')) {
return { arg: a.substring(2), type: 'option' }
}
// A single short option
if (a.startsWith('-') && (a.length === 2)) {
return { arg: a.substring(1), type: 'option' }
}
// Multiple short options
if (a.startsWith('-')) {
let splitGroup = a.substring(1).split('');
return splitGroup.map((sg) => { return {arg: sg, type: 'option'} });
}
// An option-argument or operand
return { arg: a, type: 'arg_or_operand' };
});
// Group consecutive option-args/operands
let wrapped = mapped.map((a) => [a]);
let grouped = [];
wrapped.forEach((a, i) => {
if (i === 0 || a[0].type === 'option') {
grouped.push(a);
return;
}
let prev = grouped.pop();
if (prev[0].type === 'option') {
grouped.push(prev);
grouped.push(a);
return;
}
grouped.push(prev.concat(a));
return;
});
let out = []
grouped.forEach((a, i) => {
console.log('current', a);
let next = grouped[i+1];
console.log('next', next);
if ((a[0].type === 'option')
&& next
&& (next[0].type === 'arg_or_operand')) {
console.log('next is a value');
let next_shortened = next.map(n => n.arg);
console.log('short', next_shortened);
let o = {};
o[a[0].arg] = next_shortened;
out.push(o);
grouped.splice(i, 1);
} else {
let pair = {};
pair[a[0].arg] = true;
a.forEach((b) => {
let o = {};
o[b.arg] = true;
out.push(o);
});
}
});
console.log('out', out);
}
/*
// this is good, but doesn't handle multiple operands in a row
let out = [];
mapped.forEach((a, i) => {
console.log(a, i);
if ((a.type === 'flag') && (mapped[i+1].type === 'arg_or_operand')) {
console.log('next is a value');
let pair = {};
pair[a.arg] = mapped[i+1].arg;
out.push(pair);
mapped.splice(i, 1);
} else {
let pair = {};
pair[a.arg] = true;
out.push(pair);
}
});
//console.log(out);
}
*/
/*
argv.forEach((arg) => {
// We'll treat `--long` flags and flags without dash prefixes the same,
// so just discard double-dash prefixes
@ -61,4 +168,5 @@ function processArg(a) {
} else {
return [key, true];
}
}
}
*/