333
schangxiang@126.com
2025-09-19 18966e02fb573c7e2bb0c6426ed792b38b910940
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
'use strict';
 
const yargs = require('yargs/yargs');
const flatten = require('flat');
const castArray = require('lodash/castArray');
const some = require('lodash/some');
const isPlainObject = require('lodash/isPlainObject');
const camelCase = require('lodash/camelCase');
const kebabCase = require('lodash/kebabCase');
const omitBy = require('lodash/omitBy');
 
function isAlias(key, alias) {
    return some(alias, (aliases) => castArray(aliases).indexOf(key) !== -1);
}
 
function hasDefaultValue(key, value, defaults) {
    return value === defaults[key];
}
 
function isCamelCased(key, argv) {
    return /[A-Z]/.test(key) && camelCase(key) === key && // Is it camel case?
        argv[kebabCase(key)] != null; // Is the standard version defined?
}
 
function keyToFlag(key) {
    return key.length === 1 ? `-${key}` : `--${key}`;
}
 
function unparseOption(key, value, unparsed) {
    if (typeof value === 'string') {
        unparsed.push(keyToFlag(key), value);
    } else if (value === true) {
        unparsed.push(keyToFlag(key));
    } else if (value === false) {
        unparsed.push(`--no-${key}`);
    } else if (Array.isArray(value)) {
        value.forEach((item) => unparseOption(key, item, unparsed));
    } else if (isPlainObject(value)) {
        const flattened = flatten(value, { safe: true });
 
        for (const flattenedKey in flattened) {
            unparseOption(`${key}.${flattenedKey}`, flattened[flattenedKey], unparsed);
        }
    // Fallback case (numbers and other types)
    } else if (value != null) {
        unparsed.push(keyToFlag(key), `${value}`);
    }
}
 
function unparsePositional(argv, options, unparsed) {
    const knownPositional = [];
 
    // Unparse command if set, collecting all known positional arguments
    // e.g.: build <first> <second> <rest...>
    if (options.command) {
        const { 0: cmd, index } = options.command.match(/[^<[]*/);
        const { demanded, optional } = yargs()
        .getCommandInstance()
        .parseCommand(`foo ${options.command.substr(index + cmd.length)}`);
 
        // Push command (can be a deep command)
        unparsed.push(...cmd.trim().split(/\s+/));
 
        // Push positional arguments
        [...demanded, ...optional].forEach(({ cmd: cmds, variadic }) => {
            knownPositional.push(...cmds);
 
            const cmd = cmds[0];
            const args = (variadic ? argv[cmd] || [] : [argv[cmd]])
            .filter((arg) => arg != null)
            .map((arg) => `${arg}`);
 
            unparsed.push(...args);
        });
    }
 
    // Unparse unkown positional arguments
    argv._ && unparsed.push(...argv._.slice(knownPositional.length));
 
    return knownPositional;
}
 
function unparseOptions(argv, options, knownPositional, unparsed) {
    const optionsArgv = omitBy(argv, (value, key) =>
        // Remove positional arguments
        knownPositional.includes(key) ||
        // Remove special _, -- and $0
        ['_', '--', '$0'].includes(key) ||
        // Remove aliases
        isAlias(key, options.alias) ||
        // Remove default values
        hasDefaultValue(key, value, options.default) ||
        // Remove camel-cased
        isCamelCased(key, argv));
 
    for (const key in optionsArgv) {
        unparseOption(key, optionsArgv[key], unparsed);
    }
}
 
function unparseEndOfOptions(argv, options, unparsed) {
    // Unparse ending (--) arguments if set
    argv['--'] && unparsed.push('--', ...argv['--']);
}
 
// ------------------------------------------------------------
 
function unparser(argv, options) {
    options = Object.assign({
        alias: {},
        default: {},
        command: null,
    }, options);
 
    const unparsed = [];
 
    // Unparse known & unknown positional arguments (foo <first> <second> [rest...])
    // All known positional will be returned so that they are not added as flags
    const knownPositional = unparsePositional(argv, options, unparsed);
 
    // Unparse option arguments (--foo hello --bar hi)
    unparseOptions(argv, options, knownPositional, unparsed);
 
    // Unparse "end-of-options" arguments (stuff after " -- ")
    unparseEndOfOptions(argv, options, unparsed);
 
    return unparsed;
}
 
module.exports = unparser;