@travetto/cli 8.0.0-alpha.10 → 8.0.0-alpha.12

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
@@ -75,12 +75,12 @@ export class BasicCommand {
75
75
 
76
76
  **Terminal: Basic Command Help**
77
77
  ```bash
78
- $ trv basic -h
78
+ $ trv basic --help
79
79
 
80
80
  Usage: basic [options]
81
81
 
82
82
  Options:
83
- -h, --help display help for command
83
+ --help display help for command
84
84
  ```
85
85
 
86
86
  ## Command Naming
@@ -113,13 +113,13 @@ export class BasicCommand {
113
113
 
114
114
  **Terminal: Basic Command with Flag Help**
115
115
  ```bash
116
- $ trv basic:flag -h
116
+ $ trv basic:flag --help
117
117
 
118
118
  Usage: basic:flag [options]
119
119
 
120
120
  Options:
121
121
  -l, --loud
122
- -h, --help display help for command
122
+ --help display help for command
123
123
  ```
124
124
 
125
125
  As you can see the command now has the support of a basic boolean flag to determine if the response should be loud or not. The default value here is undefined/false, and so is an opt-in experience.
@@ -158,12 +158,12 @@ export class BasicCommand {
158
158
 
159
159
  **Terminal: Basic Command**
160
160
  ```bash
161
- $ trv basic:arg -h
161
+ $ trv basic:arg --help
162
162
 
163
163
  Usage: basic:arg [options] [volume:number]
164
164
 
165
165
  Options:
166
- -h, --help display help for command
166
+ --help display help for command
167
167
  ```
168
168
 
169
169
  **Terminal: Basic Command with Invalid Loud Arg**
@@ -176,7 +176,7 @@ Execution failed:
176
176
  Usage: basic:arg [options] [volume:number]
177
177
 
178
178
  Options:
179
- -h, --help display help for command
179
+ --help display help for command
180
180
  ```
181
181
 
182
182
  **Terminal: Basic Command with Loud Arg > 7**
@@ -213,13 +213,13 @@ export class BasicCommand {
213
213
 
214
214
  **Terminal: Basic Command**
215
215
  ```bash
216
- $ trv basic:arg-list -h
216
+ $ trv basic:arg-list --help
217
217
 
218
218
  Usage: basic:arg-list [options] <volumes...:number>
219
219
 
220
220
  Options:
221
221
  -r, --reverse
222
- -h, --help display help for command
222
+ --help display help for command
223
223
  ```
224
224
 
225
225
  **Terminal: Basic Arg List**
@@ -240,7 +240,7 @@ Usage: basic:arg-list [options] <volumes...:number>
240
240
 
241
241
  Options:
242
242
  -r, --reverse
243
- -h, --help display help for command
243
+ --help display help for command
244
244
  ```
245
245
 
246
246
  **Terminal: Basic Arg List with Reverse**
@@ -279,13 +279,13 @@ export class CustomCommand {
279
279
 
280
280
  **Terminal: Custom Command Help**
281
281
  ```bash
282
- $ trv custom:arg -h
282
+ $ trv custom:arg --help
283
283
 
284
284
  Usage: custom:arg [options] [volume:number]
285
285
 
286
286
  Options:
287
287
  -m, --message <string> The message to send back to the user (default: "hello")
288
- -h, --help display help for command
288
+ --help display help for command
289
289
  ```
290
290
 
291
291
  **Terminal: Custom Command Help with overridden Text**
@@ -330,13 +330,13 @@ export class CustomCommand {
330
330
 
331
331
  **Terminal: Custom Command Help**
332
332
  ```bash
333
- $ trv custom:env-arg -h
333
+ $ trv custom:env-arg --help
334
334
 
335
335
  Usage: custom:env-arg [options] [volume:number]
336
336
 
337
337
  Options:
338
338
  -t, --text <string> The message to send back to the user (default: "hello")
339
- -h, --help display help for command
339
+ --help display help for command
340
340
  ```
341
341
 
342
342
  **Terminal: Custom Command Help with default Text**
@@ -559,7 +559,7 @@ Usage: service [options] <action:restart|start|status|stop> [services...:string]
559
559
 
560
560
  Options:
561
561
  -q, --quiet (default: false)
562
- -h, --help display help for command
562
+ --help display help for command
563
563
 
564
564
  Available Services
565
565
  --------------------
package/bin/trv.js CHANGED
@@ -3,4 +3,4 @@
3
3
  import '@travetto/runtime/support/patch.js';
4
4
  import '@travetto/compiler/bin/hook.js';
5
5
  const { invoke } = await import('@travetto/compiler/support/invoke.ts');
6
- await invoke('exec', ['@travetto/cli/support/entry.trv.ts', ...process.argv.slice(2)]);
6
+ await invoke('exec', '@travetto/cli/support/entry.trv.ts', ...process.argv.slice(2));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/cli",
3
- "version": "8.0.0-alpha.10",
3
+ "version": "8.0.0-alpha.12",
4
4
  "type": "module",
5
5
  "description": "CLI infrastructure for Travetto framework",
6
6
  "keywords": [
@@ -29,8 +29,8 @@
29
29
  "directory": "module/cli"
30
30
  },
31
31
  "dependencies": {
32
- "@travetto/schema": "^8.0.0-alpha.5",
33
- "@travetto/terminal": "^8.0.0-alpha.5"
32
+ "@travetto/schema": "^8.0.0-alpha.7",
33
+ "@travetto/terminal": "^8.0.0-alpha.7"
34
34
  },
35
35
  "travetto": {
36
36
  "displayName": "Command Line Interface",
package/src/help.ts CHANGED
@@ -4,32 +4,29 @@ import { castKey, getClass, JSONUtil, Runtime } from '@travetto/runtime';
4
4
  import { SchemaRegistryIndex, ValidationResultError } from '@travetto/schema';
5
5
 
6
6
  import { cliTpl } from './color.ts';
7
- import type { CliCommandShape } from './types.ts';
7
+ import { HELP_FLAG, type CliCommandShape } from './types.ts';
8
8
  import { CliCommandRegistryIndex, UNKNOWN_COMMAND } from './registry/registry-index.ts';
9
9
  import { CliSchemaExportUtil } from './schema-export.ts';
10
10
 
11
- const validationSourceMap: Record<string, string> = {
12
- arg: 'Argument',
13
- flag: 'Flag'
14
- };
11
+ const validationSourceMap: Record<string, string> = { arg: 'Argument', flag: 'Flag' };
15
12
 
16
13
  const ifDefined = <T>(value: T | null | '' | undefined): T | undefined =>
17
14
  (value === null || value === '' || value === undefined) ? undefined : value;
18
15
 
19
- const toItem = (name: string, pkg: string, prod?: boolean) => [name, Runtime.getInstallCommand(pkg, prod)] as const;
20
-
21
- const INSTALL_COMMANDS = new Map<string, string>([
22
- ...['test', 'test:watch', 'test:direct'].map(item => toItem(item, '@travetto/test')),
23
- ...['lint', 'lint:register', 'eslint', 'eslint:register'].map(item => toItem(item, '@travetto/eslint')),
24
- ...['model:install', 'model:export'].map(item => toItem(item, '@travetto/model', true)),
25
- ...['openapi:spec', 'openapi:client'].map(item => toItem(item, '@travetto/openapi', true)),
26
- ...['email:compile', 'email:test', 'email:editor'].map(item => toItem(item, '@travetto/email-compiler')),
27
- ...['pack', 'pack:zip', 'pack:docker'].map(item => toItem(item, '@travetto/pack')),
28
- ...['repo:publish', 'repo:version', 'repo:exec', 'repo:list', 'repo:version-sync'].map(item => toItem(item, '@travetto/repo')),
29
- toItem('web:http', '@travetto/web-http', true),
30
- toItem('doc', '@travetto/doc'),
31
- toItem('web:rpc-client', '@travetto/web-rpc', true),
32
- ]);
16
+ const MODULE_TO_COMMAND = {
17
+ '@travetto/doc': ['doc'],
18
+ '@travetto/email-compiler': ['email:compile', 'email:test', 'email:editor'],
19
+ '@travetto/eslint': ['eslint', 'eslint:register', 'lint', 'lint:register'],
20
+ '@travetto/model': ['model:install', 'model:export'],
21
+ '@travetto/openapi': ['openapi:spec', 'openapi:client'],
22
+ '@travetto/pack': ['pack', 'pack:zip', 'pack:docker'],
23
+ '@travetto/repo': ['repo:publish', 'repo:version', 'repo:exec', 'repo:list'],
24
+ '@travetto/test': ['test', 'test:watch', 'test:direct'],
25
+ '@travetto/web-http': ['web:http'],
26
+ '@travetto/web-rpc': ['web:rpc-client'],
27
+ };
28
+
29
+ const COMMAND_TO_MODULE = Object.fromEntries(Object.entries(MODULE_TO_COMMAND).flatMap(([k, v]) => v.map(sv => [sv, k])));
33
30
 
34
31
  /**
35
32
  * Utilities for showing help
@@ -37,15 +34,15 @@ const INSTALL_COMMANDS = new Map<string, string>([
37
34
  export class HelpUtil {
38
35
 
39
36
  /** Render the unknown command message */
40
- static renderUnknownCommandMessage(cmd: string): string {
41
- const install = INSTALL_COMMANDS.get(cmd);
42
- if (install) {
37
+ static renderUnknownCommandMessage(command: string): string {
38
+ const module = COMMAND_TO_MODULE[command];
39
+ if (module) {
43
40
  return cliTpl`
44
- ${{ title: 'Missing Package' }}\n${'-'.repeat(20)}\nTo use ${{ input: cmd }} please run:\n
45
- ${{ identifier: install }}
41
+ ${{ title: 'Missing Package' }}\n${'-'.repeat(20)}\nTo use ${{ input: command }} please run:\n
42
+ ${{ identifier: Runtime.getInstallCommand(module) }}
46
43
  `;
47
44
  } else {
48
- return cliTpl`${{ subtitle: 'Unknown command' }}: ${{ input: cmd }}`;
45
+ return cliTpl`${{ subtitle: 'Unknown command' }}: ${{ input: command }}`;
49
46
  }
50
47
  }
51
48
 
@@ -58,25 +55,24 @@ ${{ identifier: install }}
58
55
  const { name: commandName } = CliCommandRegistryIndex.get(getClass(command));
59
56
  const args = schema.methods.main?.parameters ?? [];
60
57
 
61
- // Ensure finalized
58
+ const usage = [cliTpl`${{ title: 'Usage:' }} ${{ param: commandName }} ${{ input: '[options]' }}`,];
59
+ const params: string[] = [];
60
+ const descriptions: string[] = [];
62
61
 
63
- const usage: string[] = [cliTpl`${{ title: 'Usage:' }} ${{ param: commandName }} ${{ input: '[options]' }}`,];
62
+ // Ensure finalized
64
63
  for (const field of args) {
65
64
  const type = field.type === String && field.enum && field.enum?.values.length <= 7 ? field.enum?.values?.join('|') : field.type.name.toLowerCase();
66
65
  const arg = `${field.name}${field.array ? '...' : ''}:${type}`;
67
66
  usage.push(cliTpl`${{ input: field.required?.active !== false ? `<${arg}>` : `[${arg}]` }}`);
68
67
  }
69
68
 
70
- const params: string[] = [];
71
- const descriptions: string[] = [];
72
-
73
69
  for (const field of Object.values(schema.fields)) {
74
70
  const key = castKey<CliCommandShape>(field.name);
75
71
  const defaultValue = ifDefined(command[key]) ?? ifDefined(field.default);
76
72
  const aliases = (field.aliases ?? [])
77
73
  .filter(flag => flag.startsWith('-'))
78
74
  .filter(flag =>
79
- (field.type !== Boolean) || ((defaultValue !== true || field.name === 'help') ? !flag.startsWith('--no-') : flag.startsWith('--'))
75
+ (field.type !== Boolean) || (defaultValue !== true ? !flag.startsWith('--no-') : flag.startsWith('--'))
80
76
  );
81
77
  let type: string | undefined;
82
78
 
@@ -86,29 +82,33 @@ ${{ identifier: install }}
86
82
  ({ type } = CliSchemaExportUtil.baseInputType(field));
87
83
  }
88
84
 
89
- const param = [
85
+ const parameter = [
90
86
  cliTpl`${{ param: aliases.join(', ') }}`,
91
87
  ...(type ? [cliTpl`${{ type: `<${type}>` }}`] : []),
92
88
  ];
93
89
 
94
- params.push(param.join(' '));
95
- const desc = [cliTpl`${{ title: field.description }}`];
90
+ params.push(parameter.join(' '));
91
+ const parts = [cliTpl`${{ title: field.description }}`];
96
92
 
97
- if (key !== 'help' && defaultValue !== undefined) {
98
- desc.push(cliTpl`(default: ${{ input: JSONUtil.toUTF8(defaultValue) }})`);
93
+ if (defaultValue !== undefined) {
94
+ parts.push(cliTpl`(default: ${{ input: JSONUtil.toUTF8(defaultValue) }})`);
99
95
  }
100
- descriptions.push(desc.join(' '));
96
+ descriptions.push(parts.join(' '));
101
97
  }
102
98
 
99
+ params.push(cliTpl`${{ param: HELP_FLAG }}`);
100
+ descriptions.push('display help for command');
101
+
102
+
103
103
  const paramWidths = params.map(item => util.stripVTControlCharacters(item).length);
104
104
  const descWidths = descriptions.map(item => util.stripVTControlCharacters(item).length);
105
105
 
106
106
  const paramWidth = Math.max(...paramWidths);
107
107
  const descWidth = Math.max(...descWidths);
108
108
 
109
- const helpText = await (command.help?.() ?? []);
110
- if (helpText.length && helpText.at(-1) !== '') {
111
- helpText.push('');
109
+ const extendedHelpText = await (command.help?.() ?? []);
110
+ if (extendedHelpText.length && extendedHelpText.at(-1) !== '') {
111
+ extendedHelpText.push('');
112
112
  }
113
113
 
114
114
  return [
@@ -119,7 +119,7 @@ ${{ identifier: install }}
119
119
  ` ${params[i]}${' '.repeat((paramWidth - paramWidths[i]))} ${descriptions[i].padEnd(descWidth)}${' '.repeat((descWidth - descWidths[i]))}`
120
120
  ),
121
121
  '',
122
- ...helpText
122
+ ...extendedHelpText
123
123
  ].map(line => line.trimEnd()).join('\n');
124
124
  }
125
125
 
package/src/parse.ts CHANGED
@@ -4,13 +4,12 @@ import path from 'node:path';
4
4
  import { Runtime } from '@travetto/runtime';
5
5
  import type { SchemaClassConfig, SchemaFieldConfig, SchemaInputConfig } from '@travetto/schema';
6
6
 
7
- import type { ParsedState } from './types.ts';
7
+ import { HELP_FLAG, type ParsedState } from './types.ts';
8
8
 
9
9
  type ParsedInput = ParsedState['all'][number];
10
10
 
11
11
  const RAW_SEPARATOR = '--';
12
12
  const VALID_FLAG = /^-{1,2}[a-z]/i;
13
- const HELP_FLAG = /^(-h|--help)$/;
14
13
  const LONG_FLAG_WITH_EQ = /^--[a-z][^= ]+=\S+/i;
15
14
  const CONFIG_PREFIX = '+=';
16
15
  const SPACE = new Set([32, 7, 13, 10]);
@@ -124,9 +123,9 @@ export class CliParseUtil {
124
123
  const max = out.includes(RAW_SEPARATOR) ? out.indexOf(RAW_SEPARATOR) : out.length;
125
124
  const valid = out.slice(0, max);
126
125
  const cmd = valid.length > 0 && !valid[0].startsWith('-') ? valid[0] : undefined;
127
- const helpIdx = valid.findIndex(flag => HELP_FLAG.test(flag));
126
+ const help = valid.includes(HELP_FLAG);
128
127
  const args = out.slice(cmd ? 1 : 0);
129
- const result = { cmd, args, help: helpIdx >= 0 };
128
+ const result = { cmd, args, help };
130
129
  return result;
131
130
  }
132
131
 
@@ -29,22 +29,10 @@ export class CliCommandRegistryAdapter implements RegistryAdapter<CliCommandConf
29
29
  this.#cls = cls;
30
30
  }
31
31
 
32
+ // TODO: handle when aliases overlap/conflict
32
33
  finalize(parent?: CliCommandConfig): void {
33
34
  // Add help command
34
35
  const schema = SchemaRegistryIndex.getConfig(this.#cls);
35
-
36
- // Add help to every command
37
- (schema.fields ??= {}).help = {
38
- type: Boolean,
39
- name: 'help',
40
- class: this.#cls,
41
- description: 'display help for command',
42
- required: { active: false },
43
- default: false,
44
- access: 'readonly',
45
- aliases: ['-h', '--help']
46
- };
47
-
48
36
  const used = new Set(Object.values(schema.fields)
49
37
  .flatMap(field => field.aliases ?? [])
50
38
  .filter(alias => !alias.startsWith(ENV_PREFIX))
package/src/types.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import type { Any, Class } from '@travetto/runtime';
2
2
 
3
+ export const HELP_FLAG = '--help';
4
+
3
5
  type OrProm<T> = T | Promise<T>;
4
6
  type ParsedFlag = { type: 'flag', input: string, array?: boolean, fieldName: string, value?: unknown };
5
7
  type ParsedArg = { type: 'arg', input: string, array?: boolean, index: number };