cli-nano 0.3.0 → 0.3.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cli-nano",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Mini command-line tool similar to `yargs` or `parseArgs` from Node.js that accepts positional arguments, flags and options.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,747 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
-
3
- import { parseArgs } from '../index.js';
4
- import type { Config } from '../interfaces.js';
5
-
6
- const config: Config = {
7
- command: {
8
- name: 'copyfiles',
9
- description: 'Copy files from a source to a destination directory',
10
- positional: [
11
- {
12
- name: 'inFile',
13
- description: 'source files',
14
- type: 'string',
15
- required: true,
16
- },
17
- {
18
- name: 'outDirectory',
19
- description: 'destination directory',
20
- required: true,
21
- },
22
- ],
23
- },
24
- options: {
25
- all: {
26
- alias: 'a',
27
- type: 'boolean',
28
- description: 'include files & directories begining with a dot (.)',
29
- },
30
- dryRun: {
31
- alias: 'd',
32
- type: 'boolean',
33
- description: 'Show what would be copied, but do not actually copy any files',
34
- },
35
- exclude: {
36
- alias: 'e',
37
- type: 'array',
38
- description: 'pattern or glob to exclude (may be passed multiple times)',
39
- },
40
- up: {
41
- type: 'number',
42
- description: 'slice a path off the bottom of the paths',
43
- },
44
- bar: {
45
- alias: 'b',
46
- required: true,
47
- description: 'a required bar option',
48
- },
49
- },
50
- version: '0.1.6',
51
- };
52
-
53
- describe('parseArgs', () => {
54
- beforeEach(() => {
55
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...[]]);
56
- });
57
-
58
- afterEach(() => {
59
- vi.restoreAllMocks();
60
- });
61
-
62
- it('should parse positional arguments correctly', () => {
63
- const args = ['file1.txt', 'output/', '--bar', 'value'];
64
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
65
-
66
- const result = parseArgs(config);
67
-
68
- expect(result.inFile).toBe('file1.txt');
69
- expect(result.outDirectory).toBe('output/');
70
- });
71
-
72
- it('should parse camelCase boolean options correctly', () => {
73
- const args = ['file1.txt', 'output/', '--all', '--no-dryRun', '--bar', 'value'];
74
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
75
-
76
- const result = parseArgs(config);
77
-
78
- expect(result.inFile).toBe('file1.txt');
79
- expect(result.outDirectory).toBe('output/');
80
- expect(result.all).toBe(true);
81
- expect(result.dryRun).toBe(false);
82
- });
83
-
84
- it('should parse kebab-case boolean options correctly', () => {
85
- const args = ['file1.txt', 'output/', '--all', '--no-dry-run', '--bar', 'value'];
86
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
87
-
88
- const result = parseArgs(config);
89
-
90
- expect(result.inFile).toBe('file1.txt');
91
- expect(result.outDirectory).toBe('output/');
92
- expect(result.all).toBe(true);
93
- expect(result.dryRun).toBe(false);
94
- });
95
-
96
- it('should parse string options correctly', () => {
97
- const args = ['file1.txt', 'output/', '--up', '2', '--bar', 'value'];
98
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
99
- const result = parseArgs(config);
100
- expect(result.up).toBe(2);
101
- });
102
-
103
- it('should parse string options correctly with an alias', () => {
104
- const args = ['file1.txt', 'output/', '--up', '2', '-b', 'value'];
105
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
106
- const result = parseArgs(config);
107
- expect(result.up).toBe(2);
108
- expect(result.bar).toBe('value');
109
- });
110
-
111
- it('should parse array options correctly when defined at the end of the command options', () => {
112
- const args = ['file1.txt', 'output/', '-b', 'value', '--exclude', 'pattern1', '--exclude', 'pattern2'];
113
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
114
- const result = parseArgs(config);
115
- expect(result.exclude).toEqual(['pattern1', 'pattern2']);
116
- expect(result.bar).toBe('value');
117
- });
118
-
119
- it('should parse array options correctly when defined in the middle of the command options with camelCase arguments', () => {
120
- const args = ['file1.txt', 'output/', '--exclude', 'pattern1', '--exclude', 'pattern2', '-b', 'value', '--dryRun'];
121
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
122
- const result = parseArgs(config);
123
- expect(result.exclude).toEqual(['pattern1', 'pattern2']);
124
- expect(result.dryRun).toBe(true);
125
- expect(result.bar).toBe('value');
126
- });
127
-
128
- it('should parse array options correctly when defined in the middle of the command options with kebab-case arguments', () => {
129
- const args = ['file1.txt', 'output/', '--exclude', 'pattern1', '--exclude', 'pattern2', '-b', 'value', '--dry-run'];
130
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
131
- const result = parseArgs(config);
132
- expect(result.exclude).toEqual(['pattern1', 'pattern2']);
133
- expect(result.dryRun).toBe(true);
134
- expect(result.bar).toBe('value');
135
- });
136
-
137
- it('should throw an error for unknown options', () => {
138
- const args = ['file1.txt', 'output/', '-b', 'value', '--unknown'];
139
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
140
- expect(() => parseArgs(config)).toThrowError('Unknown option: unknown');
141
- });
142
-
143
- it('should throw an error for unknown kebab-case options', () => {
144
- const args = ['file1.txt', 'output/', '-b', 'value', '--unknown-kebab'];
145
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
146
- expect(() => parseArgs(config)).toThrowError('Unknown option: unknown-kebab');
147
- });
148
-
149
- it('should throw an error for unknown camelCase options', () => {
150
- const args = ['file1.txt', 'output/', '-b', 'value', '--unknownCamel'];
151
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
152
- expect(() => parseArgs(config)).toThrowError('Unknown option: unknownCamel');
153
- });
154
-
155
- it('should throw when truthy and --no camelCase prefix arguments are both provided', () => {
156
- const args = ['file1.txt', 'output/', '--all', '--dryRun', '--no-dryRun', '-b', 'value'];
157
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
158
- expect(() => parseArgs(config)).toThrowError('Providing same negated and truthy argument are not allowed');
159
- });
160
-
161
- it('should throw when truthy and --no kebab-case prefix arguments are both provided', () => {
162
- const args = ['file1.txt', 'output/', '--all', '--dryRun', '--no-dry-run', '-b', 'value'];
163
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
164
- expect(() => parseArgs(config)).toThrowError('Providing same negated and truthy argument are not allowed');
165
- });
166
-
167
- it('should throw when --no prefix and truthy arguments are both provided', () => {
168
- const args = ['file1.txt', 'output/', '--all', '--no-dryRun', '--dryRun', '-b', 'value'];
169
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
170
- expect(() => parseArgs(config)).toThrowError('Providing same negated and truthy argument are not allowed');
171
- });
172
-
173
- it('should throw when positional arguments are missing', () => {
174
- const args = ['file1.txt', '--all', '--dryRun'];
175
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
176
-
177
- expect(() => parseArgs(config)).toThrow('Missing required positional argument, i.e.: "copyfiles <inFile> <outDirectory>');
178
- });
179
-
180
- it('should throw when positional arguments are missing and it will not try to read "value" as positional argument either', () => {
181
- const args = ['file1.txt', '--all', '--dryRun', '-b', 'value'];
182
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
183
-
184
- expect(() => parseArgs(config)).toThrow('Missing required positional argument, i.e.: "copyfiles <inFile> <outDirectory>');
185
- });
186
-
187
- it('should throw when required options are missing', () => {
188
- const args = ['file1.txt', 'output', '--all', '--dryRun'];
189
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
190
-
191
- expect(() => parseArgs(config)).toThrow('Missing required option: -b, --bar');
192
- });
193
-
194
- it('should throw if the same alias is defined for multiple options', () => {
195
- const configWithDupAlias: Config = {
196
- ...config,
197
- options: {
198
- foo: { alias: 'x', type: 'boolean', description: '' },
199
- bar: { alias: 'x', type: 'boolean', description: '' },
200
- },
201
- };
202
- expect(() => parseArgs(configWithDupAlias)).toThrow('Duplicate alias detected: "x" used for both "foo" and "bar"');
203
- });
204
-
205
- it('should handle help command', () =>
206
- new Promise((done: any) => {
207
- const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
208
- const args = ['--help'];
209
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
210
- try {
211
- parseArgs(config);
212
- } catch (error: any) {
213
- expect(error.message).toBe('process.exit unexpectedly called with "0"');
214
- expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Usage:'));
215
- expect(consoleLogSpy).toHaveBeenCalledWith(
216
- expect.stringContaining('copyfiles <inFile> <outDirectory> [options] Copy files from a source to a destination directory'),
217
- );
218
- expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('\nPositionals:'));
219
- expect(consoleLogSpy).toHaveBeenCalledWith(
220
- expect.stringContaining(' inFile source files [string]'),
221
- );
222
- expect(consoleLogSpy).toHaveBeenCalledWith(
223
- expect.stringContaining(' -d, --dryRun Show what would be copied, but do not actually copy any files [boolean]'),
224
- );
225
- expect(consoleLogSpy).toHaveBeenCalledWith(
226
- expect.stringContaining(
227
- ' -b, --bar a required bar option [string][required]',
228
- ),
229
- );
230
- expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('\nDefault options:'));
231
- expect(consoleLogSpy).toHaveBeenCalledWith(
232
- expect.stringContaining(' -h, --help Show help [boolean]'),
233
- );
234
- expect(consoleLogSpy).toHaveBeenCalledWith(
235
- expect.stringContaining(' -v, --version Show version number [boolean]'),
236
- );
237
- done();
238
- }
239
- }));
240
-
241
- it('should handle version command', () =>
242
- new Promise((done: any) => {
243
- const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
244
- const args = ['--version'];
245
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
246
- try {
247
- parseArgs(config);
248
- } catch (error: any) {
249
- expect(error.message).toBe('process.exit unexpectedly called with "0"');
250
- expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('0.1.6'));
251
- done();
252
- }
253
- }));
254
-
255
- it('should parse optional variadic positional arguments (zero or more)', () => {
256
- const config: Config = {
257
- command: {
258
- name: 'test',
259
- description: 'Test optional variadic',
260
- positional: [
261
- {
262
- name: 'outDir',
263
- description: 'output directory',
264
- required: true,
265
- },
266
- {
267
- name: 'inputs',
268
- description: 'input files',
269
- type: 'string',
270
- variadic: true,
271
- required: false,
272
- },
273
- ],
274
- },
275
- options: {},
276
- version: '1.0.0',
277
- };
278
- // No inputs
279
- let args = ['dist'];
280
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
281
- let result = parseArgs(config);
282
- expect(result.outDir).toBe('dist');
283
- expect(result.inputs).toEqual([]);
284
- // Multiple inputs
285
- args = ['dist', 'file1', 'file2'];
286
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
287
- result = parseArgs(config);
288
- expect(result.outDir).toBe('dist');
289
- expect(result.inputs).toEqual(['file1', 'file2']);
290
- });
291
-
292
- it('should parse a single optional variadic positional arguments (zero or more)', () => {
293
- const config: Config = {
294
- command: {
295
- name: 'test',
296
- description: 'Test optional variadic',
297
- positional: [
298
- {
299
- name: 'inputs',
300
- description: 'input files',
301
- type: 'string',
302
- variadic: true,
303
- required: true,
304
- },
305
- ],
306
- },
307
- options: {},
308
- version: '1.0.0',
309
- };
310
- // No inputs
311
- let args: string[] = [];
312
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
313
- expect(() => parseArgs(config)).toThrow('Missing required positional argument, i.e.: "test <inputs>');
314
-
315
- // Multiple inputs
316
- args = ['file1', 'file2'];
317
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
318
- const result = parseArgs(config);
319
- expect(result.inputs).toEqual(['file1', 'file2']);
320
- });
321
-
322
- it('should print usage with required variadic positional argument using <inFile..>', () => {
323
- const configWithVariadic: Config = {
324
- ...config,
325
- command: {
326
- ...config.command,
327
- positional: [
328
- {
329
- name: 'inFile',
330
- description: 'source files',
331
- type: 'string',
332
- variadic: true,
333
- required: true,
334
- },
335
- {
336
- name: 'outDirectory',
337
- description: 'destination directory',
338
- required: true,
339
- },
340
- ],
341
- },
342
- };
343
- const spy = vi.spyOn(console, 'log').mockImplementation(() => {});
344
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', '--help']);
345
- try {
346
- parseArgs(configWithVariadic);
347
- } catch {}
348
- expect(spy).toHaveBeenCalledWith(expect.stringContaining('<inFile..>'));
349
- spy.mockRestore();
350
- });
351
-
352
- it('should print usage without any positional argument defined', () => {
353
- const configWithoutPositional: Config = {
354
- ...config,
355
- command: {
356
- ...config.command,
357
- },
358
- options: {
359
- file: {
360
- description: 'source files',
361
- type: 'string',
362
- },
363
- },
364
- };
365
- const spy = vi.spyOn(console, 'log').mockImplementation(() => {});
366
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', '--help']);
367
- try {
368
- parseArgs(configWithoutPositional);
369
- } catch {}
370
- expect(spy).toHaveBeenCalledWith(expect.stringContaining('--file'));
371
- expect(spy).toHaveBeenCalledWith(expect.stringContaining('source files'));
372
- expect(spy).toHaveBeenCalledWith(expect.stringContaining('[string]'));
373
- spy.mockRestore();
374
- });
375
-
376
- it('should throw if required boolean flag is missing', () => {
377
- const config: Config = {
378
- command: {
379
- name: 'test',
380
- description: 'Test required flag',
381
- },
382
- options: {
383
- force: {
384
- alias: 'f',
385
- type: 'boolean',
386
- required: true,
387
- description: 'Force operation',
388
- },
389
- },
390
- version: '1.0.0',
391
- };
392
- const args: string[] = [];
393
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
394
- expect(() => parseArgs(config)).toThrow('Missing required option: -f, --force');
395
- });
396
-
397
- it('should parse kebab-case long option when alias is camelCase', () => {
398
- const configWithCamelAlias: Config = {
399
- ...config,
400
- options: {
401
- ...config.options,
402
- testOption: {
403
- alias: 'testAliasCamel',
404
- type: 'boolean',
405
- description: 'A test option with camelCase alias',
406
- },
407
- },
408
- };
409
- const args = ['file1.txt', 'output/', '--test-alias-camel', '-b', 'value'];
410
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
411
- const result = parseArgs(configWithCamelAlias);
412
- expect(result.testOption).toBe(true);
413
- });
414
-
415
- it('should parse camelCase long option when alias is kebab-case', () => {
416
- const configWithKebabAlias: Config = {
417
- ...config,
418
- options: {
419
- ...config.options,
420
- testOption: {
421
- alias: 'test-alias-kebab',
422
- type: 'boolean',
423
- description: 'A test option with kebab-case alias',
424
- },
425
- },
426
- };
427
- const args = ['file1.txt', 'output/', '--testAliasKebab', '-b', 'value'];
428
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
429
- const result = parseArgs(configWithKebabAlias);
430
- expect(result.testOption).toBe(true);
431
- });
432
-
433
- it('should throw if too many positional arguments are provided', () => {
434
- const args = ['file1.txt', 'output/', 'extra.txt', '-b', 'value'];
435
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
436
- expect(() => parseArgs(config)).toThrow('Unknown argument: extra.txt');
437
- });
438
-
439
- it('should throw if array option is missing a value', () => {
440
- const args = ['file1.txt', 'output/', '--exclude', '-b', 'value'];
441
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
442
- expect(() => parseArgs(config)).toThrow('Missing value for array option: exclude');
443
- });
444
-
445
- it('should throw if string option is missing a value', () => {
446
- const args = ['file1.txt', 'output/', '--bar'];
447
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
448
- expect(() => parseArgs(config)).toThrow('Missing value for option: bar');
449
- });
450
-
451
- it('should throw if number option is missing a value', () => {
452
- const args = ['file1.txt', 'output/', '--up'];
453
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
454
- expect(() => parseArgs(config)).toThrow('Missing value for option: up');
455
- });
456
-
457
- it('should throw unknown option when short flag does not match any alias', () => {
458
- const configWithNoAlias: Config = {
459
- ...config,
460
- options: {
461
- ...config.options,
462
- noAliasOpt: {
463
- type: 'boolean',
464
- description: 'Option with no alias',
465
- },
466
- },
467
- };
468
- const args = ['file1.txt', 'output/', '-x', '-b', 'value'];
469
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
470
- expect(() => parseArgs(configWithNoAlias)).toThrow('Unknown option: x');
471
- });
472
-
473
- it('should print usage with optional positional argument', () => {
474
- const configWithOptional: Config = {
475
- ...config,
476
- command: {
477
- ...config.command,
478
- positional: [
479
- {
480
- name: 'inFile',
481
- description: 'source files',
482
- type: 'string',
483
- required: false, // <-- optional positional
484
- },
485
- {
486
- name: 'outDirectory',
487
- description: 'destination directory',
488
- required: true,
489
- },
490
- ],
491
- },
492
- };
493
- const spy = vi.spyOn(console, 'log').mockImplementation(() => {});
494
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', '--help']);
495
- try {
496
- parseArgs(configWithOptional);
497
- } catch {}
498
- expect(spy).toHaveBeenCalledWith(expect.stringContaining('[inFile]'));
499
- spy.mockRestore();
500
- });
501
-
502
- it('should use default value for optional positional argument when not provided', () => {
503
- const configWithDefaultPositional: Config = {
504
- command: {
505
- name: 'test',
506
- description: 'Test default positional',
507
- positional: [
508
- {
509
- name: 'outDir',
510
- description: 'output directory',
511
- required: true,
512
- },
513
- {
514
- name: 'input',
515
- description: 'input file',
516
- type: 'string',
517
- required: false,
518
- default: 'default.txt',
519
- },
520
- ],
521
- },
522
- options: {},
523
- version: '1.0.0',
524
- };
525
- const args = ['dist'];
526
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
527
- const result = parseArgs(configWithDefaultPositional);
528
- expect(result.outDir).toBe('dist');
529
- expect(result.input).toBe('default.txt');
530
- });
531
-
532
- it('should throw if required positional comes after optional positional', () => {
533
- const configInvalid: Config = {
534
- command: {
535
- name: 'badcli',
536
- description: 'Invalid CLI',
537
- positional: [
538
- { name: 'foo', description: '', required: false },
539
- { name: 'bar', description: '', required: true },
540
- ],
541
- },
542
- options: {},
543
- version: '1.0.0',
544
- };
545
- expect(() => parseArgs(configInvalid)).toThrow(
546
- 'Invalid positional argument configuration: required positional "bar" cannot follow optional positional(s).',
547
- );
548
- });
549
-
550
- it('should use default value for optional variadic positional argument when not provided', () => {
551
- const configWithDefaultVariadic: Config = {
552
- command: {
553
- name: 'test',
554
- description: 'Test default variadic positional',
555
- positional: [
556
- {
557
- name: 'outDir',
558
- description: 'output directory',
559
- required: true,
560
- },
561
- {
562
- name: 'inputs',
563
- description: 'input files',
564
- type: 'string',
565
- variadic: true,
566
- required: false,
567
- default: ['default1.txt', 'default2.txt'],
568
- },
569
- ],
570
- },
571
- options: {},
572
- version: '1.0.0',
573
- };
574
- const args = ['dist'];
575
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
576
- const result = parseArgs(configWithDefaultVariadic);
577
- expect(result.outDir).toBe('dist');
578
- expect(result.inputs).toEqual(['default1.txt', 'default2.txt']);
579
- });
580
-
581
- it('should not use default value for option if value is provided', () => {
582
- const configWithDefault: Config = {
583
- ...config,
584
- options: {
585
- ...config.options,
586
- file: {
587
- alias: 'f',
588
- type: 'string',
589
- description: 'File path',
590
- default: '/etc/passwd',
591
- },
592
- bar: {
593
- alias: 'b',
594
- required: true,
595
- description: 'a required bar option',
596
- },
597
- },
598
- };
599
- const args = ['file1.txt', 'output/', '--file', '/tmp/override', '-b', 'value'];
600
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
601
- const result = parseArgs(configWithDefault);
602
- expect(result.file).toBe('/tmp/override');
603
- });
604
-
605
- it('should use default value for option with alias when not provided', () => {
606
- const configWithDefault: Config = {
607
- ...config,
608
- options: {
609
- ...config.options,
610
- verbose: {
611
- alias: 'V',
612
- type: 'boolean',
613
- description: 'Print more information',
614
- default: true,
615
- },
616
- bar: {
617
- alias: 'b',
618
- required: true,
619
- description: 'a required bar option',
620
- },
621
- },
622
- };
623
- const args = ['file1.txt', 'output/', '-b', 'value'];
624
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
625
- const result = parseArgs(configWithDefault);
626
- expect(result.verbose).toBe(true);
627
- });
628
-
629
- it('should use default value for boolean option when not provided', () => {
630
- const configWithDefault: Config = {
631
- ...config,
632
- options: {
633
- ...config.options,
634
- follow: {
635
- alias: 'F',
636
- type: 'boolean',
637
- description: 'Follow symbolic links',
638
- default: true,
639
- },
640
- bar: {
641
- alias: 'b',
642
- required: true,
643
- description: 'a required bar option',
644
- },
645
- },
646
- };
647
- const args = ['file1.txt', 'output/', '-b', 'value'];
648
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
649
- const result = parseArgs(configWithDefault);
650
- expect(result.follow).toBe(true);
651
- });
652
-
653
- it('should use default value for string option when not provided', () => {
654
- const configWithDefault: Config = {
655
- ...config,
656
- options: {
657
- ...config.options,
658
- file: {
659
- alias: 'f',
660
- type: 'string',
661
- description: 'File path',
662
- default: '/etc/passwd',
663
- },
664
- bar: {
665
- alias: 'b',
666
- required: true,
667
- description: 'a required bar option',
668
- },
669
- },
670
- };
671
- const args = ['file1.txt', 'output/', '-b', 'value'];
672
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
673
- const result = parseArgs(configWithDefault);
674
- expect(result.file).toBe('/etc/passwd');
675
- });
676
-
677
- it('should use default value for number option when not provided', () => {
678
- const configWithDefault: Config = {
679
- ...config,
680
- options: {
681
- ...config.options,
682
- up: {
683
- type: 'number',
684
- description: 'slice a path off the bottom of the paths',
685
- default: 5,
686
- },
687
- bar: {
688
- alias: 'b',
689
- required: true,
690
- description: 'a required bar option',
691
- },
692
- },
693
- };
694
- const args = ['file1.txt', 'output/', '-b', 'value'];
695
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
696
- const result = parseArgs(configWithDefault);
697
- expect(result.up).toBe(5);
698
- });
699
-
700
- it('should use default value for array option when not provided', () => {
701
- const configWithDefault: Config = {
702
- ...config,
703
- options: {
704
- ...config.options,
705
- exclude: {
706
- alias: 'e',
707
- type: 'array',
708
- description: 'pattern or glob to exclude',
709
- default: ['node_modules', 'dist'],
710
- },
711
- bar: {
712
- alias: 'b',
713
- required: true,
714
- description: 'a required bar option',
715
- },
716
- },
717
- };
718
- const args = ['file1.txt', 'output/', '-b', 'value'];
719
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
720
- const result = parseArgs(configWithDefault);
721
- expect(result.exclude).toEqual(['node_modules', 'dist']);
722
- });
723
-
724
- it('should override default value when option is provided', () => {
725
- const configWithDefault: Config = {
726
- ...config,
727
- options: {
728
- ...config.options,
729
- follow: {
730
- alias: 'F',
731
- type: 'boolean',
732
- description: 'Follow symbolic links',
733
- default: false,
734
- },
735
- bar: {
736
- alias: 'b',
737
- required: true,
738
- description: 'a required bar option',
739
- },
740
- },
741
- };
742
- const args = ['file1.txt', 'output/', '--follow', '-b', 'value'];
743
- vi.spyOn(process, 'argv', 'get').mockReturnValue(['node', 'cli.js', ...args]);
744
- const result = parseArgs(configWithDefault);
745
- expect(result.follow).toBe(true);
746
- });
747
- });