@travetto/runtime 5.0.0-rc.2 → 5.0.0-rc.4
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 +61 -14
- package/__index__.ts +1 -0
- package/package.json +6 -3
- package/src/context.ts +55 -49
- package/src/debug.ts +18 -0
- package/src/file-loader.ts +1 -1
- package/src/function.ts +26 -9
- package/src/trv.d.ts +6 -1
- package/src/types.ts +12 -1
- package/support/transformer.debug-method.ts +41 -0
- package/support/transformer.function-metadata.ts +9 -2
package/README.md
CHANGED
|
@@ -14,19 +14,61 @@ yarn add @travetto/runtime
|
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
Runtime is the foundation of all [Travetto](https://travetto.dev) applications. It is intended to be a minimal application set, as well as support for commonly shared functionality. It has support for the following key areas:
|
|
17
|
-
* Environment Support
|
|
18
17
|
* Runtime Context
|
|
18
|
+
* Environment Support
|
|
19
|
+
* Standard Error Support
|
|
19
20
|
* Console Management
|
|
20
21
|
* Resource Access
|
|
21
|
-
* Standard Error Support
|
|
22
22
|
* Common Utilities
|
|
23
23
|
* Time Utilities
|
|
24
24
|
* Process Execution
|
|
25
25
|
* Shutdown Management
|
|
26
26
|
* Path behavior
|
|
27
27
|
|
|
28
|
+
## Runtime Context
|
|
29
|
+
While running any code within the framework, there are common patterns/goals for interacting with the underlying code repository. These include:
|
|
30
|
+
* Determining attributes of the running environment (e.g., name, debug information, production flags)
|
|
31
|
+
* Resolving paths within the workspace (e.g. standard, tooling, resourcing, modules)
|
|
32
|
+
|
|
33
|
+
**Code: Runtime Shape**
|
|
34
|
+
```typescript
|
|
35
|
+
class $Runtime {
|
|
36
|
+
constructor(idx: ManifestIndex, resourceOverrides?: Record<string, string>);
|
|
37
|
+
/** Get env name, with support for the default env */
|
|
38
|
+
get envName(): string | undefined;
|
|
39
|
+
/** Are we in development mode */
|
|
40
|
+
get production(): boolean;
|
|
41
|
+
/** Is the app in dynamic mode? */
|
|
42
|
+
get dynamic(): boolean;
|
|
43
|
+
/** Get debug value */
|
|
44
|
+
get debug(): false | string;
|
|
45
|
+
/** Manifest main */
|
|
46
|
+
get main(): ManifestContext['main'];
|
|
47
|
+
/** Manifest workspace */
|
|
48
|
+
get workspace(): ManifestContext['workspace'];
|
|
49
|
+
/** Are we running from a mono-root? */
|
|
50
|
+
get monoRoot(): boolean;
|
|
51
|
+
/** Main source path */
|
|
52
|
+
get mainSourcePath(): string;
|
|
53
|
+
/** Produce a workspace relative path */
|
|
54
|
+
workspaceRelative(...rel: string[]): string;
|
|
55
|
+
/** Strip off the workspace path from a file */
|
|
56
|
+
stripWorkspacePath(full: string): string;
|
|
57
|
+
/** Produce a workspace path for tooling, with '@' being replaced by node_module/name folder */
|
|
58
|
+
toolPath(...rel: string[]): string;
|
|
59
|
+
/** Resolve single module path */
|
|
60
|
+
modulePath(modulePath: string): string;
|
|
61
|
+
/** Resolve resource paths */
|
|
62
|
+
resourcePaths(paths: string[] = []): string[];
|
|
63
|
+
/** Get source for function */
|
|
64
|
+
getSourceFile(fn: Function): string;
|
|
65
|
+
/** Get import for function */
|
|
66
|
+
getImport(fn: Function): string;
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
28
70
|
## Environment Support
|
|
29
|
-
The functionality we support for testing and retrieving environment information for known environment variables. They can be accessed directly on the [Env](https://github.com/travetto/travetto/tree/main/module/runtime/src/env.ts#
|
|
71
|
+
The functionality we support for testing and retrieving environment information for known environment variables. They can be accessed directly on the [Env](https://github.com/travetto/travetto/tree/main/module/runtime/src/env.ts#L108) object, and will return a scoped [EnvProp](https://github.com/travetto/travetto/tree/main/module/runtime/src/env.ts#L4), that is compatible with the property definition. E.g. only showing boolean related fields when the underlying flag supports `true` or `false`
|
|
30
72
|
|
|
31
73
|
**Code: Base Known Environment Flags**
|
|
32
74
|
```typescript
|
|
@@ -78,7 +120,12 @@ interface TravettoEnv {
|
|
|
78
120
|
/**
|
|
79
121
|
* trvc log level
|
|
80
122
|
*/
|
|
81
|
-
TRV_BUILD: 'none' | 'info' | 'debug' | 'error' | 'warn'
|
|
123
|
+
TRV_BUILD: 'none' | 'info' | 'debug' | 'error' | 'warn',
|
|
124
|
+
/**
|
|
125
|
+
* Should break on first line of a method when using the @DebugBreak decorator
|
|
126
|
+
* @default false
|
|
127
|
+
*/
|
|
128
|
+
TRV_DEBUG_BREAK: boolean;
|
|
82
129
|
}
|
|
83
130
|
```
|
|
84
131
|
|
|
@@ -114,13 +161,6 @@ export class EnvProp<T> {
|
|
|
114
161
|
}
|
|
115
162
|
```
|
|
116
163
|
|
|
117
|
-
## Resource Access
|
|
118
|
-
The primary access patterns for resources, is to directly request a file, and to resolve that file either via file-system look up or leveraging the [Manifest](https://github.com/travetto/travetto/tree/main/module/manifest#readme "Support for project indexing, manifesting, along with file watching")'s data for what resources were found at manifesting time.
|
|
119
|
-
|
|
120
|
-
The [FileLoader](https://github.com/travetto/travetto/tree/main/module/runtime/src/file-loader.ts#L11) allows for accessing information about the resources, and subsequently reading the file as text/binary or to access the resource as a `Readable` stream. If a file is not found, it will throw an [AppError](https://github.com/travetto/travetto/tree/main/module/runtime/src/error.ts#L13) with a category of 'notfound'.
|
|
121
|
-
|
|
122
|
-
The [FileLoader](https://github.com/travetto/travetto/tree/main/module/runtime/src/file-loader.ts#L11) also supports tying itself to [Env](https://github.com/travetto/travetto/tree/main/module/runtime/src/env.ts#L109)'s `TRV_RESOURCES` information on where to attempt to find a requested resource.
|
|
123
|
-
|
|
124
164
|
## Standard Error Support
|
|
125
165
|
While the framework is 100 % compatible with standard `Error` instances, there are cases in which additional functionality is desired. Within the framework we use [AppError](https://github.com/travetto/travetto/tree/main/module/runtime/src/error.ts#L13) (or its derivatives) to represent framework errors. This class is available for use in your own projects. Some of the additional benefits of using this class is enhanced error reporting, as well as better integration with other modules (e.g. the [RESTful API](https://github.com/travetto/travetto/tree/main/module/rest#readme "Declarative api for RESTful APIs with support for the dependency injection module.") module and HTTP status codes).
|
|
126
166
|
|
|
@@ -146,7 +186,7 @@ The supported operations are:
|
|
|
146
186
|
|
|
147
187
|
**Note**: All other console methods are excluded, specifically `trace`, `inspect`, `dir`, `time`/`timeEnd`
|
|
148
188
|
|
|
149
|
-
|
|
189
|
+
### How Logging is Instrumented
|
|
150
190
|
All of the logging instrumentation occurs at transpilation time. All `console.*` methods are replaced with a call to a globally defined variable that delegates to the [ConsoleManager](https://github.com/travetto/travetto/tree/main/module/runtime/src/console.ts#L35). This module, hooks into the [ConsoleManager](https://github.com/travetto/travetto/tree/main/module/runtime/src/console.ts#L35) and receives all logging events from all files compiled by the [Travetto](https://travetto.dev).
|
|
151
191
|
|
|
152
192
|
A sample of the instrumentation would be:
|
|
@@ -185,7 +225,7 @@ function work() {
|
|
|
185
225
|
}
|
|
186
226
|
```
|
|
187
227
|
|
|
188
|
-
|
|
228
|
+
#### Filtering Debug
|
|
189
229
|
The `debug` messages can be filtered using the patterns from the [debug](https://www.npmjs.com/package/debug). You can specify wild cards to only `DEBUG` specific modules, folders or files. You can specify multiple, and you can also add negations to exclude specific packages.
|
|
190
230
|
|
|
191
231
|
**Terminal: Sample environment flags**
|
|
@@ -207,6 +247,13 @@ Additionally, the logging framework will merge [debug](https://www.npmjs.com/pac
|
|
|
207
247
|
$ DEBUG=express:*,@travetto/rest npx trv run rest
|
|
208
248
|
```
|
|
209
249
|
|
|
250
|
+
## Resource Access
|
|
251
|
+
The primary access patterns for resources, is to directly request a file, and to resolve that file either via file-system look up or leveraging the [Manifest](https://github.com/travetto/travetto/tree/main/module/manifest#readme "Support for project indexing, manifesting, along with file watching")'s data for what resources were found at manifesting time.
|
|
252
|
+
|
|
253
|
+
The [FileLoader](https://github.com/travetto/travetto/tree/main/module/runtime/src/file-loader.ts#L11) allows for accessing information about the resources, and subsequently reading the file as text/binary or to access the resource as a `Readable` stream. If a file is not found, it will throw an [AppError](https://github.com/travetto/travetto/tree/main/module/runtime/src/error.ts#L13) with a category of 'notfound'.
|
|
254
|
+
|
|
255
|
+
The [FileLoader](https://github.com/travetto/travetto/tree/main/module/runtime/src/file-loader.ts#L11) also supports tying itself to [Env](https://github.com/travetto/travetto/tree/main/module/runtime/src/env.ts#L108)'s `TRV_RESOURCES` information on where to attempt to find a requested resource.
|
|
256
|
+
|
|
210
257
|
## Common Utilities
|
|
211
258
|
Common utilities used throughout the framework. Currently [Util](https://github.com/travetto/travetto/tree/main/module/runtime/src/util.ts#L17) includes:
|
|
212
259
|
* `uuid(len: number)` generates a simple uuid for use within the application.
|
|
@@ -268,7 +315,7 @@ export class TimeUtil {
|
|
|
268
315
|
```
|
|
269
316
|
|
|
270
317
|
## Process Execution
|
|
271
|
-
[ExecUtil](https://github.com/travetto/travetto/tree/main/module/runtime/src/exec.ts#
|
|
318
|
+
[ExecUtil](https://github.com/travetto/travetto/tree/main/module/runtime/src/exec.ts#L41) exposes `getResult` as a means to wrap [child_process](https://nodejs.org/api/child_process.html)'s process object. This wrapper allows for a promise-based resolution of the subprocess with the ability to capture the stderr/stdout.
|
|
272
319
|
|
|
273
320
|
A simple example would be:
|
|
274
321
|
|
package/__index__.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/runtime",
|
|
3
|
-
"version": "5.0.0-rc.
|
|
3
|
+
"version": "5.0.0-rc.4",
|
|
4
4
|
"description": "Runtime for travetto applications.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"console-manager",
|
|
@@ -24,14 +24,17 @@
|
|
|
24
24
|
"url": "https://github.com/travetto/travetto.git",
|
|
25
25
|
"directory": "module/runtime"
|
|
26
26
|
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=22.0.0"
|
|
29
|
+
},
|
|
27
30
|
"dependencies": {
|
|
28
31
|
"@travetto/manifest": "^5.0.0-rc.2",
|
|
29
32
|
"@types/debug": "^4.1.12",
|
|
30
|
-
"@types/node": "^
|
|
33
|
+
"@types/node": "^22.1.0",
|
|
31
34
|
"debug": "^4.3.5"
|
|
32
35
|
},
|
|
33
36
|
"peerDependencies": {
|
|
34
|
-
"@travetto/transformer": "^5.0.0-rc.
|
|
37
|
+
"@travetto/transformer": "^5.0.0-rc.3"
|
|
35
38
|
},
|
|
36
39
|
"peerDependenciesMeta": {
|
|
37
40
|
"@travetto/transformer": {
|
package/src/context.ts
CHANGED
|
@@ -1,100 +1,106 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import type { ManifestIndex, ManifestContext } from '@travetto/manifest';
|
|
4
4
|
|
|
5
5
|
import { Env } from './env';
|
|
6
6
|
import { RuntimeIndex } from './manifest-index';
|
|
7
7
|
import { describeFunction } from './function';
|
|
8
8
|
|
|
9
|
-
const prod = (): boolean => process.env.NODE_ENV === 'production';
|
|
10
|
-
|
|
11
|
-
const OVERRIDES = Env.TRV_RESOURCE_OVERRIDES.object ?? {};
|
|
12
|
-
|
|
13
|
-
const MODULE_ALIASES: Record<string, string> = {
|
|
14
|
-
'@': RuntimeIndex.manifest.main.name,
|
|
15
|
-
'@@': RuntimeIndex.manifest.workspace.path,
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
|
|
19
9
|
/** Constrained version of {@type ManifestContext} */
|
|
20
|
-
|
|
10
|
+
class $Runtime {
|
|
11
|
+
|
|
12
|
+
#idx: ManifestIndex;
|
|
13
|
+
#moduleAliases: Record<string, string>;
|
|
14
|
+
#resourceOverrides?: Record<string, string>;
|
|
15
|
+
|
|
16
|
+
constructor(idx: ManifestIndex, resourceOverrides?: Record<string, string>) {
|
|
17
|
+
this.#idx = idx;
|
|
18
|
+
this.#moduleAliases = {
|
|
19
|
+
'@': idx.manifest.main.name,
|
|
20
|
+
'@@': idx.manifest.workspace.path,
|
|
21
|
+
};
|
|
22
|
+
this.#resourceOverrides = resourceOverrides;
|
|
23
|
+
}
|
|
24
|
+
|
|
21
25
|
/** Get env name, with support for the default env */
|
|
22
|
-
get
|
|
23
|
-
return Env.TRV_ENV.val || (!
|
|
24
|
-
}
|
|
26
|
+
get envName(): string | undefined {
|
|
27
|
+
return Env.TRV_ENV.val || (!this.production ? this.#idx.manifest.workspace.defaultEnv : undefined);
|
|
28
|
+
}
|
|
25
29
|
|
|
26
30
|
/** Are we in development mode */
|
|
27
31
|
get production(): boolean {
|
|
28
|
-
return
|
|
29
|
-
}
|
|
32
|
+
return process.env.NODE_ENV === 'production';
|
|
33
|
+
}
|
|
30
34
|
|
|
31
35
|
/** Is the app in dynamic mode? */
|
|
32
36
|
get dynamic(): boolean {
|
|
33
37
|
return Env.TRV_DYNAMIC.isTrue;
|
|
34
|
-
}
|
|
38
|
+
}
|
|
35
39
|
|
|
36
40
|
/** Get debug value */
|
|
37
41
|
get debug(): false | string {
|
|
38
42
|
const val = Env.DEBUG.val ?? '';
|
|
39
|
-
return (!val &&
|
|
40
|
-
}
|
|
43
|
+
return (!val && this.production) || Env.DEBUG.isFalse ? false : val;
|
|
44
|
+
}
|
|
41
45
|
|
|
42
46
|
/** Manifest main */
|
|
43
47
|
get main(): ManifestContext['main'] {
|
|
44
|
-
return
|
|
45
|
-
}
|
|
48
|
+
return this.#idx.manifest.main;
|
|
49
|
+
}
|
|
46
50
|
|
|
47
51
|
/** Manifest workspace */
|
|
48
52
|
get workspace(): ManifestContext['workspace'] {
|
|
49
|
-
return
|
|
50
|
-
}
|
|
53
|
+
return this.#idx.manifest.workspace;
|
|
54
|
+
}
|
|
51
55
|
|
|
52
56
|
/** Are we running from a mono-root? */
|
|
53
57
|
get monoRoot(): boolean {
|
|
54
|
-
return !!
|
|
55
|
-
}
|
|
58
|
+
return !!this.workspace.mono && !this.main.folder;
|
|
59
|
+
}
|
|
56
60
|
|
|
57
61
|
/** Main source path */
|
|
58
62
|
get mainSourcePath(): string {
|
|
59
|
-
return
|
|
60
|
-
}
|
|
63
|
+
return this.#idx.mainModule.sourcePath;
|
|
64
|
+
}
|
|
61
65
|
|
|
62
66
|
/** Produce a workspace relative path */
|
|
63
67
|
workspaceRelative(...rel: string[]): string {
|
|
64
|
-
return path.resolve(
|
|
65
|
-
}
|
|
68
|
+
return path.resolve(this.workspace.path, ...rel);
|
|
69
|
+
}
|
|
66
70
|
|
|
67
71
|
/** Strip off the workspace path from a file */
|
|
68
72
|
stripWorkspacePath(full: string): string {
|
|
69
|
-
return full ===
|
|
70
|
-
}
|
|
73
|
+
return full === this.workspace.path ? '' : full.replace(`${this.workspace.path}/`, '');
|
|
74
|
+
}
|
|
71
75
|
|
|
72
76
|
/** Produce a workspace path for tooling, with '@' being replaced by node_module/name folder */
|
|
73
77
|
toolPath(...rel: string[]): string {
|
|
74
|
-
rel = rel.flatMap(x => x === '@' ? ['node_modules',
|
|
75
|
-
return path.resolve(
|
|
76
|
-
}
|
|
78
|
+
rel = rel.flatMap(x => x === '@' ? ['node_modules', this.#idx.manifest.main.name] : [x]);
|
|
79
|
+
return path.resolve(this.workspace.path, this.#idx.manifest.build.toolFolder, ...rel);
|
|
80
|
+
}
|
|
77
81
|
|
|
78
82
|
/** Resolve single module path */
|
|
79
83
|
modulePath(modulePath: string): string {
|
|
80
|
-
const [base, sub] = (
|
|
81
|
-
.replace(/^([^#]*)(#|$)/g, (_, v, r) => `${
|
|
84
|
+
const [base, sub] = (this.#resourceOverrides?.[modulePath] ?? modulePath)
|
|
85
|
+
.replace(/^([^#]*)(#|$)/g, (_, v, r) => `${this.#moduleAliases[v] ?? v}${r}`)
|
|
82
86
|
.split('#');
|
|
83
|
-
return path.resolve(
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/** Resolve module paths */
|
|
87
|
-
modulePaths(paths: string[]): string[] {
|
|
88
|
-
return [...new Set(paths.map(this.modulePath))];
|
|
89
|
-
},
|
|
87
|
+
return path.resolve(this.#idx.getModule(base)?.sourcePath ?? base, sub ?? '.');
|
|
88
|
+
}
|
|
90
89
|
|
|
91
90
|
/** Resolve resource paths */
|
|
92
91
|
resourcePaths(paths: string[] = []): string[] {
|
|
93
|
-
return
|
|
94
|
-
}
|
|
92
|
+
return [...paths, ...Env.TRV_RESOURCES.list ?? [], '@#resources', '@@#resources'].map(v => this.modulePath(v));
|
|
93
|
+
}
|
|
95
94
|
|
|
96
95
|
/** Get source for function */
|
|
97
|
-
|
|
98
|
-
return
|
|
96
|
+
getSourceFile(fn: Function): string {
|
|
97
|
+
return this.#idx.getFromImport(this.getImport(fn))?.sourceFile!;
|
|
99
98
|
}
|
|
100
|
-
|
|
99
|
+
|
|
100
|
+
/** Get import for function */
|
|
101
|
+
getImport(fn: Function): string {
|
|
102
|
+
return describeFunction(fn).import;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export const Runtime = new $Runtime(RuntimeIndex, Env.TRV_RESOURCE_OVERRIDES.object);
|
package/src/debug.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Env } from './env';
|
|
2
|
+
import { ClassInstance } from './types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The `@DebugBreak` indicates that a function inserts an optional debugger keyword to stop on entry
|
|
6
|
+
* @augments `@travetto/runtime:DebugBreak`
|
|
7
|
+
*/
|
|
8
|
+
export function DebugBreak(): MethodDecorator {
|
|
9
|
+
return (inst: ClassInstance, prop: string | symbol, descriptor: PropertyDescriptor) => descriptor;
|
|
10
|
+
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Determine if we should invoke the debugger
|
|
15
|
+
*/
|
|
16
|
+
export function tryDebugger(): boolean {
|
|
17
|
+
return Env.TRV_DEBUG_BREAK.isTrue;
|
|
18
|
+
}
|
package/src/file-loader.ts
CHANGED
package/src/function.ts
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
export type FunctionMetadataTag = { hash: number, lines: [number, number] };
|
|
1
|
+
export type FunctionMetadataTag = { hash: number, lines: [start: number, end: number, bodyStart?: number] };
|
|
2
2
|
export type FunctionMetadata = FunctionMetadataTag & {
|
|
3
3
|
id: string;
|
|
4
4
|
import: string;
|
|
5
|
+
module: string;
|
|
6
|
+
modulePath: string;
|
|
5
7
|
methods?: Record<string, FunctionMetadataTag>;
|
|
6
8
|
synthetic?: boolean;
|
|
9
|
+
class?: boolean;
|
|
7
10
|
abstract?: boolean;
|
|
8
11
|
};
|
|
9
12
|
|
|
10
13
|
const METADATA = Symbol.for('@travetto/runtime:function-metadata');
|
|
11
14
|
|
|
15
|
+
const pending = new Set<Function>([]);
|
|
16
|
+
|
|
12
17
|
/**
|
|
13
18
|
* Initialize the meta data for a function/class
|
|
14
19
|
* @param fn Class
|
|
@@ -20,16 +25,28 @@ const METADATA = Symbol.for('@travetto/runtime:function-metadata');
|
|
|
20
25
|
* @param `synthetic` Is this code generated at build time
|
|
21
26
|
* @private
|
|
22
27
|
*/
|
|
23
|
-
export function
|
|
24
|
-
fn: Function,
|
|
28
|
+
export function registerFunction(
|
|
29
|
+
fn: Function, [pkg, pth]: [string, string], tag: FunctionMetadataTag,
|
|
25
30
|
methods?: Record<string, FunctionMetadataTag>, abstract?: boolean, synthetic?: boolean
|
|
26
31
|
): void {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
const metadata = {
|
|
33
|
+
id: fn.name ? `${pkg}:${pth}○${fn.name}` : `${pkg}:${pth}`,
|
|
34
|
+
import: `${pkg}/${pth}`,
|
|
35
|
+
module: pkg,
|
|
36
|
+
modulePath: pth,
|
|
37
|
+
...tag, methods, abstract, synthetic, class: abstract !== undefined
|
|
38
|
+
};
|
|
39
|
+
pending.add(fn);
|
|
40
|
+
Object.defineProperties(fn, { Ⲑid: { value: metadata.id }, [METADATA]: { value: metadata } });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Flush all pending function registers
|
|
45
|
+
*/
|
|
46
|
+
export function flushPendingFunctions(): Function[] {
|
|
47
|
+
const fns = [...pending];
|
|
48
|
+
pending.clear();
|
|
49
|
+
return fns;
|
|
33
50
|
}
|
|
34
51
|
|
|
35
52
|
/**
|
package/src/trv.d.ts
CHANGED
|
@@ -54,6 +54,11 @@ declare global {
|
|
|
54
54
|
/**
|
|
55
55
|
* trvc log level
|
|
56
56
|
*/
|
|
57
|
-
TRV_BUILD: 'none' | 'info' | 'debug' | 'error' | 'warn'
|
|
57
|
+
TRV_BUILD: 'none' | 'info' | 'debug' | 'error' | 'warn',
|
|
58
|
+
/**
|
|
59
|
+
* Should break on first line of a method when using the @DebugBreak decorator
|
|
60
|
+
* @default false
|
|
61
|
+
*/
|
|
62
|
+
TRV_DEBUG_BREAK: boolean;
|
|
58
63
|
}
|
|
59
64
|
}
|
package/src/types.ts
CHANGED
|
@@ -5,8 +5,19 @@ export type ClassInstance<T = any> = T & {
|
|
|
5
5
|
constructor: ConcreteClass<T> & { Ⲑid: string };
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
+
export type AnyMap = {
|
|
9
|
+
[key: string]: any
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type Primitive = number | bigint | boolean | string | Date;
|
|
13
|
+
|
|
14
|
+
export type DeepPartial<T> = {
|
|
15
|
+
[P in keyof T]?: (T[P] extends (Primitive | undefined) ? (T[P] | undefined) :
|
|
16
|
+
(T[P] extends any[] ? (DeepPartial<T[P][number]> | null | undefined)[] : DeepPartial<T[P]>));
|
|
17
|
+
};
|
|
18
|
+
|
|
8
19
|
export const TypedObject: {
|
|
9
20
|
keys<T = unknown, K extends keyof T = keyof T>(o: T): K[];
|
|
10
21
|
fromEntries<K extends string | symbol, V>(items: ([K, V] | readonly [K, V])[]): Record<K, V>;
|
|
11
22
|
entries<K extends Record<symbol | string, unknown>>(record: K): [keyof K, K[keyof K]][];
|
|
12
|
-
} & ObjectConstructor = Object;
|
|
23
|
+
} & ObjectConstructor = Object;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
|
|
3
|
+
import { TransformerState, OnMethod, CoreUtil } from '@travetto/transformer';
|
|
4
|
+
|
|
5
|
+
const DebugⲐ = Symbol.for('@travetto/runtime:debug');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Debug transformation state
|
|
9
|
+
*/
|
|
10
|
+
interface DebugState {
|
|
11
|
+
[DebugⲐ]?: ts.Expression;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Add debugger-optional statement to methods that should be debuggable
|
|
16
|
+
*/
|
|
17
|
+
export class DebugEntryTransformer {
|
|
18
|
+
|
|
19
|
+
@OnMethod('DebugBreak')
|
|
20
|
+
static debugOnEntry(state: TransformerState & DebugState, node: ts.MethodDeclaration): ts.MethodDeclaration {
|
|
21
|
+
if (!state[DebugⲐ]) {
|
|
22
|
+
const imp = state.importFile('@travetto/runtime/src/debug').ident;
|
|
23
|
+
state[DebugⲐ] = CoreUtil.createAccess(state.factory, imp, 'tryDebugger');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return state.factory.updateMethodDeclaration(node,
|
|
27
|
+
node.modifiers,
|
|
28
|
+
node.asteriskToken,
|
|
29
|
+
node.name,
|
|
30
|
+
node.questionToken,
|
|
31
|
+
node.typeParameters,
|
|
32
|
+
node.parameters,
|
|
33
|
+
node.type,
|
|
34
|
+
node.body ? state.factory.updateBlock(node.body, [
|
|
35
|
+
state.factory.createIfStatement(state[DebugⲐ]!,
|
|
36
|
+
state.factory.createExpressionStatement(state.factory.createIdentifier('debugger'))),
|
|
37
|
+
...node.body.statements
|
|
38
|
+
]) : node.body
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -15,6 +15,7 @@ const methods = Symbol.for(`${RUNTIME_MOD}:methods`);
|
|
|
15
15
|
const cls = Symbol.for(`${RUNTIME_MOD}:class`);
|
|
16
16
|
const fn = Symbol.for(`${RUNTIME_MOD}:function`);
|
|
17
17
|
const registerImport = Symbol.for(`${RUNTIME_MOD}:registerImport`);
|
|
18
|
+
const registerFn = 'registerFunction';
|
|
18
19
|
|
|
19
20
|
interface MetadataInfo {
|
|
20
21
|
[registerImport]?: Import;
|
|
@@ -32,6 +33,12 @@ export class RegisterTransformer {
|
|
|
32
33
|
const hash = SystemUtil.naiveHash(node.getText());
|
|
33
34
|
try {
|
|
34
35
|
const range = CoreUtil.getRangeOf(state.source, node) ?? [0, 0];
|
|
36
|
+
if (ts.isMethodDeclaration(node) || ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node)) {
|
|
37
|
+
const bodyStart = CoreUtil.getRangeOf(state.source, node?.body?.statements[0])?.[0];
|
|
38
|
+
if (bodyStart) {
|
|
39
|
+
range.push(bodyStart);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
35
42
|
return { hash, lines: range };
|
|
36
43
|
} catch (err) {
|
|
37
44
|
return { hash, lines: [0, 0] };
|
|
@@ -80,7 +87,7 @@ export class RegisterTransformer {
|
|
|
80
87
|
const name = node.name?.escapedText.toString() ?? '';
|
|
81
88
|
|
|
82
89
|
const meta = state.factory.createCallExpression(
|
|
83
|
-
state.createAccess(state[registerImport].ident,
|
|
90
|
+
state.createAccess(state[registerImport].ident, registerFn),
|
|
84
91
|
[],
|
|
85
92
|
[
|
|
86
93
|
state.createIdentifier(name),
|
|
@@ -122,7 +129,7 @@ export class RegisterTransformer {
|
|
|
122
129
|
state[registerImport] ??= state.importFile(REGISTER_IMPORT);
|
|
123
130
|
const tag = this.#tag(state, node);
|
|
124
131
|
const meta = state.factory.createCallExpression(
|
|
125
|
-
state.createAccess(state[registerImport].ident,
|
|
132
|
+
state.createAccess(state[registerImport].ident, registerFn),
|
|
126
133
|
[],
|
|
127
134
|
[
|
|
128
135
|
state.createIdentifier(node.name),
|