You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
2.6 KiB
110 lines
2.6 KiB
2 years ago
|
import assert from "assert";
|
||
|
|
||
|
const argv = [...process.argv];
|
||
|
function next() {
|
||
|
return argv.shift();
|
||
|
}
|
||
|
|
||
|
function peek() {
|
||
|
return argv[0];
|
||
|
}
|
||
|
|
||
|
const positional: Array<string | boolean> = [];
|
||
|
const named: { [key: string]: string | boolean } = {};
|
||
|
|
||
|
while (argv.length) {
|
||
|
const arg = next();
|
||
|
if (arg === undefined) break;
|
||
|
|
||
|
if (arg.startsWith("--")) {
|
||
|
const match = arg.match(/^--([^=]*)(=?)(.*)$/);
|
||
|
assert(match);
|
||
|
const name = match[1];
|
||
|
if (!name.length) continue;
|
||
|
let value: string | boolean = true;
|
||
|
if (match[2] === "=") {
|
||
|
if (match[3].length) {
|
||
|
value = match[3];
|
||
|
}
|
||
|
} else {
|
||
|
const nextArg = peek();
|
||
|
if (nextArg && !nextArg.startsWith("-")) {
|
||
|
next();
|
||
|
value = nextArg;
|
||
|
}
|
||
|
}
|
||
|
named[name] = value;
|
||
|
} else if (arg.startsWith("-")) {
|
||
|
const match = arg.match(/^-(.*?)(=?)([^=a-zA-Z]*)$/);
|
||
|
assert(match);
|
||
|
const names = match[1].split("");
|
||
|
if (!names.length) continue;
|
||
|
while (names.length > 1) {
|
||
|
const name = names.shift();
|
||
|
if (name && name.length) {
|
||
|
named[name] = true;
|
||
|
}
|
||
|
}
|
||
|
let lastName = names.shift();
|
||
|
if (!lastName) continue;
|
||
|
let lastValue: string | boolean = true;
|
||
|
if (match[2] === "=") {
|
||
|
if (match[3].length) {
|
||
|
lastValue = match[3];
|
||
|
}
|
||
|
} else {
|
||
|
const nextArg = peek();
|
||
|
if (nextArg && !nextArg.startsWith("-")) {
|
||
|
next();
|
||
|
lastValue = nextArg;
|
||
|
}
|
||
|
}
|
||
|
named[lastName] = lastValue;
|
||
|
} else {
|
||
|
positional.push(arg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function getArg(...nameOrPositions: Array<string | number>) {
|
||
|
let value: string | boolean | undefined;
|
||
|
for (const nameOrPosition of nameOrPositions) {
|
||
|
if (typeof nameOrPosition === "string") {
|
||
|
const name = nameOrPosition;
|
||
|
if (name in named) {
|
||
|
value = named[name];
|
||
|
break;
|
||
|
}
|
||
|
} else if (Number.isInteger(nameOrPosition)) {
|
||
|
const position = nameOrPosition;
|
||
|
if (position < positional.length) {
|
||
|
return positional[position];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
export const ArgParse = {
|
||
|
argv: {
|
||
|
_: positional,
|
||
|
...named,
|
||
|
},
|
||
|
getStringArg(...nameOrPositions: Array<string | number>): string | undefined {
|
||
|
const value = getArg(...nameOrPositions);
|
||
|
if (typeof value === "string") {
|
||
|
return value;
|
||
|
}
|
||
|
},
|
||
|
getBooleanArg(...nameOrPositions: Array<string | number>): boolean {
|
||
|
return Boolean(getArg(...nameOrPositions));
|
||
|
},
|
||
|
getIntegerArg(
|
||
|
...nameOrPositions: Array<string | number>
|
||
|
): number | undefined {
|
||
|
const value = Number(getArg(...nameOrPositions));
|
||
|
if (Number.isInteger(value)) {
|
||
|
return value;
|
||
|
}
|
||
|
},
|
||
|
};
|