110 lines
2.6 KiB
TypeScript
110 lines
2.6 KiB
TypeScript
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;
|
|
}
|
|
},
|
|
};
|