breadc 0.8.1 → 0.8.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/README.md CHANGED
@@ -8,7 +8,7 @@ Yet another Command Line Application Framework with fully strong **[TypeScript](
8
8
 
9
9
  ## Features
10
10
 
11
- + ⚡️ **Light-weight**: Only 70 kB (Unpacked).
11
+ + ⚡️ **Light-weight**: Only 75 kB (Unpacked).
12
12
  + 📖 **East to Learn**: Breadc is basically compatible with [cac](https://github.com/cacjs/cac) and there are only 5 APIs for building a CLI application: `breadc`, `command`, `option`, `action`, `run`.
13
13
  + 💻 **TypeScript Infer**: IDE will automatically infer the type of your command action function.
14
14
 
package/dist/index.cjs CHANGED
@@ -8,44 +8,71 @@ function makePluginContainer(plugins = []) {
8
8
  const onPreCommand = {};
9
9
  const onPostCommand = {};
10
10
  for (const plugin of plugins) {
11
- for (const [key, fn] of Object.entries(plugin.onPreCommand ?? {})) {
11
+ if (typeof plugin.onPreCommand === "function") {
12
+ const key = "*";
12
13
  if (!(key in onPreCommand)) {
13
14
  onPreCommand[key] = [];
14
15
  }
15
- onPreCommand[key].push(fn);
16
+ onPreCommand[key].push(plugin.onPreCommand);
17
+ } else {
18
+ for (const [key, fn] of Object.entries(plugin.onPreCommand ?? {})) {
19
+ if (!(key in onPreCommand)) {
20
+ onPreCommand[key] = [];
21
+ }
22
+ onPreCommand[key].push(fn);
23
+ }
16
24
  }
17
- for (const [key, fn] of Object.entries(plugin.onPostCommand ?? {})) {
25
+ if (typeof plugin.onPostCommand === "function") {
26
+ const key = "*";
18
27
  if (!(key in onPostCommand)) {
19
28
  onPostCommand[key] = [];
20
29
  }
21
- onPostCommand[key].push(fn);
30
+ onPostCommand[key].push(plugin.onPostCommand);
31
+ } else {
32
+ for (const [key, fn] of Object.entries(plugin.onPostCommand ?? {})) {
33
+ if (!(key in onPostCommand)) {
34
+ onPostCommand[key] = [];
35
+ }
36
+ onPostCommand[key].push(fn);
37
+ }
22
38
  }
23
39
  }
24
- const run = async (container, command) => {
40
+ const run = async (container, command, result) => {
25
41
  const prefix = command._arguments.filter((a) => a.type === "const").map((a) => a.name);
42
+ if (prefix.length === 0) {
43
+ prefix.push("_");
44
+ }
26
45
  for (let i = 0; i <= prefix.length; i++) {
27
46
  const key = i === 0 ? "*" : prefix.slice(0, i).map(
28
47
  (t, idx) => idx === 0 ? t : t[0].toUpperCase() + t.slice(1)
29
48
  ).join("");
30
49
  const fns = container[key];
31
50
  if (fns && fns.length > 0) {
32
- await Promise.all(fns.map((fn) => fn()));
51
+ await Promise.all(fns.map((fn) => fn(result)));
33
52
  }
34
53
  }
35
54
  };
36
55
  return {
37
56
  async preRun(breadc) {
57
+ if (plugins.length === 0)
58
+ return;
38
59
  for (const p of plugins) {
39
60
  await p.onPreRun?.(breadc);
40
61
  }
41
62
  },
42
- async preCommand(command) {
43
- await run(onPreCommand, command);
63
+ async preCommand(command, result) {
64
+ if (plugins.length === 0)
65
+ return;
66
+ await run(onPreCommand, command, result);
44
67
  },
45
- async postCommand(command) {
46
- await run(onPostCommand, command);
68
+ async postCommand(command, result) {
69
+ if (plugins.length === 0)
70
+ return;
71
+ await run(onPostCommand, command, result);
47
72
  },
48
73
  async postRun(breadc) {
74
+ if (plugins.length === 0)
75
+ return;
49
76
  for (const p of plugins) {
50
77
  await p.onPostRun?.(breadc);
51
78
  }
@@ -101,6 +128,7 @@ class Token {
101
128
  return this._type = "string";
102
129
  }
103
130
  }
131
+ /* c8 ignore next 1 */
104
132
  }
105
133
  class Lexer {
106
134
  constructor(rawArgs) {
@@ -113,7 +141,7 @@ class Lexer {
113
141
  return value ? new Token(value) : void 0;
114
142
  }
115
143
  hasNext() {
116
- return this.cursor + 1 < this.rawArgs.length;
144
+ return this.cursor < this.rawArgs.length;
117
145
  }
118
146
  peek() {
119
147
  const value = this.rawArgs[this.cursor];
@@ -126,7 +154,7 @@ class Lexer {
126
154
  const value = that.rawArgs[that.cursor];
127
155
  that.cursor += 1;
128
156
  return {
129
- value: value ? new Token(value) : void 0,
157
+ value: value !== void 0 ? new Token(value) : void 0,
130
158
  done: that.cursor > that.rawArgs.length
131
159
  };
132
160
  }
@@ -313,13 +341,13 @@ const initContextOptions = (options, context) => {
313
341
  };
314
342
 
315
343
  function makeCommand(format, config, root, container) {
316
- let cursor = root;
317
344
  const args = [];
318
345
  const options = [];
319
346
  const command = {
320
347
  callback: void 0,
321
348
  format,
322
349
  description: config.description ?? "",
350
+ _default: false,
323
351
  _arguments: args,
324
352
  _options: options,
325
353
  option(format2, _config, _config2 = {}) {
@@ -328,87 +356,72 @@ function makeCommand(format, config, root, container) {
328
356
  options.push(option);
329
357
  return command;
330
358
  },
359
+ alias(format2) {
360
+ const aliasArgs = [];
361
+ const node2 = makeNode(aliasArgs);
362
+ function* g() {
363
+ for (const f of format2.split(" ")) {
364
+ yield { type: "const", name: f };
365
+ }
366
+ for (const a of args.filter((a2) => a2.type !== "const")) {
367
+ yield a;
368
+ }
369
+ return void 0;
370
+ }
371
+ insertTreeNode(aliasArgs, node2, g());
372
+ return command;
373
+ },
331
374
  action(fn) {
332
- command.callback = async (...args2) => {
333
- await container.preCommand(command);
334
- const result = await fn(...args2);
335
- await container.postCommand(command);
375
+ command.callback = async (parsed) => {
376
+ await container.preCommand(command, parsed);
377
+ const result = await fn(...parsed.arguments, {
378
+ ...parsed.options,
379
+ "--": parsed["--"]
380
+ });
381
+ await container.postCommand(command, parsed);
336
382
  return result;
337
383
  };
338
384
  }
339
385
  };
340
- const node = makeTreeNode({
341
- command,
342
- init(context) {
343
- initContextOptions(options, context);
344
- },
345
- finish(context) {
346
- const rest = context.result["--"];
347
- for (let i = 0; i < args.length; i++) {
348
- if (args[i].type === "const") {
349
- if (rest[i] !== args[i].name) {
350
- throw new ParseError(`Sub-command ${args[i].name} mismatch`);
351
- }
352
- } else if (args[i].type === "require") {
353
- if (i >= rest.length) {
354
- throw new ParseError(
355
- `You must provide require argument ${args[i].name}`
356
- );
386
+ const node = makeNode(args);
387
+ insertTreeNode(args, node, parseCommandFormat(format));
388
+ return command;
389
+ function makeNode(args2) {
390
+ return makeTreeNode({
391
+ command,
392
+ init(context) {
393
+ initContextOptions(options, context);
394
+ },
395
+ finish(context) {
396
+ const rest = context.result["--"];
397
+ for (let i = 0; i < args2.length; i++) {
398
+ if (args2[i].type === "const") {
399
+ if (rest[i] !== args2[i].name) {
400
+ throw new ParseError(`Sub-command ${args2[i].name} mismatch`);
401
+ }
402
+ } else if (args2[i].type === "require") {
403
+ if (i >= rest.length) {
404
+ throw new ParseError(
405
+ `You must provide require argument ${args2[i].name}`
406
+ );
407
+ }
408
+ context.result.arguments.push(rest[i]);
409
+ } else if (args2[i].type === "optional") {
410
+ context.result.arguments.push(rest[i]);
411
+ } else if (args2[i].type === "rest") {
412
+ context.result.arguments.push(rest.splice(i));
357
413
  }
358
- context.result.arguments.push(rest[i]);
359
- } else if (args[i].type === "optional") {
360
- context.result.arguments.push(rest[i]);
361
- } else if (args[i].type === "rest") {
362
- context.result.arguments.push(rest.splice(i));
363
414
  }
415
+ context.result["--"] = rest.splice(args2.length);
364
416
  }
365
- context.result["--"] = rest.splice(args.length);
366
- }
367
- });
368
- {
369
- let state = 0;
370
- for (let i = 0; i < format.length; i++) {
371
- if (format[i] === "<") {
372
- if (state !== 0 && state !== 1) {
373
- throw new BreadcError(
374
- `Required arguments should be placed before optional or rest arguments`
375
- );
376
- }
377
- const start = i;
378
- while (i < format.length && format[i] !== ">") {
379
- i++;
380
- }
381
- const name = format.slice(start + 1, i);
382
- state = 1;
383
- args.push({ type: "require", name });
384
- } else if (format[i] === "[") {
385
- if (state !== 0 && state !== 1) {
386
- throw new BreadcError(
387
- `There is at most one optional or rest arguments`
388
- );
389
- }
390
- const start = i;
391
- while (i < format.length && format[i] !== "]") {
392
- i++;
393
- }
394
- const name = format.slice(start + 1, i);
395
- state = 2;
396
- if (name.startsWith("...")) {
397
- args.push({ type: "rest", name });
398
- } else {
399
- args.push({ type: "optional", name });
400
- }
401
- } else if (format[i] !== " ") {
402
- if (state !== 0) {
403
- throw new BreadcError(
404
- `Sub-command should be placed at the beginning`
405
- );
406
- }
407
- const start = i;
408
- while (i < format.length && format[i] !== " ") {
409
- i++;
410
- }
411
- const name = format.slice(start, i);
417
+ });
418
+ }
419
+ function insertTreeNode(args2, node2, parsed) {
420
+ let cursor = root;
421
+ for (const arg of parsed) {
422
+ args2.push(arg);
423
+ if (arg.type === "const") {
424
+ const name = arg.name;
412
425
  if (cursor.children.has(name)) {
413
426
  cursor = cursor.children.get(name);
414
427
  } else {
@@ -431,28 +444,74 @@ function makeCommand(format, config, root, container) {
431
444
  cursor.children.set(name, internalNode);
432
445
  cursor = internalNode;
433
446
  }
434
- state = 0;
435
- args.push({ type: "const", name });
436
447
  }
437
448
  }
438
449
  cursor.command = command;
439
450
  if (cursor !== root) {
440
451
  for (const [key, value] of cursor.children) {
441
- node.children.set(key, value);
452
+ node2.children.set(key, value);
442
453
  }
443
- cursor.children = node.children;
444
- cursor.next = node.next;
445
- cursor.init = node.init;
446
- cursor.finish = node.finish;
454
+ cursor.children = node2.children;
455
+ cursor.next = node2.next;
456
+ cursor.init = node2.init;
457
+ cursor.finish = node2.finish;
447
458
  } else {
448
- cursor.finish = node.finish;
459
+ command._default = true;
460
+ cursor.finish = node2.finish;
449
461
  }
450
462
  }
451
- return command;
463
+ }
464
+ function* parseCommandFormat(format) {
465
+ let state = 0;
466
+ for (let i = 0; i < format.length; i++) {
467
+ if (format[i] === "<") {
468
+ if (state !== 0 && state !== 1) {
469
+ throw new BreadcError(
470
+ `Required arguments should be placed before optional or rest arguments`
471
+ );
472
+ }
473
+ const start = i;
474
+ while (i < format.length && format[i] !== ">") {
475
+ i++;
476
+ }
477
+ const name = format.slice(start + 1, i);
478
+ state = 1;
479
+ yield { type: "require", name };
480
+ } else if (format[i] === "[") {
481
+ if (state !== 0 && state !== 1) {
482
+ throw new BreadcError(
483
+ `There is at most one optional or rest arguments`
484
+ );
485
+ }
486
+ const start = i;
487
+ while (i < format.length && format[i] !== "]") {
488
+ i++;
489
+ }
490
+ const name = format.slice(start + 1, i);
491
+ state = 2;
492
+ if (name.startsWith("...")) {
493
+ yield { type: "rest", name };
494
+ } else {
495
+ yield { type: "optional", name };
496
+ }
497
+ } else if (format[i] !== " ") {
498
+ if (state !== 0) {
499
+ throw new BreadcError(`Sub-command should be placed at the beginning`);
500
+ }
501
+ const start = i;
502
+ while (i < format.length && format[i] !== " ") {
503
+ i++;
504
+ }
505
+ const name = format.slice(start, i);
506
+ state = 0;
507
+ yield { type: "const", name };
508
+ }
509
+ }
510
+ return void 0;
452
511
  }
453
512
  function makeVersionCommand(name, config) {
454
513
  const command = {
455
- callback() {
514
+ async callback() {
456
515
  const text = `${name}/${config.version ? config.version : "unknown"}`;
457
516
  console.log(text);
458
517
  return text;
@@ -461,11 +520,12 @@ function makeVersionCommand(name, config) {
461
520
  description: "Print version",
462
521
  _arguments: [],
463
522
  _options: [],
464
- option() {
465
- return command;
466
- },
467
- action() {
468
- }
523
+ // @ts-ignore
524
+ option: void 0,
525
+ // @ts-ignore
526
+ alias: void 0,
527
+ // @ts-ignore
528
+ action: void 0
469
529
  };
470
530
  const node = makeTreeNode({
471
531
  command,
@@ -527,9 +587,9 @@ function makeHelpCommand(name, config) {
527
587
  return commands;
528
588
  }
529
589
  const command = {
530
- callback(option2) {
531
- const context = option2.__context__;
532
- const cursor = option2.__cursor__;
590
+ async callback(parsed) {
591
+ const context = parsed.options.__context__;
592
+ const cursor = parsed.options.__cursor__;
533
593
  const output = [
534
594
  `${name}/${config.version ? config.version : "unknown"}`,
535
595
  () => {
@@ -570,11 +630,12 @@ function makeHelpCommand(name, config) {
570
630
  description: "Print help",
571
631
  _arguments: [],
572
632
  _options: [],
573
- option() {
574
- return command;
575
- },
576
- action() {
577
- }
633
+ // @ts-ignore
634
+ option: void 0,
635
+ // @ts-ignore
636
+ alias: void 0,
637
+ // @ts-ignore
638
+ action: void 0
578
639
  };
579
640
  const node = makeTreeNode({
580
641
  command,
@@ -627,7 +688,7 @@ function breadc(name, config = {}) {
627
688
  command(text, _config = {}) {
628
689
  const config2 = typeof _config === "string" ? { description: _config } : _config;
629
690
  const command = makeCommand(text, config2, root, container);
630
- if (command._arguments.length === 0 || command._arguments[0].type !== "const") {
691
+ if (command._default) {
631
692
  defaultCommand = command;
632
693
  }
633
694
  return command;
@@ -642,10 +703,7 @@ function breadc(name, config = {}) {
642
703
  if (command) {
643
704
  if (command.callback) {
644
705
  await container.preRun(breadc2);
645
- const r = command.callback(...result.arguments, {
646
- ...result.options,
647
- "--": result["--"]
648
- });
706
+ const r = await command.callback(result);
649
707
  await container.postRun(breadc2);
650
708
  return r;
651
709
  }
package/dist/index.d.ts CHANGED
@@ -101,13 +101,15 @@ interface Breadc<GlobalOption extends object = {}> {
101
101
  run<T = any>(args: string[]): Promise<T>;
102
102
  }
103
103
  interface Command<F extends string = string, AT extends any[] = ExtractCommand<F>, CommandOption extends object = {}, GlobalOption extends object = {}> {
104
- callback?: ActionFn<ExtractCommand<F>, CommandOption & GlobalOption>;
104
+ callback?: (result: ParseResult) => Promise<any>;
105
105
  format: F;
106
106
  description: string;
107
+ _default: boolean;
107
108
  _arguments: Argument[];
108
109
  _options: Option[];
109
110
  option<OF extends string = string, OT extends string | boolean = ExtractOptionType<OF>, OR extends any = ExtractOptionType<OF>>(format: OF, description?: string, option?: OptionOption<OT, OR>): Command<F, AT, CommandOption & ExtractOption<OF, OR>, GlobalOption>;
110
111
  option<OF extends string = string, OT extends string | boolean = ExtractOptionType<OF>, OR extends any = ExtractOptionType<OF>>(format: OF, option?: OptionOption<OT, OR>): Command<F, AT, CommandOption & ExtractOption<OF, OR>, GlobalOption>;
112
+ alias(format: string): Command<F, AT, CommandOption, GlobalOption>;
111
113
  action(fn: ActionFn<AT, CommandOption & GlobalOption>): void;
112
114
  }
113
115
  interface CommandOption {
@@ -133,10 +135,11 @@ interface OptionOption<T extends string | boolean, R extends any = T> {
133
135
  default?: T;
134
136
  cast?: (value: T) => R;
135
137
  }
138
+ type CommandHookFn = (result: ParseResult) => void | Promise<void>;
136
139
  interface Plugin {
137
140
  onPreRun(breadc: Breadc): void | Promise<void>;
138
- onPreCommand: Record<string, () => void | Promise<void>>;
139
- onPostCommand: Record<string, () => void | Promise<void>>;
141
+ onPreCommand: Record<string, CommandHookFn> | CommandHookFn;
142
+ onPostCommand: Record<string, CommandHookFn> | CommandHookFn;
140
143
  onPostRun(breadc: Breadc): void | Promise<void>;
141
144
  }
142
145
 
package/dist/index.mjs CHANGED
@@ -4,44 +4,71 @@ function makePluginContainer(plugins = []) {
4
4
  const onPreCommand = {};
5
5
  const onPostCommand = {};
6
6
  for (const plugin of plugins) {
7
- for (const [key, fn] of Object.entries(plugin.onPreCommand ?? {})) {
7
+ if (typeof plugin.onPreCommand === "function") {
8
+ const key = "*";
8
9
  if (!(key in onPreCommand)) {
9
10
  onPreCommand[key] = [];
10
11
  }
11
- onPreCommand[key].push(fn);
12
+ onPreCommand[key].push(plugin.onPreCommand);
13
+ } else {
14
+ for (const [key, fn] of Object.entries(plugin.onPreCommand ?? {})) {
15
+ if (!(key in onPreCommand)) {
16
+ onPreCommand[key] = [];
17
+ }
18
+ onPreCommand[key].push(fn);
19
+ }
12
20
  }
13
- for (const [key, fn] of Object.entries(plugin.onPostCommand ?? {})) {
21
+ if (typeof plugin.onPostCommand === "function") {
22
+ const key = "*";
14
23
  if (!(key in onPostCommand)) {
15
24
  onPostCommand[key] = [];
16
25
  }
17
- onPostCommand[key].push(fn);
26
+ onPostCommand[key].push(plugin.onPostCommand);
27
+ } else {
28
+ for (const [key, fn] of Object.entries(plugin.onPostCommand ?? {})) {
29
+ if (!(key in onPostCommand)) {
30
+ onPostCommand[key] = [];
31
+ }
32
+ onPostCommand[key].push(fn);
33
+ }
18
34
  }
19
35
  }
20
- const run = async (container, command) => {
36
+ const run = async (container, command, result) => {
21
37
  const prefix = command._arguments.filter((a) => a.type === "const").map((a) => a.name);
38
+ if (prefix.length === 0) {
39
+ prefix.push("_");
40
+ }
22
41
  for (let i = 0; i <= prefix.length; i++) {
23
42
  const key = i === 0 ? "*" : prefix.slice(0, i).map(
24
43
  (t, idx) => idx === 0 ? t : t[0].toUpperCase() + t.slice(1)
25
44
  ).join("");
26
45
  const fns = container[key];
27
46
  if (fns && fns.length > 0) {
28
- await Promise.all(fns.map((fn) => fn()));
47
+ await Promise.all(fns.map((fn) => fn(result)));
29
48
  }
30
49
  }
31
50
  };
32
51
  return {
33
52
  async preRun(breadc) {
53
+ if (plugins.length === 0)
54
+ return;
34
55
  for (const p of plugins) {
35
56
  await p.onPreRun?.(breadc);
36
57
  }
37
58
  },
38
- async preCommand(command) {
39
- await run(onPreCommand, command);
59
+ async preCommand(command, result) {
60
+ if (plugins.length === 0)
61
+ return;
62
+ await run(onPreCommand, command, result);
40
63
  },
41
- async postCommand(command) {
42
- await run(onPostCommand, command);
64
+ async postCommand(command, result) {
65
+ if (plugins.length === 0)
66
+ return;
67
+ await run(onPostCommand, command, result);
43
68
  },
44
69
  async postRun(breadc) {
70
+ if (plugins.length === 0)
71
+ return;
45
72
  for (const p of plugins) {
46
73
  await p.onPostRun?.(breadc);
47
74
  }
@@ -97,6 +124,7 @@ class Token {
97
124
  return this._type = "string";
98
125
  }
99
126
  }
127
+ /* c8 ignore next 1 */
100
128
  }
101
129
  class Lexer {
102
130
  constructor(rawArgs) {
@@ -109,7 +137,7 @@ class Lexer {
109
137
  return value ? new Token(value) : void 0;
110
138
  }
111
139
  hasNext() {
112
- return this.cursor + 1 < this.rawArgs.length;
140
+ return this.cursor < this.rawArgs.length;
113
141
  }
114
142
  peek() {
115
143
  const value = this.rawArgs[this.cursor];
@@ -122,7 +150,7 @@ class Lexer {
122
150
  const value = that.rawArgs[that.cursor];
123
151
  that.cursor += 1;
124
152
  return {
125
- value: value ? new Token(value) : void 0,
153
+ value: value !== void 0 ? new Token(value) : void 0,
126
154
  done: that.cursor > that.rawArgs.length
127
155
  };
128
156
  }
@@ -309,13 +337,13 @@ const initContextOptions = (options, context) => {
309
337
  };
310
338
 
311
339
  function makeCommand(format, config, root, container) {
312
- let cursor = root;
313
340
  const args = [];
314
341
  const options = [];
315
342
  const command = {
316
343
  callback: void 0,
317
344
  format,
318
345
  description: config.description ?? "",
346
+ _default: false,
319
347
  _arguments: args,
320
348
  _options: options,
321
349
  option(format2, _config, _config2 = {}) {
@@ -324,87 +352,72 @@ function makeCommand(format, config, root, container) {
324
352
  options.push(option);
325
353
  return command;
326
354
  },
355
+ alias(format2) {
356
+ const aliasArgs = [];
357
+ const node2 = makeNode(aliasArgs);
358
+ function* g() {
359
+ for (const f of format2.split(" ")) {
360
+ yield { type: "const", name: f };
361
+ }
362
+ for (const a of args.filter((a2) => a2.type !== "const")) {
363
+ yield a;
364
+ }
365
+ return void 0;
366
+ }
367
+ insertTreeNode(aliasArgs, node2, g());
368
+ return command;
369
+ },
327
370
  action(fn) {
328
- command.callback = async (...args2) => {
329
- await container.preCommand(command);
330
- const result = await fn(...args2);
331
- await container.postCommand(command);
371
+ command.callback = async (parsed) => {
372
+ await container.preCommand(command, parsed);
373
+ const result = await fn(...parsed.arguments, {
374
+ ...parsed.options,
375
+ "--": parsed["--"]
376
+ });
377
+ await container.postCommand(command, parsed);
332
378
  return result;
333
379
  };
334
380
  }
335
381
  };
336
- const node = makeTreeNode({
337
- command,
338
- init(context) {
339
- initContextOptions(options, context);
340
- },
341
- finish(context) {
342
- const rest = context.result["--"];
343
- for (let i = 0; i < args.length; i++) {
344
- if (args[i].type === "const") {
345
- if (rest[i] !== args[i].name) {
346
- throw new ParseError(`Sub-command ${args[i].name} mismatch`);
347
- }
348
- } else if (args[i].type === "require") {
349
- if (i >= rest.length) {
350
- throw new ParseError(
351
- `You must provide require argument ${args[i].name}`
352
- );
382
+ const node = makeNode(args);
383
+ insertTreeNode(args, node, parseCommandFormat(format));
384
+ return command;
385
+ function makeNode(args2) {
386
+ return makeTreeNode({
387
+ command,
388
+ init(context) {
389
+ initContextOptions(options, context);
390
+ },
391
+ finish(context) {
392
+ const rest = context.result["--"];
393
+ for (let i = 0; i < args2.length; i++) {
394
+ if (args2[i].type === "const") {
395
+ if (rest[i] !== args2[i].name) {
396
+ throw new ParseError(`Sub-command ${args2[i].name} mismatch`);
397
+ }
398
+ } else if (args2[i].type === "require") {
399
+ if (i >= rest.length) {
400
+ throw new ParseError(
401
+ `You must provide require argument ${args2[i].name}`
402
+ );
403
+ }
404
+ context.result.arguments.push(rest[i]);
405
+ } else if (args2[i].type === "optional") {
406
+ context.result.arguments.push(rest[i]);
407
+ } else if (args2[i].type === "rest") {
408
+ context.result.arguments.push(rest.splice(i));
353
409
  }
354
- context.result.arguments.push(rest[i]);
355
- } else if (args[i].type === "optional") {
356
- context.result.arguments.push(rest[i]);
357
- } else if (args[i].type === "rest") {
358
- context.result.arguments.push(rest.splice(i));
359
410
  }
411
+ context.result["--"] = rest.splice(args2.length);
360
412
  }
361
- context.result["--"] = rest.splice(args.length);
362
- }
363
- });
364
- {
365
- let state = 0;
366
- for (let i = 0; i < format.length; i++) {
367
- if (format[i] === "<") {
368
- if (state !== 0 && state !== 1) {
369
- throw new BreadcError(
370
- `Required arguments should be placed before optional or rest arguments`
371
- );
372
- }
373
- const start = i;
374
- while (i < format.length && format[i] !== ">") {
375
- i++;
376
- }
377
- const name = format.slice(start + 1, i);
378
- state = 1;
379
- args.push({ type: "require", name });
380
- } else if (format[i] === "[") {
381
- if (state !== 0 && state !== 1) {
382
- throw new BreadcError(
383
- `There is at most one optional or rest arguments`
384
- );
385
- }
386
- const start = i;
387
- while (i < format.length && format[i] !== "]") {
388
- i++;
389
- }
390
- const name = format.slice(start + 1, i);
391
- state = 2;
392
- if (name.startsWith("...")) {
393
- args.push({ type: "rest", name });
394
- } else {
395
- args.push({ type: "optional", name });
396
- }
397
- } else if (format[i] !== " ") {
398
- if (state !== 0) {
399
- throw new BreadcError(
400
- `Sub-command should be placed at the beginning`
401
- );
402
- }
403
- const start = i;
404
- while (i < format.length && format[i] !== " ") {
405
- i++;
406
- }
407
- const name = format.slice(start, i);
413
+ });
414
+ }
415
+ function insertTreeNode(args2, node2, parsed) {
416
+ let cursor = root;
417
+ for (const arg of parsed) {
418
+ args2.push(arg);
419
+ if (arg.type === "const") {
420
+ const name = arg.name;
408
421
  if (cursor.children.has(name)) {
409
422
  cursor = cursor.children.get(name);
410
423
  } else {
@@ -427,28 +440,74 @@ function makeCommand(format, config, root, container) {
427
440
  cursor.children.set(name, internalNode);
428
441
  cursor = internalNode;
429
442
  }
430
- state = 0;
431
- args.push({ type: "const", name });
432
443
  }
433
444
  }
434
445
  cursor.command = command;
435
446
  if (cursor !== root) {
436
447
  for (const [key, value] of cursor.children) {
437
- node.children.set(key, value);
448
+ node2.children.set(key, value);
438
449
  }
439
- cursor.children = node.children;
440
- cursor.next = node.next;
441
- cursor.init = node.init;
442
- cursor.finish = node.finish;
450
+ cursor.children = node2.children;
451
+ cursor.next = node2.next;
452
+ cursor.init = node2.init;
453
+ cursor.finish = node2.finish;
443
454
  } else {
444
- cursor.finish = node.finish;
455
+ command._default = true;
456
+ cursor.finish = node2.finish;
445
457
  }
446
458
  }
447
- return command;
459
+ }
460
+ function* parseCommandFormat(format) {
461
+ let state = 0;
462
+ for (let i = 0; i < format.length; i++) {
463
+ if (format[i] === "<") {
464
+ if (state !== 0 && state !== 1) {
465
+ throw new BreadcError(
466
+ `Required arguments should be placed before optional or rest arguments`
467
+ );
468
+ }
469
+ const start = i;
470
+ while (i < format.length && format[i] !== ">") {
471
+ i++;
472
+ }
473
+ const name = format.slice(start + 1, i);
474
+ state = 1;
475
+ yield { type: "require", name };
476
+ } else if (format[i] === "[") {
477
+ if (state !== 0 && state !== 1) {
478
+ throw new BreadcError(
479
+ `There is at most one optional or rest arguments`
480
+ );
481
+ }
482
+ const start = i;
483
+ while (i < format.length && format[i] !== "]") {
484
+ i++;
485
+ }
486
+ const name = format.slice(start + 1, i);
487
+ state = 2;
488
+ if (name.startsWith("...")) {
489
+ yield { type: "rest", name };
490
+ } else {
491
+ yield { type: "optional", name };
492
+ }
493
+ } else if (format[i] !== " ") {
494
+ if (state !== 0) {
495
+ throw new BreadcError(`Sub-command should be placed at the beginning`);
496
+ }
497
+ const start = i;
498
+ while (i < format.length && format[i] !== " ") {
499
+ i++;
500
+ }
501
+ const name = format.slice(start, i);
502
+ state = 0;
503
+ yield { type: "const", name };
504
+ }
505
+ }
506
+ return void 0;
448
507
  }
449
508
  function makeVersionCommand(name, config) {
450
509
  const command = {
451
- callback() {
510
+ async callback() {
452
511
  const text = `${name}/${config.version ? config.version : "unknown"}`;
453
512
  console.log(text);
454
513
  return text;
@@ -457,11 +516,12 @@ function makeVersionCommand(name, config) {
457
516
  description: "Print version",
458
517
  _arguments: [],
459
518
  _options: [],
460
- option() {
461
- return command;
462
- },
463
- action() {
464
- }
519
+ // @ts-ignore
520
+ option: void 0,
521
+ // @ts-ignore
522
+ alias: void 0,
523
+ // @ts-ignore
524
+ action: void 0
465
525
  };
466
526
  const node = makeTreeNode({
467
527
  command,
@@ -523,9 +583,9 @@ function makeHelpCommand(name, config) {
523
583
  return commands;
524
584
  }
525
585
  const command = {
526
- callback(option2) {
527
- const context = option2.__context__;
528
- const cursor = option2.__cursor__;
586
+ async callback(parsed) {
587
+ const context = parsed.options.__context__;
588
+ const cursor = parsed.options.__cursor__;
529
589
  const output = [
530
590
  `${name}/${config.version ? config.version : "unknown"}`,
531
591
  () => {
@@ -566,11 +626,12 @@ function makeHelpCommand(name, config) {
566
626
  description: "Print help",
567
627
  _arguments: [],
568
628
  _options: [],
569
- option() {
570
- return command;
571
- },
572
- action() {
573
- }
629
+ // @ts-ignore
630
+ option: void 0,
631
+ // @ts-ignore
632
+ alias: void 0,
633
+ // @ts-ignore
634
+ action: void 0
574
635
  };
575
636
  const node = makeTreeNode({
576
637
  command,
@@ -623,7 +684,7 @@ function breadc(name, config = {}) {
623
684
  command(text, _config = {}) {
624
685
  const config2 = typeof _config === "string" ? { description: _config } : _config;
625
686
  const command = makeCommand(text, config2, root, container);
626
- if (command._arguments.length === 0 || command._arguments[0].type !== "const") {
687
+ if (command._default) {
627
688
  defaultCommand = command;
628
689
  }
629
690
  return command;
@@ -638,10 +699,7 @@ function breadc(name, config = {}) {
638
699
  if (command) {
639
700
  if (command.callback) {
640
701
  await container.preRun(breadc2);
641
- const r = command.callback(...result.arguments, {
642
- ...result.options,
643
- "--": result["--"]
644
- });
702
+ const r = await command.callback(result);
645
703
  await container.postRun(breadc2);
646
704
  return r;
647
705
  }
package/package.json CHANGED
@@ -1,13 +1,12 @@
1
1
  {
2
2
  "name": "breadc",
3
- "version": "0.8.1",
3
+ "version": "0.8.3",
4
4
  "description": "Yet another Command Line Application Framework with fully strong TypeScript support",
5
5
  "keywords": [
6
6
  "breadc",
7
7
  "cli",
8
8
  "framework",
9
9
  "command-line",
10
- "minimist",
11
10
  "typescript"
12
11
  ],
13
12
  "homepage": "https://github.com/yjl9903/Breadc#readme",
@@ -35,7 +34,7 @@
35
34
  "dist"
36
35
  ],
37
36
  "dependencies": {
38
- "@breadc/color": "0.8.1"
37
+ "@breadc/color": "0.8.3"
39
38
  },
40
39
  "devDependencies": {
41
40
  "@types/node": "^18.11.18",