gunshi 0.12.0 → 0.13.0
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/README.md +13 -312
- package/lib/{cli-C-y15OeH.js → cli-D_4MqIMP.js} +3 -1
- package/lib/generator.d.ts +1 -1
- package/lib/generator.js +1 -1
- package/lib/index.d.ts +3 -3
- package/lib/index.js +3 -2
- package/lib/renderer/index.d.ts +1 -1
- package/lib/{types.d-DIY9YbHU.d.ts → types.d-DqtZy3HN.d.ts} +5 -0
- package/package.json +7 -4
package/README.md
CHANGED
|
@@ -32,8 +32,6 @@ Gunshi is designed to simplify the creation of modern command-line interfaces:
|
|
|
32
32
|
|
|
33
33
|
## 💿 Installation
|
|
34
34
|
|
|
35
|
-
### 🐢 Node
|
|
36
|
-
|
|
37
35
|
```sh
|
|
38
36
|
# npm
|
|
39
37
|
npm install --save gunshi
|
|
@@ -43,41 +41,16 @@ pnpm add gunshi
|
|
|
43
41
|
|
|
44
42
|
## yarn
|
|
45
43
|
yarn add gunshi
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### 🦕 Deno
|
|
49
44
|
|
|
50
|
-
|
|
45
|
+
## deno
|
|
51
46
|
deno add jsr:@kazupon/gunshi
|
|
52
|
-
```
|
|
53
47
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
```sh
|
|
48
|
+
## bun
|
|
57
49
|
bun add gunshi
|
|
58
50
|
```
|
|
59
51
|
|
|
60
52
|
## 🚀 Usage
|
|
61
53
|
|
|
62
|
-
### 📏 Simple API
|
|
63
|
-
|
|
64
|
-
Gunshi has a simple API that is a facade:
|
|
65
|
-
|
|
66
|
-
```js
|
|
67
|
-
import { cli } from 'gunshi'
|
|
68
|
-
|
|
69
|
-
const args = process.argv.slice(2)
|
|
70
|
-
// run a simple command
|
|
71
|
-
await cli(args, () => {
|
|
72
|
-
// something logic ...
|
|
73
|
-
console.log('Hello from Gunshi!', args)
|
|
74
|
-
})
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### ⚙️ Declarative Configuration
|
|
78
|
-
|
|
79
|
-
Configure commands declaratively:
|
|
80
|
-
|
|
81
54
|
```js
|
|
82
55
|
import { cli } from 'gunshi'
|
|
83
56
|
|
|
@@ -121,289 +94,7 @@ await cli(process.argv.slice(2), command, {
|
|
|
121
94
|
})
|
|
122
95
|
```
|
|
123
96
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
### 🛡️ Type-Safe Arguments
|
|
127
|
-
|
|
128
|
-
Gunshi provides type-safe argument parsing with TypeScript:
|
|
129
|
-
|
|
130
|
-
```ts
|
|
131
|
-
import { cli } from 'gunshi'
|
|
132
|
-
import type { ArgOptions, Command, CommandContext } from 'gunshi'
|
|
133
|
-
|
|
134
|
-
// type-safe arguments parsing example
|
|
135
|
-
// this demonstrates how to define and use typed command options with `satisfies`
|
|
136
|
-
|
|
137
|
-
// define 'type-safe' command options with types
|
|
138
|
-
const options = {
|
|
139
|
-
// define string option with short alias
|
|
140
|
-
name: {
|
|
141
|
-
type: 'string',
|
|
142
|
-
short: 'n'
|
|
143
|
-
},
|
|
144
|
-
// define number option with default value
|
|
145
|
-
age: {
|
|
146
|
-
type: 'number',
|
|
147
|
-
short: 'a',
|
|
148
|
-
default: 25
|
|
149
|
-
},
|
|
150
|
-
// define boolean flag
|
|
151
|
-
verbose: {
|
|
152
|
-
type: 'boolean',
|
|
153
|
-
short: 'v'
|
|
154
|
-
}
|
|
155
|
-
} satisfies ArgOptions
|
|
156
|
-
|
|
157
|
-
// define 'type-safe' command
|
|
158
|
-
const command = {
|
|
159
|
-
name: 'type-safe',
|
|
160
|
-
options,
|
|
161
|
-
run: (ctx: CommandContext<UserOptions, UserValues>) => {
|
|
162
|
-
const { name, age, verbose } = ctx.values
|
|
163
|
-
console.log(`Hello, ${name || 'World'}! You are ${age} years old.`)
|
|
164
|
-
}
|
|
165
|
-
} satisfies Command<typeof options>
|
|
166
|
-
|
|
167
|
-
await cli(process.argv.slice(2), command)
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
For more detailed examples, check out the [playground/type-safe](https://github.com/kazupon/gunshi/tree/main/playground/type-safe) in the repository.
|
|
171
|
-
|
|
172
|
-
### 🧩 Composable Sub-commands
|
|
173
|
-
|
|
174
|
-
Run a CLI with composable sub-commands:
|
|
175
|
-
|
|
176
|
-
```js
|
|
177
|
-
import { cli } from 'gunshi'
|
|
178
|
-
|
|
179
|
-
// define 'create' command
|
|
180
|
-
const createCommand = {
|
|
181
|
-
name: 'create',
|
|
182
|
-
description: 'Create a new resource',
|
|
183
|
-
options: {
|
|
184
|
-
name: { type: 'string', short: 'n' }
|
|
185
|
-
},
|
|
186
|
-
run: ctx => {
|
|
187
|
-
console.log(`Creating resource: ${ctx.values.name}`)
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// define 'list' command
|
|
192
|
-
const listCommand = {
|
|
193
|
-
name: 'list',
|
|
194
|
-
description: 'List all resources',
|
|
195
|
-
run: () => {
|
|
196
|
-
console.log('Listing all resources...')
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// prepare a Map of sub-commands
|
|
201
|
-
const subCommands = new Map()
|
|
202
|
-
subCommands.set('create', createCommand)
|
|
203
|
-
subCommands.set('list', listCommand)
|
|
204
|
-
|
|
205
|
-
// define the main ('resource-manager') command
|
|
206
|
-
const mainCommand = {
|
|
207
|
-
name: 'resource-manager',
|
|
208
|
-
description: 'Manage resources',
|
|
209
|
-
run: () => {
|
|
210
|
-
console.log('Use one of the sub-commands: create, list')
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// run the CLI with composable sub-commands
|
|
215
|
-
await cli(process.argv.slice(2), mainCommand, {
|
|
216
|
-
name: 'my-app',
|
|
217
|
-
version: '1.0.0',
|
|
218
|
-
subCommands
|
|
219
|
-
})
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
For more detailed examples, check out the [playground/composable](https://github.com/kazupon/gunshi/tree/main/playground/composable) in the repository.
|
|
223
|
-
|
|
224
|
-
### ⏳ Lazy & Async Command Loading
|
|
225
|
-
|
|
226
|
-
Load commands lazily and execute them asynchronously:
|
|
227
|
-
|
|
228
|
-
```js
|
|
229
|
-
import { cli } from 'gunshi'
|
|
230
|
-
|
|
231
|
-
// define a command that will be loaded lazily
|
|
232
|
-
const lazyCommand = async () => {
|
|
233
|
-
// simulate async loading
|
|
234
|
-
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
235
|
-
|
|
236
|
-
// return the actual command
|
|
237
|
-
return {
|
|
238
|
-
name: 'lazy',
|
|
239
|
-
description: 'A command that is loaded lazily',
|
|
240
|
-
run: async ctx => {
|
|
241
|
-
// async execution
|
|
242
|
-
await new Promise(resolve => setTimeout(resolve, 500))
|
|
243
|
-
console.log('Command executed!')
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// prepare a Map of sub-commands with lazy-loaded commands
|
|
249
|
-
const subCommands = new Map()
|
|
250
|
-
subCommands.set('lazy', lazyCommand)
|
|
251
|
-
|
|
252
|
-
// run the CLI with lazy-loaded commands
|
|
253
|
-
await cli(
|
|
254
|
-
process.argv.slice(2),
|
|
255
|
-
{ name: 'main', run: () => {} },
|
|
256
|
-
{
|
|
257
|
-
name: 'my-app',
|
|
258
|
-
subCommands
|
|
259
|
-
}
|
|
260
|
-
)
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
For more detailed examples, check out the [playground/lazy-async](https://github.com/kazupon/gunshi/tree/main/playground/lazy-async) in the repository.
|
|
264
|
-
|
|
265
|
-
### 📜 Auto Usage Generation
|
|
266
|
-
|
|
267
|
-
Gunshi automatically generates usage information:
|
|
268
|
-
|
|
269
|
-
```js
|
|
270
|
-
import { cli } from 'gunshi'
|
|
271
|
-
|
|
272
|
-
const command = {
|
|
273
|
-
name: 'app',
|
|
274
|
-
description: 'My application',
|
|
275
|
-
options: {
|
|
276
|
-
path: {
|
|
277
|
-
type: 'string',
|
|
278
|
-
short: 'p',
|
|
279
|
-
description: 'File or directory path'
|
|
280
|
-
},
|
|
281
|
-
recursive: {
|
|
282
|
-
type: 'boolean',
|
|
283
|
-
short: 'r',
|
|
284
|
-
description: 'Operate recursively on directories'
|
|
285
|
-
},
|
|
286
|
-
operation: {
|
|
287
|
-
type: 'string',
|
|
288
|
-
short: 'o',
|
|
289
|
-
required: true,
|
|
290
|
-
description: 'Operation to perform (list, copy, move, delete)'
|
|
291
|
-
}
|
|
292
|
-
},
|
|
293
|
-
// define examples
|
|
294
|
-
examples: '# Example\n$ my-app --operation list --path ./src',
|
|
295
|
-
run: ctx => {
|
|
296
|
-
// command implementation
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// run with --help to see the automatically generated usage information
|
|
301
|
-
await cli(process.argv.slice(2), command, {
|
|
302
|
-
name: 'my-app',
|
|
303
|
-
version: '1.0.0'
|
|
304
|
-
})
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
For more detailed examples, check out the [playground/auto-usage](https://github.com/kazupon/gunshi/tree/main/playground/auto-usage) in the repository.
|
|
308
|
-
|
|
309
|
-
### 🎨 Custom Usage Generation
|
|
310
|
-
|
|
311
|
-
Customize the usage message generation:
|
|
312
|
-
|
|
313
|
-
```js
|
|
314
|
-
import { cli } from 'gunshi'
|
|
315
|
-
|
|
316
|
-
// define custom header renderer
|
|
317
|
-
const customHeaderRenderer = ctx => {
|
|
318
|
-
return Promise.resolve(`
|
|
319
|
-
╔═══════════════════════╗
|
|
320
|
-
║ ${ctx.env.name.toUpperCase()} ║
|
|
321
|
-
╚═══════════════════════╝
|
|
322
|
-
${ctx.env.description}
|
|
323
|
-
Version: ${ctx.env.version}
|
|
324
|
-
`)
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// define custom usage renderer
|
|
328
|
-
const customUsageRenderer = ctx => {
|
|
329
|
-
const lines = []
|
|
330
|
-
lines.push('USAGE:')
|
|
331
|
-
lines.push(` $ ${ctx.env.name} [options]`)
|
|
332
|
-
lines.push('')
|
|
333
|
-
lines.push('OPTIONS:')
|
|
334
|
-
|
|
335
|
-
for (const [key, option] of Object.entries(ctx.options || Object.create(null))) {
|
|
336
|
-
const shortFlag = option.short ? `-${option.short}, ` : ' '
|
|
337
|
-
lines.push(` ${shortFlag}--${key.padEnd(10)} ${ctx.translate(key)}`)
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
return Promise.resolve(lines.join('\n'))
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// run with custom renderers
|
|
344
|
-
await cli(
|
|
345
|
-
process.argv.slice(2),
|
|
346
|
-
{ name: 'app', run: () => {} },
|
|
347
|
-
{
|
|
348
|
-
name: 'my-app',
|
|
349
|
-
version: '1.0.0',
|
|
350
|
-
description: 'My application',
|
|
351
|
-
renderHeader: customHeaderRenderer,
|
|
352
|
-
renderUsage: customUsageRenderer
|
|
353
|
-
}
|
|
354
|
-
)
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
For more detailed examples, check out the [playground/custom-usage](https://github.com/kazupon/gunshi/tree/main/playground/custom-usage) in the repository.
|
|
358
|
-
|
|
359
|
-
### 🌍 Internationalization
|
|
360
|
-
|
|
361
|
-
Support internationalization:
|
|
362
|
-
|
|
363
|
-
```js
|
|
364
|
-
import { cli } from 'gunshi'
|
|
365
|
-
import enUS from './locales/en-US.json' with { type: 'json' }
|
|
366
|
-
|
|
367
|
-
const command = {
|
|
368
|
-
name: 'greeter',
|
|
369
|
-
options: {
|
|
370
|
-
name: {
|
|
371
|
-
type: 'string',
|
|
372
|
-
short: 'n'
|
|
373
|
-
},
|
|
374
|
-
formal: {
|
|
375
|
-
type: 'boolean',
|
|
376
|
-
short: 'f'
|
|
377
|
-
}
|
|
378
|
-
},
|
|
379
|
-
// resource fetcher for translations
|
|
380
|
-
resource: async ctx => {
|
|
381
|
-
if (ctx.locale.toString() === 'ja-JP') {
|
|
382
|
-
const resource = await import('./locales/ja-JP.json', { with: { type: 'json' } })
|
|
383
|
-
return resource.default
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// default to English
|
|
387
|
-
return enUS
|
|
388
|
-
},
|
|
389
|
-
run: ctx => {
|
|
390
|
-
const { name = 'World', formal } = ctx.values
|
|
391
|
-
const greeting = formal ? ctx.translate('formal_greeting') : ctx.translate('informal_greeting')
|
|
392
|
-
console.log(`${greeting}, ${name}!`)
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// run with locale support
|
|
397
|
-
await cli(process.argv.slice(2), command, {
|
|
398
|
-
name: 'my-app',
|
|
399
|
-
version: '1.0.0',
|
|
400
|
-
// set the locale via an environment variable
|
|
401
|
-
// if Node v21 or later is used, you can use the built-in `navigator.language` instead)
|
|
402
|
-
locale: new Intl.Locale(process.env.MY_LOCALE || 'en-US')
|
|
403
|
-
})
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
For more detailed examples, check out the [playground/i18n](https://github.com/kazupon/gunshi/tree/main/playground/i18n) in the repository.
|
|
97
|
+
About more details and usage, see [documentations](https://gunshi.dev)
|
|
407
98
|
|
|
408
99
|
## 💁♀️ Showcases
|
|
409
100
|
|
|
@@ -423,6 +114,16 @@ This project is inspired and powered by:
|
|
|
423
114
|
|
|
424
115
|
Thank you!
|
|
425
116
|
|
|
117
|
+
## 🤝 Sponsors
|
|
118
|
+
|
|
119
|
+
The development of Gunish is supported by my OSS sponsors!
|
|
120
|
+
|
|
121
|
+
<p align="center">
|
|
122
|
+
<a href="https://cdn.jsdelivr.net/gh/kazupon/sponsors/sponsors.svg">
|
|
123
|
+
<img src='https://cdn.jsdelivr.net/gh/kazupon/sponsors/sponsors.svg'/>
|
|
124
|
+
</a>
|
|
125
|
+
</p>
|
|
126
|
+
|
|
426
127
|
## ©️ License
|
|
427
128
|
|
|
428
129
|
[MIT](http://opensource.org/licenses/MIT)
|
|
@@ -60,7 +60,7 @@ var DefaultTranslation = class {
|
|
|
60
60
|
//#endregion
|
|
61
61
|
//#region src/context.ts
|
|
62
62
|
const BUILT_IN_PREFIX_CODE = BUILT_IN_PREFIX.codePointAt(0);
|
|
63
|
-
async function createCommandContext({ options, values, positionals, command, commandOptions, omitted = false }) {
|
|
63
|
+
async function createCommandContext({ options, values, positionals, args, command, commandOptions, omitted = false }) {
|
|
64
64
|
/**
|
|
65
65
|
* normailize the options schema and values, to avoid prototype pollution
|
|
66
66
|
*/
|
|
@@ -121,6 +121,7 @@ async function createCommandContext({ options, values, positionals, command, com
|
|
|
121
121
|
options: _options,
|
|
122
122
|
values,
|
|
123
123
|
positionals,
|
|
124
|
+
_: args,
|
|
124
125
|
log: commandOptions.usageSilent ? NOOP : log,
|
|
125
126
|
loadCommands,
|
|
126
127
|
translate
|
|
@@ -179,6 +180,7 @@ async function cli(args, entry, opts = {}) {
|
|
|
179
180
|
options,
|
|
180
181
|
values,
|
|
181
182
|
positionals,
|
|
183
|
+
args,
|
|
182
184
|
omitted,
|
|
183
185
|
command,
|
|
184
186
|
commandOptions: resolvedCommandOptions
|
package/lib/generator.d.ts
CHANGED
package/lib/generator.js
CHANGED
package/lib/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ArgOptions } from 'args-tokens';
|
|
2
|
-
export { ArgOptionSchema, ArgOptions, ArgValues } from 'args-tokens';
|
|
3
|
-
import { C as Command, b as CommandRunner, a as CommandOptions, T as TranslationAdapter, c as TranslationAdapterFactoryOptions } from './types.d-
|
|
4
|
-
export { f as CommandBuiltinKeys, d as CommandBuiltinOptionsKeys, e as CommandBuiltinResourceKeys, h as CommandContext, g as CommandEnvironment, i as CommandResource, j as CommandResourceFetcher, l as Commandable, D as DEFAULT_LOCALE, G as GenerateNamespacedKey, L as LazyCommand, k as TranslationAdapterFactory } from './types.d-
|
|
2
|
+
export { ArgOptionSchema, ArgOptions, ArgValues, parseArgs, resolveArgs } from 'args-tokens';
|
|
3
|
+
import { C as Command, b as CommandRunner, a as CommandOptions, T as TranslationAdapter, c as TranslationAdapterFactoryOptions } from './types.d-DqtZy3HN.js';
|
|
4
|
+
export { f as CommandBuiltinKeys, d as CommandBuiltinOptionsKeys, e as CommandBuiltinResourceKeys, h as CommandContext, g as CommandEnvironment, i as CommandResource, j as CommandResourceFetcher, l as Commandable, D as DEFAULT_LOCALE, G as GenerateNamespacedKey, L as LazyCommand, k as TranslationAdapterFactory } from './types.d-DqtZy3HN.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Run the command.
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_LOCALE } from "./renderer-DAUAIZxV.js";
|
|
2
|
-
import { DefaultTranslation, cli } from "./cli-
|
|
2
|
+
import { DefaultTranslation, cli } from "./cli-D_4MqIMP.js";
|
|
3
|
+
import { parseArgs, resolveArgs } from "args-tokens";
|
|
3
4
|
|
|
4
|
-
export { DEFAULT_LOCALE, DefaultTranslation, cli };
|
|
5
|
+
export { DEFAULT_LOCALE, DefaultTranslation, cli, parseArgs, resolveArgs };
|
package/lib/renderer/index.d.ts
CHANGED
|
@@ -235,6 +235,11 @@ interface CommandContext<
|
|
|
235
235
|
*/
|
|
236
236
|
positionals: string[];
|
|
237
237
|
/**
|
|
238
|
+
* Original command line arguments.
|
|
239
|
+
* This argument is passed from `cli` function.
|
|
240
|
+
*/
|
|
241
|
+
_: string[];
|
|
242
|
+
/**
|
|
238
243
|
* Whether the currently executing command has been executed with the sub-command name omitted.
|
|
239
244
|
*/
|
|
240
245
|
omitted: boolean;
|
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.
|
|
4
|
+
"version": "0.13.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "kazuya kawaguchi",
|
|
7
7
|
"email": "kawakazu80@gmail.com"
|
|
@@ -87,13 +87,15 @@
|
|
|
87
87
|
"eslint-plugin-regexp": "^2.7.0",
|
|
88
88
|
"eslint-plugin-unicorn": "^58.0.0",
|
|
89
89
|
"eslint-plugin-unused-imports": "^4.1.4",
|
|
90
|
+
"eslint-plugin-vue": "^10.0.0",
|
|
91
|
+
"eslint-plugin-vue-composable": "^1.0.0",
|
|
90
92
|
"eslint-plugin-yml": "^1.17.0",
|
|
91
93
|
"gh-changelogen": "^0.2.8",
|
|
92
94
|
"jsr": "^0.13.4",
|
|
93
95
|
"knip": "^5.46.3",
|
|
94
96
|
"lint-staged": "^15.5.0",
|
|
95
97
|
"messageformat": "4.0.0-10",
|
|
96
|
-
"pkg-pr-new": "^0.0.
|
|
98
|
+
"pkg-pr-new": "^0.0.42",
|
|
97
99
|
"prettier": "^3.5.3",
|
|
98
100
|
"tsdown": "^0.6.10",
|
|
99
101
|
"typedoc": "^0.28.1",
|
|
@@ -103,8 +105,9 @@
|
|
|
103
105
|
"typescript-eslint": "^8.28.0",
|
|
104
106
|
"vitepress": "^1.6.3",
|
|
105
107
|
"vitepress-plugin-group-icons": "^1.3.8",
|
|
106
|
-
"vitepress-plugin-llms": "^0.0.
|
|
107
|
-
"vitest": "^3.0.9"
|
|
108
|
+
"vitepress-plugin-llms": "^0.0.22",
|
|
109
|
+
"vitest": "^3.0.9",
|
|
110
|
+
"vue": "^3.5.13"
|
|
108
111
|
},
|
|
109
112
|
"prettier": "@kazupon/prettier-config",
|
|
110
113
|
"lint-staged": {
|