bob-core 1.2.2 → 1.2.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.
Files changed (99) hide show
  1. package/dist/bob-core.cjs +8 -0
  2. package/dist/bob-core.js +515 -0
  3. package/dist/package-B_d-lCr-.js +29 -0
  4. package/dist/package-D1PCfkN9.cjs +1 -0
  5. package/dist/{cjs → types}/src/Cli.d.ts +4 -4
  6. package/dist/{esm → types}/src/Command.d.ts +2 -2
  7. package/dist/{cjs → types}/src/CommandParser.d.ts +1 -1
  8. package/dist/{cjs → types}/src/CommandRegistry.d.ts +1 -1
  9. package/dist/{cjs → types}/src/ExceptionHandler.d.ts +1 -1
  10. package/dist/{esm → types}/src/commands/HelpCommand.d.ts +2 -2
  11. package/dist/{esm → types}/src/errors/BadCommandOption.d.ts +1 -1
  12. package/dist/{cjs → types}/src/errors/BadCommandParameter.d.ts +1 -1
  13. package/dist/{cjs → types}/src/errors/CommandNotFoundError.d.ts +1 -1
  14. package/dist/{esm → types}/src/errors/InvalidOption.d.ts +2 -2
  15. package/dist/{cjs → types}/src/errors/MissingRequiredArgumentValue.d.ts +2 -2
  16. package/dist/{cjs → types}/src/errors/MissingSignatureArgument.d.ts +2 -2
  17. package/dist/{cjs → types}/src/errors/MissingSignatureOption.d.ts +2 -2
  18. package/dist/{cjs → types}/src/options/HelpOption.d.ts +2 -2
  19. package/package.json +13 -20
  20. package/dist/cjs/package.json +0 -1
  21. package/dist/cjs/src/Cli.js +0 -66
  22. package/dist/cjs/src/Command.d.ts +0 -34
  23. package/dist/cjs/src/Command.js +0 -97
  24. package/dist/cjs/src/Command.test.d.ts +0 -1
  25. package/dist/cjs/src/Command.test.js +0 -52
  26. package/dist/cjs/src/CommandParser.js +0 -239
  27. package/dist/cjs/src/CommandParser.test.d.ts +0 -1
  28. package/dist/cjs/src/CommandParser.test.js +0 -177
  29. package/dist/cjs/src/CommandRegistry.js +0 -149
  30. package/dist/cjs/src/ExceptionHandler.js +0 -14
  31. package/dist/cjs/src/commands/HelpCommand.d.ts +0 -14
  32. package/dist/cjs/src/commands/HelpCommand.js +0 -90
  33. package/dist/cjs/src/contracts/CommandOption.js +0 -2
  34. package/dist/cjs/src/contracts/index.js +0 -17
  35. package/dist/cjs/src/errors/BadCommandOption.d.ts +0 -11
  36. package/dist/cjs/src/errors/BadCommandOption.js +0 -36
  37. package/dist/cjs/src/errors/BadCommandParameter.js +0 -36
  38. package/dist/cjs/src/errors/BobError.js +0 -6
  39. package/dist/cjs/src/errors/CommandNotFoundError.js +0 -30
  40. package/dist/cjs/src/errors/InvalidOption.d.ts +0 -8
  41. package/dist/cjs/src/errors/InvalidOption.js +0 -32
  42. package/dist/cjs/src/errors/MissingRequiredArgumentValue.js +0 -23
  43. package/dist/cjs/src/errors/MissingSignatureArgument.js +0 -31
  44. package/dist/cjs/src/errors/MissingSignatureOption.js +0 -31
  45. package/dist/cjs/src/errors/index.js +0 -19
  46. package/dist/cjs/src/index.js +0 -21
  47. package/dist/cjs/src/lib/string.js +0 -6
  48. package/dist/cjs/src/options/HelpOption.js +0 -77
  49. package/dist/cjs/src/options/index.js +0 -17
  50. package/dist/esm/package.json +0 -50
  51. package/dist/esm/src/Cli.d.ts +0 -26
  52. package/dist/esm/src/Cli.js +0 -59
  53. package/dist/esm/src/Command.js +0 -93
  54. package/dist/esm/src/Command.test.d.ts +0 -1
  55. package/dist/esm/src/Command.test.js +0 -50
  56. package/dist/esm/src/CommandParser.d.ts +0 -46
  57. package/dist/esm/src/CommandParser.js +0 -232
  58. package/dist/esm/src/CommandParser.test.d.ts +0 -1
  59. package/dist/esm/src/CommandParser.test.js +0 -175
  60. package/dist/esm/src/CommandRegistry.d.ts +0 -17
  61. package/dist/esm/src/CommandRegistry.js +0 -109
  62. package/dist/esm/src/ExceptionHandler.d.ts +0 -4
  63. package/dist/esm/src/ExceptionHandler.js +0 -10
  64. package/dist/esm/src/commands/HelpCommand.js +0 -51
  65. package/dist/esm/src/contracts/CommandOption.d.ts +0 -7
  66. package/dist/esm/src/contracts/CommandOption.js +0 -1
  67. package/dist/esm/src/contracts/index.d.ts +0 -1
  68. package/dist/esm/src/contracts/index.js +0 -1
  69. package/dist/esm/src/errors/BadCommandOption.js +0 -29
  70. package/dist/esm/src/errors/BadCommandParameter.d.ts +0 -11
  71. package/dist/esm/src/errors/BadCommandParameter.js +0 -29
  72. package/dist/esm/src/errors/BobError.d.ts +0 -3
  73. package/dist/esm/src/errors/BobError.js +0 -2
  74. package/dist/esm/src/errors/CommandNotFoundError.d.ts +0 -7
  75. package/dist/esm/src/errors/CommandNotFoundError.js +0 -23
  76. package/dist/esm/src/errors/InvalidOption.js +0 -25
  77. package/dist/esm/src/errors/MissingRequiredArgumentValue.d.ts +0 -7
  78. package/dist/esm/src/errors/MissingRequiredArgumentValue.js +0 -16
  79. package/dist/esm/src/errors/MissingSignatureArgument.d.ts +0 -8
  80. package/dist/esm/src/errors/MissingSignatureArgument.js +0 -24
  81. package/dist/esm/src/errors/MissingSignatureOption.d.ts +0 -8
  82. package/dist/esm/src/errors/MissingSignatureOption.js +0 -24
  83. package/dist/esm/src/errors/index.d.ts +0 -3
  84. package/dist/esm/src/errors/index.js +0 -3
  85. package/dist/esm/src/index.d.ts +0 -5
  86. package/dist/esm/src/index.js +0 -5
  87. package/dist/esm/src/lib/string.d.ts +0 -1
  88. package/dist/esm/src/lib/string.js +0 -3
  89. package/dist/esm/src/options/HelpOption.d.ts +0 -9
  90. package/dist/esm/src/options/HelpOption.js +0 -70
  91. package/dist/esm/src/options/index.d.ts +0 -1
  92. package/dist/esm/src/options/index.js +0 -1
  93. /package/dist/{cjs → types}/src/contracts/CommandOption.d.ts +0 -0
  94. /package/dist/{cjs → types}/src/contracts/index.d.ts +0 -0
  95. /package/dist/{cjs → types}/src/errors/BobError.d.ts +0 -0
  96. /package/dist/{cjs → types}/src/errors/index.d.ts +0 -0
  97. /package/dist/{cjs → types}/src/index.d.ts +0 -0
  98. /package/dist/{cjs → types}/src/lib/string.d.ts +0 -0
  99. /package/dist/{cjs → types}/src/options/index.d.ts +0 -0
@@ -1,232 +0,0 @@
1
- import minimist from 'minimist';
2
- import { MissingRequiredArgumentValue } from "./errors/MissingRequiredArgumentValue.js";
3
- import { MissingSignatureOption } from "./errors/MissingSignatureOption.js";
4
- import { MissingSignatureArgument } from "./errors/MissingSignatureArgument.js";
5
- import { InvalidOption } from "./errors/InvalidOption.js";
6
- export class CommandParser {
7
- signature;
8
- helperDefinitions;
9
- defaultCommandOptions;
10
- command;
11
- arguments = {};
12
- options = {};
13
- argumentsSignature = {};
14
- optionSignatures = {};
15
- optionAliases = {};
16
- constructor(signature, helperDefinitions, defaultCommandOptions, ...args) {
17
- this.signature = signature;
18
- this.helperDefinitions = helperDefinitions;
19
- this.defaultCommandOptions = defaultCommandOptions;
20
- const [command, ...signatureParams] = signature.split(/\{(.*?)\}/g).map(param => param.trim()).filter(Boolean);
21
- const { _: paramValues, ...optionValues } = minimist(args);
22
- this.command = command;
23
- this.parseSignature(signatureParams);
24
- this.parseDefaultOptions();
25
- this.handleArguments(paramValues);
26
- this.handleOptions(optionValues);
27
- }
28
- option(name) {
29
- if (!this.optionSignatures[name]) {
30
- throw new MissingSignatureOption(name, Object.values(this.optionSignatures));
31
- }
32
- return this.options[name];
33
- }
34
- setOption(name, value) {
35
- if (!this.optionSignatures[name]) {
36
- throw new MissingSignatureOption(name, Object.values(this.optionSignatures));
37
- }
38
- this.options[name] = value;
39
- }
40
- optionHelp(name) {
41
- const optionSignature = this.optionSignatures[name];
42
- if (!optionSignature) {
43
- throw new MissingSignatureOption(name, Object.values(this.optionSignatures));
44
- }
45
- return this.optionSignatures[name].help;
46
- }
47
- argument(name) {
48
- if (!this.argumentsSignature[name]) {
49
- throw new MissingSignatureArgument(name, Object.values(this.argumentsSignature));
50
- }
51
- return this.arguments[name];
52
- }
53
- setArgument(name, value) {
54
- if (!this.argumentsSignature[name]) {
55
- throw new MissingSignatureArgument(name, Object.values(this.argumentsSignature));
56
- }
57
- this.arguments[name] = value;
58
- }
59
- argumentHelp(name) {
60
- const argumentSignature = this.argumentsSignature[name];
61
- if (!argumentSignature) {
62
- throw new MissingSignatureArgument(name, Object.values(this.argumentsSignature));
63
- }
64
- return this.argumentsSignature[name].help;
65
- }
66
- getArgumentSignatures() {
67
- return this.argumentsSignature;
68
- }
69
- getOptionSignatures() {
70
- return this.optionSignatures;
71
- }
72
- getParamValue(value, signature) {
73
- if (signature.type === 'boolean') {
74
- if (value === 'true' || value === '1') {
75
- return true;
76
- }
77
- else if (value === 'false' || value === '0') {
78
- return false;
79
- }
80
- return Boolean(value);
81
- }
82
- if (signature.type === 'array') {
83
- if (!value) {
84
- return [];
85
- }
86
- return Array.isArray(value) ? value : [value];
87
- }
88
- return value ?? signature.defaultValue;
89
- }
90
- handleArguments(paramValues) {
91
- for (const [argument, value] of Object.entries(this.arguments)) {
92
- const argSignature = this.argumentsSignature[argument];
93
- if (argSignature.variadic) {
94
- this.arguments[argument] = paramValues;
95
- }
96
- else {
97
- const paramValue = paramValues.shift();
98
- this.arguments[argument] = this.getParamValue(paramValue, argSignature);
99
- }
100
- }
101
- }
102
- handleOptions(optionValues) {
103
- for (const [option, value] of Object.entries(optionValues)) {
104
- const optionAlias = this.optionAliases[option];
105
- const optionSignature = this.optionSignatures[option] ?? this.optionSignatures[optionAlias];
106
- if (!optionSignature) {
107
- throw new InvalidOption(option, Object.values(this.optionSignatures));
108
- }
109
- this.options[option] = this.getParamValue(value, optionSignature);
110
- for (const alias of optionSignature.alias ?? []) {
111
- if (optionValues[alias]) {
112
- this.options[optionSignature.name] = optionValues[alias];
113
- }
114
- }
115
- }
116
- }
117
- parseSignature(params) {
118
- for (const paramSignature of params) {
119
- const param = this.parseParamSignature(paramSignature);
120
- if (param.isOption) {
121
- this.options[param.name] = param.defaultValue ?? null;
122
- this.optionSignatures[param.name] = param;
123
- for (const alias of param.alias ?? []) {
124
- this.optionAliases[alias] = param.name;
125
- }
126
- }
127
- else {
128
- this.arguments[param.name] = param.defaultValue ?? null;
129
- this.argumentsSignature[param.name] = param;
130
- }
131
- }
132
- }
133
- parseDefaultOptions() {
134
- if (this.defaultCommandOptions.length) {
135
- for (const option of this.defaultCommandOptions) {
136
- this.optionSignatures[option.option] = {
137
- name: option.option,
138
- type: option.defaultValue == null ? 'string' : typeof option.defaultValue,
139
- optional: true,
140
- alias: option.alias,
141
- variadic: false,
142
- help: option.description,
143
- defaultValue: option.defaultValue ?? null,
144
- isOption: true
145
- };
146
- this.options[option.option] = option.defaultValue;
147
- if (option.alias) {
148
- for (const alias of option.alias) {
149
- this.optionAliases[alias] = option.option;
150
- }
151
- }
152
- }
153
- }
154
- }
155
- parseParamSignature(argument) {
156
- const arg = {
157
- name: argument,
158
- optional: false,
159
- type: 'string',
160
- help: undefined,
161
- defaultValue: null,
162
- variadic: false,
163
- isOption: false
164
- };
165
- if (arg.name.includes(':')) {
166
- const [name, help] = arg.name.split(':');
167
- arg.name = name.trim();
168
- arg.help = help.trim();
169
- }
170
- if (arg.name.includes('=')) {
171
- const [name, defaultValue] = arg.name.split('=');
172
- arg.name = name.trim();
173
- arg.defaultValue = defaultValue.trim();
174
- arg.optional = true;
175
- if (!arg.defaultValue.length) {
176
- arg.defaultValue = null;
177
- }
178
- else if (arg.defaultValue === 'true') {
179
- arg.defaultValue = true;
180
- arg.type = 'boolean';
181
- }
182
- else if (arg.defaultValue === 'false') {
183
- arg.defaultValue = false;
184
- arg.type = 'boolean';
185
- }
186
- }
187
- else {
188
- if (arg.name.startsWith('--')) {
189
- arg.optional = true;
190
- arg.defaultValue = false;
191
- arg.type = 'boolean';
192
- }
193
- }
194
- if (arg.name.includes('|')) {
195
- const [name, ...alias] = arg.name.split('|');
196
- arg.name = name.trim();
197
- arg.alias = alias.map(a => a.trim());
198
- }
199
- if (arg.name.startsWith('--')) {
200
- arg.isOption = true;
201
- arg.name = arg.name.slice(2);
202
- }
203
- if (arg.defaultValue === '*') {
204
- arg.defaultValue = [];
205
- arg.type = 'array';
206
- }
207
- if (arg.name.endsWith('?')) {
208
- arg.optional = true;
209
- arg.name = arg.name.slice(0, -1);
210
- }
211
- if (arg.name.endsWith('*')) {
212
- arg.type = 'array';
213
- arg.variadic = true;
214
- arg.defaultValue = [];
215
- arg.name = arg.name.slice(0, -1);
216
- }
217
- arg.help = arg.help ?? this.helperDefinitions[arg.name] ?? this.helperDefinitions[`--${arg.name}`];
218
- return arg;
219
- }
220
- validate() {
221
- // validate arguments
222
- for (const [argument, value] of Object.entries(this.arguments)) {
223
- const argSignature = this.argumentsSignature[argument];
224
- if (!value && !argSignature.optional) {
225
- throw new MissingRequiredArgumentValue(argSignature);
226
- }
227
- if (!value?.length && argSignature.variadic && !argSignature.optional) {
228
- throw new MissingRequiredArgumentValue(argSignature);
229
- }
230
- }
231
- }
232
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,175 +0,0 @@
1
- import { CommandParser } from './CommandParser.js';
2
- import { MissingRequiredArgumentValue } from "./errors/MissingRequiredArgumentValue.js";
3
- class TestCommandOptions {
4
- option = 'testOption';
5
- description = 'Test option';
6
- defaultValue = 'default';
7
- alias = ['t'];
8
- async handler() {
9
- return 0;
10
- }
11
- }
12
- describe('CommandParser', () => {
13
- let commandParser;
14
- const parseCommand = (signature, args, helperDefinition = {}, defaultCommandOptions = []) => {
15
- return new CommandParser(signature, helperDefinition, defaultCommandOptions, ...args);
16
- };
17
- it('should parse signature without arguments & options', () => {
18
- commandParser = parseCommand('test', []);
19
- expect(commandParser.command).toBe('test');
20
- });
21
- describe('Arguments', () => {
22
- it('should parse signature with arguments', () => {
23
- commandParser = parseCommand('test {arg1} {arg2}', ['value1', 'value2']);
24
- expect(commandParser.argument('arg1')).toBe('value1');
25
- expect(commandParser.argument('arg2')).toBe('value2');
26
- });
27
- it('should parse signature with optional arguments', () => {
28
- commandParser = parseCommand('test {arg1?} {arg2?}', ['value1']);
29
- expect(commandParser.argument('arg1')).toBe('value1');
30
- expect(commandParser.argument('arg2')).toBeNull();
31
- });
32
- it('should parse signature with optional arguments with default value', () => {
33
- commandParser = parseCommand('test {arg1?} {arg2=defaultValue1}', ['value1']);
34
- expect(commandParser.argument('arg1')).toBe('value1');
35
- expect(commandParser.argument('arg2')).toBe('defaultValue1');
36
- });
37
- it('should parse signature with variadic arguments', () => {
38
- commandParser = parseCommand('test {arg1*}', ['value1', 'value2']);
39
- expect(commandParser.argument('arg1')).toEqual(['value1', 'value2']);
40
- });
41
- it('should parse signature with optional variadic arguments', () => {
42
- commandParser = parseCommand('test {arg1*?}', ['value1', 'value2']);
43
- expect(commandParser.argument('arg1')).toEqual(['value1', 'value2']);
44
- });
45
- it('should parse signature with optional variadic arguments without value', () => {
46
- commandParser = parseCommand('test {arg1*?}', []);
47
- expect(commandParser.argument('arg1')).toEqual([]);
48
- });
49
- it('should set argument value', () => {
50
- commandParser = parseCommand('test {arg1}', ['value1']);
51
- commandParser.setArgument('arg1', 'newValue');
52
- expect(commandParser.argument('arg1')).toBe('newValue');
53
- });
54
- it('should throw error when argument is missing with setArgument', () => {
55
- commandParser = parseCommand('test {arg1}', []);
56
- expect(() => commandParser.setArgument('arg2', 'newValue')).toThrowError(Error);
57
- });
58
- it('calling validate method should throw error when argument is missing', () => {
59
- commandParser = parseCommand('test {arg1}', []);
60
- expect(() => commandParser.validate()).toThrowError(MissingRequiredArgumentValue);
61
- });
62
- it('calling validate should throw with variadic argument is missing', () => {
63
- commandParser = parseCommand('test {arg1*}', []);
64
- expect(() => commandParser.validate()).toThrowError(MissingRequiredArgumentValue);
65
- });
66
- });
67
- describe('Options', () => {
68
- it('boolean option should be false when not provided', () => {
69
- commandParser = parseCommand('test {--option}', []);
70
- expect(commandParser.option('option')).toBeFalsy();
71
- });
72
- it('boolean option should be true when provided', () => {
73
- commandParser = parseCommand('test {--option}', ['--option']);
74
- expect(commandParser.option('option')).toBeTruthy();
75
- });
76
- it('boolean option should be true when provided with value', () => {
77
- commandParser = parseCommand('test {--option}', ['--option=true']);
78
- expect(commandParser.option('option')).toBeTruthy();
79
- });
80
- it('boolean option should be false when provided with value', () => {
81
- commandParser = parseCommand('test {--option}', ['--option=false']);
82
- expect(commandParser.option('option')).toBeFalsy();
83
- });
84
- it('string option should be null when not provided', () => {
85
- commandParser = parseCommand('test {--option=}', []);
86
- expect(commandParser.option('option')).toBeNull();
87
- });
88
- it('string option should be value when provided', () => {
89
- commandParser = parseCommand('test {--option=}', ['--option=value']);
90
- expect(commandParser.option('option')).toBe('value');
91
- });
92
- it('string option should take the default value when not provided', () => {
93
- commandParser = parseCommand('test {--option=default}', []);
94
- expect(commandParser.option('option')).toBe('default');
95
- });
96
- it('string option should take the provided value with default value', () => {
97
- commandParser = parseCommand('test {--option=default}', ['--option=value']);
98
- expect(commandParser.option('option')).toBe('value');
99
- });
100
- it('array option should be empty when not provided', () => {
101
- commandParser = parseCommand('test {--option=*}', []);
102
- expect(commandParser.option('option')).toEqual([]);
103
- });
104
- it('array option should be value when provided', () => {
105
- commandParser = parseCommand('test {--option=*}', ['--option=value1', '--option=value2']);
106
- expect(commandParser.option('option')).toEqual(['value1', 'value2']);
107
- });
108
- });
109
- describe('Mixed', () => {
110
- it('should parse signature with arguments and options', () => {
111
- commandParser = parseCommand('test {arg1} {arg2} {--option}', ['value1', 'value2', '--option']);
112
- expect(commandParser.argument('arg1')).toBe('value1');
113
- expect(commandParser.argument('arg2')).toBe('value2');
114
- expect(commandParser.option('option')).toBeTruthy();
115
- });
116
- it('should parse signature with optional arguments and options', () => {
117
- commandParser = parseCommand('test {arg1?} {arg2?} {--option}', ['value1', '--option']);
118
- expect(commandParser.argument('arg1')).toBe('value1');
119
- expect(commandParser.argument('arg2')).toBeNull();
120
- expect(commandParser.option('option')).toBeTruthy();
121
- });
122
- });
123
- describe('Helper', () => {
124
- it('should parse help signature', () => {
125
- commandParser = parseCommand('test {arg1} {arg2:help 1} {--option : option help 2 }', ['value1', 'value2', '--option']);
126
- expect(commandParser.argumentHelp('arg1')).toBeUndefined();
127
- expect(commandParser.argumentHelp('arg2')).toBe('help 1');
128
- expect(commandParser.optionHelp('option')).toBe('option help 2');
129
- });
130
- it('should define help with helperDefinition', () => {
131
- commandParser = parseCommand('test {arg1} {arg2} {--option} {--option2}', ['value1', 'value2', '--option'], {
132
- arg1: 'arg1 help',
133
- arg2: 'arg2 help',
134
- '--option': 'option help'
135
- });
136
- expect(commandParser.argumentHelp('arg1')).toBe('arg1 help');
137
- expect(commandParser.argumentHelp('arg2')).toBe('arg2 help');
138
- expect(commandParser.optionHelp('option')).toBe('option help');
139
- expect(commandParser.optionHelp('option2')).toBeUndefined();
140
- });
141
- it('should define help with helperDefinition with default value', () => {
142
- commandParser = parseCommand('test {arg1:arg1 help} {arg2} {--option=default}', ['value1', 'value2'], {
143
- arg2: 'arg2 help',
144
- '--option': 'option help'
145
- });
146
- expect(commandParser.argumentHelp('arg1')).toBe('arg1 help');
147
- expect(commandParser.argumentHelp('arg2')).toBe('arg2 help');
148
- expect(commandParser.optionHelp('option')).toBe('option help');
149
- });
150
- });
151
- describe('DefaultCommandOptions', () => {
152
- it('should parse default command options', () => {
153
- commandParser = parseCommand('test', [], {}, [new TestCommandOptions()]);
154
- expect(commandParser.option('testOption')).toBe('default');
155
- });
156
- it('should parse default command options with provided value', () => {
157
- commandParser = parseCommand('test', ['--testOption=value'], {}, [new TestCommandOptions()]);
158
- expect(commandParser.option('testOption')).toBe('value');
159
- });
160
- it('should parse default command options with provided value with alias', () => {
161
- commandParser = parseCommand('test', ['-t=value'], {}, [new TestCommandOptions()]);
162
- expect(commandParser.option('testOption')).toBe('value');
163
- });
164
- it('should parse default command option help', () => {
165
- commandParser = parseCommand('test', [], {}, [new TestCommandOptions()]);
166
- expect(commandParser.optionHelp('testOption')).toBe('Test option');
167
- });
168
- it('should handle null default value', () => {
169
- const option = new TestCommandOptions();
170
- option.defaultValue = null;
171
- commandParser = parseCommand('test', ['--testOption=value'], {}, [option]);
172
- expect(commandParser.option('testOption')).toBe('value');
173
- });
174
- });
175
- });
@@ -1,17 +0,0 @@
1
- import { Command } from "./Command.js";
2
- export type CommandResolver = (path: string) => Promise<Command>;
3
- export declare class CommandRegistry {
4
- private readonly commands;
5
- get commandSuffix(): string;
6
- constructor();
7
- getAvailableCommands(): string[];
8
- getCommands(): Command[];
9
- private commandResolver;
10
- setCommandResolver(resolver: (path: string) => Promise<Command>): void;
11
- registerCommand(command: Command, force?: boolean): void;
12
- loadCommandsPath(commandsPath: string): Promise<void>;
13
- runCommand(ctx: any, command: string | Command, ...args: any[]): Promise<number>;
14
- private suggestCommand;
15
- private askRunSimilarCommand;
16
- private listCommandsFiles;
17
- }
@@ -1,109 +0,0 @@
1
- import * as fs from "node:fs";
2
- import path from "path";
3
- import * as SS from "string-similarity";
4
- import chalk from "chalk";
5
- import { CommandNotFoundError } from "./errors/CommandNotFoundError.js";
6
- export class CommandRegistry {
7
- commands = {};
8
- get commandSuffix() {
9
- return "Command";
10
- }
11
- constructor() { }
12
- getAvailableCommands() {
13
- return Object.keys(this.commands);
14
- }
15
- getCommands() {
16
- return Object.values(this.commands);
17
- }
18
- commandResolver = async (path) => {
19
- const CommandClass = (await import(path)).default;
20
- let command;
21
- if (CommandClass?.default) {
22
- command = new CommandClass.default();
23
- }
24
- else {
25
- command = new CommandClass();
26
- }
27
- return command;
28
- };
29
- setCommandResolver(resolver) {
30
- this.commandResolver = resolver;
31
- }
32
- registerCommand(command, force = false) {
33
- const commandName = command.signature.split(' ')[0];
34
- if (!commandName) {
35
- throw new Error('Command signature is invalid, it must have a command name.');
36
- }
37
- if (!force && this.commands[commandName]) {
38
- throw new Error(`Command ${commandName} already registered.`);
39
- }
40
- this.commands[commandName] = command;
41
- }
42
- async loadCommandsPath(commandsPath) {
43
- for await (const file of this.listCommandsFiles(commandsPath)) {
44
- try {
45
- const command = await this.commandResolver(file);
46
- this.registerCommand(command);
47
- }
48
- catch (e) {
49
- throw new Error(`Command ${file} failed to load. ${e}`);
50
- }
51
- }
52
- }
53
- async runCommand(ctx, command, ...args) {
54
- const commandToRun = typeof command === 'string' ? this.commands[command] : command;
55
- const commandSignature = typeof command === 'string' ? command : commandToRun.command;
56
- if (!commandToRun) {
57
- const suggestedCommand = await this.suggestCommand(commandSignature);
58
- if (suggestedCommand) {
59
- return await this.runCommand(ctx, suggestedCommand, ...args);
60
- }
61
- return 1;
62
- }
63
- return await commandToRun.run(ctx, ...args);
64
- }
65
- async suggestCommand(command) {
66
- const availableCommands = this.getAvailableCommands();
67
- const { bestMatch, bestMatchIndex, ratings } = SS.findBestMatch(command, availableCommands);
68
- const similarCommands = ratings.filter(r => r.rating > 0.3).map(r => r.target);
69
- if ((bestMatch.rating > 0 && similarCommands.length <= 1) || (bestMatch.rating > 0.7 && similarCommands.length > 1)) {
70
- const commandToAsk = availableCommands[bestMatchIndex];
71
- const runCommand = await this.askRunSimilarCommand(command, commandToAsk);
72
- if (runCommand) {
73
- return commandToAsk;
74
- }
75
- else {
76
- return null;
77
- }
78
- }
79
- throw new CommandNotFoundError(command, similarCommands);
80
- }
81
- async askRunSimilarCommand(command, commandToAsk) {
82
- const readline = require('readline').createInterface({
83
- input: process.stdin,
84
- output: process.stdout
85
- });
86
- console.log(chalk ` {bgRed ERROR } Command {yellow ${command}} not found.\n`);
87
- return new Promise((resolve) => {
88
- readline.question(chalk `{green Do you want to run {yellow ${commandToAsk}} instead?} {white (yes/no)} [{yellow no}]\n > `, (answer) => {
89
- resolve(answer === 'yes' || answer === 'y');
90
- readline.close();
91
- });
92
- });
93
- }
94
- async *listCommandsFiles(basePath) {
95
- const dirEntry = fs.readdirSync(basePath, { withFileTypes: true });
96
- for (const dirent of dirEntry) {
97
- const direntPath = path.resolve(basePath, dirent.name);
98
- if (dirent.isDirectory()) {
99
- yield* this.listCommandsFiles(path.resolve(basePath, dirent.name));
100
- }
101
- else {
102
- if (!direntPath.endsWith(`${this.commandSuffix}.ts`) && !direntPath.endsWith(`${this.commandSuffix}.js`)) {
103
- continue;
104
- }
105
- yield direntPath;
106
- }
107
- }
108
- }
109
- }
@@ -1,4 +0,0 @@
1
- import { BobError } from "./errors/index.js";
2
- export declare class ExceptionHandler {
3
- handle(err: Error | BobError): number;
4
- }
@@ -1,10 +0,0 @@
1
- import { BobError } from "./errors/index.js";
2
- export class ExceptionHandler {
3
- handle(err) {
4
- if (err instanceof BobError) {
5
- err.pretty();
6
- return -1;
7
- }
8
- throw err;
9
- }
10
- }
@@ -1,51 +0,0 @@
1
- import chalk from "chalk";
2
- import { Command } from "../Command.js";
3
- import { generateSpace } from "../lib/string.js";
4
- export default class HelpCommand extends Command {
5
- opts;
6
- signature = 'help';
7
- description = 'Show help';
8
- constructor(opts) {
9
- super();
10
- this.opts = opts;
11
- }
12
- async handle() {
13
- const commands = this.opts.commandRegistry.getCommands();
14
- const cliName = this.opts.cliName ?? 'Bob CLI';
15
- const version = this.opts.cliVersion ?? '0.0.0';
16
- const coreVersion = (await import('../../package.json'))?.default?.version ?? '0.0.0';
17
- console.log(chalk `${cliName} {green ${version}} (core: {yellow ${coreVersion}})
18
-
19
- {yellow Usage}:
20
- command [options] [arguments]
21
-
22
- {yellow Available commands}:
23
- `);
24
- const maxCommandLength = Math.max(...commands.map(command => command.command.length)) ?? 0;
25
- const commandByGroups = {};
26
- for (const command of commands) {
27
- const commandGroup = command.command.split(':')[0];
28
- if (!commandByGroups[commandGroup]) {
29
- commandByGroups[commandGroup] = [];
30
- }
31
- commandByGroups[commandGroup].push(command);
32
- }
33
- const sortedCommandsByGroups = Object.entries(commandByGroups)
34
- .sort(([groupA], [groupB]) => groupA.toLowerCase().localeCompare(groupB.toLowerCase()))
35
- .sort(([, commandsA], [, commandsB]) => commandsA.length - commandsB.length);
36
- for (const [group, groupCommands] of sortedCommandsByGroups) {
37
- const isGrouped = groupCommands.length > 1;
38
- if (isGrouped) {
39
- console.log(chalk `{yellow ${group}}:`);
40
- }
41
- const sortedGroupCommands = groupCommands.sort((a, b) => a.command.toLowerCase().localeCompare(b.command.toLowerCase()));
42
- for (const command of sortedGroupCommands) {
43
- let spaces = generateSpace(maxCommandLength - command.command.length);
44
- if (isGrouped) {
45
- spaces = spaces.slice(2);
46
- }
47
- console.log(chalk `${isGrouped ? ' ' : ''}{green ${command.command}} ${spaces} ${command.description}`);
48
- }
49
- }
50
- }
51
- }
@@ -1,7 +0,0 @@
1
- export interface CommandOption<C> {
2
- option: string;
3
- alias?: string[];
4
- defaultValue: string | boolean | Array<string> | null;
5
- description?: string;
6
- handler(this: C): Promise<number | void>;
7
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export * from './CommandOption.js';
@@ -1 +0,0 @@
1
- export * from './CommandOption.js';
@@ -1,29 +0,0 @@
1
- import chalk from "chalk";
2
- import { BobError } from "../errors/BobError.js";
3
- export class BadCommandOption extends BobError {
4
- param;
5
- constructor(param) {
6
- let message = `Option "${param.option}" value is invalid.`;
7
- if (param.reason) {
8
- message += ` Reason: ${param.reason}`;
9
- }
10
- else {
11
- message += ` Value: "${param.value}"`;
12
- }
13
- super(message);
14
- this.param = param;
15
- }
16
- pretty() {
17
- const log = console.log;
18
- log(chalk ` {white.bgRed ERROR } Option {bold.yellow ${this.param.option}} value is invalid. `);
19
- if (this.param.value || this.param.reason) {
20
- log('');
21
- }
22
- if (this.param.value) {
23
- log(chalk ` {blue Value}: ${this.param.value}`);
24
- }
25
- if (this.param.reason) {
26
- log(chalk ` {yellow Reason}: ${this.param.reason}`);
27
- }
28
- }
29
- }
@@ -1,11 +0,0 @@
1
- import { BobError } from "../errors/BobError.js";
2
- export type ParameterProps = {
3
- param: string;
4
- value?: string;
5
- reason?: string;
6
- };
7
- export declare class BadCommandParameter extends BobError {
8
- readonly param: ParameterProps;
9
- constructor(param: ParameterProps);
10
- pretty(): void;
11
- }