@travetto/cli 3.4.8 → 3.4.9

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
@@ -411,6 +411,10 @@ export class RunCommand {
411
411
  **Code: Anatomy of a Command**
412
412
  ```typescript
413
413
  export interface CliCommandShape<T extends unknown[] = unknown[]> {
414
+ /**
415
+ * Parsed state
416
+ */
417
+ _parsed?: ParsedState;
414
418
  /**
415
419
  * Action target of the command
416
420
  */
@@ -493,7 +497,7 @@ As noted in the example above, `fields` is specified in this execution, with sup
493
497
  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.
494
498
 
495
499
  ### Custom Validation
496
- 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#L10) errors that are returned will be shared with the user, and fail to invoke the `main` method.
500
+ 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#L22) errors that are returned will be shared with the user, and fail to invoke the `main` method.
497
501
 
498
502
  **Code: CliValidationError**
499
503
  ```typescript
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/cli",
3
- "version": "3.4.8",
3
+ "version": "3.4.9",
4
4
  "description": "CLI infrastructure for Travetto framework",
5
5
  "keywords": [
6
6
  "cli",
package/src/execute.ts CHANGED
@@ -19,13 +19,11 @@ export class ExecutionManager {
19
19
  */
20
20
  static async #runCommand(cmd: CliCommandShape, args: string[]): Promise<RunResponse> {
21
21
  const schema = await CliCommandSchemaUtil.getSchema(cmd);
22
- const state = await CliParseUtil.parse(schema, args);
22
+ cmd._parsed = await CliParseUtil.parse(schema, args);
23
23
  const cfg = CliCommandRegistry.getConfig(cmd);
24
24
 
25
- CliParseUtil.setState(cmd, state);
26
-
27
25
  await cmd.preBind?.();
28
- const known = await CliCommandSchemaUtil.bindInput(cmd, state);
26
+ const known = await CliCommandSchemaUtil.bindInput(cmd, cmd._parsed);
29
27
 
30
28
  await cmd.preValidate?.();
31
29
  await CliCommandSchemaUtil.validate(cmd, known);
package/src/parse.ts CHANGED
@@ -1,19 +1,9 @@
1
1
  import fs from 'fs/promises';
2
2
 
3
3
  import { RootIndex, path } from '@travetto/manifest';
4
- import { CliCommandInput, CliCommandSchema, CliCommandShape } from './types';
5
-
6
- type ParsedFlag = { type: 'flag', input: string, array?: boolean, fieldName: string, value?: unknown };
7
- type ParsedArg = { type: 'arg', input: string, array?: boolean, index: number };
8
- type ParsedUnknown = { type: 'unknown', input: string };
9
- type ParsedInput = ParsedUnknown | ParsedFlag | ParsedArg;
10
-
11
- export type ParsedState = {
12
- inputs: string[];
13
- all: ParsedInput[];
14
- flags: ParsedFlag[];
15
- unknown: string[];
16
- };
4
+ import { CliCommandInput, CliCommandSchema, ParsedState } from './types';
5
+
6
+ type ParsedInput = ParsedState['all'][number];
17
7
 
18
8
  const RAW_SEP = '--';
19
9
  const VALID_FLAG = /^-{1,2}[a-z]/i;
@@ -21,8 +11,21 @@ const HELP_FLAG = /^-h|--help$/;
21
11
  const LONG_FLAG_WITH_EQ = /^--[a-z][^= ]+=\S+/i;
22
12
  const CONFIG_PRE = '+=';
23
13
  const ENV_PRE = 'env.';
24
- const ParsedⲐ = Symbol.for('@travetto/cli:parsed');
25
14
  const SPACE = new Set([32, 7, 13, 10]);
15
+ const MODULE_FLAG = '--module';
16
+ const MODULE_SHORT = '-m';
17
+
18
+ const getModuleValue = (arr: string[]): string => {
19
+ for (let i = 0; i < arr.length; i += 1) {
20
+ const x = arr[i];
21
+ if (x.startsWith(`${MODULE_FLAG}=`)) {
22
+ return x.split('=')[1];
23
+ } else if (!x.startsWith('-') && (arr[i - 1] === MODULE_SHORT || arr[i - 1] === MODULE_FLAG)) {
24
+ return x;
25
+ }
26
+ }
27
+ return process.env.TRV_MODULE || RootIndex.mainModuleName;
28
+ };
26
29
 
27
30
  const isBoolFlag = (x?: CliCommandInput): boolean => x?.type === 'boolean' && !x.array;
28
31
 
@@ -90,20 +93,19 @@ export class CliParseUtil {
90
93
  /**
91
94
  * Read configuration file given flag
92
95
  */
93
- static async readFlagFile(flag: string): Promise<string[]> {
96
+ static async readFlagFile(flag: string, mod: string): Promise<string[]> {
94
97
  const key = flag.replace(CONFIG_PRE, '');
95
- const mod = RootIndex.mainModuleName;
96
98
 
97
99
  // We have a file
98
100
  const rel = (key.includes('/') ? key : `@/support/pack.${key}.flags`)
99
101
  .replace('@@/', `${RootIndex.manifest.workspacePath}/`)
100
102
  .replace('@/', `${mod}/`)
101
- .replace(/^(@[^\/]+\/[^\/]+)/, (_, imp) => {
103
+ .replace(/^(@[^\/]+\/[^\/]+)(\/.*)$/, (_, imp, rest) => {
102
104
  const val = RootIndex.getModule(imp);
103
105
  if (!val) {
104
- throw new Error(`Unknown module file: ${key}, unable to proceed`);
106
+ throw new Error(`Unknown module file: ${_}, unable to proceed`);
105
107
  }
106
- return val.sourcePath;
108
+ return `${val.sourcePath}${rest}`;
107
109
  });
108
110
 
109
111
  const file = path.resolve(rel);
@@ -136,12 +138,13 @@ export class CliParseUtil {
136
138
  const out = argv.slice(offset);
137
139
  const max = out.includes(RAW_SEP) ? out.indexOf(RAW_SEP) : out.length;
138
140
  const valid = out.slice(0, max);
141
+ const mod = getModuleValue(valid);
139
142
  const cmd = valid.length > 0 && !valid[0].startsWith('-') ? valid[0] : undefined;
140
143
  const helpIdx = valid.findIndex(x => HELP_FLAG.test(x));
141
144
  const args = [];
142
145
  for (const item of out.slice(cmd ? 1 : 0)) {
143
146
  if (item.startsWith(CONFIG_PRE)) {
144
- args.push(...await this.readFlagFile(item));
147
+ args.push(...await this.readFlagFile(item, mod));
145
148
  } else {
146
149
  args.push(item);
147
150
  }
@@ -210,22 +213,8 @@ export class CliParseUtil {
210
213
  return {
211
214
  inputs,
212
215
  all: out,
213
- unknown: out.filter((x): x is ParsedUnknown => x.type === 'unknown').map(x => x.input),
214
- flags: out.filter((x): x is ParsedFlag => x.type === 'flag')
216
+ unknown: out.filter(x => x.type === 'unknown').map(x => x.input),
217
+ flags: out.filter((x): x is ParsedInput & { type: 'flag' } => x.type === 'flag')
215
218
  };
216
219
  }
217
-
218
- /**
219
- * Get parse state from the command
220
- */
221
- static getState(cmd: CliCommandShape & { [ParsedⲐ]?: ParsedState }): ParsedState | undefined {
222
- return cmd[ParsedⲐ];
223
- }
224
-
225
- /**
226
- * Set state for a command
227
- */
228
- static setState(cmd: CliCommandShape & { [ParsedⲐ]?: ParsedState }, state: ParsedState): void {
229
- cmd[ParsedⲐ] = state;
230
- }
231
220
  }
package/src/types.ts CHANGED
@@ -4,6 +4,18 @@ type OrProm<T> = T | Promise<T>;
4
4
 
5
5
  export type RunResponse = { wait(): Promise<unknown> } | { on(event: 'close', cb: Function): unknown } | Closeable | void | undefined;
6
6
 
7
+ type ParsedFlag = { type: 'flag', input: string, array?: boolean, fieldName: string, value?: unknown };
8
+ type ParsedArg = { type: 'arg', input: string, array?: boolean, index: number };
9
+ type ParsedUnknown = { type: 'unknown', input: string };
10
+ type ParsedInput = ParsedUnknown | ParsedFlag | ParsedArg;
11
+
12
+ export type ParsedState = {
13
+ inputs: string[];
14
+ all: ParsedInput[];
15
+ flags: ParsedFlag[];
16
+ unknown: string[];
17
+ };
18
+
7
19
  /**
8
20
  * Constrained version of Schema's Validation Error
9
21
  */
@@ -22,6 +34,10 @@ export type CliValidationError = {
22
34
  * CLI Command Contract
23
35
  */
24
36
  export interface CliCommandShape<T extends unknown[] = unknown[]> {
37
+ /**
38
+ * Parsed state
39
+ */
40
+ _parsed?: ParsedState;
25
41
  /**
26
42
  * Action target of the command
27
43
  */
@@ -1,8 +1,9 @@
1
1
  import fs from 'fs/promises';
2
2
 
3
3
  import { ShutdownManager } from '@travetto/base';
4
- import { CliCommandShape, CliCommand, CliValidationError, CliParseUtil } from '@travetto/cli';
4
+ import { CliCommandShape, CliCommand, CliValidationError, ParsedState } from '@travetto/cli';
5
5
  import { path, RootIndex } from '@travetto/manifest';
6
+ import { Ignore } from '@travetto/schema';
6
7
 
7
8
  /**
8
9
  * Allows for running of main entry points
@@ -10,6 +11,9 @@ import { path, RootIndex } from '@travetto/manifest';
10
11
  @CliCommand({ hidden: true })
11
12
  export class MainCommand implements CliCommandShape {
12
13
 
14
+ @Ignore()
15
+ _parsed: ParsedState;
16
+
13
17
  async #getImport(fileOrImport: string): Promise<string | undefined> {
14
18
  // If referenced file exists
15
19
  let file = fileOrImport;
@@ -32,7 +36,7 @@ export class MainCommand implements CliCommandShape {
32
36
  const imp = await this.#getImport(fileOrImport);
33
37
  const mod = await import(imp!);
34
38
 
35
- await ShutdownManager.exitWithResponse(await mod.main(...args, ...CliParseUtil.getState(this)?.unknown ?? []));
39
+ await ShutdownManager.exitWithResponse(await mod.main(...args, ...this._parsed.unknown));
36
40
  } catch (err) {
37
41
  await ShutdownManager.exitWithResponse(err, true);
38
42
  }