@travetto/cli 7.0.0-rc.5 → 7.0.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/README.md CHANGED
@@ -59,7 +59,7 @@ This module also has a tight integration with the [VSCode plugin](https://market
59
59
  At it's heart, a cli command is the contract defined by what flags, and what arguments the command supports. Within the framework this requires three criteria to be met:
60
60
  * The file must be located in the `support/` folder, and have a name that matches `cli.*.ts`
61
61
  * The file must be a class that has a main method
62
- * The class must use the [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#L85) decorator
62
+ * The class must use the [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#L98) decorator
63
63
 
64
64
  **Code: Basic Command**
65
65
  ```typescript
@@ -94,7 +94,7 @@ Examples of mappings:
94
94
  The pattern is that underscores(_) translate to colons (:), and the `cli.` prefix, and `.ts` suffix are dropped.
95
95
 
96
96
  ## Binding Flags
97
- [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#L85) is a wrapper for [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L19), and so every class that uses the [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#L85) decorator is now a full [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L19) class. The fields of the class represent the flags that are available to the command.
97
+ [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#L98) is a wrapper for [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L19), and so every class that uses the [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#L98) decorator is now a full [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L19) class. The fields of the class represent the flags that are available to the command.
98
98
 
99
99
  **Code: Basic Command with Flag**
100
100
  ```typescript
@@ -131,7 +131,7 @@ $ trv basic:flag --loud
131
131
  HELLO
132
132
  ```
133
133
 
134
- The [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#L85) supports the following data types for flags:
134
+ The [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#L98) supports the following data types for flags:
135
135
  * Boolean values
136
136
  * Number values. The [@Integer](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L166), [@Float](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L173), [@Precision](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L159), [@Min](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L93) and [@Max](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L104) decorators help provide additional validation.
137
137
  * String values. [@MinLength](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L93), [@MaxLength](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L104), [@Match](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L84) and [@Enum](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/input.ts#L58) provide additional constraints
@@ -390,7 +390,7 @@ npx trv call:db --host localhost --port 3306 --username app --password <custom>
390
390
  ```
391
391
 
392
392
  ## VSCode Integration
393
- By default, cli commands do not expose themselves to the VSCode extension, as the majority of them are not intended for that sort of operation. [Web API](https://github.com/travetto/travetto/tree/main/module/web#readme "Declarative support for creating Web Applications") does expose a cli target `web:http` that will show up, to help run/debug a web application. Any command can mark itself as being a run target, and will be eligible for running from within the [VSCode plugin](https://marketplace.visualstudio.com/items?itemName=arcsine.travetto-plugin). This is achieved by setting the `runTarget` field on the [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#L85) decorator. This means the target will be visible within the editor tooling.
393
+ By default, cli commands do not expose themselves to the VSCode extension, as the majority of them are not intended for that sort of operation. [Web API](https://github.com/travetto/travetto/tree/main/module/web#readme "Declarative support for creating Web Applications") does expose a cli target `web:http` that will show up, to help run/debug a web application. Any command can mark itself as being a run target, and will be eligible for running from within the [VSCode plugin](https://marketplace.visualstudio.com/items?itemName=arcsine.travetto-plugin). This is achieved by setting the `runTarget` field on the [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/registry/decorator.ts#L98) decorator. This means the target will be visible within the editor tooling.
394
394
 
395
395
  **Code: Simple Run Target**
396
396
  ```typescript
@@ -472,7 +472,7 @@ import type { WebHttpServer } from '../src/types.ts';
472
472
  /**
473
473
  * Run a web server
474
474
  */
475
- @CliCommand({ runTarget: true, with: { debugIpc: true, restartForDev: true, module: true, env: true } })
475
+ @CliCommand({ runTarget: true, with: { debugIpc: 'optional', restartOnChange: true, module: true, env: true } })
476
476
  export class WebHttpCommand implements CliCommandShape {
477
477
 
478
478
  /** Port to run on */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/cli",
3
- "version": "7.0.0-rc.5",
3
+ "version": "7.0.0",
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": "^7.0.0-rc.5",
33
- "@travetto/terminal": "^7.0.0-rc.5"
32
+ "@travetto/schema": "^7.0.0",
33
+ "@travetto/terminal": "^7.0.0"
34
34
  },
35
35
  "travetto": {
36
36
  "displayName": "Command Line Interface",
@@ -1,4 +1,4 @@
1
- import { Class, ClassInstance, Env, Runtime, RuntimeIndex, describeFunction, getClass } from '@travetto/runtime';
1
+ import { Class, ClassInstance, Env, Runtime, RuntimeIndex, TypedObject, castTo, describeFunction, getClass } from '@travetto/runtime';
2
2
  import { SchemaFieldConfig, SchemaRegistryIndex, ValidationError } from '@travetto/schema';
3
3
 
4
4
  import { CliCommandShape } from '../types.ts';
@@ -18,19 +18,23 @@ type CliCommandConfigOptions = {
18
18
  /** Module to run for */
19
19
  module?: boolean;
20
20
  /** Should debug invocation trigger via ipc */
21
- debugIpc?: boolean;
22
- /** Should restart on code change */
23
- restartForDev?: boolean;
21
+ debugIpc?: boolean | 'optional';
22
+ /** Should restart on source change */
23
+ restartOnChange?: boolean | 'optional';
24
24
  };
25
25
  };
26
26
 
27
- const FIELD_CONFIG: {
28
- name: keyof Exclude<CliCommandConfigOptions['with'], undefined>;
27
+ type WithConfig = Required<Exclude<CliCommandConfigOptions['with'], undefined>>;
28
+ type WithHandler<K extends keyof WithConfig> = (config?: WithConfig[K]) => ({
29
+ name: K;
29
30
  field: Partial<SchemaFieldConfig>;
30
- run: (cmd: Cmd) => (Promise<unknown> | unknown);
31
- }[] =
32
- [
33
- {
31
+ run?: (cmd: Cmd) => (Promise<unknown> | unknown);
32
+ } | undefined)
33
+
34
+ const FIELD_CONFIG: { [K in keyof WithConfig]: WithHandler<K> } = {
35
+ env: (config) => {
36
+ if (!config) return;
37
+ return {
34
38
  name: 'env',
35
39
  run: cmd => Env.TRV_ENV.set(cmd.env || Runtime.env),
36
40
  field: {
@@ -39,10 +43,12 @@ const FIELD_CONFIG: {
39
43
  description: 'Application environment',
40
44
  required: { active: false },
41
45
  },
42
- },
43
- {
46
+ }
47
+ },
48
+ module: (config) => {
49
+ if (!config) return;
50
+ return {
44
51
  name: 'module',
45
- run: (): void => { },
46
52
  field: {
47
53
  type: String,
48
54
  aliases: ['-m', CliParseUtil.toEnvField(Env.TRV_MODULE.key)],
@@ -50,30 +56,37 @@ const FIELD_CONFIG: {
50
56
  specifiers: ['module'],
51
57
  required: { active: Runtime.monoRoot },
52
58
  },
53
- },
54
- {
59
+ }
60
+ },
61
+ debugIpc: (config) => {
62
+ if (!config) return;
63
+ return {
55
64
  name: 'debugIpc',
56
- run: cmd => CliUtil.debugIfIpc(cmd).then((executed) => executed && process.exit(0)),
65
+ run: cmd => CliUtil.runWithDebugIpc(cmd).then((executed) => executed && process.exit(0)),
57
66
  field: {
58
67
  type: Boolean,
59
- aliases: ['-di'],
68
+ aliases: ['-di', CliParseUtil.toEnvField(Env.TRV_DEBUG_IPC.key)],
60
69
  description: 'Should debug invocation trigger via ipc',
61
- default: true,
70
+ default: config !== 'optional',
62
71
  required: { active: false },
63
72
  },
64
- },
65
- {
66
- name: 'restartForDev',
67
- run: cmd => CliUtil.runWithRestartOnCodeChanges(cmd),
73
+ };
74
+ },
75
+ restartOnChange: (config) => {
76
+ if (!config) return;
77
+ return {
78
+ name: 'restartOnChange',
79
+ run: cmd => CliUtil.runWithRestartOnChange(cmd),
68
80
  field: {
69
81
  type: Boolean,
70
- aliases: ['-cr'],
82
+ aliases: ['-rc', CliParseUtil.toEnvField(Env.TRV_RESTART_ON_CHANGE.key)],
71
83
  description: 'Should the invocation automatically restart on source changes',
72
- default: Runtime.envType === 'development',
84
+ default: config !== 'optional' && Runtime.envType === 'development',
73
85
  required: { active: false },
74
86
  },
75
- }
76
- ];
87
+ };
88
+ }
89
+ };
77
90
 
78
91
  /**
79
92
  * Decorator to register a CLI command
@@ -91,13 +104,13 @@ export function CliCommand(config: CliCommandConfigOptions = {}) {
91
104
  return;
92
105
  }
93
106
 
94
- const VALID_FIELDS = FIELD_CONFIG.filter(field => !!config.with?.[field.name]);
107
+ const VALID_FIELDS = TypedObject.keys(FIELD_CONFIG).map((name) => FIELD_CONFIG[name](castTo(config.with?.[name]))).filter(x => !!x);
95
108
 
96
109
  CliCommandRegistryIndex.getForRegister(target).register({
97
110
  runTarget: config.runTarget,
98
111
  preMain: async (cmd: Cmd) => {
99
112
  for (const field of VALID_FIELDS) {
100
- await field.run(cmd);
113
+ await field.run?.(cmd);
101
114
  }
102
115
  }
103
116
  });
@@ -105,7 +118,8 @@ export function CliCommand(config: CliCommandConfigOptions = {}) {
105
118
  const commandModule = description.module;
106
119
 
107
120
  for (const { name, field: { type, ...field } } of VALID_FIELDS) {
108
- adapter.registerField(name, field, { type });
121
+ adapter.registerField(name, { type }, field);
122
+ Object.defineProperty(target.prototype, name, { value: field.default, writable: true });
109
123
  }
110
124
 
111
125
  const runtimeModule = config.runtimeModule ?? (config.with?.module ? 'current' : undefined);
package/src/trv.d.ts CHANGED
@@ -8,8 +8,12 @@ declare module '@travetto/runtime' {
8
8
  */
9
9
  TRV_CLI_IPC: string;
10
10
  /**
11
- * Determines (assuming the operation supports it), that restart behavior can trigger
11
+ * Overrides behavior for allowing restart on changes
12
12
  */
13
- TRV_CAN_RESTART: boolean;
13
+ TRV_RESTART_ON_CHANGE: boolean;
14
+ /**
15
+ * Overrides behavior for triggering debug session via IPC
16
+ */
17
+ TRV_DEBUG_IPC: boolean;
14
18
  }
15
19
  }
package/src/types.ts CHANGED
@@ -90,7 +90,7 @@ export type CliCommandShapeFields = {
90
90
  /**
91
91
  * Should the invocation run with auto-restart on source changes
92
92
  */
93
- restartForDev?: boolean;
93
+ restartOnChange?: boolean;
94
94
  /**
95
95
  * The module to run the command from
96
96
  */
package/src/util.ts CHANGED
@@ -37,9 +37,8 @@ export class CliUtil {
37
37
  /**
38
38
  * Run a command as restartable, linking into self
39
39
  */
40
- static async runWithRestartOnCodeChanges<T extends CliCommandShapeFields & CliCommandShape>(cmd: T, config?: RunWithRestartOptions): Promise<boolean> {
41
-
42
- if (Env.TRV_CAN_RESTART.isFalse || cmd.restartForDev !== true) {
40
+ static async runWithRestartOnChange<T extends CliCommandShapeFields & CliCommandShape>(cmd: T, config?: RunWithRestartOptions): Promise<boolean> {
41
+ if (cmd.restartOnChange !== true) {
43
42
  process.on('message', event => isCodeRestart(event) && process.exit(event.code));
44
43
  return false;
45
44
  }
@@ -48,7 +47,7 @@ export class CliUtil {
48
47
  let exhaustedRestarts = false;
49
48
  let subProcess: ChildProcess | undefined;
50
49
 
51
- const env = { ...process.env, ...Env.TRV_CAN_RESTART.export(false) };
50
+ const env = { ...process.env, ...Env.TRV_RESTART_ON_CHANGE.export(false) };
52
51
  const maxRetries = config?.maxRetriesPerMinute ?? 5;
53
52
  const relayInterrupt = config?.relayInterrupt ?? true;
54
53
  const restarts: number[] = [];
@@ -103,8 +102,8 @@ export class CliUtil {
103
102
  /**
104
103
  * Dispatch IPC payload
105
104
  */
106
- static async triggerIpc<T extends CliCommandShape>(action: 'run', cmd: T): Promise<boolean> {
107
- if (!Env.TRV_CLI_IPC.isSet) {
105
+ static async runWithDebugIpc<T extends CliCommandShapeFields & CliCommandShape>(cmd: T): Promise<boolean> {
106
+ if (cmd.debugIpc !== true || !Env.TRV_CLI_IPC.isSet) {
108
107
  return false;
109
108
  }
110
109
 
@@ -116,7 +115,7 @@ export class CliUtil {
116
115
 
117
116
  const env: Record<string, string> = {};
118
117
  const request = {
119
- type: `@travetto/cli:${action}`,
118
+ type: `@travetto/cli:run`,
120
119
  data: {
121
120
  name: cmd._cfg!.name,
122
121
  env,
@@ -133,13 +132,6 @@ export class CliUtil {
133
132
  return sent.ok;
134
133
  }
135
134
 
136
- /**
137
- * Debug if IPC available
138
- */
139
- static async debugIfIpc<T extends CliCommandShapeFields & CliCommandShape>(cmd: T): Promise<boolean> {
140
- return cmd.debugIpc === true && this.triggerIpc('run', cmd);
141
- }
142
-
143
135
  /**
144
136
  * Write data to channel and ensure its flushed before continuing
145
137
  */