@travetto/cli 8.0.0-alpha.0 → 8.0.0-alpha.10
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 +59 -50
- package/__index__.ts +0 -1
- package/bin/trv.js +1 -0
- package/package.json +3 -3
- package/src/execute.ts +41 -49
- package/src/help.ts +48 -7
- package/src/parse.ts +33 -1
- package/src/registry/decorator.ts +125 -132
- package/src/registry/registry-adapter.ts +21 -7
- package/src/registry/registry-index.ts +10 -8
- package/src/schema-export.ts +4 -3
- package/src/schema.ts +35 -40
- package/src/service.ts +18 -1
- package/src/types.ts +6 -69
- package/src/util.ts +25 -30
- package/support/cli.cli_schema.ts +21 -18
- package/support/cli.main.ts +13 -14
- package/support/cli.service.ts +44 -36
- package/support/entry.trv.ts +1 -1
- package/src/error.ts +0 -58
package/src/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Class } from '@travetto/runtime';
|
|
1
|
+
import type { Any, Class } from '@travetto/runtime';
|
|
2
2
|
|
|
3
3
|
type OrProm<T> = T | Promise<T>;
|
|
4
4
|
type ParsedFlag = { type: 'flag', input: string, array?: boolean, fieldName: string, value?: unknown };
|
|
@@ -13,89 +13,26 @@ export type ParsedState = {
|
|
|
13
13
|
unknown: string[];
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
/**
|
|
17
|
-
* Constrained version of Schema's Validation Error
|
|
18
|
-
* @concrete
|
|
19
|
-
*/
|
|
20
|
-
export interface CliValidationError {
|
|
21
|
-
/**
|
|
22
|
-
* The error message
|
|
23
|
-
*/
|
|
24
|
-
message: string;
|
|
25
|
-
/**
|
|
26
|
-
* Source of validation
|
|
27
|
-
*/
|
|
28
|
-
source?: 'flag' | 'arg' | 'custom';
|
|
29
|
-
};
|
|
30
|
-
|
|
31
16
|
/**
|
|
32
17
|
* CLI Command Contract
|
|
33
18
|
* @concrete
|
|
34
19
|
*/
|
|
35
|
-
export interface CliCommandShape
|
|
36
|
-
/**
|
|
37
|
-
* Parsed state
|
|
38
|
-
*/
|
|
39
|
-
_parsed?: ParsedState;
|
|
40
|
-
/**
|
|
41
|
-
* Config
|
|
42
|
-
*/
|
|
43
|
-
_cfg?: CliCommandConfig;
|
|
20
|
+
export interface CliCommandShape {
|
|
44
21
|
/**
|
|
45
22
|
* Action target of the command
|
|
46
23
|
*/
|
|
47
|
-
main(...args:
|
|
24
|
+
main(...args: unknown[]): OrProm<undefined | void>;
|
|
48
25
|
/**
|
|
49
26
|
* Run before main runs
|
|
50
27
|
*/
|
|
51
|
-
|
|
28
|
+
finalize?(help?: boolean): OrProm<void>;
|
|
52
29
|
/**
|
|
53
30
|
* Extra help
|
|
54
31
|
*/
|
|
55
32
|
help?(): OrProm<string[]>;
|
|
56
|
-
/**
|
|
57
|
-
* Run before help is displayed
|
|
58
|
-
*/
|
|
59
|
-
preHelp?(): OrProm<void>;
|
|
60
|
-
/**
|
|
61
|
-
* Is the command active/eligible for usage
|
|
62
|
-
*/
|
|
63
|
-
isActive?(): boolean;
|
|
64
|
-
/**
|
|
65
|
-
* Run before binding occurs
|
|
66
|
-
*/
|
|
67
|
-
preBind?(): OrProm<void>;
|
|
68
|
-
/**
|
|
69
|
-
* Run before validation occurs
|
|
70
|
-
*/
|
|
71
|
-
preValidate?(): OrProm<void>;
|
|
72
|
-
/**
|
|
73
|
-
* Validation method
|
|
74
|
-
*/
|
|
75
|
-
validate?(...args: T): OrProm<CliValidationError | CliValidationError[] | undefined>;
|
|
76
33
|
}
|
|
77
34
|
|
|
78
|
-
|
|
79
|
-
* Command shape common fields
|
|
80
|
-
*/
|
|
81
|
-
export type CliCommandShapeFields = {
|
|
82
|
-
/**
|
|
83
|
-
* Profiles to run the application under
|
|
84
|
-
*/
|
|
85
|
-
profiles?: string[];
|
|
86
|
-
/**
|
|
87
|
-
* Should the cli invocation trigger a debug session, via IPC
|
|
88
|
-
*/
|
|
89
|
-
debugIpc?: boolean;
|
|
90
|
-
/**
|
|
91
|
-
* Should the invocation run with auto-restart on source changes
|
|
92
|
-
*/
|
|
93
|
-
restartOnChange?: boolean;
|
|
94
|
-
/**
|
|
95
|
-
* The module to run the command from
|
|
96
|
-
*/
|
|
97
|
-
module?: string;
|
|
98
|
-
};
|
|
35
|
+
export type PreMainHandler<T extends Any = Any> = { priority: number, handler: (cmd: T) => Any };
|
|
99
36
|
|
|
100
37
|
/**
|
|
101
38
|
* CLI Command schema shape
|
|
@@ -104,5 +41,5 @@ export interface CliCommandConfig {
|
|
|
104
41
|
cls: Class<CliCommandShape>;
|
|
105
42
|
name: string;
|
|
106
43
|
runTarget?: boolean;
|
|
107
|
-
preMain
|
|
44
|
+
preMain: PreMainHandler[];
|
|
108
45
|
}
|
package/src/util.ts
CHANGED
|
@@ -2,13 +2,12 @@ import { spawn, type ChildProcess } from 'node:child_process';
|
|
|
2
2
|
|
|
3
3
|
import { RuntimeError, JSONUtil, Env, ExecUtil, Runtime, ShutdownManager, Util, WatchUtil } from '@travetto/runtime';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const validEnv = (key: string): boolean =>
|
|
10
|
-
|
|
11
|
-
);
|
|
5
|
+
const IPC_VALID_ENV = new Set(['NODE_OPTIONS', 'PATH', Env.DEBUG.key, Env.NODE_ENV.key]);
|
|
6
|
+
const IPC_INVALID_ENV = new Set([
|
|
7
|
+
Env.TRV_CLI_IPC, Env.TRV_DEBUG_IPC, Env.TRV_DEBUG_BREAK, Env.TRV_MANIFEST, Env.TRV_MODULE, Env.TRV_RESTART_TARGET
|
|
8
|
+
].map(item => item.key));
|
|
9
|
+
const validEnv = ([key]: [key: string, value: unknown]): boolean =>
|
|
10
|
+
IPC_VALID_ENV.has(key) || (key.startsWith('TRV_') && !IPC_INVALID_ENV.has(key));
|
|
12
11
|
|
|
13
12
|
export class CliUtil {
|
|
14
13
|
/**
|
|
@@ -16,34 +15,29 @@ export class CliUtil {
|
|
|
16
15
|
*/
|
|
17
16
|
static getSimpleModuleName(placeholder: string, module?: string): string {
|
|
18
17
|
const simple = (module ?? Runtime.main.name).replace(/[\/]/, '_').replace(/@/, '');
|
|
19
|
-
|
|
20
|
-
return placeholder;
|
|
21
|
-
} else if (!module && Runtime.monoRoot) {
|
|
22
|
-
return placeholder;
|
|
23
|
-
} else {
|
|
24
|
-
return placeholder.replace('<module>', simple);
|
|
25
|
-
}
|
|
18
|
+
return simple ? placeholder.replace('<module>', simple) : placeholder;
|
|
26
19
|
}
|
|
27
20
|
|
|
28
21
|
/**
|
|
29
22
|
* Run a command as restartable, linking into self
|
|
30
23
|
*/
|
|
31
|
-
static async runWithRestartOnChange
|
|
24
|
+
static async runWithRestartOnChange(restartOnChange?: boolean): Promise<void> {
|
|
32
25
|
if (Env.TRV_RESTART_TARGET.isTrue) {
|
|
33
26
|
Env.TRV_RESTART_TARGET.clear();
|
|
34
27
|
ShutdownManager.disableInterrupt();
|
|
35
28
|
return;
|
|
36
|
-
} else if (
|
|
29
|
+
} else if (restartOnChange !== true) {
|
|
37
30
|
return; // Not restarting, run normal
|
|
38
31
|
}
|
|
39
32
|
|
|
40
33
|
ShutdownManager.disableInterrupt();
|
|
41
34
|
|
|
42
35
|
let child: ChildProcess | undefined;
|
|
43
|
-
|
|
36
|
+
await WatchUtil.watchCompilerEvents('file', () => ShutdownManager.shutdownChild(child!, { reason: 'restart', mode: 'exit' }));
|
|
37
|
+
|
|
44
38
|
process
|
|
45
39
|
.on('SIGINT', () => ShutdownManager.shutdownChild(child!, { mode: 'exit' }))
|
|
46
|
-
.on('message',
|
|
40
|
+
.on('message', message => child?.send?.(message!));
|
|
47
41
|
|
|
48
42
|
const env = { ...process.env, ...Env.TRV_RESTART_TARGET.export(true) };
|
|
49
43
|
|
|
@@ -72,43 +66,44 @@ export class CliUtil {
|
|
|
72
66
|
/**
|
|
73
67
|
* Dispatch IPC payload
|
|
74
68
|
*/
|
|
75
|
-
static async runWithDebugIpc
|
|
76
|
-
if (
|
|
69
|
+
static async runWithDebugIpc(name: string): Promise<void> {
|
|
70
|
+
if (!Env.TRV_CLI_IPC.isSet) {
|
|
77
71
|
return; // Not debugging, run normal
|
|
78
72
|
}
|
|
79
73
|
|
|
80
|
-
const
|
|
74
|
+
const doFetch = fetch.bind(null, Env.TRV_CLI_IPC.value!);
|
|
81
75
|
|
|
76
|
+
const info = await doFetch().catch(() => ({ ok: false }));
|
|
82
77
|
if (!info.ok) {
|
|
83
78
|
return; // Server not running, run normal
|
|
84
79
|
}
|
|
85
80
|
|
|
86
|
-
const env: Record<string, string> = {};
|
|
87
81
|
const request = {
|
|
88
82
|
type: '@travetto/cli:run',
|
|
89
83
|
data: {
|
|
90
|
-
name
|
|
91
|
-
env,
|
|
92
|
-
|
|
84
|
+
name,
|
|
85
|
+
env: Object.fromEntries(Object.entries(process.env).filter(validEnv)),
|
|
86
|
+
cwd: process.cwd(),
|
|
93
87
|
args: process.argv.slice(3),
|
|
94
88
|
}
|
|
95
89
|
};
|
|
96
|
-
console.log('Triggering IPC request', request);
|
|
97
90
|
|
|
98
|
-
|
|
99
|
-
const sent = await
|
|
91
|
+
console.log('Triggering IPC request', request);
|
|
92
|
+
const sent = await doFetch({ method: 'POST', body: JSONUtil.toUTF8(request) });
|
|
100
93
|
|
|
101
94
|
if (!sent.ok) {
|
|
102
95
|
throw new RuntimeError(`IPC Request failed: ${sent.status} ${await sent.text()}`);
|
|
103
96
|
}
|
|
97
|
+
|
|
98
|
+
await ShutdownManager.shutdown({ mode: 'exit' });
|
|
104
99
|
}
|
|
105
100
|
|
|
106
101
|
/**
|
|
107
102
|
* Write data to channel and ensure its flushed before continuing
|
|
108
103
|
*/
|
|
109
104
|
static async writeAndEnsureComplete(data: unknown, channel: 'stdout' | 'stderr' = 'stdout'): Promise<void> {
|
|
110
|
-
|
|
111
|
-
JSONUtil.toUTF8Pretty(data),
|
|
105
|
+
await new Promise<unknown>(resolve => process[channel].write(typeof data === 'string' ? data :
|
|
106
|
+
JSONUtil.toUTF8Pretty(data), resolve));
|
|
112
107
|
}
|
|
113
108
|
|
|
114
109
|
/**
|
|
@@ -1,12 +1,29 @@
|
|
|
1
1
|
import { Env } from '@travetto/runtime';
|
|
2
|
-
import { IsPrivate } from '@travetto/schema';
|
|
2
|
+
import { IsPrivate, MethodValidator, type ValidationError } from '@travetto/schema';
|
|
3
3
|
|
|
4
4
|
import { CliCommand } from '../src/registry/decorator.ts';
|
|
5
|
-
import type { CliCommandShape
|
|
5
|
+
import type { CliCommandShape } from '../src/types.ts';
|
|
6
6
|
import { CliCommandRegistryIndex } from '../src/registry/registry-index.ts';
|
|
7
7
|
import { CliUtil } from '../src/util.ts';
|
|
8
8
|
import { CliSchemaExportUtil } from '../src/schema-export.ts';
|
|
9
9
|
|
|
10
|
+
async function nameValidator(names?: string[]): Promise<ValidationError | undefined> {
|
|
11
|
+
if (!names || names.length === 0) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const resolved = await CliCommandRegistryIndex.load(names);
|
|
15
|
+
const invalid = names.find(name => !resolved.find(result => result.command === name));
|
|
16
|
+
|
|
17
|
+
if (invalid) {
|
|
18
|
+
return {
|
|
19
|
+
source: 'arg',
|
|
20
|
+
kind: 'invalid',
|
|
21
|
+
path: 'names',
|
|
22
|
+
message: `name: ${invalid} is not a valid cli command`
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
10
27
|
/**
|
|
11
28
|
* Generates the schema for all CLI operations
|
|
12
29
|
*/
|
|
@@ -14,25 +31,11 @@ import { CliSchemaExportUtil } from '../src/schema-export.ts';
|
|
|
14
31
|
@IsPrivate()
|
|
15
32
|
export class CliSchemaCommand implements CliCommandShape {
|
|
16
33
|
|
|
17
|
-
|
|
18
|
-
if (!names || names.length === 0) {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
const resolved = await CliCommandRegistryIndex.load(names);
|
|
22
|
-
const invalid = names.find(name => !resolved.find(result => result.command === name));
|
|
23
|
-
|
|
24
|
-
if (invalid) {
|
|
25
|
-
return {
|
|
26
|
-
source: 'arg',
|
|
27
|
-
message: `name: ${invalid} is not a valid cli command`
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
preMain(): void {
|
|
34
|
+
finalize(): void {
|
|
33
35
|
Env.DEBUG.set(false);
|
|
34
36
|
}
|
|
35
37
|
|
|
38
|
+
@MethodValidator(nameValidator)
|
|
36
39
|
async main(names?: string[]): Promise<void> {
|
|
37
40
|
const resolved = await CliCommandRegistryIndex.load(names);
|
|
38
41
|
|
package/support/cli.main.ts
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { JSONUtil, Runtime } from '@travetto/runtime';
|
|
2
|
-
import { type CliCommandShape, CliCommand,
|
|
3
|
-
import {
|
|
2
|
+
import { type CliCommandShape, CliCommand, CliParseUtil } from '@travetto/cli';
|
|
3
|
+
import { IsPrivate, MethodValidator, type ValidationError } from '@travetto/schema';
|
|
4
|
+
|
|
5
|
+
async function validateMain(fileOrImport: string): Promise<ValidationError | undefined> {
|
|
6
|
+
try {
|
|
7
|
+
await Runtime.importFrom(fileOrImport);
|
|
8
|
+
} catch {
|
|
9
|
+
return { message: `Unknown file: ${fileOrImport}`, source: 'arg', kind: 'invalid', path: 'fileOrImport' };
|
|
10
|
+
}
|
|
11
|
+
};
|
|
4
12
|
|
|
5
13
|
/**
|
|
6
14
|
* Allows for running of main entry points
|
|
@@ -9,22 +17,13 @@ import { Ignore, IsPrivate } from '@travetto/schema';
|
|
|
9
17
|
@IsPrivate()
|
|
10
18
|
export class MainCommand implements CliCommandShape {
|
|
11
19
|
|
|
12
|
-
@
|
|
13
|
-
_parsed: ParsedState;
|
|
14
|
-
|
|
15
|
-
async validate(fileOrImport: string): Promise<CliValidationError | undefined> {
|
|
16
|
-
try {
|
|
17
|
-
await Runtime.importFrom(fileOrImport);
|
|
18
|
-
} catch {
|
|
19
|
-
return { message: `Unknown file: ${fileOrImport}` };
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
20
|
+
@MethodValidator(validateMain)
|
|
23
21
|
async main(fileOrImport: string, args: string[] = []): Promise<void> {
|
|
22
|
+
const parsed = CliParseUtil.getState(this);
|
|
24
23
|
let result: unknown;
|
|
25
24
|
try {
|
|
26
25
|
const module = await Runtime.importFrom<{ main(..._: unknown[]): Promise<unknown> }>(fileOrImport);
|
|
27
|
-
result = await module.main(...args, ...
|
|
26
|
+
result = await module.main(...args, ...parsed?.unknown ?? []);
|
|
28
27
|
} catch (error) {
|
|
29
28
|
result = error;
|
|
30
29
|
process.exitCode = Math.max(process.exitCode ? +process.exitCode : 1, 1);
|
package/support/cli.service.ts
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { stripVTControlCharacters } from 'node:util';
|
|
2
|
+
|
|
3
|
+
import { type CliCommandShape, CliCommand, cliTpl } from '@travetto/cli';
|
|
2
4
|
import { Terminal } from '@travetto/terminal';
|
|
3
|
-
import { AsyncQueue,
|
|
5
|
+
import { AsyncQueue, Util } from '@travetto/runtime';
|
|
6
|
+
import { MethodValidator, type ValidationError } from '@travetto/schema';
|
|
7
|
+
|
|
8
|
+
import { ServiceRunner, type ServiceAction } from '../src/service.ts';
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
async function validateService(_: ServiceAction, services: string[]): Promise<ValidationError | undefined> {
|
|
11
|
+
const all = await ServiceRunner.findServices(services);
|
|
12
|
+
|
|
13
|
+
if (!all.length) {
|
|
14
|
+
return { message: 'No services found', source: 'arg', kind: 'invalid', path: 'services' };
|
|
15
|
+
}
|
|
16
|
+
}
|
|
6
17
|
|
|
7
18
|
/**
|
|
8
19
|
* Allows for running services
|
|
@@ -10,30 +21,10 @@ import { ServiceRunner, type ServiceDescriptor, type ServiceAction } from '../sr
|
|
|
10
21
|
@CliCommand()
|
|
11
22
|
export class CliServiceCommand implements CliCommandShape {
|
|
12
23
|
|
|
13
|
-
|
|
14
|
-
return (await Promise.all(
|
|
15
|
-
RuntimeIndex.find({
|
|
16
|
-
module: module => module.roles.includes('std'),
|
|
17
|
-
folder: folder => folder === 'support',
|
|
18
|
-
file: file => /support\/service[.]/.test(file.sourceFile)
|
|
19
|
-
})
|
|
20
|
-
.map(file => Runtime.importFrom<{ service: ServiceDescriptor }>(file.import).then(value => value.service))
|
|
21
|
-
))
|
|
22
|
-
.filter(file => !!file)
|
|
23
|
-
.filter(file => services?.length ? services.includes(file.name) : true)
|
|
24
|
-
.toSorted((a, b) => a.name.localeCompare(b.name));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async validate(action: ServiceAction, services: string[]): Promise<CliValidationError | undefined> {
|
|
28
|
-
const all = await this.#getServices(services);
|
|
29
|
-
|
|
30
|
-
if (!all.length) {
|
|
31
|
-
return { message: 'No services found' };
|
|
32
|
-
}
|
|
33
|
-
}
|
|
24
|
+
quiet = false;
|
|
34
25
|
|
|
35
26
|
async help(): Promise<string[]> {
|
|
36
|
-
const all = await
|
|
27
|
+
const all = await ServiceRunner.findServices([]);
|
|
37
28
|
return [
|
|
38
29
|
cliTpl`${{ title: 'Available Services' }}`,
|
|
39
30
|
'-'.repeat(20),
|
|
@@ -41,33 +32,50 @@ export class CliServiceCommand implements CliCommandShape {
|
|
|
41
32
|
];
|
|
42
33
|
}
|
|
43
34
|
|
|
35
|
+
@MethodValidator(validateService)
|
|
44
36
|
async main(action: ServiceAction, services: string[] = []): Promise<void> {
|
|
45
|
-
const all = await
|
|
37
|
+
const all = await ServiceRunner.findServices(services);
|
|
46
38
|
const maxName = Math.max(...all.map(service => service.name.length), 'Service'.length) + 3;
|
|
47
39
|
const maxVersion = Math.max(...all.map(service => `${service.version}`.length), 'Version'.length) + 3;
|
|
48
40
|
const maxStatus = 20;
|
|
49
41
|
const queue = new AsyncQueue<{ idx: number, text: string, done?: boolean }>();
|
|
50
42
|
|
|
43
|
+
const failureMessages: string[] = [];
|
|
44
|
+
|
|
51
45
|
const jobs = all.map(async (descriptor, i) => {
|
|
52
46
|
const identifier = descriptor.name.padEnd(maxName);
|
|
53
47
|
const type = `${descriptor.version}`.padStart(maxVersion - 3).padEnd(maxVersion);
|
|
54
|
-
let
|
|
48
|
+
let message: string;
|
|
55
49
|
for await (const [valueType, value] of new ServiceRunner(descriptor).action(action)) {
|
|
56
50
|
const details = { [valueType === 'message' ? 'subtitle' : valueType]: value };
|
|
57
|
-
queue.add({ idx: i, text:
|
|
51
|
+
queue.add({ idx: i, text: message = cliTpl`${{ identifier }} ${{ type }} ${details}` });
|
|
52
|
+
if (valueType === 'failure') {
|
|
53
|
+
failureMessages.push(message);
|
|
54
|
+
}
|
|
58
55
|
}
|
|
59
|
-
queue.add({ idx: i, done: true, text:
|
|
56
|
+
queue.add({ idx: i, done: true, text: message! });
|
|
60
57
|
});
|
|
61
58
|
|
|
62
59
|
Promise.all(jobs).then(() => Util.queueMacroTask()).then(() => queue.close());
|
|
63
60
|
|
|
64
|
-
const term = new Terminal();
|
|
65
|
-
await term.writer.writeLines([
|
|
66
|
-
'',
|
|
67
|
-
cliTpl`${{ title: 'Service'.padEnd(maxName) }} ${{ title: 'Version'.padEnd(maxVersion) }} ${{ title: 'Status' }}`,
|
|
68
|
-
''.padEnd(maxName + maxVersion + maxStatus + 3, '-'),
|
|
69
|
-
]).commit();
|
|
70
61
|
|
|
71
|
-
|
|
62
|
+
if (this.quiet) {
|
|
63
|
+
for await (const _ of queue) { }
|
|
64
|
+
if (failureMessages.length) {
|
|
65
|
+
console.error('Failure');
|
|
66
|
+
failureMessages.map(stripVTControlCharacters).map(item => console.error(item));
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
const term = new Terminal();
|
|
70
|
+
await term.writer.writeLines([
|
|
71
|
+
'',
|
|
72
|
+
cliTpl`${{ title: 'Service'.padEnd(maxName) }} ${{ title: 'Version'.padEnd(maxVersion) }} ${{ title: 'Status' }}`,
|
|
73
|
+
''.padEnd(maxName + maxVersion + maxStatus + 3, '-'),
|
|
74
|
+
]).commit();
|
|
75
|
+
|
|
76
|
+
await term.streamList(queue);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
process.exitCode = failureMessages.length ? 1 : 0;
|
|
72
80
|
}
|
|
73
81
|
}
|
package/support/entry.trv.ts
CHANGED
package/src/error.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { RuntimeError, Runtime } from '@travetto/runtime';
|
|
2
|
-
|
|
3
|
-
import { cliTpl } from './color.ts';
|
|
4
|
-
import type { CliValidationError, CliCommandShape } from './types.ts';
|
|
5
|
-
|
|
6
|
-
const COMMAND_PACKAGE = [
|
|
7
|
-
[/^test(:watch)?$/, 'test', false],
|
|
8
|
-
[/^lint(:register)?$/, 'eslint', false],
|
|
9
|
-
[/^model:(install|export)$/, 'model', true],
|
|
10
|
-
[/^openapi:(spec|client)$/, 'openapi', true],
|
|
11
|
-
[/^email:(compile|editor)$/, 'email-compiler', false],
|
|
12
|
-
[/^pack(:zip|:docker)?$/, 'pack', false],
|
|
13
|
-
[/^web:http$/, 'web-http', true],
|
|
14
|
-
[/^web:rpc-client$/, 'web-rpc', true],
|
|
15
|
-
] as const;
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Provides a contract for unknown commands
|
|
19
|
-
*/
|
|
20
|
-
export class CliUnknownCommandError extends Error {
|
|
21
|
-
|
|
22
|
-
#getMissingCommandHelp(cmd: string): string | undefined {
|
|
23
|
-
const matchedConfig = COMMAND_PACKAGE.find(([regex]) => regex.test(cmd));
|
|
24
|
-
if (matchedConfig) {
|
|
25
|
-
const [, pkg, production] = matchedConfig;
|
|
26
|
-
const install = Runtime.getInstallCommand(`@travetto/${pkg}`, production);
|
|
27
|
-
return cliTpl`
|
|
28
|
-
${{ title: 'Missing Package' }}\n${'-'.repeat(20)}\nTo use ${{ input: cmd }} please run:\n
|
|
29
|
-
${{ identifier: install }}
|
|
30
|
-
`;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
help?: string;
|
|
35
|
-
cmd: string;
|
|
36
|
-
|
|
37
|
-
constructor(cmd: string) {
|
|
38
|
-
super(`Unknown command: ${cmd}`);
|
|
39
|
-
this.cmd = cmd;
|
|
40
|
-
this.help = this.#getMissingCommandHelp(cmd);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
get defaultMessage(): string {
|
|
44
|
-
return cliTpl`${{ subtitle: 'Unknown command' }}: ${{ input: this.cmd }}`;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Provides a basic error wrapper for cli validation issues
|
|
50
|
-
*/
|
|
51
|
-
export class CliValidationResultError extends RuntimeError<{ errors: CliValidationError[] }> {
|
|
52
|
-
command: CliCommandShape;
|
|
53
|
-
|
|
54
|
-
constructor(command: CliCommandShape, errors: CliValidationError[]) {
|
|
55
|
-
super('', { details: { errors } });
|
|
56
|
-
this.command = command;
|
|
57
|
-
}
|
|
58
|
-
}
|