@travetto/cli 6.0.0-rc.1 → 6.0.0-rc.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.
package/README.md CHANGED
@@ -43,14 +43,13 @@ Commands:
43
43
  repo:publish Publish all pending modules
44
44
  repo:version Version all changed dependencies
45
45
  repo:version-sync Enforces all packages to write out their versions and dependencies
46
- rest:client Run client rest operation
47
- rest:rpc Run client rest operation
48
46
  run:double Doubles a number
49
- run:rest Run a rest server as an application
50
47
  scaffold Command to run scaffolding
51
48
  service Allows for running services
52
49
  test Launch test framework and execute tests
53
50
  test:watch Invoke the test watcher
51
+ web:http Run a web server
52
+ web:rpc-client Generate the web-rpc client
54
53
  ```
55
54
 
56
55
  This listing is from the [Travetto](https://travetto.dev) monorepo, and represents the majority of tools that can be invoked from the command line.
@@ -91,10 +90,11 @@ Examples of mappings:
91
90
  * `cli.test.ts` maps to `test`
92
91
  * `cli.pack_docker.ts` maps to `pack:docker`
93
92
  * `cli.email_template.ts` maps to `email:template`
93
+
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/decorators.ts#L84) is a wrapper for [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L14), and so every class that uses the [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/decorators.ts#L84) decorator is now a full [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L14) 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/decorators.ts#L84) is a wrapper for [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L13), and so every class that uses the [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/decorators.ts#L84) decorator is now a full [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L13) 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
@@ -133,9 +133,9 @@ HELLO
133
133
 
134
134
  The [@CliCommand](https://github.com/travetto/travetto/tree/main/module/cli/src/decorators.ts#L84) supports the following data types for flags:
135
135
  * Boolean values
136
- * Number values. The [@Integer](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L166), [@Float](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L172), [@Precision](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L160), [@Min](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L101) and [@Max](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L111) decorators help provide additional validation.
137
- * String values. [@MinLength](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L101), [@MaxLength](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L111), [@Match](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L93) and [@Enum](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L72) provide additional constraints
138
- * Date values. The [@Min](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L101) and [@Max](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L111) decorators help provide additional validation.
136
+ * Number values. The [@Integer](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L164), [@Float](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L170), [@Precision](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L158), [@Min](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L99) and [@Max](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L109) decorators help provide additional validation.
137
+ * String values. [@MinLength](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L99), [@MaxLength](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L109), [@Match](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L91) and [@Enum](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L70) provide additional constraints
138
+ * Date values. The [@Min](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L99) and [@Max](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/field.ts#L109) decorators help provide additional validation.
139
139
  * String lists. Same as String, but allowing multiple values.
140
140
  * Numeric lists. Same as Number, but allowing multiple values.
141
141
 
@@ -206,7 +206,7 @@ export class BasicCommand {
206
206
  reverse?: boolean;
207
207
 
208
208
  main(@Min(1) @Max(10) volumes: number[]) {
209
- console.log(volumes.sort((a, b) => (a - b) * (this.reverse ? -1 : 1)).join(' '));
209
+ console.log(volumes.toSorted((a, b) => (a - b) * (this.reverse ? -1 : 1)).join(' '));
210
210
  }
211
211
  }
212
212
  ```
@@ -251,7 +251,7 @@ $ trv basic:arglist -r 10 5 3 9 8 1
251
251
  ```
252
252
 
253
253
  ## Customization
254
- By default, all fields are treated as flags and all parameters of `main()` are treated as arguments within the validation process. Like the standard [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L14) behavior, we can leverage the metadata of the fields/parameters to help provide additional customization/context for the users of the commands.
254
+ By default, all fields are treated as flags and all parameters of `main()` are treated as arguments within the validation process. Like the standard [@Schema](https://github.com/travetto/travetto/tree/main/module/schema/src/decorator/schema.ts#L13) behavior, we can leverage the metadata of the fields/parameters to help provide additional customization/context for the users of the commands.
255
255
 
256
256
  **Code: Custom Command with Metadata**
257
257
  ```typescript
@@ -381,6 +381,7 @@ The flag files can be included in one of a few ways:
381
381
  * `+=<name>` - This translates into `<mod>/support/<name>.flags`, which is a convenient shorthand.
382
382
  * `+=<mod>/path/file.flags` - This is a path-related file that will be resolved from the module's location.
383
383
  * `+=/path/file.flags` - This is an absolute path that will be read from the root of the file system.
384
+
384
385
  Ultimately, after resolution, the content of these files will be injected inline within the location.
385
386
 
386
387
  **Code: Final arguments after Flag File resolution**
@@ -389,7 +390,7 @@ npx trv call:db --host localhost --port 3306 --username app --password <custom>
389
390
  ```
390
391
 
391
392
  ## VSCode Integration
392
- 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. [RESTful API](https://github.com/travetto/travetto/tree/main/module/rest#readme "Declarative api for RESTful APIs with support for the dependency injection module.") does expose a cli target `run:rest` that will show up, to help run/debug a rest 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/decorators.ts#L84) 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 api for Web Applications with support for the dependency injection.") 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/decorators.ts#L84) decorator. This means the target will be visible within the editor tooling.
393
394
 
394
395
  **Code: Simple Run Target**
395
396
  ```typescript
@@ -424,7 +425,7 @@ export interface CliCommandShape<T extends unknown[] = unknown[]> {
424
425
  /**
425
426
  * Action target of the command
426
427
  */
427
- main(...args: T): OrProm<RunResponse>;
428
+ main(...args: T): OrProm<undefined | void>;
428
429
  /**
429
430
  * Run before main runs
430
431
  */
@@ -457,22 +458,23 @@ export interface CliCommandShape<T extends unknown[] = unknown[]> {
457
458
  ```
458
459
 
459
460
  ### Dependency Injection
460
- If the goal is to run a more complex application, which may include depending on [Dependency Injection](https://github.com/travetto/travetto/tree/main/module/di#readme "Dependency registration/management and injection support."), we can take a look at [RESTful API](https://github.com/travetto/travetto/tree/main/module/rest#readme "Declarative api for RESTful APIs with support for the dependency injection module.")'s target:
461
+ If the goal is to run a more complex application, which may include depending on [Dependency Injection](https://github.com/travetto/travetto/tree/main/module/di#readme "Dependency registration/management and injection support."), we can take a look at [Web API](https://github.com/travetto/travetto/tree/main/module/web#readme "Declarative api for Web Applications with support for the dependency injection.")'s target:
461
462
 
462
463
  **Code: Simple Run Target**
463
464
  ```typescript
464
- import { Runtime } from '@travetto/runtime';
465
+ import { Runtime, ShutdownManager, toConcrete } from '@travetto/runtime';
465
466
  import { DependencyRegistry } from '@travetto/di';
466
467
  import { CliCommand, CliCommandShape } from '@travetto/cli';
468
+ import { NetUtil } from '@travetto/web';
469
+ import { RootRegistry } from '@travetto/registry';
467
470
 
468
- import { ServerHandle } from '../src/types';
469
- import { RestNetUtil } from '../src/util/net';
471
+ import type { WebHttpServer } from '../src/types.ts';
470
472
 
471
473
  /**
472
- * Run a rest server as an application
474
+ * Run a web server
473
475
  */
474
476
  @CliCommand({ runTarget: true, with: { debugIpc: true, canRestart: true, module: true, env: true } })
475
- export class RunRestCommand implements CliCommandShape {
477
+ export class WebHttpCommand implements CliCommandShape {
476
478
 
477
479
  /** Port to run on */
478
480
  port?: number;
@@ -482,35 +484,40 @@ export class RunRestCommand implements CliCommandShape {
482
484
 
483
485
  preMain(): void {
484
486
  if (this.port) {
485
- process.env.REST_PORT = `${this.port}`;
487
+ process.env.WEB_HTTP_PORT = `${this.port}`;
486
488
  }
487
489
  }
488
490
 
489
- async main(): Promise<ServerHandle | void> {
490
- const { RestApplication } = await import('../src/application/rest');
491
+ async main(): Promise<void> {
492
+ await RootRegistry.init();
493
+ const instance = await DependencyRegistry.getInstance(toConcrete<WebHttpServer>());
494
+
495
+ let res;
491
496
  try {
492
- return await DependencyRegistry.runInstance(RestApplication);
497
+ res = await instance.serve();
493
498
  } catch (err) {
494
- if (RestNetUtil.isInuseError(err) && !Runtime.production && this.killConflict) {
495
- await RestNetUtil.freePort(err.port);
496
- return await DependencyRegistry.runInstance(RestApplication);
499
+ if (NetUtil.isPortUsedError(err) && !Runtime.production && this.killConflict) {
500
+ await NetUtil.freePort(err.port);
501
+ res = await instance.serve();
497
502
  }
498
503
  throw err;
499
504
  }
505
+ ShutdownManager.onGracefulShutdown(res.kill, this);
506
+ return res.wait;
500
507
  }
501
508
  }
502
509
  ```
503
510
 
504
- As noted in the example above, `fields` is specified in this execution, with support for `module`, and `env`. These env flag is directly tied to the [Runtime](https://github.com/travetto/travetto/tree/main/module/runtime/src/env.ts#L114) `name` defined in the [Runtime](https://github.com/travetto/travetto/tree/main/module/runtime#readme "Runtime for travetto applications.") module.
511
+ As noted in the example above, `fields` is specified in this execution, with support for `module`, and `env`. These env flag is directly tied to the [Runtime](https://github.com/travetto/travetto/tree/main/module/runtime/src/context.ts#L12) `name` defined in the [Runtime](https://github.com/travetto/travetto/tree/main/module/runtime#readme "Runtime for travetto applications.") module.
505
512
 
506
513
  The `module` field is slightly more complex, but is geared towards supporting commands within a monorepo context. This flag ensures that a module is specified if running from the root of the monorepo, and that the module provided is real, and can run the desired command. When running from an explicit module folder in the monorepo, the module flag is ignored.
507
514
 
508
515
  ### Custom Validation
509
- In addition to dependency injection, the command contract also allows for a custom validation function, which will have access to bound command (flags, and args) as well as the unknown arguments. When a command implements this method, any [CliValidationError](https://github.com/travetto/travetto/tree/main/module/cli/src/types.ts#L37) errors that are returned will be shared with the user, and fail to invoke the `main` method.
516
+ In addition to dependency injection, the command contract also allows for a custom validation function, which will have access to bound command (flags, and args) as well as the unknown arguments. When a command implements this method, any [CliValidationError](https://github.com/travetto/travetto/tree/main/module/cli/src/types.ts#L32) errors that are returned will be shared with the user, and fail to invoke the `main` method.
510
517
 
511
518
  **Code: CliValidationError**
512
519
  ```typescript
513
- export type CliValidationError = {
520
+ export interface CliValidationError {
514
521
  /**
515
522
  * The error message
516
523
  */
package/__index__.ts CHANGED
@@ -1,14 +1,14 @@
1
- import type { } from './src/trv';
2
- export * from './src/types';
3
- export * from './src/decorators';
4
- export * from './src/execute';
5
- export * from './src/error';
6
- export * from './src/schema';
7
- export * from './src/registry';
8
- export * from './src/help';
9
- export * from './src/color';
10
- export * from './src/module';
11
- export * from './src/scm';
12
- export * from './src/parse';
13
- export * from './src/service';
14
- export * from './src/util';
1
+ import type { } from './src/trv.d.ts';
2
+ export * from './src/types.ts';
3
+ export * from './src/decorators.ts';
4
+ export * from './src/execute.ts';
5
+ export * from './src/error.ts';
6
+ export * from './src/schema.ts';
7
+ export * from './src/registry.ts';
8
+ export * from './src/help.ts';
9
+ export * from './src/color.ts';
10
+ export * from './src/module.ts';
11
+ export * from './src/scm.ts';
12
+ export * from './src/parse.ts';
13
+ export * from './src/service.ts';
14
+ export * from './src/util.ts';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/cli",
3
- "version": "6.0.0-rc.1",
3
+ "version": "6.0.0-rc.3",
4
4
  "description": "CLI infrastructure for Travetto framework",
5
5
  "keywords": [
6
6
  "cli",
@@ -28,8 +28,8 @@
28
28
  "directory": "module/cli"
29
29
  },
30
30
  "dependencies": {
31
- "@travetto/schema": "^6.0.0-rc.1",
32
- "@travetto/terminal": "^6.0.0-rc.1"
31
+ "@travetto/schema": "^6.0.0-rc.2",
32
+ "@travetto/terminal": "^6.0.0-rc.2"
33
33
  },
34
34
  "travetto": {
35
35
  "displayName": "Command Line Interface",
package/src/decorators.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { Class, ClassInstance, Env, Runtime, RuntimeIndex, describeFunction } from '@travetto/runtime';
2
2
  import { FieldConfig, SchemaRegistry } from '@travetto/schema';
3
3
 
4
- import { CliCommandShape, CliCommandShapeFields } from './types';
5
- import { CliCommandRegistry } from './registry';
6
- import { CliModuleUtil } from './module';
7
- import { CliParseUtil } from './parse';
8
- import { CliUtil } from './util';
4
+ import { CliCommandShape, CliCommandShapeFields } from './types.ts';
5
+ import { CliCommandRegistry } from './registry.ts';
6
+ import { CliModuleUtil } from './module.ts';
7
+ import { CliParseUtil } from './parse.ts';
8
+ import { CliUtil } from './util.ts';
9
9
 
10
10
  type Cmd = CliCommandShape & { env?: string };
11
11
 
package/src/error.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { AppError, Runtime } from '@travetto/runtime';
2
2
  import { PackageUtil } from '@travetto/manifest';
3
3
 
4
- import { cliTpl } from './color';
5
- import { CliValidationError, CliCommandShape } from './types';
4
+ import { cliTpl } from './color.ts';
5
+ import { CliValidationError, CliCommandShape } from './types.ts';
6
6
 
7
7
  const COMMAND_PACKAGE = [
8
8
  [/^test(:watch)?$/, 'test', false],
@@ -12,7 +12,8 @@ const COMMAND_PACKAGE = [
12
12
  [/^openapi:(spec|client)$/, 'openapi', true],
13
13
  [/^email:(compile|editor)$/, 'email-compiler', false],
14
14
  [/^pack(:zip|:docker)?$/, 'pack', false],
15
- [/^run:rest$/, 'rest', false],
15
+ [/^web:http$/, 'web-http-server', false],
16
+ [/^web:rpc-client$/, 'web-rpc', false],
16
17
  ] as const;
17
18
 
18
19
  /**
package/src/execute.ts CHANGED
@@ -1,12 +1,11 @@
1
1
  import { ConsoleManager, Runtime, ShutdownManager } from '@travetto/runtime';
2
2
 
3
- import { HelpUtil } from './help';
4
- import { CliCommandRegistry } from './registry';
5
- import { CliCommandSchemaUtil } from './schema';
6
- import { CliUnknownCommandError, CliValidationResultError } from './error';
7
- import { CliParseUtil } from './parse';
8
- import { CliUtil } from './util';
9
- import { CliCommandShape } from './types';
3
+ import { HelpUtil } from './help.ts';
4
+ import { CliCommandRegistry } from './registry.ts';
5
+ import { CliCommandSchemaUtil } from './schema.ts';
6
+ import { CliUnknownCommandError, CliValidationResultError } from './error.ts';
7
+ import { CliParseUtil } from './parse.ts';
8
+ import { CliCommandShape } from './types.ts';
10
9
 
11
10
  /**
12
11
  * Execution manager
@@ -55,8 +54,7 @@ export class ExecutionManager {
55
54
  await command.preMain?.();
56
55
 
57
56
  ConsoleManager.debug(Runtime.debug);
58
- const result = await command.main(...boundArgs);
59
- await CliUtil.listenForResponse(result);
57
+ await command.main(...boundArgs);
60
58
  }
61
59
 
62
60
  /**
package/src/help.ts CHANGED
@@ -2,12 +2,12 @@ import util from 'node:util';
2
2
 
3
3
  import { castKey, castTo, Primitive } from '@travetto/runtime';
4
4
 
5
- import { cliTpl } from './color';
6
- import { CliCommandShape } from './types';
7
- import { CliCommandRegistry } from './registry';
8
- import { CliCommandSchemaUtil } from './schema';
9
- import { CliValidationResultError } from './error';
10
- import { isBoolFlag } from './parse';
5
+ import { cliTpl } from './color.ts';
6
+ import { CliCommandShape } from './types.ts';
7
+ import { CliCommandRegistry } from './registry.ts';
8
+ import { CliCommandSchemaUtil } from './schema.ts';
9
+ import { CliValidationResultError } from './error.ts';
10
+ import { isBoolFlag } from './parse.ts';
11
11
 
12
12
  const validationSourceMap = {
13
13
  custom: '',
@@ -97,7 +97,7 @@ export class HelpUtil {
97
97
  */
98
98
  static async renderAllHelp(title?: string): Promise<string> {
99
99
  const rows: string[] = [];
100
- const keys = [...CliCommandRegistry.getCommandMapping().keys()].sort((a, b) => a.localeCompare(b));
100
+ const keys = [...CliCommandRegistry.getCommandMapping().keys()].toSorted((a, b) => a.localeCompare(b));
101
101
  const maxWidth = keys.reduce((a, b) => Math.max(a, util.stripVTControlCharacters(b).length), 0);
102
102
 
103
103
  for (const cmd of keys) {
package/src/module.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Runtime, RuntimeIndex } from '@travetto/runtime';
2
2
  import type { IndexedModule } from '@travetto/manifest';
3
3
 
4
- import { CliScmUtil } from './scm';
4
+ import { CliScmUtil } from './scm.ts';
5
5
 
6
6
  type ModuleGraphEntry = { children: Set<string>, name: string, active: Set<string>, parents?: string[] };
7
7
 
@@ -35,7 +35,7 @@ export class CliModuleUtil {
35
35
  }
36
36
 
37
37
  return [...out.values()]
38
- .sort((a, b) => a.name.localeCompare(b.name));
38
+ .toSorted((a, b) => a.name.localeCompare(b.name));
39
39
  }
40
40
 
41
41
  /**
package/src/parse.ts CHANGED
@@ -2,7 +2,7 @@ import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
 
4
4
  import { Runtime } from '@travetto/runtime';
5
- import { CliCommandInput, CliCommandSchema, ParsedState } from './types';
5
+ import { CliCommandInput, CliCommandSchema, ParsedState } from './types.ts';
6
6
 
7
7
  type ParsedInput = ParsedState['all'][number];
8
8
 
@@ -77,15 +77,32 @@ export class CliParseUtil {
77
77
  return { next: i, value: collected.length ? String.fromCharCode(...collected) : undefined };
78
78
  }
79
79
 
80
+ /**
81
+ * Get a user-specified module if present
82
+ */
83
+ static getSpecifiedModule(schema: CliCommandSchema, args: string[]): string | undefined {
84
+ const SEP = args.includes(RAW_SEP) ? args.indexOf(RAW_SEP) : args.length;
85
+ const input = schema.flags.find(x => x.type === 'module');
86
+ const ENV_KEY = input?.flagNames?.filter(x => x.startsWith(ENV_PRE)).map(x => x.replace(ENV_PRE, ''))[0] ?? '';
87
+ const flags = new Set(input?.flagNames ?? []);
88
+ const check = (k?: string, v?: string): string | undefined => flags.has(k!) ? v : undefined;
89
+ return args.reduce(
90
+ (m, x, i, arr) =>
91
+ (i < SEP ? check(arr[i - 1], x) ?? check(...x.split('=')) : undefined) ?? m,
92
+ process.env[ENV_KEY]
93
+ );
94
+ }
95
+
80
96
  /**
81
97
  * Read configuration file given flag
82
98
  */
83
- static async readFlagFile(flag: string, mod: string): Promise<string[]> {
99
+ static async readFlagFile(flag: string, mod?: string): Promise<string[]> {
84
100
  const key = flag.replace(CONFIG_PRE, '');
101
+ const overrides = { '@': mod ?? Runtime.main.name };
85
102
 
86
103
  // We have a file
87
104
  const rel = (key.includes('/') ? key : `@#support/pack.${key}.flags`)
88
- .replace(/^(@[^#]*)#(.*)$/, (_, imp, rest) => `${Runtime.modulePath(imp)}/${rest}`);
105
+ .replace(/^(@[^#]*)#(.*)$/, (_, imp, rest) => `${Runtime.modulePath(imp, overrides)}/${rest}`);
89
106
 
90
107
  const file = path.resolve(rel);
91
108
 
@@ -129,15 +146,7 @@ export class CliParseUtil {
129
146
  */
130
147
  static async expandArgs(schema: CliCommandSchema, args: string[]): Promise<string[]> {
131
148
  const SEP = args.includes(RAW_SEP) ? args.indexOf(RAW_SEP) : args.length;
132
- const input = schema.flags.find(x => x.type === 'module');
133
- const ENV_KEY = input?.flagNames?.filter(x => x.startsWith(ENV_PRE)).map(x => x.replace(ENV_PRE, ''))[0] ?? '';
134
- const flags = new Set(input?.flagNames ?? []);
135
- const check = (k?: string, v?: string): string | undefined => flags.has(k!) ? v : undefined;
136
- const mod = args.reduce(
137
- (m, x, i, arr) =>
138
- (i < SEP ? check(arr[i - 1], x) ?? check(...x.split('=')) : undefined) ?? m,
139
- process.env[ENV_KEY] || Runtime.main.name
140
- );
149
+ const mod = this.getSpecifiedModule(schema, args);
141
150
  return (await Promise.all(args.map((x, i) =>
142
151
  x.startsWith(CONFIG_PRE) && (i < SEP || SEP < 0) ? this.readFlagFile(x, mod) : x))).flat();
143
152
  }
package/src/registry.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { asConstructable, Class, classConstruct, describeFunction, Runtime, RuntimeIndex } from '@travetto/runtime';
2
2
 
3
- import { CliCommandConfig, CliCommandShape } from './types';
4
- import { CliUnknownCommandError } from './error';
3
+ import { CliCommandConfig, CliCommandShape } from './types.ts';
4
+ import { CliUnknownCommandError } from './error.ts';
5
5
 
6
6
  const CLI_FILE_REGEX = /\/cli[.](?<name>.{0,100}?)([.]tsx?)?$/;
7
7
  const getName = (s: string): string => (s.match(CLI_FILE_REGEX)?.groups?.name ?? s).replaceAll('_', ':');
package/src/schema.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { castKey, castTo, Class } from '@travetto/runtime';
2
2
  import { BindUtil, FieldConfig, SchemaRegistry, SchemaValidator, ValidationResultError } from '@travetto/schema';
3
3
 
4
- import { CliCommandRegistry } from './registry';
5
- import { ParsedState, CliCommandInput, CliCommandSchema, CliCommandShape } from './types';
6
- import { CliValidationResultError } from './error';
4
+ import { CliCommandRegistry } from './registry.ts';
5
+ import { ParsedState, CliCommandInput, CliCommandSchema, CliCommandShape } from './types.ts';
6
+ import { CliValidationResultError } from './error.ts';
7
7
 
8
8
  const LONG_FLAG = /^--[a-z][^= ]+/i;
9
9
  const SHORT_FLAG = /^-[a-z]/i;
package/src/scm.ts CHANGED
@@ -48,18 +48,18 @@ export class CliScmUtil {
48
48
  */
49
49
  static async findChangedFiles(fromHash: string, toHash: string = 'HEAD'): Promise<string[]> {
50
50
  const ws = Runtime.workspace.path;
51
- const res = await ExecUtil.getResult(spawn('git', ['diff', '--name-only', `${fromHash}..${toHash}`, ':!**/DOC.*', ':!**/README.*'], { cwd: ws }), { catch: true });
52
- if (!res.valid) {
53
- throw new AppError('Unable to detect changes between', { category: 'data', details: { fromHash, toHash, output: (res.stderr || res.stdout) } });
51
+ const result = await ExecUtil.getResult(spawn('git', ['diff', '--name-only', `${fromHash}..${toHash}`, ':!**/DOC.*', ':!**/README.*'], { cwd: ws }), { catch: true });
52
+ if (!result.valid) {
53
+ throw new AppError('Unable to detect changes between', { category: 'data', details: { fromHash, toHash, output: (result.stderr || result.stdout) } });
54
54
  }
55
55
  const out = new Set<string>();
56
- for (const line of res.stdout.split(/\n/g)) {
56
+ for (const line of result.stdout.split(/\n/g)) {
57
57
  const entry = RuntimeIndex.getEntry(path.resolve(ws, line));
58
58
  if (entry) {
59
59
  out.add(entry.sourceFile);
60
60
  }
61
61
  }
62
- return [...out].sort((a, b) => a.localeCompare(b));
62
+ return [...out].toSorted((a, b) => a.localeCompare(b));
63
63
  }
64
64
 
65
65
  /**
@@ -77,7 +77,7 @@ export class CliScmUtil {
77
77
  .filter(x => !!x);
78
78
 
79
79
  return [...new Set(mods)]
80
- .sort((a, b) => a.name.localeCompare(b.name));
80
+ .toSorted((a, b) => a.name.localeCompare(b.name));
81
81
  }
82
82
 
83
83
  /**
package/src/service.ts CHANGED
@@ -53,9 +53,9 @@ export class ServiceRunner {
53
53
  if (!this.svc.ready?.url || !full) {
54
54
  return true;
55
55
  } else {
56
- const req = await fetch(this.svc.ready.url, { method: 'GET' });
57
- const text = await req.text();
58
- if (req.ok && (this.svc.ready.test?.(text) ?? true)) {
56
+ const response = await fetch(this.svc.ready.url, { method: 'GET' });
57
+ const text = await response.text();
58
+ if (response.ok && (this.svc.ready.test?.(text) ?? true)) {
59
59
  return true;
60
60
  }
61
61
  }
package/src/types.ts CHANGED
@@ -1,12 +1,6 @@
1
1
  import { Class } from '@travetto/runtime';
2
2
 
3
3
  type OrProm<T> = T | Promise<T>;
4
-
5
- export type RunResponse =
6
- { wait(): Promise<unknown> } |
7
- { on(event: 'close', cb: Function): unknown } |
8
- { close: () => (void | Promise<void>) } | void | undefined;
9
-
10
4
  type ParsedFlag = { type: 'flag', input: string, array?: boolean, fieldName: string, value?: unknown };
11
5
  type ParsedArg = { type: 'arg', input: string, array?: boolean, index: number };
12
6
  type ParsedUnknown = { type: 'unknown', input: string };
@@ -33,8 +27,9 @@ export type ParsedState = {
33
27
 
34
28
  /**
35
29
  * Constrained version of Schema's Validation Error
30
+ * @concrete
36
31
  */
37
- export type CliValidationError = {
32
+ export interface CliValidationError {
38
33
  /**
39
34
  * The error message
40
35
  */
@@ -47,6 +42,7 @@ export type CliValidationError = {
47
42
 
48
43
  /**
49
44
  * CLI Command Contract
45
+ * @concrete
50
46
  */
51
47
  export interface CliCommandShape<T extends unknown[] = unknown[]> {
52
48
 
@@ -61,7 +57,7 @@ export interface CliCommandShape<T extends unknown[] = unknown[]> {
61
57
  /**
62
58
  * Action target of the command
63
59
  */
64
- main(...args: T): OrProm<RunResponse>;
60
+ main(...args: T): OrProm<undefined | void>;
65
61
  /**
66
62
  * Run before main runs
67
63
  */
package/src/util.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { spawn } from 'node:child_process';
2
2
 
3
- import { Env, ExecUtil, ShutdownManager, Runtime } from '@travetto/runtime';
3
+ import { Env, ExecUtil, Runtime } from '@travetto/runtime';
4
4
 
5
- import { CliCommandShape, CliCommandShapeFields, RunResponse } from './types';
5
+ import { CliCommandShape, CliCommandShapeFields } from './types.ts';
6
6
 
7
7
  const IPC_ALLOWED_ENV = new Set(['NODE_OPTIONS']);
8
8
  const IPC_INVALID_ENV = new Set(['PS1', 'INIT_CWD', 'COLOR', 'LANGUAGE', 'PROFILEHOME', '_']);
@@ -11,7 +11,6 @@ const validEnv = (k: string): boolean => IPC_ALLOWED_ENV.has(k) || (!IPC_INVALID
11
11
  export class CliUtil {
12
12
  /**
13
13
  * Get a simplified version of a module name
14
- * @returns
15
14
  */
16
15
  static getSimpleModuleName(placeholder: string, module?: string): string {
17
16
  const simple = (module ?? Runtime.main.name).replace(/[\/]/, '_').replace(/@/, '');
@@ -88,21 +87,4 @@ export class CliUtil {
88
87
  static async writeAndEnsureComplete(data: unknown, channel: 'stdout' | 'stderr' = 'stdout'): Promise<void> {
89
88
  return await new Promise(r => process[channel].write(typeof data === 'string' ? data : JSON.stringify(data, null, 2), () => r()));
90
89
  }
91
-
92
- /**
93
- * Listen for a run response to finish
94
- */
95
- static async listenForResponse(result: RunResponse): Promise<void> {
96
- // Listen to result if non-empty
97
- if (result !== undefined && result !== null) {
98
- if ('close' in result) {
99
- ShutdownManager.onGracefulShutdown(async () => result.close()); // Tie shutdown into app close
100
- }
101
- if ('wait' in result) {
102
- await result.wait(); // Wait for close signal
103
- } else if ('on' in result) {
104
- await new Promise<void>(res => result.on('close', res)); // Wait for callback
105
- }
106
- }
107
- }
108
90
  }
@@ -1,10 +1,10 @@
1
1
  import { Env } from '@travetto/runtime';
2
2
 
3
- import { CliCommand } from '../src/decorators';
4
- import { CliCommandSchema, CliCommandShape, CliValidationError } from '../src/types';
5
- import { CliCommandRegistry } from '../src/registry';
6
- import { CliCommandSchemaUtil } from '../src/schema';
7
- import { CliUtil } from '../src/util';
3
+ import { CliCommand } from '../src/decorators.ts';
4
+ import { CliCommandSchema, CliCommandShape, CliValidationError } from '../src/types.ts';
5
+ import { CliCommandRegistry } from '../src/registry.ts';
6
+ import { CliCommandSchemaUtil } from '../src/schema.ts';
7
+ import { CliUtil } from '../src/util.ts';
8
8
 
9
9
  /**
10
10
  * Generates the schema for all CLI operations
@@ -20,18 +20,18 @@ export class MainCommand implements CliCommandShape {
20
20
  }
21
21
 
22
22
  async main(fileOrImport: string, args: string[] = []): Promise<void> {
23
- let res: unknown;
23
+ let result: unknown;
24
24
  try {
25
25
  const mod = await Runtime.importFrom<{ main(..._: unknown[]): Promise<unknown> }>(fileOrImport);
26
- res = await mod.main(...args, ...this._parsed.unknown);
26
+ result = await mod.main(...args, ...this._parsed.unknown);
27
27
  } catch (err) {
28
- res = err;
28
+ result = err;
29
29
  process.exitCode = Math.max(process.exitCode ? +process.exitCode : 1, 1);
30
30
  }
31
31
 
32
- if (res !== undefined) {
33
- if (process.connected) { process.send?.(res); }
34
- const payload = typeof res === 'string' ? res : (res instanceof Error ? res.stack : JSON.stringify(res));
32
+ if (result !== undefined) {
33
+ if (process.connected) { process.send?.(result); }
34
+ const payload = typeof result === 'string' ? result : (result instanceof Error ? result.stack : JSON.stringify(result));
35
35
  process[process.exitCode ? 'stderr' : 'stdout'].write(`${payload}\n`);
36
36
  }
37
37
  }
@@ -2,7 +2,7 @@ import { CliCommandShape, CliCommand, cliTpl, CliValidationError } from '@travet
2
2
  import { Terminal } from '@travetto/terminal';
3
3
  import { AsyncQueue, Runtime, RuntimeIndex, Util } from '@travetto/runtime';
4
4
 
5
- import { ServiceRunner, ServiceDescriptor, ServiceAction } from '../src/service';
5
+ import { ServiceRunner, ServiceDescriptor, ServiceAction } from '../src/service.ts';
6
6
 
7
7
  /**
8
8
  * Allows for running services
@@ -21,7 +21,7 @@ export class CliServiceCommand implements CliCommandShape {
21
21
  ))
22
22
  .filter(x => !!x)
23
23
  .filter(x => services?.length ? services.includes(x.name) : true)
24
- .sort((a, b) => a.name.localeCompare(b.name));
24
+ .toSorted((a, b) => a.name.localeCompare(b.name));
25
25
  }
26
26
 
27
27
  async validate(action: ServiceAction, services: string[]): Promise<CliValidationError | undefined> {
@@ -1,7 +1,7 @@
1
1
  import ts from 'typescript';
2
2
 
3
3
  import { TransformerState, DecoratorMeta, AfterClass } from '@travetto/transformer';
4
- import { SchemaTransformUtil } from '@travetto/schema/support/transformer/util';
4
+ import { SchemaTransformUtil } from '@travetto/schema/support/transformer/util.ts';
5
5
 
6
6
  /**
7
7
  * Converts classes with `@CliCommand` to `@Schema` and maps the main method