gunshi 0.5.2 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/{context-B5z7lnoV.js → context-DmZAeiph.js} +2 -23
- package/lib/context.js +2 -1
- package/lib/index.js +3 -190
- package/lib/renderer/index.d.ts +26 -0
- package/lib/renderer/index.js +4 -0
- package/lib/renderer-MpQ9U28q.js +192 -0
- package/lib/utils-NHs5DuHk.js +24 -0
- package/package.json +5 -5
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { create, deepFreeze, resolveLazyCommand } from "./utils-NHs5DuHk.js";
|
|
1
2
|
|
|
2
3
|
//#region locales/en-US.json
|
|
3
4
|
var COMMAND = "COMMAND";
|
|
@@ -56,28 +57,6 @@ const COMMAND_I18N_RESOURCE_KEYS = [
|
|
|
56
57
|
"FORMORE"
|
|
57
58
|
];
|
|
58
59
|
|
|
59
|
-
//#endregion
|
|
60
|
-
//#region src/utils.ts
|
|
61
|
-
async function resolveLazyCommand(cmd, name, entry = false) {
|
|
62
|
-
const resolved = Object.assign(create(), typeof cmd == "function" ? await cmd() : cmd, { default: entry });
|
|
63
|
-
if (resolved.name == null && name) resolved.name = name;
|
|
64
|
-
return deepFreeze(resolved);
|
|
65
|
-
}
|
|
66
|
-
function create(obj = null) {
|
|
67
|
-
return Object.create(obj);
|
|
68
|
-
}
|
|
69
|
-
function log(...args) {
|
|
70
|
-
console.log(...args);
|
|
71
|
-
}
|
|
72
|
-
function deepFreeze(obj) {
|
|
73
|
-
if (obj === null || typeof obj !== "object") return obj;
|
|
74
|
-
for (const key of Object.keys(obj)) {
|
|
75
|
-
const value = obj[key];
|
|
76
|
-
if (typeof value === "object" && value !== null) deepFreeze(value);
|
|
77
|
-
}
|
|
78
|
-
return Object.freeze(obj);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
60
|
//#endregion
|
|
82
61
|
//#region src/context.ts
|
|
83
62
|
const DEFAULT_LOCALE = "en-US";
|
|
@@ -196,4 +175,4 @@ async function loadCommandResource(ctx, command) {
|
|
|
196
175
|
}
|
|
197
176
|
|
|
198
177
|
//#endregion
|
|
199
|
-
export { COMMAND_OPTIONS_DEFAULT, COMMON_OPTIONS, DEFAULT_LOCALE,
|
|
178
|
+
export { COMMAND_OPTIONS_DEFAULT, COMMON_OPTIONS, DEFAULT_LOCALE, createCommandContext };
|
package/lib/context.js
CHANGED
package/lib/index.js
CHANGED
|
@@ -1,195 +1,8 @@
|
|
|
1
|
-
import { COMMAND_OPTIONS_DEFAULT, COMMON_OPTIONS,
|
|
1
|
+
import { COMMAND_OPTIONS_DEFAULT, COMMON_OPTIONS, createCommandContext } from "./context-DmZAeiph.js";
|
|
2
|
+
import { create, log, resolveLazyCommand } from "./utils-NHs5DuHk.js";
|
|
3
|
+
import { renderHeader, renderUsage, renderValidationErrors } from "./renderer-MpQ9U28q.js";
|
|
2
4
|
import { parseArgs, resolveArgs } from "args-tokens";
|
|
3
5
|
|
|
4
|
-
//#region src/renderer/header.ts
|
|
5
|
-
function renderHeader(ctx) {
|
|
6
|
-
const title = ctx.env.description || ctx.env.name || "";
|
|
7
|
-
return Promise.resolve(title ? `${title} (${ctx.env.name || ""}${ctx.env.version ? ` v${ctx.env.version}` : ""})` : title);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
//#endregion
|
|
11
|
-
//#region src/renderer/usage.ts
|
|
12
|
-
async function renderUsage(ctx) {
|
|
13
|
-
const messages = [];
|
|
14
|
-
if (!ctx.omitted && hasDescription(ctx)) messages.push(ctx.description, "");
|
|
15
|
-
messages.push(...await renderUsageSection(ctx), "");
|
|
16
|
-
if (ctx.omitted && await hasCommands(ctx)) messages.push(...await renderCommandsSection(ctx), "");
|
|
17
|
-
if (hasOptions(ctx)) messages.push(...await renderOptionsSection(ctx), "");
|
|
18
|
-
if (hasExamples(ctx)) messages.push(...renderExamplesSection(ctx), "");
|
|
19
|
-
return messages.join("\n");
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Render the options section
|
|
23
|
-
* @param ctx A {@link CommandContext | command context}
|
|
24
|
-
* @returns A rendered options section
|
|
25
|
-
*/
|
|
26
|
-
async function renderOptionsSection(ctx) {
|
|
27
|
-
const messages = [];
|
|
28
|
-
messages.push(`${ctx.translation("OPTIONS")}:`);
|
|
29
|
-
const optionsPairs = getOptionsPairs(ctx);
|
|
30
|
-
messages.push(await generateOptionsUsage(ctx, optionsPairs));
|
|
31
|
-
return messages;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Render the examples section
|
|
35
|
-
* @param ctx A {@link CommandContext | command context}
|
|
36
|
-
* @returns A rendered examples section
|
|
37
|
-
*/
|
|
38
|
-
function renderExamplesSection(ctx) {
|
|
39
|
-
const messages = [];
|
|
40
|
-
const examples = ctx.usage.examples.split("\n").map((example) => example.padStart(ctx.env.leftMargin + example.length));
|
|
41
|
-
messages.push(`${ctx.translation("EXAMPLES")}:`, ...examples);
|
|
42
|
-
return messages;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Render the usage section
|
|
46
|
-
* @param ctx A {@link CommandContext | command context}
|
|
47
|
-
* @returns A rendered usage section
|
|
48
|
-
*/
|
|
49
|
-
async function renderUsageSection(ctx) {
|
|
50
|
-
const messages = [`${ctx.translation("USAGE")}:`];
|
|
51
|
-
if (ctx.omitted) {
|
|
52
|
-
const defaultCommand = `${resolveEntry(ctx)}${await hasCommands(ctx) ? ` [${resolveSubCommand(ctx)}]` : ""} ${hasOptions(ctx) ? `<${ctx.translation("OPTIONS")}>` : ""} `;
|
|
53
|
-
messages.push(defaultCommand.padStart(ctx.env.leftMargin + defaultCommand.length));
|
|
54
|
-
if (await hasCommands(ctx)) {
|
|
55
|
-
const commandsUsage = `${resolveEntry(ctx)} <${ctx.translation("COMMANDS")}>`;
|
|
56
|
-
messages.push(commandsUsage.padStart(ctx.env.leftMargin + commandsUsage.length));
|
|
57
|
-
}
|
|
58
|
-
} else {
|
|
59
|
-
const usageStr = `${resolveEntry(ctx)} ${resolveSubCommand(ctx)} ${generateOptionsSymbols(ctx)}`;
|
|
60
|
-
messages.push(usageStr.padStart(ctx.env.leftMargin + usageStr.length));
|
|
61
|
-
}
|
|
62
|
-
return messages;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Render the commands section
|
|
66
|
-
* @param ctx A {@link CommandContext | command context}
|
|
67
|
-
* @returns A rendered commands section
|
|
68
|
-
*/
|
|
69
|
-
async function renderCommandsSection(ctx) {
|
|
70
|
-
const messages = [`${ctx.translation("COMMANDS")}:`];
|
|
71
|
-
const loadedCommands = await ctx.loadCommands();
|
|
72
|
-
const commandMaxLength = Math.max(...loadedCommands.map((cmd) => (cmd.name || "").length));
|
|
73
|
-
const commandsStr = await Promise.all(loadedCommands.map((cmd) => {
|
|
74
|
-
const key = cmd.name || "";
|
|
75
|
-
const desc = cmd.description || "";
|
|
76
|
-
const command = `${key.padEnd(commandMaxLength + ctx.env.middleMargin)}${desc} `;
|
|
77
|
-
return `${command.padStart(ctx.env.leftMargin + command.length)} `;
|
|
78
|
-
}));
|
|
79
|
-
messages.push(...commandsStr, "", ctx.translation("FORMORE"));
|
|
80
|
-
messages.push(...loadedCommands.map((cmd) => {
|
|
81
|
-
const commandHelp = `${ctx.env.name} ${cmd.name} --help`;
|
|
82
|
-
return `${commandHelp.padStart(ctx.env.leftMargin + commandHelp.length)}`;
|
|
83
|
-
}));
|
|
84
|
-
return messages;
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Resolve the entry command name
|
|
88
|
-
* @param ctx A {@link CommandContext | command context}
|
|
89
|
-
* @returns The entry command name
|
|
90
|
-
*/
|
|
91
|
-
function resolveEntry(ctx) {
|
|
92
|
-
return ctx.env.name || ctx.translation("COMMAND");
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Resolve the sub command name
|
|
96
|
-
* @param ctx A {@link CommandContext | command context}
|
|
97
|
-
* @returns The sub command name
|
|
98
|
-
*/
|
|
99
|
-
function resolveSubCommand(ctx) {
|
|
100
|
-
return ctx.name || ctx.translation("SUBCOMMAND");
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Check if the command has a description
|
|
104
|
-
* @param ctx A {@link CommandContext | command context}
|
|
105
|
-
* @returns True if the command has a description
|
|
106
|
-
*/
|
|
107
|
-
function hasDescription(ctx) {
|
|
108
|
-
return !!ctx.description;
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Check if the command has sub commands
|
|
112
|
-
* @param ctx A {@link CommandContext | command context}
|
|
113
|
-
* @returns True if the command has sub commands
|
|
114
|
-
*/
|
|
115
|
-
async function hasCommands(ctx) {
|
|
116
|
-
const loadedCommands = await ctx.loadCommands();
|
|
117
|
-
return loadedCommands.length > 1;
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Check if the command has options
|
|
121
|
-
* @param ctx A {@link CommandContext | command context}
|
|
122
|
-
* @returns True if the command has options
|
|
123
|
-
*/
|
|
124
|
-
function hasOptions(ctx) {
|
|
125
|
-
return !!(ctx.options && Object.keys(ctx.options).length > 0);
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Check if the command has examples
|
|
129
|
-
* @param ctx A {@link CommandContext | command context}
|
|
130
|
-
* @returns True if the command has examples
|
|
131
|
-
*/
|
|
132
|
-
function hasExamples(ctx) {
|
|
133
|
-
return !!ctx.usage.examples;
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* Check if all options have default values
|
|
137
|
-
* @param ctx A {@link CommandContext | command context}
|
|
138
|
-
* @returns True if all options have default values
|
|
139
|
-
*/
|
|
140
|
-
function hasAllDefaultOptions(ctx) {
|
|
141
|
-
return !!(ctx.options && Object.values(ctx.options).every((opt) => opt.default));
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* Generate options symbols for usage
|
|
145
|
-
* @param ctx A {@link CommandContext | command context}
|
|
146
|
-
* @returns Options symbols for usage
|
|
147
|
-
*/
|
|
148
|
-
function generateOptionsSymbols(ctx) {
|
|
149
|
-
return hasOptions(ctx) ? hasAllDefaultOptions(ctx) ? `[${ctx.translation("OPTIONS")}]` : `<${ctx.translation("OPTIONS")}>` : "";
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Get options pairs for usage
|
|
153
|
-
* @param ctx A {@link CommandContext | command context}
|
|
154
|
-
* @returns Options pairs for usage
|
|
155
|
-
*/
|
|
156
|
-
function getOptionsPairs(ctx) {
|
|
157
|
-
return Object.entries(ctx.options).reduce((acc, [name, value]) => {
|
|
158
|
-
let key = `--${name}`;
|
|
159
|
-
if (value.short) key = `-${value.short}, ${key}`;
|
|
160
|
-
if (value.type !== "boolean") key = value.default ? `${key} [${name}]` : `${key} <${name}>`;
|
|
161
|
-
acc[name] = key;
|
|
162
|
-
return acc;
|
|
163
|
-
}, create());
|
|
164
|
-
}
|
|
165
|
-
/**
|
|
166
|
-
* Generate options usage
|
|
167
|
-
* @param ctx A {@link CommandContext | command context}
|
|
168
|
-
* @param optionsPairs Options pairs for usage
|
|
169
|
-
* @returns Generated options usage
|
|
170
|
-
*/
|
|
171
|
-
async function generateOptionsUsage(ctx, optionsPairs) {
|
|
172
|
-
const optionsMaxLength = Math.max(...Object.entries(optionsPairs).map(([_, value]) => value.length));
|
|
173
|
-
const optionSchemaMaxLength = ctx.env.usageOptionType ? Math.max(...Object.entries(optionsPairs).map(([key, _]) => ctx.options[key].type.length)) : 0;
|
|
174
|
-
const usages = await Promise.all(Object.entries(optionsPairs).map(([key, value]) => {
|
|
175
|
-
const rawDesc = ctx.translation(key);
|
|
176
|
-
const optionsSchema = ctx.env.usageOptionType ? `[${ctx.options[key].type}] ` : "";
|
|
177
|
-
const desc = `${optionsSchema ? optionsSchema.padEnd(optionSchemaMaxLength + 3) : ""}${rawDesc}`;
|
|
178
|
-
const option = `${value.padEnd(optionsMaxLength + ctx.env.middleMargin)}${desc}`;
|
|
179
|
-
return `${option.padStart(ctx.env.leftMargin + option.length)}`;
|
|
180
|
-
}));
|
|
181
|
-
return usages.join("\n");
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
//#endregion
|
|
185
|
-
//#region src/renderer/validation.ts
|
|
186
|
-
function renderValidationErrors(_ctx, error) {
|
|
187
|
-
const messages = [];
|
|
188
|
-
for (const err of error.errors) messages.push(err.message);
|
|
189
|
-
return Promise.resolve(messages.join("\n"));
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
//#endregion
|
|
193
6
|
//#region src/cli.ts
|
|
194
7
|
async function cli(args, entry, opts = {}) {
|
|
195
8
|
const tokens = parseArgs(args);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ArgOptions } from 'args-tokens';
|
|
2
|
+
import { b as CommandContext } from '../types.d-veidyA82.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Render the header
|
|
6
|
+
* @param ctx A {@link CommandContext | command context}
|
|
7
|
+
* @returns A rendered header
|
|
8
|
+
*/
|
|
9
|
+
declare function renderHeader<Options extends ArgOptions>(ctx: Readonly<CommandContext<Options>>): Promise<string>;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Render the usage
|
|
13
|
+
* @param ctx A {@link CommandContext | command context}
|
|
14
|
+
* @returns A rendered usage
|
|
15
|
+
*/
|
|
16
|
+
declare function renderUsage<Options extends ArgOptions>(ctx: Readonly<CommandContext<Options>>): Promise<string>;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Render the validation errors
|
|
20
|
+
* @param ctx A {@link CommandContext | command context}
|
|
21
|
+
* @param error An {@link AggregateError} of option in `args-token` validation
|
|
22
|
+
* @returns A rendered validation error
|
|
23
|
+
*/
|
|
24
|
+
declare function renderValidationErrors<Options extends ArgOptions>(_ctx: CommandContext<Options>, error: AggregateError): Promise<string>;
|
|
25
|
+
|
|
26
|
+
export { renderHeader, renderUsage, renderValidationErrors };
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { create } from "./utils-NHs5DuHk.js";
|
|
2
|
+
|
|
3
|
+
//#region src/renderer/header.ts
|
|
4
|
+
function renderHeader(ctx) {
|
|
5
|
+
const title = ctx.env.description || ctx.env.name || "";
|
|
6
|
+
return Promise.resolve(title ? `${title} (${ctx.env.name || ""}${ctx.env.version ? ` v${ctx.env.version}` : ""})` : title);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/renderer/usage.ts
|
|
11
|
+
async function renderUsage(ctx) {
|
|
12
|
+
const messages = [];
|
|
13
|
+
if (!ctx.omitted && hasDescription(ctx)) messages.push(ctx.description, "");
|
|
14
|
+
messages.push(...await renderUsageSection(ctx), "");
|
|
15
|
+
if (ctx.omitted && await hasCommands(ctx)) messages.push(...await renderCommandsSection(ctx), "");
|
|
16
|
+
if (hasOptions(ctx)) messages.push(...await renderOptionsSection(ctx), "");
|
|
17
|
+
if (hasExamples(ctx)) messages.push(...renderExamplesSection(ctx), "");
|
|
18
|
+
return messages.join("\n");
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Render the options section
|
|
22
|
+
* @param ctx A {@link CommandContext | command context}
|
|
23
|
+
* @returns A rendered options section
|
|
24
|
+
*/
|
|
25
|
+
async function renderOptionsSection(ctx) {
|
|
26
|
+
const messages = [];
|
|
27
|
+
messages.push(`${ctx.translation("OPTIONS")}:`);
|
|
28
|
+
const optionsPairs = getOptionsPairs(ctx);
|
|
29
|
+
messages.push(await generateOptionsUsage(ctx, optionsPairs));
|
|
30
|
+
return messages;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Render the examples section
|
|
34
|
+
* @param ctx A {@link CommandContext | command context}
|
|
35
|
+
* @returns A rendered examples section
|
|
36
|
+
*/
|
|
37
|
+
function renderExamplesSection(ctx) {
|
|
38
|
+
const messages = [];
|
|
39
|
+
const examples = ctx.usage.examples.split("\n").map((example) => example.padStart(ctx.env.leftMargin + example.length));
|
|
40
|
+
messages.push(`${ctx.translation("EXAMPLES")}:`, ...examples);
|
|
41
|
+
return messages;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Render the usage section
|
|
45
|
+
* @param ctx A {@link CommandContext | command context}
|
|
46
|
+
* @returns A rendered usage section
|
|
47
|
+
*/
|
|
48
|
+
async function renderUsageSection(ctx) {
|
|
49
|
+
const messages = [`${ctx.translation("USAGE")}:`];
|
|
50
|
+
if (ctx.omitted) {
|
|
51
|
+
const defaultCommand = `${resolveEntry(ctx)}${await hasCommands(ctx) ? ` [${resolveSubCommand(ctx)}]` : ""} ${hasOptions(ctx) ? `<${ctx.translation("OPTIONS")}>` : ""} `;
|
|
52
|
+
messages.push(defaultCommand.padStart(ctx.env.leftMargin + defaultCommand.length));
|
|
53
|
+
if (await hasCommands(ctx)) {
|
|
54
|
+
const commandsUsage = `${resolveEntry(ctx)} <${ctx.translation("COMMANDS")}>`;
|
|
55
|
+
messages.push(commandsUsage.padStart(ctx.env.leftMargin + commandsUsage.length));
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
const usageStr = `${resolveEntry(ctx)} ${resolveSubCommand(ctx)} ${generateOptionsSymbols(ctx)}`;
|
|
59
|
+
messages.push(usageStr.padStart(ctx.env.leftMargin + usageStr.length));
|
|
60
|
+
}
|
|
61
|
+
return messages;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Render the commands section
|
|
65
|
+
* @param ctx A {@link CommandContext | command context}
|
|
66
|
+
* @returns A rendered commands section
|
|
67
|
+
*/
|
|
68
|
+
async function renderCommandsSection(ctx) {
|
|
69
|
+
const messages = [`${ctx.translation("COMMANDS")}:`];
|
|
70
|
+
const loadedCommands = await ctx.loadCommands();
|
|
71
|
+
const commandMaxLength = Math.max(...loadedCommands.map((cmd) => (cmd.name || "").length));
|
|
72
|
+
const commandsStr = await Promise.all(loadedCommands.map((cmd) => {
|
|
73
|
+
const key = cmd.name || "";
|
|
74
|
+
const desc = cmd.description || "";
|
|
75
|
+
const command = `${key.padEnd(commandMaxLength + ctx.env.middleMargin)}${desc} `;
|
|
76
|
+
return `${command.padStart(ctx.env.leftMargin + command.length)} `;
|
|
77
|
+
}));
|
|
78
|
+
messages.push(...commandsStr, "", ctx.translation("FORMORE"));
|
|
79
|
+
messages.push(...loadedCommands.map((cmd) => {
|
|
80
|
+
const commandHelp = `${ctx.env.name} ${cmd.name} --help`;
|
|
81
|
+
return `${commandHelp.padStart(ctx.env.leftMargin + commandHelp.length)}`;
|
|
82
|
+
}));
|
|
83
|
+
return messages;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Resolve the entry command name
|
|
87
|
+
* @param ctx A {@link CommandContext | command context}
|
|
88
|
+
* @returns The entry command name
|
|
89
|
+
*/
|
|
90
|
+
function resolveEntry(ctx) {
|
|
91
|
+
return ctx.env.name || ctx.translation("COMMAND");
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Resolve the sub command name
|
|
95
|
+
* @param ctx A {@link CommandContext | command context}
|
|
96
|
+
* @returns The sub command name
|
|
97
|
+
*/
|
|
98
|
+
function resolveSubCommand(ctx) {
|
|
99
|
+
return ctx.name || ctx.translation("SUBCOMMAND");
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Check if the command has a description
|
|
103
|
+
* @param ctx A {@link CommandContext | command context}
|
|
104
|
+
* @returns True if the command has a description
|
|
105
|
+
*/
|
|
106
|
+
function hasDescription(ctx) {
|
|
107
|
+
return !!ctx.description;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Check if the command has sub commands
|
|
111
|
+
* @param ctx A {@link CommandContext | command context}
|
|
112
|
+
* @returns True if the command has sub commands
|
|
113
|
+
*/
|
|
114
|
+
async function hasCommands(ctx) {
|
|
115
|
+
const loadedCommands = await ctx.loadCommands();
|
|
116
|
+
return loadedCommands.length > 1;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Check if the command has options
|
|
120
|
+
* @param ctx A {@link CommandContext | command context}
|
|
121
|
+
* @returns True if the command has options
|
|
122
|
+
*/
|
|
123
|
+
function hasOptions(ctx) {
|
|
124
|
+
return !!(ctx.options && Object.keys(ctx.options).length > 0);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Check if the command has examples
|
|
128
|
+
* @param ctx A {@link CommandContext | command context}
|
|
129
|
+
* @returns True if the command has examples
|
|
130
|
+
*/
|
|
131
|
+
function hasExamples(ctx) {
|
|
132
|
+
return !!ctx.usage.examples;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Check if all options have default values
|
|
136
|
+
* @param ctx A {@link CommandContext | command context}
|
|
137
|
+
* @returns True if all options have default values
|
|
138
|
+
*/
|
|
139
|
+
function hasAllDefaultOptions(ctx) {
|
|
140
|
+
return !!(ctx.options && Object.values(ctx.options).every((opt) => opt.default));
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Generate options symbols for usage
|
|
144
|
+
* @param ctx A {@link CommandContext | command context}
|
|
145
|
+
* @returns Options symbols for usage
|
|
146
|
+
*/
|
|
147
|
+
function generateOptionsSymbols(ctx) {
|
|
148
|
+
return hasOptions(ctx) ? hasAllDefaultOptions(ctx) ? `[${ctx.translation("OPTIONS")}]` : `<${ctx.translation("OPTIONS")}>` : "";
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Get options pairs for usage
|
|
152
|
+
* @param ctx A {@link CommandContext | command context}
|
|
153
|
+
* @returns Options pairs for usage
|
|
154
|
+
*/
|
|
155
|
+
function getOptionsPairs(ctx) {
|
|
156
|
+
return Object.entries(ctx.options).reduce((acc, [name, value]) => {
|
|
157
|
+
let key = `--${name}`;
|
|
158
|
+
if (value.short) key = `-${value.short}, ${key}`;
|
|
159
|
+
if (value.type !== "boolean") key = value.default ? `${key} [${name}]` : `${key} <${name}>`;
|
|
160
|
+
acc[name] = key;
|
|
161
|
+
return acc;
|
|
162
|
+
}, create());
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Generate options usage
|
|
166
|
+
* @param ctx A {@link CommandContext | command context}
|
|
167
|
+
* @param optionsPairs Options pairs for usage
|
|
168
|
+
* @returns Generated options usage
|
|
169
|
+
*/
|
|
170
|
+
async function generateOptionsUsage(ctx, optionsPairs) {
|
|
171
|
+
const optionsMaxLength = Math.max(...Object.entries(optionsPairs).map(([_, value]) => value.length));
|
|
172
|
+
const optionSchemaMaxLength = ctx.env.usageOptionType ? Math.max(...Object.entries(optionsPairs).map(([key, _]) => ctx.options[key].type.length)) : 0;
|
|
173
|
+
const usages = await Promise.all(Object.entries(optionsPairs).map(([key, value]) => {
|
|
174
|
+
const rawDesc = ctx.translation(key);
|
|
175
|
+
const optionsSchema = ctx.env.usageOptionType ? `[${ctx.options[key].type}] ` : "";
|
|
176
|
+
const desc = `${optionsSchema ? optionsSchema.padEnd(optionSchemaMaxLength + 3) : ""}${rawDesc}`;
|
|
177
|
+
const option = `${value.padEnd(optionsMaxLength + ctx.env.middleMargin)}${desc}`;
|
|
178
|
+
return `${option.padStart(ctx.env.leftMargin + option.length)}`;
|
|
179
|
+
}));
|
|
180
|
+
return usages.join("\n");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
//#endregion
|
|
184
|
+
//#region src/renderer/validation.ts
|
|
185
|
+
function renderValidationErrors(_ctx, error) {
|
|
186
|
+
const messages = [];
|
|
187
|
+
for (const err of error.errors) messages.push(err.message);
|
|
188
|
+
return Promise.resolve(messages.join("\n"));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
//#endregion
|
|
192
|
+
export { renderHeader, renderUsage, renderValidationErrors };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/utils.ts
|
|
3
|
+
async function resolveLazyCommand(cmd, name, entry = false) {
|
|
4
|
+
const resolved = Object.assign(create(), typeof cmd == "function" ? await cmd() : cmd, { default: entry });
|
|
5
|
+
if (resolved.name == null && name) resolved.name = name;
|
|
6
|
+
return deepFreeze(resolved);
|
|
7
|
+
}
|
|
8
|
+
function create(obj = null) {
|
|
9
|
+
return Object.create(obj);
|
|
10
|
+
}
|
|
11
|
+
function log(...args) {
|
|
12
|
+
console.log(...args);
|
|
13
|
+
}
|
|
14
|
+
function deepFreeze(obj) {
|
|
15
|
+
if (obj === null || typeof obj !== "object") return obj;
|
|
16
|
+
for (const key of Object.keys(obj)) {
|
|
17
|
+
const value = obj[key];
|
|
18
|
+
if (typeof value === "object" && value !== null) deepFreeze(value);
|
|
19
|
+
}
|
|
20
|
+
return Object.freeze(obj);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
export { create, deepFreeze, log, resolveLazyCommand };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gunshi",
|
|
3
3
|
"description": "Modern javascript command-line library",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.3",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "kazuya kawaguchi",
|
|
7
7
|
"email": "kawakazu80@gmail.com"
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
"default": "./lib/context.js"
|
|
50
50
|
},
|
|
51
51
|
"./renderer": {
|
|
52
|
-
"types": "./lib/renderer.d.ts",
|
|
53
|
-
"import": "./lib/renderer.js",
|
|
54
|
-
"require": "./lib/renderer.js",
|
|
55
|
-
"default": "./lib/renderer.js"
|
|
52
|
+
"types": "./lib/renderer/index.d.ts",
|
|
53
|
+
"import": "./lib/renderer/index.js",
|
|
54
|
+
"require": "./lib/renderer/index.js",
|
|
55
|
+
"default": "./lib/renderer/index.js"
|
|
56
56
|
},
|
|
57
57
|
"./package.json": "./package.json",
|
|
58
58
|
"./*": "./*"
|