@breadc/core 1.0.0-beta.2 → 1.0.0-beta.4
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 +16 -5
- package/dist/index.d.mts +7 -5
- package/dist/index.mjs +74 -41
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 🥪 Breadc
|
|
2
2
|
|
|
3
|
-
[](https://deepwiki.com/yjl9903/Breadc)
|
|
4
|
+
[](https://www.npmjs.com/package/breadc)
|
|
5
|
+
[](https://github.com/yjl9903/Breadc/actions/workflows/ci.yml)
|
|
6
|
+
[](https://codecov.io/gh/yjl9903/Breadc)
|
|
4
7
|
|
|
5
|
-
Yet another Command Line Application Framework
|
|
8
|
+
Yet another **Command Line Application Framework** desgined for **[TypeScript](https://www.typescriptlang.org/)**.
|
|
9
|
+
|
|
10
|
+
- **TypeScript Infer**: infer command arguments, option values, and action signatures in IDE automatically
|
|
11
|
+
- **Command**: support default command, command alias, and nested sub-commands like `git remote add <name> <url>`
|
|
12
|
+
- **Group**: organize commands by modules and build large multi-command CLI applications with clear structure
|
|
13
|
+
- **Option**: support boolean, required, optional, spread options, `--no-*` negation, and `--` passthrough arguments
|
|
14
|
+
- **Middleware**: support middleware pipeline and unknown option handling
|
|
15
|
+
- **Builtin CLI Features**: provide common help / version options and i18n support out of the box
|
|
6
16
|
|
|
7
17
|

|
|
8
18
|
|
|
@@ -39,8 +49,9 @@ If you are using IDEs that support TypeScript (like [Visual Studio Code](https:/
|
|
|
39
49
|
|
|
40
50
|
## Inspiration
|
|
41
51
|
|
|
42
|
-
|
|
43
|
-
|
|
52
|
+
- [cac](https://github.com/cacjs/cac): Simple yet powerful framework for building command-line apps.
|
|
53
|
+
- [Commander.js](https://github.com/tj/commander.js): Node.js command-line interfaces made easy.
|
|
54
|
+
- [TypeScript: Documentation - Template Literal Types](https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html)
|
|
44
55
|
|
|
45
56
|
## License
|
|
46
57
|
|
package/dist/index.d.mts
CHANGED
|
@@ -321,7 +321,7 @@ type InternalCommand = Command & {
|
|
|
321
321
|
/**
|
|
322
322
|
* @internal
|
|
323
323
|
*/
|
|
324
|
-
_actionFn?:
|
|
324
|
+
_actionFn?: (...args: any[]) => unknown;
|
|
325
325
|
};
|
|
326
326
|
type OptionType = 'boolean' | 'required' | 'optional' | 'spread';
|
|
327
327
|
type InternalOption = Option & {
|
|
@@ -529,9 +529,9 @@ type Breadc<Data extends {} = {}, Options extends Record<never, never> = {}> = {
|
|
|
529
529
|
*/
|
|
530
530
|
use<Middleware extends ActionMiddleware<Data, ActionMiddlewareNextFn>>(middleware: Middleware): Breadc<InferMiddlewareData<Middleware>, Options>;
|
|
531
531
|
/**
|
|
532
|
-
*
|
|
532
|
+
* Unknown command middleware
|
|
533
533
|
*/
|
|
534
|
-
onUnknownCommand(middleware?:
|
|
534
|
+
onUnknownCommand(middleware?: UnknownCommandMiddleware<Data>): Breadc<Data, Options>;
|
|
535
535
|
/**
|
|
536
536
|
* Allow unknown option middleware
|
|
537
537
|
*/
|
|
@@ -567,7 +567,7 @@ type Group<Spec extends string = string, Init extends GroupInit<Spec> = GroupIni
|
|
|
567
567
|
option<OS extends string, Initial extends NonTrueNullable<InferOptionInitialType<OS>>, OI extends NonNullableOptionInit<OS, Initial>>(spec: OS, description: string, init: OI): Group<Spec, Init, Data, Options & InferOption<OS, Initial, OI>>;
|
|
568
568
|
option<OS extends string, Initial extends InferOptionInitialType<OS>, OI extends OptionInit<OS, Initial>>(spec: OS, description?: string, init?: OI): Group<Spec, Init, Data, Options & InferOption<OS, Initial, OI>>;
|
|
569
569
|
command<S extends string, I extends CommandInit<S>>(spec: S, description?: string, init?: I): Command<S, I, Data, Options, InferArgumentsType<S>, unknown>;
|
|
570
|
-
command<S extends string, I extends CommandInit<S>>(command: Command<S, I, Options>): Command<S, I, Data, Options, InferArgumentsType<S>, unknown>;
|
|
570
|
+
command<S extends string, I extends CommandInit<S>>(command: Command<S, I, Data, Options>): Command<S, I, Data, Options, InferArgumentsType<S>, unknown>;
|
|
571
571
|
/**
|
|
572
572
|
* Action middleware
|
|
573
573
|
*/
|
|
@@ -577,7 +577,7 @@ type Group<Spec extends string = string, Init extends GroupInit<Spec> = GroupIni
|
|
|
577
577
|
*/
|
|
578
578
|
allowUnknownOption(middleware?: UnknownOptionMiddleware<Data>): Group<Spec, Init, Data, Options>;
|
|
579
579
|
};
|
|
580
|
-
type Command<Spec extends string = string, Init extends CommandInit<Spec> = CommandInit<Spec>, Data extends {} = {}, Options extends Record<never, never> =
|
|
580
|
+
type Command<Spec extends string = string, Init extends CommandInit<Spec> = CommandInit<Spec>, Data extends {} = {}, Options extends Record<never, never> = Record<never, never>, Arguments extends unknown[] = InferArgumentsType<Spec>, Return extends unknown = unknown> = {
|
|
581
581
|
spec: Spec;
|
|
582
582
|
init: Init | undefined;
|
|
583
583
|
/**
|
|
@@ -657,6 +657,7 @@ declare function printVersion(context: Context): string;
|
|
|
657
657
|
//#region src/error.d.ts
|
|
658
658
|
declare abstract class BreadcError extends Error {}
|
|
659
659
|
type BreadcAppErrorCause = {
|
|
660
|
+
group?: InternalGroup;
|
|
660
661
|
command?: InternalCommand;
|
|
661
662
|
commands?: (InternalCommand | InternalGroup)[];
|
|
662
663
|
};
|
|
@@ -665,6 +666,7 @@ type BreadcAppErrorInput = BreadcAppErrorCause & {
|
|
|
665
666
|
};
|
|
666
667
|
declare class BreadcAppError extends BreadcError {
|
|
667
668
|
static DUPLICATED_DEFAULT_COMMAND: string;
|
|
669
|
+
static DUPLICATED_DEFAULT_GROUP_COMMAND: string;
|
|
668
670
|
static DUPLICATED_GROUP: string;
|
|
669
671
|
static DUPLICATED_COMMAND: string;
|
|
670
672
|
static NO_ACTION_BOUND: string;
|
package/dist/index.mjs
CHANGED
|
@@ -38,6 +38,7 @@ function rawOption(spec, type, long, short, init) {
|
|
|
38
38
|
//#region src/error.ts
|
|
39
39
|
var BreadcError = class extends Error {};
|
|
40
40
|
var RuntimeError = class extends BreadcError {
|
|
41
|
+
static UNEXPECTED_ARGUMENTS = "Detect unexpected redundant arguments";
|
|
41
42
|
static REQUIRED_ARGUMENT_MISSING = "Missing required argument";
|
|
42
43
|
static OPTIONAL_ARGUMENT_ACCEPT_ONCE = "Optional argument can only be assigned once";
|
|
43
44
|
static REQUIRED_ARGUMENT_ACCEPT_ONCE = "Required argument can only be assigned once";
|
|
@@ -60,6 +61,7 @@ var RuntimeError = class extends BreadcError {
|
|
|
60
61
|
};
|
|
61
62
|
var BreadcAppError = class extends BreadcError {
|
|
62
63
|
static DUPLICATED_DEFAULT_COMMAND = `Find duplicated default commands`;
|
|
64
|
+
static DUPLICATED_DEFAULT_GROUP_COMMAND = `Find duplicated default group commands`;
|
|
63
65
|
static DUPLICATED_GROUP = `Find duplicated groups`;
|
|
64
66
|
static DUPLICATED_COMMAND = `Find duplicated commands`;
|
|
65
67
|
static NO_ACTION_BOUND = `There is no action function bound in this command`;
|
|
@@ -112,6 +114,16 @@ var ResolveOptionError = class extends BreadcError {
|
|
|
112
114
|
}
|
|
113
115
|
};
|
|
114
116
|
|
|
117
|
+
//#endregion
|
|
118
|
+
//#region src/breadc/shared.ts
|
|
119
|
+
function resolveOptionInput(spec, description, init) {
|
|
120
|
+
return typeof spec === "string" ? option(spec, description, init) : spec;
|
|
121
|
+
}
|
|
122
|
+
const defaultUnknownOptionMiddleware = (_ctx, key, value) => ({
|
|
123
|
+
name: key,
|
|
124
|
+
value
|
|
125
|
+
});
|
|
126
|
+
|
|
115
127
|
//#endregion
|
|
116
128
|
//#region src/breadc/command.ts
|
|
117
129
|
function command(spec, init) {
|
|
@@ -134,8 +146,7 @@ function command(spec, init) {
|
|
|
134
146
|
return run;
|
|
135
147
|
};
|
|
136
148
|
run.option = (spec, description, init) => {
|
|
137
|
-
|
|
138
|
-
options.push(option$5);
|
|
149
|
+
options.push(resolveOptionInput(spec, description, init));
|
|
139
150
|
return run;
|
|
140
151
|
};
|
|
141
152
|
run.use = (middleware) => {
|
|
@@ -146,10 +157,7 @@ function command(spec, init) {
|
|
|
146
157
|
run.allowUnknownOption = (middleware) => {
|
|
147
158
|
if (!run._unknownOptionMiddlewares) run._unknownOptionMiddlewares = [];
|
|
148
159
|
if (typeof middleware === "function") run._unknownOptionMiddlewares.push(middleware);
|
|
149
|
-
else run._unknownOptionMiddlewares.push(
|
|
150
|
-
name: key,
|
|
151
|
-
value
|
|
152
|
-
}));
|
|
160
|
+
else run._unknownOptionMiddlewares.push(defaultUnknownOptionMiddleware);
|
|
153
161
|
return run;
|
|
154
162
|
};
|
|
155
163
|
run.action = (fn) => {
|
|
@@ -799,9 +807,9 @@ function buildVersionOption(context) {
|
|
|
799
807
|
const { breadc } = context;
|
|
800
808
|
if (breadc._version) return breadc._version;
|
|
801
809
|
const spec = typeof breadc._init.builtin?.version === "object" ? breadc._init.builtin.version.spec : void 0;
|
|
802
|
-
const option$
|
|
803
|
-
breadc._version = option$
|
|
804
|
-
return option$
|
|
810
|
+
const option$2 = spec ? resolveOption(option(spec, "Print version")) : rawOption("-v, --version", "boolean", "version", "v", { description: "Print version" });
|
|
811
|
+
breadc._version = option$2;
|
|
812
|
+
return option$2;
|
|
805
813
|
}
|
|
806
814
|
function printVersion(context) {
|
|
807
815
|
const { breadc } = context;
|
|
@@ -849,7 +857,7 @@ function formatCommand(command) {
|
|
|
849
857
|
const args = formatArgument(command).join(" ");
|
|
850
858
|
return pieces && args ? `${pieces} ${args}` : pieces;
|
|
851
859
|
}
|
|
852
|
-
function
|
|
860
|
+
function commandStartsWith(command, prefix) {
|
|
853
861
|
if (prefix.length === 0) return true;
|
|
854
862
|
for (const pieces of command._pieces) {
|
|
855
863
|
if (pieces.length < prefix.length) continue;
|
|
@@ -862,6 +870,18 @@ function commandMatched(command, prefix) {
|
|
|
862
870
|
}
|
|
863
871
|
return false;
|
|
864
872
|
}
|
|
873
|
+
function commandIncludes(command, prefix) {
|
|
874
|
+
for (const pieces of command._pieces) {
|
|
875
|
+
if (pieces.length > prefix.length) continue;
|
|
876
|
+
let ok = true;
|
|
877
|
+
for (let i = 0; i < pieces.length; i++) if (pieces[i] !== prefix[i]) {
|
|
878
|
+
ok = false;
|
|
879
|
+
break;
|
|
880
|
+
}
|
|
881
|
+
if (ok) return true;
|
|
882
|
+
}
|
|
883
|
+
return false;
|
|
884
|
+
}
|
|
865
885
|
function collect(context, pieces) {
|
|
866
886
|
const allCommands = [];
|
|
867
887
|
const commands = [];
|
|
@@ -876,17 +896,17 @@ function collect(context, pieces) {
|
|
|
876
896
|
resolveGroup(group);
|
|
877
897
|
buildGroup(group);
|
|
878
898
|
allCommands.push(...group._commands);
|
|
879
|
-
if (
|
|
880
|
-
for (const command of group._commands) if (
|
|
899
|
+
if (commandIncludes(group, pieces)) for (const option of group._options) append(option);
|
|
900
|
+
for (const command of group._commands) if (commandStartsWith(command, pieces)) {
|
|
881
901
|
commands.push(command);
|
|
882
|
-
for (const option of command._options) append(option);
|
|
902
|
+
if (commandIncludes(command, pieces)) for (const option of command._options) append(option);
|
|
883
903
|
}
|
|
884
904
|
} else {
|
|
885
905
|
resolveCommand(command);
|
|
886
906
|
allCommands.push(command);
|
|
887
|
-
if (
|
|
907
|
+
if (commandStartsWith(command, pieces)) {
|
|
888
908
|
commands.push(command);
|
|
889
|
-
for (const option of command._options) append(option);
|
|
909
|
+
if (commandIncludes(command, pieces)) for (const option of command._options) append(option);
|
|
890
910
|
}
|
|
891
911
|
}
|
|
892
912
|
if (context.breadc._init.builtin?.help !== false) append(buildHelpOption(context));
|
|
@@ -901,9 +921,9 @@ function buildHelpOption(context) {
|
|
|
901
921
|
const { breadc } = context;
|
|
902
922
|
if (breadc._help) return breadc._help;
|
|
903
923
|
const spec = typeof breadc._init.builtin?.help === "object" ? breadc._init.builtin.help.spec : void 0;
|
|
904
|
-
const option$
|
|
905
|
-
breadc._help = option$
|
|
906
|
-
return option$
|
|
924
|
+
const option$1 = spec ? resolveOption(option(spec, "Print help")) : rawOption("-h, --help", "boolean", "help", "h", { description: "Print help" });
|
|
925
|
+
breadc._help = option$1;
|
|
926
|
+
return option$1;
|
|
907
927
|
}
|
|
908
928
|
function printHelp(context) {
|
|
909
929
|
const { breadc, pieces } = context;
|
|
@@ -950,10 +970,14 @@ function parse(app, argv) {
|
|
|
950
970
|
commands: defaultCommands
|
|
951
971
|
});
|
|
952
972
|
const defaultCommand = defaultCommands[0];
|
|
953
|
-
doParse(context$1, defaultCommand !== void 0 && context$1.breadc._commands.length === 1 ? defaultCommand : void 0);
|
|
954
|
-
if (context$1.command || isVersion(context$1) || isHelp(context$1)) {} else if (
|
|
973
|
+
doParse(context$1, void 0, defaultCommand !== void 0 && context$1.breadc._commands.length === 1 ? defaultCommand : void 0);
|
|
974
|
+
if (context$1.command || isVersion(context$1) || isHelp(context$1)) {} else if (context$1.group) {
|
|
975
|
+
const matchedGroup = context$1.group;
|
|
976
|
+
reset(context$1);
|
|
977
|
+
doParse(context$1, matchedGroup, void 0);
|
|
978
|
+
} else if (defaultCommand) {
|
|
955
979
|
reset(context$1);
|
|
956
|
-
doParse(context$1, defaultCommand);
|
|
980
|
+
doParse(context$1, void 0, defaultCommand);
|
|
957
981
|
}
|
|
958
982
|
return context$1;
|
|
959
983
|
}
|
|
@@ -973,7 +997,7 @@ function isVersion(context) {
|
|
|
973
997
|
if (version && context.options.get(version.long)?.value()) return true;
|
|
974
998
|
else return false;
|
|
975
999
|
}
|
|
976
|
-
function doParse(context, defaultCommand) {
|
|
1000
|
+
function doParse(context, defaultGroup, defaultCommand) {
|
|
977
1001
|
const { breadc, tokens, options: matchedOptions } = context;
|
|
978
1002
|
let index = 0;
|
|
979
1003
|
let matchedGroup = void 0;
|
|
@@ -1010,10 +1034,8 @@ function doParse(context, defaultCommand) {
|
|
|
1010
1034
|
}
|
|
1011
1035
|
if (defaultCommand) {
|
|
1012
1036
|
matchedCommand = defaultCommand;
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
addPendingOptions(command._options);
|
|
1016
|
-
}
|
|
1037
|
+
buildCommand(defaultCommand);
|
|
1038
|
+
addPendingOptions(defaultCommand._options);
|
|
1017
1039
|
} else for (const command of breadc._commands) if (!command._default) for (let alias = 0; alias < command._pieces.length; alias++) addPendingCommand(command, alias);
|
|
1018
1040
|
while (!tokens.isEnd) {
|
|
1019
1041
|
const token = tokens.next();
|
|
@@ -1035,7 +1057,22 @@ function doParse(context, defaultCommand) {
|
|
|
1035
1057
|
});
|
|
1036
1058
|
buildGroup(group);
|
|
1037
1059
|
addPendingOptions(group._options);
|
|
1038
|
-
|
|
1060
|
+
if (matchedGroup && matchedGroup === defaultGroup) {
|
|
1061
|
+
const defaultCommands = matchedGroup._commands.filter((command) => command._pieces.some((p) => p.length === index));
|
|
1062
|
+
if (defaultCommands.length === 1) {
|
|
1063
|
+
const defaultCommand = defaultCommands[0];
|
|
1064
|
+
matchedCommand = defaultCommand;
|
|
1065
|
+
buildCommand(defaultCommand);
|
|
1066
|
+
addPendingOptions(defaultCommand._options);
|
|
1067
|
+
} else if (defaultCommands.length > 1) throw new BreadcAppError(BreadcAppError.DUPLICATED_DEFAULT_GROUP_COMMAND, {
|
|
1068
|
+
context,
|
|
1069
|
+
group: matchedGroup,
|
|
1070
|
+
commands: defaultCommands
|
|
1071
|
+
});
|
|
1072
|
+
} else for (const command of group._commands) for (let alias = 0; alias < command._pieces.length; alias++) {
|
|
1073
|
+
if (command._pieces[alias].length === index) continue;
|
|
1074
|
+
addPendingCommand(command, alias);
|
|
1075
|
+
}
|
|
1039
1076
|
} else {
|
|
1040
1077
|
if (!matchedCommand || matchedCommand === command) matchedCommand = command;
|
|
1041
1078
|
else throw new BreadcAppError(BreadcAppError.DUPLICATED_COMMAND, {
|
|
@@ -1075,6 +1112,7 @@ function doParse(context, defaultCommand) {
|
|
|
1075
1112
|
context.group = matchedGroup;
|
|
1076
1113
|
context.command = matchedCommand;
|
|
1077
1114
|
if (matchedCommand) {
|
|
1115
|
+
if (unknown.length > 0) throw new RuntimeError(RuntimeError.UNEXPECTED_ARGUMENTS, { context });
|
|
1078
1116
|
let i = 0;
|
|
1079
1117
|
for (; i < matchedCommand._arguments.length; i++) {
|
|
1080
1118
|
const argument = matchedCommand._arguments[i];
|
|
@@ -1169,12 +1207,14 @@ function group(spec, init) {
|
|
|
1169
1207
|
_actionMiddlewares: actionMiddlewares,
|
|
1170
1208
|
_unknownOptionMiddlewares: unknownOptionMiddlewares,
|
|
1171
1209
|
option(spec, description, init) {
|
|
1172
|
-
|
|
1173
|
-
options.push(option$2);
|
|
1210
|
+
options.push(resolveOptionInput(spec, description, init));
|
|
1174
1211
|
return group;
|
|
1175
1212
|
},
|
|
1176
|
-
command(spec, init) {
|
|
1177
|
-
const command$2 = typeof spec === "string" ? command(spec, init
|
|
1213
|
+
command(spec, description, init) {
|
|
1214
|
+
const command$2 = typeof spec === "string" ? command(spec, description || init ? {
|
|
1215
|
+
description,
|
|
1216
|
+
...init
|
|
1217
|
+
} : void 0) : spec;
|
|
1178
1218
|
command$2._group = group;
|
|
1179
1219
|
commands.push(command$2);
|
|
1180
1220
|
return command$2;
|
|
@@ -1185,10 +1225,7 @@ function group(spec, init) {
|
|
|
1185
1225
|
},
|
|
1186
1226
|
allowUnknownOption(middleware) {
|
|
1187
1227
|
if (typeof middleware === "function") unknownOptionMiddlewares.push(middleware);
|
|
1188
|
-
else unknownOptionMiddlewares.push(
|
|
1189
|
-
name: key,
|
|
1190
|
-
value
|
|
1191
|
-
}));
|
|
1228
|
+
else unknownOptionMiddlewares.push(defaultUnknownOptionMiddleware);
|
|
1192
1229
|
return group;
|
|
1193
1230
|
}
|
|
1194
1231
|
};
|
|
@@ -1213,8 +1250,7 @@ function breadc(name, init = {}) {
|
|
|
1213
1250
|
_unknownOptionMiddlewares: unknownOptionMiddlewares,
|
|
1214
1251
|
_unknownCommandMiddlewares: unknownCommandMiddlewares,
|
|
1215
1252
|
option(spec, description, init) {
|
|
1216
|
-
|
|
1217
|
-
options.push(option$1);
|
|
1253
|
+
options.push(resolveOptionInput(spec, description, init));
|
|
1218
1254
|
return app;
|
|
1219
1255
|
},
|
|
1220
1256
|
group(spec, init) {
|
|
@@ -1240,10 +1276,7 @@ function breadc(name, init = {}) {
|
|
|
1240
1276
|
},
|
|
1241
1277
|
allowUnknownOption(middleware) {
|
|
1242
1278
|
if (typeof middleware === "function") unknownOptionMiddlewares.push(middleware);
|
|
1243
|
-
else unknownOptionMiddlewares.push(
|
|
1244
|
-
name: key,
|
|
1245
|
-
value
|
|
1246
|
-
}));
|
|
1279
|
+
else unknownOptionMiddlewares.push(defaultUnknownOptionMiddleware);
|
|
1247
1280
|
return app;
|
|
1248
1281
|
},
|
|
1249
1282
|
parse(argv) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@breadc/core",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.4",
|
|
4
4
|
"description": "Yet another Command Line Application Framework with fully strong TypeScript support",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"breadc",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"dist"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@breadc/color": "1.0.0-beta.
|
|
36
|
+
"@breadc/color": "1.0.0-beta.4"
|
|
37
37
|
},
|
|
38
38
|
"size-limit": [
|
|
39
39
|
{
|