awais-tool
Version:
Get to know via `npx itishaawais`
116 lines (102 loc) • 3.72 kB
JavaScript
import process from "node:process";
import { dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { readPackageUpSync } from "read-package-up";
import normalizePackageData from "normalize-package-data";
import { decamelizeFlagKey, joinFlagKeys } from "./utils.js";
const validateOptions = (options) => {
const invalidOptionFilters = {
flags: {
keyContainsDashes: {
filter: ([flagKey]) => flagKey.includes("-") && flagKey !== "--",
message: (flagKeys) =>
`Flag keys may not contain '-'. Invalid flags: ${joinFlagKeys(flagKeys, "")}`,
},
aliasIsSet: {
filter: ([, flag]) => Object.hasOwn(flag, "alias"),
message: (flagKeys) =>
`The option \`alias\` has been renamed to \`shortFlag\`. The following flags need to be updated: ${joinFlagKeys(flagKeys)}`,
},
choicesNotAnArray: {
filter: ([, flag]) =>
Object.hasOwn(flag, "choices") && !Array.isArray(flag.choices),
message: (flagKeys) =>
`The option \`choices\` must be an array. Invalid flags: ${joinFlagKeys(flagKeys)}`,
},
choicesNotMatchFlagType: {
filter: ([, flag]) =>
flag.type &&
Array.isArray(flag.choices) &&
flag.choices.some((choice) => typeof choice !== flag.type),
message(flagKeys) {
const flagKeysAndTypes = flagKeys.map(
(flagKey) =>
`(\`${decamelizeFlagKey(flagKey)}\`, type: '${options.flags[flagKey].type}')`
);
return `Each value of the option \`choices\` must be of the same type as its flag. Invalid flags: ${flagKeysAndTypes.join(", ")}`;
},
},
defaultNotInChoices: {
filter: ([, flag]) =>
flag.default &&
Array.isArray(flag.choices) &&
![flag.default].flat().every((value) => flag.choices.includes(value)),
message: (flagKeys) =>
`Each value of the option \`default\` must exist within the option \`choices\`. Invalid flags: ${joinFlagKeys(flagKeys)}`,
},
},
};
const errorMessages = [];
for (const [optionKey, filters] of Object.entries(invalidOptionFilters)) {
const optionEntries = Object.entries(options[optionKey]);
for (const { filter, message } of Object.values(filters)) {
const invalidOptions = optionEntries.filter((option) => filter(option));
const invalidOptionKeys = invalidOptions.map(([key]) => key);
if (invalidOptions.length > 0) {
errorMessages.push(message(invalidOptionKeys));
}
}
}
if (errorMessages.length > 0) {
throw new Error(errorMessages.join("\n"));
}
};
export const buildOptions = (helpText, options) => {
if (typeof helpText !== "string") {
options = helpText;
helpText = "";
}
if (!options.importMeta?.url) {
throw new TypeError(
"The `importMeta` option is required. Its value must be `import.meta`."
);
}
const foundPackage =
options.pkg ??
readPackageUpSync({
cwd: dirname(fileURLToPath(options.importMeta.url)),
normalize: false,
})?.packageJson;
// eslint-disable-next-line unicorn/prevent-abbreviations
const pkg = foundPackage ?? {};
normalizePackageData(pkg);
const parsedOptions = {
argv: process.argv.slice(2),
flags: {},
inferType: false,
input: "string",
description: pkg.description ?? false,
help: helpText,
version: pkg.version || "No version found",
autoHelp: true,
autoVersion: true,
booleanDefault: false,
allowUnknownFlags: true,
allowParentFlags: true,
helpIndent: 2,
...options,
pkg,
};
validateOptions(parsedOptions);
return parsedOptions;
};