@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 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#L109) 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`
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
- ## How Logging is Instrumented
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
- ### Filtering Debug
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#L39) 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.
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
@@ -2,6 +2,7 @@
2
2
  /// <reference path="./src/global.d.ts" />
3
3
  export * from './src/console';
4
4
  export * from './src/context';
5
+ export * from './src/debug';
5
6
  export * from './src/error';
6
7
  export * from './src/exec';
7
8
  export * from './src/env';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/runtime",
3
- "version": "5.0.0-rc.2",
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": "^20.14.10",
33
+ "@types/node": "^22.1.0",
31
34
  "debug": "^4.3.5"
32
35
  },
33
36
  "peerDependencies": {
34
- "@travetto/transformer": "^5.0.0-rc.2"
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 { type ManifestContext } from '@travetto/manifest';
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
- export const Runtime = {
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 name(): string | undefined {
23
- return Env.TRV_ENV.val || (!prod() ? RuntimeIndex.manifest.workspace.defaultEnv : undefined);
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 prod();
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 && prod()) || Env.DEBUG.isFalse ? false : 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 RuntimeIndex.manifest.main;
45
- },
48
+ return this.#idx.manifest.main;
49
+ }
46
50
 
47
51
  /** Manifest workspace */
48
52
  get workspace(): ManifestContext['workspace'] {
49
- return RuntimeIndex.manifest.workspace;
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 !!RuntimeIndex.manifest.workspace.mono && !RuntimeIndex.manifest.main.folder;
55
- },
58
+ return !!this.workspace.mono && !this.main.folder;
59
+ }
56
60
 
57
61
  /** Main source path */
58
62
  get mainSourcePath(): string {
59
- return RuntimeIndex.mainModule.sourcePath;
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(RuntimeIndex.manifest.workspace.path, ...rel);
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 === RuntimeIndex.manifest.workspace.path ? '' : full.replace(`${RuntimeIndex.manifest.workspace.path}/`, '');
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', RuntimeIndex.manifest.main.name] : [x]);
75
- return path.resolve(RuntimeIndex.manifest.workspace.path, RuntimeIndex.manifest.build.toolFolder, ...rel);
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] = (OVERRIDES[modulePath] ?? modulePath)
81
- .replace(/^([^#]*)(#|$)/g, (_, v, r) => `${MODULE_ALIASES[v] ?? 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(RuntimeIndex.getModule(base)?.sourcePath ?? base, sub ?? '.');
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 this.modulePaths([...paths, ...Env.TRV_RESOURCES.list ?? [], '@#resources', '@@#resources']);
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
- getSource(fn: Function): string {
98
- return RuntimeIndex.getFromImport(describeFunction(fn).import)?.sourceFile!;
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
+ }
@@ -13,7 +13,7 @@ export class FileLoader {
13
13
  #searchPaths: readonly string[];
14
14
 
15
15
  constructor(paths: string[]) {
16
- this.#searchPaths = paths;
16
+ this.#searchPaths = [...new Set(paths)]; // Dedupe
17
17
  }
18
18
 
19
19
  /**
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 register(
24
- fn: Function, module: [string, string], tag: FunctionMetadataTag,
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
- let id = module.join(':');
28
- if (fn.name) {
29
- id = `${id}○${fn.name}`;
30
- }
31
- const value = { id, import: module.join('/'), ...tag, methods, abstract, synthetic };
32
- Object.defineProperties(fn, { Ⲑid: { value: id }, [METADATA]: { value } });
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, 'register'),
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, 'register'),
132
+ state.createAccess(state[registerImport].ident, registerFn),
126
133
  [],
127
134
  [
128
135
  state.createIdentifier(node.name),