react-native-test-app
Version:
react-native-test-app provides a test app for all supported platforms as a package
130 lines (119 loc) • 3.14 kB
JavaScript
// @ts-check
;
/**
* @typedef {{
* description: string;
* type: "string" | "boolean";
* multiple?: boolean;
* short?: string;
* default?: string | boolean | string[];
* }} Option;
*
* @typedef {{ [key: string]: Option }} Options;
*/
/**
* @template {Option} O
* @typedef {O extends { type: "boolean" }
* ? boolean
* : O extends { type: "string", multiple: true }
* ? string[]
* : string
* } InferredOptionType<O>;
*/
/**
* @template {Options} O
* @typedef {{ [key in keyof O]: InferredOptionType<O[key]> }} InferredOptionTypes<O>;
*/
/**
* @template {Options} O
* @typedef {InferredOptionTypes<O> & { _: string[] }} Args;
*/
/**
* @template {Options} O
* @param {NonNullable<unknown>} values
* @param {O} _options (Unused; only present for type inference)
* @returns {values is Args<O>}
*/
function coerce(values, _options) {
return Boolean(typeof values === "object" && "help" in values);
}
/**
* Generates help message.
* @param {string} description
* @param {Record<string, { short?: string; description: string; }>} options
* @returns {string}
*/
function formatHelp(description, options) {
const flags = Object.entries(options);
const indent = " ";
const minWidth =
Math.max(...flags.map(([flag]) => flag.length)) + indent.length * 2;
// @ts-expect-error This expression is not callable
const ui = require("cliui")();
for (const [flag, config] of flags) {
ui.div(
{ text: "", width: 2 },
{ text: config.short ? `-${config.short},` : "", width: 4 },
{ text: `--${flag}`, width: minWidth + 2 },
{ text: config.description }
);
}
const script = require("node:path").basename(process.argv[1]);
return [
`usage: ${script} [options]`,
"",
description,
"",
"Options:",
ui.toString(),
"",
].join("\n");
}
/**
* Parses command line arguments.
*
* @see {@link https://nodejs.org/api/util.html#utilparseargsconfig}
*
* @template {Options} O
* @param {string} description
* @param {O} options
* @param {(args: Args<O>) => void} callback
*/
function parseArgs(description, options, callback) {
const mergedOptions = {
help: {
description: "Show this help message",
type: "boolean",
short: "h",
default: false,
},
version: {
description: "Show version number",
type: "boolean",
short: "v",
default: false,
},
...options,
};
const { parseArgs } = require("node:util");
const { values, positionals } = parseArgs({
args: process.argv.slice(2),
options: mergedOptions,
strict: true,
allowPositionals: true,
tokens: false,
});
if (!coerce(values, mergedOptions)) {
throw new Error("Failed to parse command-line arguments");
}
if (values.help) {
console.log(formatHelp(description, mergedOptions));
} else if (values.version) {
const { name, version } = require("../package.json");
console.log(`${name} ${version}`);
} else {
values._ = positionals;
callback(values);
}
}
exports.parseArgs = parseArgs;