@black-flag/extensions
Version:
A collection of set-theoretic declarative-first APIs for yargs and Black Flag
782 lines (781 loc) • 32.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getInvocableExtendedHandler = getInvocableExtendedHandler;
exports.withBuilderExtensions = withBuilderExtensions;
exports.withUsageExtensions = withUsageExtensions;
require("core-js/modules/es.array.push.js");
require("core-js/modules/es.iterator.constructor.js");
require("core-js/modules/es.iterator.find.js");
require("core-js/modules/es.iterator.for-each.js");
require("core-js/modules/es.iterator.map.js");
require("core-js/modules/es.iterator.some.js");
require("core-js/modules/es.set.difference.v2.js");
require("core-js/modules/es.set.intersection.v2.js");
require("core-js/modules/es.set.is-disjoint-from.v2.js");
require("core-js/modules/es.set.is-subset-of.v2.js");
require("core-js/modules/es.set.is-superset-of.v2.js");
require("core-js/modules/es.set.symmetric-difference.v2.js");
require("core-js/modules/es.set.union.v2.js");
require("core-js/modules/esnext.array.group.js");
var _nodeUtil = require("node:util");
var _types = require("node:util/types");
var _js = require("@-xun/js");
var _core = require("@black-flag/core");
var _util = require("@black-flag/core/util");
var _lodash = _interopRequireDefault(require("lodash.camelcase"));
var _rejoinder = require("rejoinder");
var _constant = require("./constant.js");
var _error = require("./error.js");
exports.BfeErrorMessage = _error.BfeErrorMessage;
var _symbols = require("./symbols.js");
exports.$artificiallyInvoked = _symbols.$artificiallyInvoked;
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const alphaSort = new Intl.Collator(undefined, {
numeric: true
});
function withBuilderExtensions(customBuilder, {
commonOptions = ['help'],
disableAutomaticGrouping = false,
enableAutomaticSorting = false
} = {}) {
const xbuilderDebug = (0, _rejoinder.createDebugLogger)({
namespace: `${_constant.globalDebuggerNamespace}:withBuilderExtensions`
});
xbuilderDebug('entered withBuilderExtensions function');
let optionsMetadata = undefined;
let latestProgram = undefined;
let latestBfBuilderObject = undefined;
let latestBfParserConfiguration = undefined;
xbuilderDebug('exited withBuilderExtensions function');
return [function builder(blackFlag, helpOrVersionSet, argv) {
const builderDebug = xbuilderDebug.extend('builder');
const isFirstPass = !argv;
const isSecondPass = !isFirstPass;
builderDebug('entered withBuilderExtensions::builder wrapper function');
builderDebug('isFirstPass: %O', isFirstPass);
builderDebug('isSecondPass: %O', isSecondPass);
builderDebug('current argv: %O', argv);
let defaultedOptions = undefined;
if (isSecondPass) {
defaultedOptions = latestProgram.parsed?.defaulted;
hardAssert(defaultedOptions, _error.BfeErrorMessage.UnexpectedlyFalsyDetailedArguments());
deleteDefaultedArguments({
argv,
defaultedOptions
});
}
latestProgram = blackFlag;
builderDebug('calling customBuilder (if a function) and returning builder object');
let builderObject = (0, _js.safeDeepClone)((typeof customBuilder === 'function' ? customBuilder(blackFlag, helpOrVersionSet, argv) : customBuilder) || {});
Object.values(builderObject).forEach(builderObjectValue => {
if (builderObjectValue.default === undefined) {
delete builderObjectValue.default;
}
});
if (enableAutomaticSorting) {
builderDebug(`commencing automatic options sorting (${isFirstPass ? 'first' : 'second'} pass)`);
const keys = Object.keys(builderObject).sort((k1, k2) => alphaSort.compare(k1, k2));
builderObject = Object.fromEntries(keys.map(k => [k, builderObject[k]]));
}
builderDebug('builderObject (maybe auto-sorted; undefined defaults deleted): %O', builderObject);
if (isSecondPass) {
Object.entries(builderObject).forEach(([subOption, subOptionConfig]) => {
const {
subOptionOf
} = subOptionConfig;
if (subOptionOf) {
builderDebug('evaluating suboption configuration for %O', subOption);
Object.entries(subOptionOf).forEach(([superOption, updaters_]) => {
const updaters = [updaters_].flat();
builderDebug('saw entry for super-option %O (%O potential updates)', superOption, updaters.length);
updaters.forEach(({
when,
update
}, index) => {
if (superOption in argv && when(argv[superOption], argv)) {
subOptionConfig = typeof update === 'function' ? update(subOptionConfig, argv) : update;
builderDebug('accepted configuration update #%o to suboption %O: %O', index + 1, subOption, subOptionConfig);
} else {
builderDebug('rejected configuration update #%o to suboption %O: when() returned falsy', index + 1, subOption);
}
});
});
builderObject[subOption] = subOptionConfig;
builderDebug('applied suboption configuration for %O', builderObject[subOption]);
}
delete subOptionConfig.subOptionOf;
});
}
const parserConfiguration = getParserConfigurationFromBlackFlagInstance(blackFlag);
const optionLocalMetadata = analyzeBuilderObject({
builderObject,
commonOptions,
parserConfiguration
});
builderDebug('option local metadata: %O', optionLocalMetadata);
if (!disableAutomaticGrouping) {
builderDebug(`commencing automatic options grouping (${isFirstPass ? 'first' : 'second'} pass)`);
const {
demanded,
demandedAtLeastOne,
demandedMutuallyExclusive,
optional,
customGroups
} = optionLocalMetadata;
if (demanded.length) {
blackFlag.group(demanded, 'Required Options:');
builderDebug('added "Required" grouping: %O', demanded);
}
demandedAtLeastOne.forEach((group, index) => {
const count = index + 1;
const options = Object.keys(group);
blackFlag.group(options, `Required Options ${demandedAtLeastOne.length > 1 ? `${count} ` : ''}(at least one):`);
builderDebug(`added "Required (at least one)" grouping #%O: %O`, count, options);
});
demandedMutuallyExclusive.forEach((group, index) => {
const count = index + 1;
const options = Object.keys(group);
blackFlag.group(options, `Required Options ${demandedAtLeastOne.length > 1 ? `${count} ` : ''}(mutually exclusive):`);
builderDebug(`added "Required (mutually exclusive)" grouping #%O: %O`, count, options);
});
for (const [groupName, options] of Object.entries(customGroups)) {
blackFlag.group(options, groupName);
builderDebug(`added custom "${groupName}" grouping: %O`, options);
}
if (optional.length) {
blackFlag.group(optional, 'Optional Options:');
builderDebug('added "Optional" grouping: %O', optional);
}
if (commonOptions.length) {
const commonOptions_ = commonOptions.map(o => String(o));
blackFlag.group(commonOptions_, 'Common Options:');
builderDebug('added "Common" grouping: %O', commonOptions_);
}
} else {
builderDebug(`automatic options grouping disabled (at ${isFirstPass ? 'first' : 'second'} pass)`);
}
if (isSecondPass) {
optionsMetadata = optionLocalMetadata;
builderDebug('stored option local metadata => option metadata');
}
latestBfBuilderObject = builderObject;
latestBfParserConfiguration = parserConfiguration;
builderDebug('stored latestBfBuilderObject and latestBfParserConfiguration');
builderDebug('transmuting BFE builder to BF builder');
const finalBuilderObject = transmuteBFEBuilderToBFBuilder({
builderObject,
deleteGroupProps: !disableAutomaticGrouping,
isGeneratingSecondPassHelpText: helpOrVersionSet && isSecondPass,
optionsMetadata,
argv
});
builderDebug('final transmuted builderObject: %O', finalBuilderObject);
builderDebug('exited withBuilderExtensions::builder wrapper function');
return finalBuilderObject;
}, function withHandlerExtensions(customHandler) {
return async function handler(realArgv) {
const debug = (0, _rejoinder.createDebugLogger)({
namespace: `${_constant.globalDebuggerNamespace}:withHandlerExtensions`
});
debug('entered withHandlerExtensions::handler wrapper function');
debug('option metadata: %O', optionsMetadata);
hardAssert(optionsMetadata, _error.BfeErrorMessage.IllegalHandlerInvocation());
debug('real argv: %O', realArgv);
const {
[_symbols.$artificiallyInvoked]: wasInvokedArtificially
} = realArgv;
debug('wasInvokedArtificially: %O', wasInvokedArtificially);
if (wasInvokedArtificially) {
debug.warn('skipped bfe checks due to presence of $artificiallyInvoked');
} else {
const defaultedOptions = latestProgram.parsed?.defaulted;
debug('defaultedOptions: %O', defaultedOptions);
hardAssert(defaultedOptions, _error.BfeErrorMessage.UnexpectedlyFalsyDetailedArguments());
deleteDefaultedArguments({
argv: realArgv,
defaultedOptions
});
debug('real argv with defaults deleted: %O', realArgv);
const canonicalArgv = deriveCanonicalArgv(optionsMetadata, realArgv);
debug('"canonical argv" used for checks: %O', canonicalArgv);
optionsMetadata.required.forEach(({
[_symbols.$genesis]: requirer,
...requireds
}) => {
hardAssert(requirer !== undefined, _error.BfeErrorMessage.MetadataInvariantViolated('requires'));
if (canonicalArgv.has(requirer)) {
const missingRequiredKeyValues = [];
Object.entries(requireds).forEach(required => {
const [requiredKey, requiredValue] = required;
const givenValue = canonicalArgv.get(requiredKey);
const givenValueIsArray = Array.isArray(givenValue);
if (!canonicalArgv.has(requiredKey) || requiredValue !== _symbols.$exists && (givenValueIsArray && !givenValue.some(value => (0, _nodeUtil.isDeepStrictEqual)(value, requiredValue)) || !givenValueIsArray && !(0, _nodeUtil.isDeepStrictEqual)(givenValue, requiredValue))) {
missingRequiredKeyValues.push(required);
}
});
softAssert(!missingRequiredKeyValues.length, _error.BfeErrorMessage.RequiresViolation(requirer, missingRequiredKeyValues));
}
});
optionsMetadata.conflicted.forEach(({
[_symbols.$genesis]: conflicter,
...conflicteds
}) => {
hardAssert(conflicter !== undefined, _error.BfeErrorMessage.MetadataInvariantViolated('conflicts'));
if (canonicalArgv.has(conflicter)) {
const seenConflictingKeyValues = [];
Object.entries(conflicteds).forEach(keyValue => {
const [conflictedKey, conflictedValue] = keyValue;
const givenValue = canonicalArgv.get(conflictedKey);
const givenValueIsArray = Array.isArray(givenValue);
if (canonicalArgv.has(conflictedKey) && (conflictedValue === _symbols.$exists || givenValueIsArray && givenValue.some(value => (0, _nodeUtil.isDeepStrictEqual)(value, conflictedValue)) || !givenValueIsArray && (0, _nodeUtil.isDeepStrictEqual)(givenValue, conflictedValue))) {
seenConflictingKeyValues.push(keyValue);
}
});
softAssert(!seenConflictingKeyValues.length, _error.BfeErrorMessage.ConflictsViolation(conflicter, seenConflictingKeyValues));
}
});
optionsMetadata.demandedIf.forEach(({
[_symbols.$genesis]: demanded,
...demanders
}) => {
hardAssert(demanded !== undefined, _error.BfeErrorMessage.MetadataInvariantViolated('demandThisOptionIf'));
const sawDemanded = canonicalArgv.has(demanded);
Object.entries(demanders).forEach(demander => {
const [demanderKey, demanderValue] = demander;
const givenValue = canonicalArgv.get(demanderKey);
const givenValueIsArray = Array.isArray(givenValue);
const sawADemander = canonicalArgv.has(demanderKey) && (demanderValue === _symbols.$exists || givenValueIsArray && givenValue.some(value => (0, _nodeUtil.isDeepStrictEqual)(value, demanderValue)) || !givenValueIsArray && (0, _nodeUtil.isDeepStrictEqual)(givenValue, demanderValue));
softAssert(!sawADemander || sawDemanded, _error.BfeErrorMessage.DemandIfViolation(demanded, demander));
});
});
optionsMetadata.demandedAtLeastOne.forEach(group => {
const groupEntries = Object.entries(group);
const sawAtLeastOne = groupEntries.some(keyValue => {
const [key, value] = keyValue;
const givenValue = canonicalArgv.get(key);
const givenValueIsArray = Array.isArray(givenValue);
return canonicalArgv.has(key) && (value === _symbols.$exists || givenValueIsArray && givenValue.some(value_ => (0, _nodeUtil.isDeepStrictEqual)(value_, value)) || !givenValueIsArray && (0, _nodeUtil.isDeepStrictEqual)(givenValue, value));
});
softAssert(sawAtLeastOne, _error.BfeErrorMessage.DemandOrViolation(groupEntries));
});
optionsMetadata.demandedMutuallyExclusive.forEach(group => {
const groupEntries = Object.entries(group);
let sawAtLeastOne = undefined;
groupEntries.forEach(keyValue => {
const [key, value] = keyValue;
const givenValue = canonicalArgv.get(key);
const givenValueIsArray = Array.isArray(givenValue);
if (canonicalArgv.has(key) && (value === _symbols.$exists || givenValueIsArray && givenValue.some(value_ => (0, _nodeUtil.isDeepStrictEqual)(value_, value)) || !givenValueIsArray && (0, _nodeUtil.isDeepStrictEqual)(givenValue, value))) {
if (sawAtLeastOne !== undefined) {
softAssert(false, _error.BfeErrorMessage.DemandSpecificXorViolation(sawAtLeastOne, keyValue));
}
sawAtLeastOne = keyValue;
}
});
softAssert(sawAtLeastOne, _error.BfeErrorMessage.DemandGenericXorViolation(groupEntries));
});
const impliedKeyValues = {};
optionsMetadata.implied.forEach(({
[_symbols.$genesis]: implier,
[_symbols.$canonical]: canonicalImplications,
...expandedImplications
}) => {
hardAssert(implier !== undefined, _error.BfeErrorMessage.MetadataInvariantViolated('implies'));
if (canonicalArgv.has(implier) && (optionsMetadata.implyVacuously.includes(implier) || canonicalArgv.get(implier) !== false)) {
Object.assign(impliedKeyValues, expandedImplications);
if (!optionsMetadata.implyLoosely.includes(implier)) {
const seenConflictingKeyValues = [];
Object.entries(canonicalImplications).forEach(keyValue => {
const [key, value] = keyValue;
if (canonicalArgv.has(key) && !(0, _nodeUtil.isDeepStrictEqual)(canonicalArgv.get(key), value)) {
seenConflictingKeyValues.push([key, canonicalArgv.get(key)]);
}
});
softAssert(!seenConflictingKeyValues.length, _error.BfeErrorMessage.ImpliesViolation(implier, seenConflictingKeyValues));
}
}
});
Object.assign(realArgv, {
...optionsMetadata.defaults,
...impliedKeyValues,
...realArgv
});
debug('final argv (defaults and implies merged): %O', realArgv);
for (const [currentArgument, checkFunctions_] of Object.entries(optionsMetadata.checks)) {
if (currentArgument in realArgv) {
const checkFunctions = [checkFunctions_].flat();
await Promise.all(checkFunctions.map(async checkFn => {
let result;
try {
result = await checkFn(realArgv[currentArgument], realArgv);
} catch (error) {
result = error;
}
if (!result || typeof result === 'string' || (0, _types.isNativeError)(result)) {
throw _core.CliError.isError(result) ? result : new _core.CliError(result || _error.BfeErrorMessage.CheckFailed(currentArgument));
}
}));
}
}
}
debug('invoking customHandler (or defaultHandler if undefined)');
await (customHandler ?? defaultHandler)(realArgv);
debug('exited withHandlerExtensions::handler wrapper function');
};
}];
function deleteDefaultedArguments({
argv,
defaultedOptions
}) {
hardAssert(latestBfBuilderObject, _error.BfeErrorMessage.GuruMeditation());
hardAssert(latestBfParserConfiguration, _error.BfeErrorMessage.GuruMeditation());
Object.keys(defaultedOptions).forEach(defaultedOption => {
expandOptionNameAndAliasesWithRespectToParserConfiguration({
option: defaultedOption,
aliases: latestBfBuilderObject[defaultedOption].alias,
parserConfiguration: latestBfParserConfiguration
}).forEach(expandedName => delete argv[expandedName]);
});
latestBfBuilderObject = undefined;
latestBfParserConfiguration = undefined;
}
}
function withUsageExtensions(config, moreConfig) {
const {
altDescription = '$1.',
trim = true,
appendPeriod = true,
prependNewlines = true,
includeOptions = prependNewlines,
includeSubCommand = false
} = typeof config === 'string' ? {
altDescription: config,
...moreConfig
} : {
...config,
...moreConfig
};
return `Usage: $000${includeSubCommand === 'required' ? ' <subcommand>' : includeSubCommand ? ' [subcommand]' : ''}${includeOptions ? ' [...options]' : ''}${prependNewlines ? '\n\n' : ''}${altDescription[trim ? 'trim' : 'toString']()}${appendPeriod && !altDescription.endsWith('.') ? '.' : ''}`;
}
async function getInvocableExtendedHandler(maybeCommand, context) {
const debug = (0, _rejoinder.createDebugLogger)({
namespace: `${_constant.globalDebuggerNamespace}:getInvocableExtendedHandler`
});
debug('safely deep cloning context argument');
context = (0, _js.safeDeepClone)(context, context.state.extensions);
debug('resolving maybePromisedCommand');
let command;
try {
command = await maybeCommand;
} catch (error) {
throw new _core.CliError(_error.BfeErrorMessage.FrameworkError(_error.BfeErrorMessage.FalsyCommandExport()), {
cause: error,
suggestedExitCode: _core.FrameworkExitCode.AssertionFailed
});
}
hardAssert(command, _error.BfeErrorMessage.FalsyCommandExport());
if (command.default !== undefined) {
command = command.default;
}
if (command?.default !== undefined) {
command = command.default;
}
let config;
if (typeof command === 'function') {
config = await command(context);
} else {
hardAssert(command && typeof command === 'object', _error.BfeErrorMessage.FalsyCommandExport());
config = command;
}
const {
builder,
handler
} = config;
hardAssert(handler, _error.BfeErrorMessage.CommandHandlerNotAFunction());
debug('returned immediately invocable handler function');
return async function (argv) {
const fakeYargsWarning = '<this is a pseudo-yargs instance passed around by getInvocableExtendedHandler>';
const argv_ = (0, _js.safeDeepClone)({
[_symbols.$artificiallyInvoked]: true,
$0: config.name || '???',
_: [],
...argv,
[_core.$executionContext]: context
}, context.state.extensions);
if (typeof builder === 'function') {
const {
default: makeVanillaYargs
} = await import('yargs/yargs');
const dummyYargs = makeVanillaYargs();
const fakeBlackFlag = dummyYargs;
dummyYargs.parsed = {
'//': fakeYargsWarning,
argv: argv_,
defaulted: {},
aliases: {},
configuration: new Proxy({}, {
get() {
return true;
}
}),
error: null,
newAliases: {}
};
debug('invoking builder (for the first time)');
builder(fakeBlackFlag, false, undefined);
debug('invoking builder (for the second time)');
builder(fakeBlackFlag, false, {
'//': fakeYargsWarning,
...argv_
});
} else {
debug('warning: no callable builder function was returned!');
}
debug('invoking handler');
return handler(argv_);
};
}
function transmuteBFEBuilderToBFBuilder({
builderObject,
deleteGroupProps,
isGeneratingSecondPassHelpText,
optionsMetadata,
argv
}) {
const vanillaYargsBuilderObject = {};
for (const [option, builderObjectValue] of Object.entries(builderObject)) {
const [bfeBuilderObjectValue, vanillaYargsBuilderObjectValue] = separateExtensionsFromBuilderObjectValue({
builderObjectValue
});
const {
demandThisOption
} = bfeBuilderObjectValue;
const genericVanillaYargsBuilderObjectValue = vanillaYargsBuilderObjectValue;
if (demandThisOption !== undefined) {
genericVanillaYargsBuilderObjectValue.demandOption = demandThisOption;
}
if (bfeBuilderObjectValue.default !== undefined) {
genericVanillaYargsBuilderObjectValue.default = bfeBuilderObjectValue.default;
}
if (genericVanillaYargsBuilderObjectValue.coerce !== undefined) {
const coercer = genericVanillaYargsBuilderObjectValue.coerce;
genericVanillaYargsBuilderObjectValue.coerce = parameter => {
return coercer(vanillaYargsBuilderObjectValue.array ? [parameter].flat() : parameter);
};
}
if (deleteGroupProps) {
delete vanillaYargsBuilderObjectValue.group;
}
vanillaYargsBuilderObject[option] = vanillaYargsBuilderObjectValue;
}
if (isGeneratingSecondPassHelpText) {
hardAssert(optionsMetadata && argv, _error.BfeErrorMessage.GuruMeditation());
const canonicalArgv = deriveCanonicalArgv(optionsMetadata, argv);
optionsMetadata.implied.forEach(({
[_symbols.$genesis]: implier,
[_symbols.$canonical]: canonicalImplications
}) => {
hardAssert(implier !== undefined, _error.BfeErrorMessage.MetadataInvariantViolated('implies'));
if (canonicalArgv.has(implier) && (optionsMetadata.implyVacuously.includes(implier) || canonicalArgv.get(implier) !== false)) {
Object.entries(canonicalImplications).forEach(([impliedArg, impliedValue]) => {
vanillaYargsBuilderObject[impliedArg].default = impliedValue;
});
}
});
}
return vanillaYargsBuilderObject;
}
function analyzeBuilderObject({
builderObject,
commonOptions,
parserConfiguration
}) {
const metadata = {
required: [],
conflicted: [],
implied: [],
implyLoosely: [],
implyVacuously: [],
demandedIf: [],
demanded: [],
demandedAtLeastOne: [],
demandedMutuallyExclusive: [],
optional: [],
defaults: {},
checks: {},
optionNames: new Set(),
optionNamesAsSeenInArgv: {},
customGroups: {}
};
for (const [option, builderObjectValue] of Object.entries(builderObject)) {
const [{
requires,
conflicts,
check,
default: default_,
implies,
looseImplications,
vacuousImplications,
demandThisOptionIf,
demandThisOption,
demandThisOptionOr,
demandThisOptionXor
}, {
alias: optionAliases
}] = separateExtensionsFromBuilderObjectValue({
builderObjectValue
});
const allPossibleOptionNamesAndAliasesSet = expandOptionNameAndAliasesWithRespectToParserConfiguration({
option,
aliases: optionAliases,
parserConfiguration
});
const conflictingNamesSet = metadata.optionNames.intersection(allPossibleOptionNamesAndAliasesSet);
hardAssert(conflictingNamesSet.size === 0, _error.BfeErrorMessage.DuplicateOptionName(getFirstValueFromNonEmptySet(conflictingNamesSet)));
metadata.optionNames = metadata.optionNames.union(allPossibleOptionNamesAndAliasesSet);
allPossibleOptionNamesAndAliasesSet.forEach(expandedName => {
metadata.optionNamesAsSeenInArgv[expandedName] = option;
});
if (requires !== undefined) {
const normalizedOption = validateAndFlattenExtensionValue(requires, builderObject, option);
addToSet(metadata.required, {
...normalizedOption,
[_symbols.$genesis]: option
});
}
if (conflicts !== undefined) {
const normalizedOption = validateAndFlattenExtensionValue(conflicts, builderObject, option);
addToSet(metadata.conflicted, {
...normalizedOption,
[_symbols.$genesis]: option
});
}
if (check !== undefined) {
metadata.checks[option] = check;
}
if (default_ !== undefined) {
allPossibleOptionNamesAndAliasesSet.forEach(expandedName => {
metadata.defaults[expandedName] = default_;
});
}
if (implies !== undefined) {
const canonicalNormalizedImplications = validateAndFlattenExtensionValue(implies, builderObject, option);
const expandedNormalizedImplications = {};
Object.entries(canonicalNormalizedImplications).forEach(([impliedOption, impliedValue]) => {
const {
alias: impliedOptionAliases
} = builderObject[impliedOption];
expandOptionNameAndAliasesWithRespectToParserConfiguration({
option: impliedOption,
aliases: impliedOptionAliases,
parserConfiguration
}).forEach(expandedName => {
expandedNormalizedImplications[expandedName] = impliedValue;
});
});
addToSet(metadata.implied, {
...expandedNormalizedImplications,
[_symbols.$canonical]: canonicalNormalizedImplications,
[_symbols.$genesis]: option
});
}
if (looseImplications) {
metadata.implyLoosely.push(option);
}
if (vacuousImplications) {
metadata.implyVacuously.push(option);
}
if (demandThisOption !== undefined) {
metadata.demanded.push(option);
}
if (demandThisOptionIf !== undefined) {
const normalizedOption = validateAndFlattenExtensionValue(demandThisOptionIf, builderObject, option);
addToSet(metadata.demandedIf, {
...normalizedOption,
[_symbols.$genesis]: option
});
}
if (demandThisOptionOr !== undefined) {
const normalizedOption = validateAndFlattenExtensionValue(demandThisOptionOr, builderObject, option);
addToSet(metadata.demandedAtLeastOne, {
...normalizedOption,
[option]: _symbols.$exists
});
}
if (demandThisOptionXor !== undefined) {
const normalizedOption = validateAndFlattenExtensionValue(demandThisOptionXor, builderObject, option);
addToSet(metadata.demandedMutuallyExclusive, {
...normalizedOption,
[option]: _symbols.$exists
});
}
}
for (const [option, {
group: groupOverride
}] of Object.entries(builderObject)) {
const isExplicitlyDemanded = !!(metadata.demanded.includes(option) || metadata.demandedAtLeastOne.some(record => option in record) || metadata.demandedMutuallyExclusive.some(record => option in record));
const hasExplicitGroupOverride = !!groupOverride;
const commonOptionsIncludesOption = commonOptions.includes(option);
if (hasExplicitGroupOverride) {
(metadata.customGroups[groupOverride] ||= []).push(option);
} else {
if (!isExplicitlyDemanded && !commonOptionsIncludesOption) {
metadata.optional.push(option);
}
}
}
return metadata;
}
function expandOptionNameAndAliasesWithRespectToParserConfiguration({
option,
aliases,
parserConfiguration
}) {
const {
'camel-case-expansion': camelCaseExpansion,
'strip-aliased': stripAliased,
'strip-dashed': stripDashed
} = {
'camel-case-expansion': true,
'strip-aliased': false,
'strip-dashed': false,
...parserConfiguration
};
const targetNames = [option, stripAliased ? [] : aliases ?? []].flat();
const expandedNamesSet = new Set();
targetNames.forEach(name => {
if (camelCaseExpansion) {
const camelCasedName = (0, _lodash.default)(name);
if (camelCasedName !== name && (!stripDashed || !name.includes('-'))) {
add(name);
}
add(camelCasedName);
} else {
add(name);
}
});
return expandedNamesSet;
function add(name) {
hardAssert(!expandedNamesSet.has(name), _error.BfeErrorMessage.DuplicateOptionName(name));
expandedNamesSet.add(name);
}
}
function getParserConfigurationFromBlackFlagInstance(blackFlag) {
hardAssert(typeof blackFlag.getInternalMethods === 'function', _error.BfeErrorMessage.UnexpectedValueFromInternalYargsMethod());
const yargsInternalMethods = blackFlag.getInternalMethods();
hardAssert(typeof yargsInternalMethods.getParserConfiguration === 'function', _error.BfeErrorMessage.UnexpectedValueFromInternalYargsMethod());
const parserConfiguration = yargsInternalMethods.getParserConfiguration();
hardAssert(parserConfiguration && typeof parserConfiguration === 'object', _error.BfeErrorMessage.UnexpectedValueFromInternalYargsMethod());
return parserConfiguration;
}
function separateExtensionsFromBuilderObjectValue({
builderObjectValue: builderObjectValue
}) {
const {
check,
conflicts,
default: default_,
demandThisOption,
demandThisOptionIf,
demandThisOptionOr,
demandThisOptionXor,
implies,
looseImplications,
vacuousImplications,
requires,
subOptionOf,
...vanillaYargsConfig
} = builderObjectValue;
const bfeConfig = {
check,
conflicts,
demandThisOption,
demandThisOptionIf,
demandThisOptionOr,
demandThisOptionXor,
implies,
looseImplications,
vacuousImplications,
requires,
subOptionOf
};
hardAssert(!('default' in builderObjectValue) || default_ !== undefined, _error.BfeErrorMessage.GuruMeditation());
return [{
...bfeConfig,
default: default_,
coerce: undefined
}, vanillaYargsConfig];
}
function validateAndFlattenExtensionValue(extendedOption, builderObject, optionName) {
const mergedConfig = {};
if (Array.isArray(extendedOption)) {
extendedOption.forEach(option => {
mergeInto(option);
});
} else {
mergeInto(extendedOption);
}
Object.keys(mergedConfig).forEach(referredOptionName => {
hardAssert(referredOptionName in builderObject, _error.BfeErrorMessage.ReferencedNonExistentOption(optionName, referredOptionName));
});
return mergedConfig;
function mergeInto(option) {
if (typeof option === 'string') {
mergedConfig[option] = _symbols.$exists;
} else {
Object.assign(mergedConfig, option);
}
}
}
function deriveCanonicalArgv(optionsMetadata, argv) {
const canonicalArgv = new Map();
Object.entries(optionsMetadata.optionNamesAsSeenInArgv).forEach(([maybeNameInRealArgv, canonicalName]) => {
const valueInRealArgv = argv[maybeNameInRealArgv];
if (valueInRealArgv !== undefined) {
canonicalArgv.set(canonicalName, valueInRealArgv);
}
});
return canonicalArgv;
}
function addToSet(arrayAsSet, element) {
const hasElement = arrayAsSet.find(item => (0, _nodeUtil.isDeepStrictEqual)(item, element));
if (!hasElement) {
arrayAsSet.push(element);
}
}
function defaultHandler() {
throw new _util.CommandNotImplementedError();
}
function getFirstValueFromNonEmptySet(set) {
return set.values().next().value;
}
function softAssert(valueOrMessage, message) {
let shouldThrow = true;
if (typeof message === 'string') {
const value = valueOrMessage;
shouldThrow = !value;
} else {
message = String(valueOrMessage);
}
if (shouldThrow) {
throw new _core.CliError(message, {
suggestedExitCode: _core.FrameworkExitCode.DefaultError
});
}
}
function hardAssert(valueOrMessage, message) {
let shouldThrow = true;
if (typeof message === 'string') {
const value = valueOrMessage;
shouldThrow = !value;
} else {
message = String(valueOrMessage);
}
if (shouldThrow) {
throw new _core.CliError(_error.BfeErrorMessage.FrameworkError(message), {
suggestedExitCode: _core.FrameworkExitCode.AssertionFailed
});
}
}