breadc 0.1.1 → 0.4.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/dist/index.mjs CHANGED
@@ -1,33 +1,284 @@
1
- import { blue, yellow, red } from 'kolorist';
1
+ import { blue, yellow, red, gray } from 'kolorist';
2
2
  export { default as kolorist } from 'kolorist';
3
- import minimist from 'minimist';
4
- export { default as minimist } from 'minimist';
5
- import createDebug from 'debug';
6
- export { default as createDebug } from 'debug';
7
3
 
8
- function createDefaultLogger(name) {
9
- const debug = createDebug(name + ":breadc");
10
- return {
11
- println(message) {
12
- console.log(message);
13
- },
14
- info(message, ...args) {
15
- console.log(`${blue("INFO")} ${message}`, ...args);
16
- },
17
- warn(message, ...args) {
18
- console.log(`${yellow("WARN")} ${message}`, ...args);
19
- },
20
- error(message, ...args) {
21
- console.log(`${red("ERROR")} ${message}`, ...args);
22
- },
23
- debug(message, ...args) {
24
- debug(message, ...args);
4
+ var minimist = function (args, opts) {
5
+ if (!opts) opts = {};
6
+
7
+ var flags = { bools : {}, strings : {}, unknownFn: null };
8
+
9
+ if (typeof opts['unknown'] === 'function') {
10
+ flags.unknownFn = opts['unknown'];
11
+ }
12
+
13
+ if (typeof opts['boolean'] === 'boolean' && opts['boolean']) {
14
+ flags.allBools = true;
15
+ } else {
16
+ [].concat(opts['boolean']).filter(Boolean).forEach(function (key) {
17
+ flags.bools[key] = true;
18
+ });
19
+ }
20
+
21
+ var aliases = {};
22
+ Object.keys(opts.alias || {}).forEach(function (key) {
23
+ aliases[key] = [].concat(opts.alias[key]);
24
+ aliases[key].forEach(function (x) {
25
+ aliases[x] = [key].concat(aliases[key].filter(function (y) {
26
+ return x !== y;
27
+ }));
28
+ });
29
+ });
30
+
31
+ [].concat(opts.string).filter(Boolean).forEach(function (key) {
32
+ flags.strings[key] = true;
33
+ if (aliases[key]) {
34
+ flags.strings[aliases[key]] = true;
35
+ }
36
+ });
37
+
38
+ var defaults = opts['default'] || {};
39
+
40
+ var argv = { _ : [] };
41
+ Object.keys(flags.bools).forEach(function (key) {
42
+ setArg(key, defaults[key] === undefined ? false : defaults[key]);
43
+ });
44
+
45
+ var notFlags = [];
46
+
47
+ if (args.indexOf('--') !== -1) {
48
+ notFlags = args.slice(args.indexOf('--')+1);
49
+ args = args.slice(0, args.indexOf('--'));
50
+ }
51
+
52
+ function argDefined(key, arg) {
53
+ return (flags.allBools && /^--[^=]+$/.test(arg)) ||
54
+ flags.strings[key] || flags.bools[key] || aliases[key];
55
+ }
56
+
57
+ function setArg (key, val, arg) {
58
+ if (arg && flags.unknownFn && !argDefined(key, arg)) {
59
+ if (flags.unknownFn(arg) === false) return;
60
+ }
61
+
62
+ var value = !flags.strings[key] && isNumber(val)
63
+ ? Number(val) : val
64
+ ;
65
+ setKey(argv, key.split('.'), value);
66
+
67
+ (aliases[key] || []).forEach(function (x) {
68
+ setKey(argv, x.split('.'), value);
69
+ });
25
70
  }
71
+
72
+ function setKey (obj, keys, value) {
73
+ var o = obj;
74
+ for (var i = 0; i < keys.length-1; i++) {
75
+ var key = keys[i];
76
+ if (isConstructorOrProto(o, key)) return;
77
+ if (o[key] === undefined) o[key] = {};
78
+ if (o[key] === Object.prototype || o[key] === Number.prototype
79
+ || o[key] === String.prototype) o[key] = {};
80
+ if (o[key] === Array.prototype) o[key] = [];
81
+ o = o[key];
82
+ }
83
+
84
+ var key = keys[keys.length - 1];
85
+ if (isConstructorOrProto(o, key)) return;
86
+ if (o === Object.prototype || o === Number.prototype
87
+ || o === String.prototype) o = {};
88
+ if (o === Array.prototype) o = [];
89
+ if (o[key] === undefined || flags.bools[key] || typeof o[key] === 'boolean') {
90
+ o[key] = value;
91
+ }
92
+ else if (Array.isArray(o[key])) {
93
+ o[key].push(value);
94
+ }
95
+ else {
96
+ o[key] = [ o[key], value ];
97
+ }
98
+ }
99
+
100
+ function aliasIsBoolean(key) {
101
+ return aliases[key].some(function (x) {
102
+ return flags.bools[x];
103
+ });
104
+ }
105
+
106
+ for (var i = 0; i < args.length; i++) {
107
+ var arg = args[i];
108
+
109
+ if (/^--.+=/.test(arg)) {
110
+ // Using [\s\S] instead of . because js doesn't support the
111
+ // 'dotall' regex modifier. See:
112
+ // http://stackoverflow.com/a/1068308/13216
113
+ var m = arg.match(/^--([^=]+)=([\s\S]*)$/);
114
+ var key = m[1];
115
+ var value = m[2];
116
+ if (flags.bools[key]) {
117
+ value = value !== 'false';
118
+ }
119
+ setArg(key, value, arg);
120
+ }
121
+ else if (/^--no-.+/.test(arg)) {
122
+ var key = arg.match(/^--no-(.+)/)[1];
123
+ setArg(key, false, arg);
124
+ }
125
+ else if (/^--.+/.test(arg)) {
126
+ var key = arg.match(/^--(.+)/)[1];
127
+ var next = args[i + 1];
128
+ if (next !== undefined && !/^-/.test(next)
129
+ && !flags.bools[key]
130
+ && !flags.allBools
131
+ && (aliases[key] ? !aliasIsBoolean(key) : true)) {
132
+ setArg(key, next, arg);
133
+ i++;
134
+ }
135
+ else if (/^(true|false)$/.test(next)) {
136
+ setArg(key, next === 'true', arg);
137
+ i++;
138
+ }
139
+ else {
140
+ setArg(key, flags.strings[key] ? '' : true, arg);
141
+ }
142
+ }
143
+ else if (/^-[^-]+/.test(arg)) {
144
+ var letters = arg.slice(1,-1).split('');
145
+
146
+ var broken = false;
147
+ for (var j = 0; j < letters.length; j++) {
148
+ var next = arg.slice(j+2);
149
+
150
+ if (next === '-') {
151
+ setArg(letters[j], next, arg);
152
+ continue;
153
+ }
154
+
155
+ if (/[A-Za-z]/.test(letters[j]) && /=/.test(next)) {
156
+ setArg(letters[j], next.split('=')[1], arg);
157
+ broken = true;
158
+ break;
159
+ }
160
+
161
+ if (/[A-Za-z]/.test(letters[j])
162
+ && /-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) {
163
+ setArg(letters[j], next, arg);
164
+ broken = true;
165
+ break;
166
+ }
167
+
168
+ if (letters[j+1] && letters[j+1].match(/\W/)) {
169
+ setArg(letters[j], arg.slice(j+2), arg);
170
+ broken = true;
171
+ break;
172
+ }
173
+ else {
174
+ setArg(letters[j], flags.strings[letters[j]] ? '' : true, arg);
175
+ }
176
+ }
177
+
178
+ var key = arg.slice(-1)[0];
179
+ if (!broken && key !== '-') {
180
+ if (args[i+1] && !/^(-|--)[^-]/.test(args[i+1])
181
+ && !flags.bools[key]
182
+ && (aliases[key] ? !aliasIsBoolean(key) : true)) {
183
+ setArg(key, args[i+1], arg);
184
+ i++;
185
+ }
186
+ else if (args[i+1] && /^(true|false)$/.test(args[i+1])) {
187
+ setArg(key, args[i+1] === 'true', arg);
188
+ i++;
189
+ }
190
+ else {
191
+ setArg(key, flags.strings[key] ? '' : true, arg);
192
+ }
193
+ }
194
+ }
195
+ else {
196
+ if (!flags.unknownFn || flags.unknownFn(arg) !== false) {
197
+ argv._.push(
198
+ flags.strings['_'] || !isNumber(arg) ? arg : Number(arg)
199
+ );
200
+ }
201
+ if (opts.stopEarly) {
202
+ argv._.push.apply(argv._, args.slice(i + 1));
203
+ break;
204
+ }
205
+ }
206
+ }
207
+
208
+ Object.keys(defaults).forEach(function (key) {
209
+ if (!hasKey(argv, key.split('.'))) {
210
+ setKey(argv, key.split('.'), defaults[key]);
211
+
212
+ (aliases[key] || []).forEach(function (x) {
213
+ setKey(argv, x.split('.'), defaults[key]);
214
+ });
215
+ }
216
+ });
217
+
218
+ if (opts['--']) {
219
+ argv['--'] = new Array();
220
+ notFlags.forEach(function(key) {
221
+ argv['--'].push(key);
222
+ });
223
+ }
224
+ else {
225
+ notFlags.forEach(function(key) {
226
+ argv._.push(key);
227
+ });
228
+ }
229
+
230
+ return argv;
231
+ };
232
+
233
+ function hasKey (obj, keys) {
234
+ var o = obj;
235
+ keys.slice(0,-1).forEach(function (key) {
236
+ o = (o[key] || {});
237
+ });
238
+
239
+ var key = keys[keys.length - 1];
240
+ return key in o;
241
+ }
242
+
243
+ function isNumber (x) {
244
+ if (typeof x === 'number') return true;
245
+ if (/^0x[0-9a-f]+$/i.test(x)) return true;
246
+ return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x);
247
+ }
248
+
249
+
250
+ function isConstructorOrProto (obj, key) {
251
+ return key === 'constructor' && typeof obj[key] === 'function' || key === '__proto__';
252
+ }
253
+
254
+ function createDefaultLogger(name, logger) {
255
+ const println = !!logger && typeof logger === "function" ? logger : logger?.println ?? ((message, ...args) => {
256
+ console.log(message, ...args);
257
+ });
258
+ const info = typeof logger === "object" && logger?.info ? logger.info : (message, ...args) => {
259
+ println(`${blue("INFO")} ${message}`, ...args);
260
+ };
261
+ const warn = typeof logger === "object" && logger?.warn ? logger.warn : (message, ...args) => {
262
+ println(`${yellow("WARN")} ${message}`, ...args);
263
+ };
264
+ const error = typeof logger === "object" && logger?.error ? logger.error : (message, ...args) => {
265
+ println(`${red("ERROR")} ${message}`, ...args);
266
+ };
267
+ const debug = typeof logger === "object" && logger?.debug ? logger.debug : (message, ...args) => {
268
+ println(`${gray(name)} ${message}`, ...args);
269
+ };
270
+ return {
271
+ println,
272
+ info,
273
+ warn,
274
+ error,
275
+ debug
26
276
  };
27
277
  }
28
278
 
29
279
  const _Option = class {
30
280
  constructor(format, config = {}) {
281
+ this.format = format;
31
282
  const match = _Option.OptionRE.exec(format);
32
283
  if (match) {
33
284
  if (match[3]) {
@@ -43,25 +294,28 @@ const _Option = class {
43
294
  throw new Error(`Can not parse option format from "${format}"`);
44
295
  }
45
296
  this.description = config.description ?? "";
46
- this.construct = config.construct ?? ((text) => text ?? config.default ?? void 0);
297
+ this.required = format.indexOf("<") !== -1;
298
+ this.default = config.default;
299
+ this.construct = config.construct;
47
300
  }
48
301
  };
49
302
  let Option = _Option;
50
303
  Option.OptionRE = /^(-[a-zA-Z], )?--([a-zA-Z.]+)( \[[a-zA-Z]+\]| <[a-zA-Z]+>)?$/;
51
304
 
52
- class Command {
305
+ const _Command = class {
53
306
  constructor(format, config) {
54
307
  this.options = [];
55
308
  this.format = config.condition ? [format] : format.split(" ").map((t) => t.trim()).filter(Boolean);
309
+ this.default = this.format.length === 0 || this.format[0][0] === "[" || this.format[0][0] === "<";
56
310
  this.description = config.description ?? "";
57
311
  this.conditionFn = config.condition;
58
312
  this.logger = config.logger;
313
+ if (this.format.length > _Command.MaxDep) {
314
+ this.logger.warn(`Command format string "${format}" is too long`);
315
+ }
59
316
  }
60
317
  option(format, configOrDescription = "", otherConfig = {}) {
61
- const config = otherConfig;
62
- if (typeof configOrDescription === "string") {
63
- config.description = configOrDescription;
64
- }
318
+ const config = typeof configOrDescription === "object" ? configOrDescription : { ...otherConfig, description: configOrDescription };
65
319
  try {
66
320
  const option = new Option(format, config);
67
321
  this.options.push(option);
@@ -70,13 +324,18 @@ class Command {
70
324
  }
71
325
  return this;
72
326
  }
327
+ get hasConditionFn() {
328
+ return !!this.conditionFn;
329
+ }
73
330
  shouldRun(args) {
74
331
  if (this.conditionFn) {
75
332
  return this.conditionFn(args);
76
333
  } else {
77
- const isArg = (t) => t[0] !== "[" && t[0] !== "<";
334
+ if (this.default)
335
+ return true;
336
+ const isCmd = (t) => t[0] !== "[" && t[0] !== "<";
78
337
  for (let i = 0; i < this.format.length; i++) {
79
- if (isArg(this.format[i])) {
338
+ if (!isCmd(this.format[i])) {
80
339
  return true;
81
340
  }
82
341
  if (i >= args["_"].length || this.format[i] !== args["_"][i]) {
@@ -86,7 +345,7 @@ class Command {
86
345
  return true;
87
346
  }
88
347
  }
89
- parseArgs(args) {
348
+ parseArgs(args, globalOptions) {
90
349
  if (this.conditionFn) {
91
350
  const argumentss2 = args["_"];
92
351
  const options2 = args;
@@ -97,33 +356,62 @@ class Command {
97
356
  options: args
98
357
  };
99
358
  }
100
- const isArg = (t) => t[0] !== "[" && t[0] !== "<";
359
+ const isCmd = (t) => t[0] !== "[" && t[0] !== "<";
101
360
  const argumentss = [];
102
361
  for (let i = 0; i < this.format.length; i++) {
103
- if (isArg(this.format[i]))
362
+ if (isCmd(this.format[i]))
104
363
  continue;
105
364
  if (i < args["_"].length) {
106
365
  if (this.format[i].startsWith("[...")) {
107
- argumentss.push(args["_"].slice(i));
366
+ argumentss.push(args["_"].slice(i).map(String));
108
367
  } else {
109
- argumentss.push(args["_"][i]);
368
+ argumentss.push(String(args["_"][i]));
110
369
  }
111
370
  } else {
112
371
  if (this.format[i].startsWith("<")) {
372
+ this.logger.warn(`You should provide the argument "${this.format[i]}"`);
113
373
  argumentss.push(void 0);
114
374
  } else if (this.format[i].startsWith("[...")) {
115
375
  argumentss.push([]);
116
376
  } else if (this.format[i].startsWith("[")) {
117
377
  argumentss.push(void 0);
118
- } else ;
378
+ } else {
379
+ this.logger.warn(`unknown format string ("${this.format[i]}")`);
380
+ }
119
381
  }
120
382
  }
383
+ const fullOptions = globalOptions.concat(this.options).reduce((map, o) => {
384
+ map.set(o.name, o);
385
+ return map;
386
+ }, /* @__PURE__ */ new Map());
121
387
  const options = args;
122
388
  delete options["_"];
389
+ for (const [name, rawOption] of fullOptions) {
390
+ if (rawOption.required) {
391
+ if (options[name] === void 0) {
392
+ options[name] = false;
393
+ } else if (options[name] === "") {
394
+ options[name] = true;
395
+ }
396
+ } else {
397
+ if (options[name] === false) {
398
+ options[name] = void 0;
399
+ } else if (!(name in options)) {
400
+ options[name] = void 0;
401
+ }
402
+ }
403
+ if (rawOption.construct) {
404
+ options[name] = rawOption.construct(options[name]);
405
+ } else if (rawOption.default) {
406
+ if (!options[name]) {
407
+ options[name] = rawOption.default;
408
+ }
409
+ }
410
+ }
123
411
  return {
124
412
  command: this,
125
413
  arguments: argumentss,
126
- options: args
414
+ options
127
415
  };
128
416
  }
129
417
  action(fn) {
@@ -131,17 +419,29 @@ class Command {
131
419
  return this;
132
420
  }
133
421
  async run(...args) {
134
- this.actionFn && this.actionFn(...args);
422
+ if (this.actionFn) {
423
+ this.actionFn(...args);
424
+ } else {
425
+ this.logger.warn(`You may miss action function in "${this.format}"`);
426
+ }
135
427
  }
136
- }
137
- Command.MaxDep = 4;
138
- function createVersionCommand(breadc) {
428
+ };
429
+ let Command = _Command;
430
+ Command.MaxDep = 5;
431
+ function createHelpCommand(breadc) {
432
+ let helpCommand = void 0;
139
433
  return new Command("-h, --help", {
140
434
  condition(args) {
141
- const isEmpty = !args["_"].length && !args["--"]?.length;
142
- if (args.help && isEmpty) {
143
- return true;
144
- } else if (args.h && isEmpty) {
435
+ const isEmpty = !args["--"]?.length;
436
+ if ((args.help || args.h) && isEmpty) {
437
+ if (args["_"].length > 0) {
438
+ for (const cmd of breadc.commands) {
439
+ if (!cmd.hasConditionFn && !cmd.default && cmd.shouldRun(args)) {
440
+ helpCommand = cmd;
441
+ return true;
442
+ }
443
+ }
444
+ }
145
445
  return true;
146
446
  } else {
147
447
  return false;
@@ -149,10 +449,12 @@ function createVersionCommand(breadc) {
149
449
  },
150
450
  logger: breadc.logger
151
451
  }).action(() => {
152
- breadc.logger.println("Help");
452
+ for (const line of breadc.help(helpCommand)) {
453
+ breadc.logger.println(line);
454
+ }
153
455
  });
154
456
  }
155
- function createHelpCommand(breadc) {
457
+ function createVersionCommand(breadc) {
156
458
  return new Command("-v, --version", {
157
459
  condition(args) {
158
460
  const isEmpty = !args["_"].length && !args["--"]?.length;
@@ -166,7 +468,7 @@ function createHelpCommand(breadc) {
166
468
  },
167
469
  logger: breadc.logger
168
470
  }).action(() => {
169
- breadc.logger.println(`${breadc.name}/${breadc.version}`);
471
+ breadc.logger.println(breadc.version());
170
472
  });
171
473
  }
172
474
 
@@ -175,22 +477,78 @@ class Breadc {
175
477
  this.options = [];
176
478
  this.commands = [];
177
479
  this.name = name;
178
- this.version = option.version ?? "unknown";
179
- this.logger = option.logger ?? createDefaultLogger(name);
480
+ this._version = option.version ?? "unknown";
481
+ this.description = option.description;
482
+ this.logger = createDefaultLogger(name, option.logger);
180
483
  const breadc = {
181
484
  name: this.name,
182
- version: this.version,
485
+ version: () => this.version.call(this),
486
+ help: (command) => this.help.call(this, command),
183
487
  logger: this.logger,
184
488
  options: this.options,
185
489
  commands: this.commands
186
490
  };
187
- this.commands = [createVersionCommand(breadc), createHelpCommand(breadc)];
491
+ this.commands.push(createVersionCommand(breadc), createHelpCommand(breadc));
188
492
  }
189
- option(format, configOrDescription = "", otherConfig = {}) {
190
- const config = otherConfig;
191
- if (typeof configOrDescription === "string") {
192
- config.description = configOrDescription;
493
+ version() {
494
+ return `${this.name}/${this._version}`;
495
+ }
496
+ help(command) {
497
+ const output = [];
498
+ const println = (msg) => output.push(msg);
499
+ println(this.version());
500
+ if (!command) {
501
+ if (this.description) {
502
+ println("");
503
+ if (Array.isArray(this.description)) {
504
+ for (const line of this.description) {
505
+ println(line);
506
+ }
507
+ } else {
508
+ println(this.description);
509
+ }
510
+ }
511
+ } else {
512
+ if (command.description) {
513
+ println("");
514
+ println(command.description);
515
+ }
516
+ }
517
+ if (!command) {
518
+ if (this.defaultCommand) {
519
+ println(``);
520
+ println(`Usage:`);
521
+ println(` $ ${this.name} ${this.defaultCommand.format.join(" ")}`);
522
+ }
523
+ } else {
524
+ println(``);
525
+ println(`Usage:`);
526
+ println(` $ ${this.name} ${command.format.join(" ")}`);
193
527
  }
528
+ if (!command && this.commands.length > 2) {
529
+ println(``);
530
+ println(`Commands:`);
531
+ const commandHelps = this.commands.filter((c) => !c.hasConditionFn).map((c) => [` $ ${this.name} ${c.format.join(" ")}`, c.description]);
532
+ for (const line of twoColumn(commandHelps)) {
533
+ println(line);
534
+ }
535
+ }
536
+ println(``);
537
+ println(`Options:`);
538
+ const optionHelps = [].concat([
539
+ ...command ? command.options.map((o) => [` ${o.format}`, o.description]) : [],
540
+ ...this.options.map((o) => [` ${o.format}`, o.description]),
541
+ [` -h, --help`, `Display this message`],
542
+ [` -v, --version`, `Display version number`]
543
+ ]);
544
+ for (const line of twoColumn(optionHelps)) {
545
+ println(line);
546
+ }
547
+ println(``);
548
+ return output;
549
+ }
550
+ option(format, configOrDescription = "", otherConfig = {}) {
551
+ const config = typeof configOrDescription === "object" ? configOrDescription : { ...otherConfig, description: configOrDescription };
194
552
  try {
195
553
  const option = new Option(format, config);
196
554
  this.options.push(option);
@@ -199,13 +557,23 @@ class Breadc {
199
557
  }
200
558
  return this;
201
559
  }
202
- command(format, config = {}) {
560
+ command(format, configOrDescription = "", otherConfig = {}) {
561
+ const config = typeof configOrDescription === "object" ? configOrDescription : { ...otherConfig, description: configOrDescription };
203
562
  const command = new Command(format, { ...config, logger: this.logger });
563
+ if (command.default) {
564
+ if (this.defaultCommand) {
565
+ this.logger.warn("You can not have two default commands.");
566
+ }
567
+ this.defaultCommand = command;
568
+ }
204
569
  this.commands.push(command);
205
570
  return command;
206
571
  }
207
572
  parse(args) {
208
- const allowOptions = [this.options, this.commands.map((c) => c.options)].flat();
573
+ const allowOptions = [
574
+ ...this.options,
575
+ ...this.commands.flatMap((c) => c.options)
576
+ ];
209
577
  const alias = allowOptions.reduce((map, o) => {
210
578
  if (o.shortcut) {
211
579
  map[o.shortcut] = o.name;
@@ -215,16 +583,31 @@ class Breadc {
215
583
  const argv = minimist(args, {
216
584
  string: allowOptions.filter((o) => o.type === "string").map((o) => o.name),
217
585
  boolean: allowOptions.filter((o) => o.type === "boolean").map((o) => o.name),
218
- alias
586
+ alias,
587
+ unknown: (t) => {
588
+ if (t[0] !== "-")
589
+ return true;
590
+ else {
591
+ if (["--help", "-h", "--version", "-v"].includes(t)) {
592
+ return true;
593
+ } else {
594
+ this.logger.warn(`Find unknown flag "${t}"`);
595
+ return false;
596
+ }
597
+ }
598
+ }
219
599
  });
220
600
  for (const shortcut of Object.keys(alias)) {
221
601
  delete argv[shortcut];
222
602
  }
223
603
  for (const command of this.commands) {
224
- if (command.shouldRun(argv)) {
225
- return command.parseArgs(argv);
604
+ if (!command.default && command.shouldRun(argv)) {
605
+ return command.parseArgs(argv, this.options);
226
606
  }
227
607
  }
608
+ if (this.defaultCommand) {
609
+ return this.defaultCommand.parseArgs(argv, this.options);
610
+ }
228
611
  const argumentss = argv["_"];
229
612
  const options = argv;
230
613
  delete options["_"];
@@ -241,9 +624,17 @@ class Breadc {
241
624
  }
242
625
  }
243
626
  }
627
+ function twoColumn(texts, split = " ") {
628
+ const left = padRight(texts.map((t) => t[0]));
629
+ return left.map((l, idx) => l + split + texts[idx][1]);
630
+ }
631
+ function padRight(texts, fill = " ") {
632
+ const length = texts.map((t) => t.length).reduce((max, l) => Math.max(max, l), 0);
633
+ return texts.map((t) => t + fill.repeat(length - t.length));
634
+ }
244
635
 
245
636
  function breadc(name, option = {}) {
246
637
  return new Breadc(name, option);
247
638
  }
248
639
 
249
- export { breadc as default };
640
+ export { breadc as default, minimist };