@travetto/runtime 5.0.0-rc.8 → 5.0.0-rc.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
@@ -71,7 +71,7 @@ class $Runtime {
71
71
  ```
72
72
 
73
73
  ## Environment Support
74
- 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`
74
+ 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#L6), that is compatible with the property definition. E.g. only showing boolean related fields when the underlying flag supports `true` or `false`
75
75
 
76
76
  **Code: Base Known Environment Flags**
77
77
  ```typescript
@@ -133,7 +133,7 @@ interface TravettoEnv {
133
133
  ```
134
134
 
135
135
  ### Environment Property
136
- For a given [EnvProp](https://github.com/travetto/travetto/tree/main/module/runtime/src/env.ts#L4), we support the ability to access different properties as a means to better facilitate environment variable usage.
136
+ For a given [EnvProp](https://github.com/travetto/travetto/tree/main/module/runtime/src/env.ts#L6), we support the ability to access different properties as a means to better facilitate environment variable usage.
137
137
 
138
138
  **Code: EnvProp Shape**
139
139
  ```typescript
@@ -165,9 +165,9 @@ export class EnvProp<T> {
165
165
  ```
166
166
 
167
167
  ## Standard Error Support
168
- 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).
168
+ 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#L15) (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).
169
169
 
170
- The [AppError](https://github.com/travetto/travetto/tree/main/module/runtime/src/error.ts#L13) takes in a message, and an optional payload and / or error classification. The currently supported error classifications are:
170
+ The [AppError](https://github.com/travetto/travetto/tree/main/module/runtime/src/error.ts#L15) takes in a message, and an optional payload and / or error classification. The currently supported error classifications are:
171
171
  * `general` - General purpose errors
172
172
  * `system` - Synonym for `general`
173
173
  * `data` - Data format, content, etc are incorrect. Generally correlated to bad input.
@@ -214,6 +214,7 @@ export function work() {
214
214
  Object.defineProperty(exports, "__esModule", { value: true });
215
215
  exports.work = work;
216
216
  const tslib_1 = require("tslib");
217
+ const Ⲑ_function_1 = tslib_1.__importStar(require("@travetto/runtime/src/function.js"));
217
218
  const ᚕ_c = tslib_1.__importStar(require("@travetto/runtime/src/console.js"));
218
219
  var ᚕm = ["@travetto/runtime", "doc/transpile.ts"];
219
220
  function work() {
@@ -226,6 +227,7 @@ function work() {
226
227
  }
227
228
  ᚕ_c.log({ level: "debug", import: ᚕm, line: 9, scope: "work", args: ['End Work'] });
228
229
  }
230
+ Ⲑ_function_1.registerFunction(work, ᚕm, { hash: 1030247697, lines: [1, 10, 2] });
229
231
  ```
230
232
 
231
233
  #### Filtering Debug
@@ -253,12 +255,12 @@ $ DEBUG=express:*,@travetto/rest npx trv run rest
253
255
  ## Resource Access
254
256
  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.
255
257
 
256
- 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'.
258
+ 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#L15) with a category of 'notfound'.
257
259
 
258
- 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.
260
+ 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.
259
261
 
260
262
  ## Common Utilities
261
- Common utilities used throughout the framework. Currently [Util](https://github.com/travetto/travetto/tree/main/module/runtime/src/util.ts#L18) includes:
263
+ Common utilities used throughout the framework. Currently [Util](https://github.com/travetto/travetto/tree/main/module/runtime/src/util.ts#L19) includes:
262
264
  * `uuid(len: number)` generates a simple uuid for use within the application.
263
265
  * `allowDenyMatcher(rules[])` builds a matching function that leverages the rules as an allow/deny list, where order of the rules matters. Negative rules are prefixed by '!'.
264
266
  * `hash(text: string, size?: number)` produces a full sha512 hash.
@@ -318,7 +320,7 @@ export class TimeUtil {
318
320
  ```
319
321
 
320
322
  ## Process Execution
321
- [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.
323
+ [ExecUtil](https://github.com/travetto/travetto/tree/main/module/runtime/src/exec.ts#L42) 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.
322
324
 
323
325
  A simple example would be:
324
326
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/runtime",
3
- "version": "5.0.0-rc.8",
3
+ "version": "5.0.0-rc.9",
4
4
  "description": "Runtime for travetto applications.",
5
5
  "keywords": [
6
6
  "console-manager",
@@ -28,13 +28,13 @@
28
28
  "node": ">=22.0.0"
29
29
  },
30
30
  "dependencies": {
31
- "@travetto/manifest": "^5.0.0-rc.4",
31
+ "@travetto/manifest": "^5.0.0-rc.5",
32
32
  "@types/debug": "^4.1.12",
33
33
  "@types/node": "^22.1.0",
34
34
  "debug": "^4.3.5"
35
35
  },
36
36
  "peerDependencies": {
37
- "@travetto/transformer": "^5.0.0-rc.5"
37
+ "@travetto/transformer": "^5.0.0-rc.6"
38
38
  },
39
39
  "peerDependenciesMeta": {
40
40
  "@travetto/transformer": {
package/src/env.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { castKey, castTo } from './types';
2
+
1
3
  const IS_TRUE = /^(true|yes|on|1)$/i;
2
4
  const IS_FALSE = /^(false|no|off|0)$/i;
3
5
 
@@ -26,8 +28,7 @@ export class EnvProp<T> {
26
28
  } else if (Array.isArray(val)) {
27
29
  out = val.join(',');
28
30
  } else if (typeof val === 'object') {
29
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
30
- out = Object.entries(val as Record<string, string>).map(([k, v]) => `${k}=${v}`).join(',');
31
+ out = Object.entries(val).map(([k, v]) => `${k}=${v}`).join(',');
31
32
  } else {
32
33
  out = `${val}`;
33
34
  }
@@ -52,8 +53,7 @@ export class EnvProp<T> {
52
53
 
53
54
  /** Add values to list */
54
55
  add(...items: string[]): void {
55
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
56
- this.set([... new Set([...this.list ?? [], ...items])] as T);
56
+ process.env[this.key] = [... new Set([...this.list ?? [], ...items])].join(',');
57
57
  }
58
58
 
59
59
  /** Read value as int */
@@ -95,12 +95,12 @@ type AllType = {
95
95
  };
96
96
 
97
97
  function delegate<T extends object>(base: T): AllType & T {
98
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
99
- return new Proxy(base as AllType & T, {
98
+ return new Proxy(castTo(base), {
100
99
  get(target, prop): unknown {
101
100
  return typeof prop !== 'string' ? undefined :
102
- // @ts-expect-error
103
- (prop in base ? base[prop] : target[prop] ??= new EnvProp(prop));
101
+ (prop in base ? base[castKey(prop)] :
102
+ target[castKey<typeof target>(prop)] ??= castTo(new EnvProp(prop))
103
+ );
104
104
  }
105
105
  });
106
106
  }
package/src/error.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { castTo } from './types';
2
+
1
3
  export type ErrorCategory =
2
4
  'general' |
3
5
  'notfound' |
@@ -20,8 +22,7 @@ export class AppError<T = unknown> extends Error {
20
22
  ('type' in e && typeof e.type === 'string') &&
21
23
  ('at' in e && typeof e.at === 'number')
22
24
  ) {
23
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
24
- const err = new AppError(e.message, e.category as ErrorCategory, 'details' in e ? e.details : undefined);
25
+ const err = new AppError(e.message, castTo(e.category), 'details' in e ? e.details : undefined);
25
26
  err.at = new Date(e.at);
26
27
  err.type = e.type;
27
28
  return err;
@@ -59,8 +60,7 @@ export class AppError<T = unknown> extends Error {
59
60
  category: this.category,
60
61
  type: this.type,
61
62
  at: this.at.toISOString(),
62
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
63
- details: this.details as Record<string, unknown>,
63
+ details: castTo(this.details),
64
64
  };
65
65
  }
66
66
  }
package/src/exec.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { ChildProcess } from 'node:child_process';
2
2
  import { Readable } from 'node:stream';
3
3
  import { createInterface } from 'node:readline/promises';
4
+ import { castTo } from './types';
4
5
 
5
6
  const MINUTE = (1000 * 60);
6
7
 
@@ -93,8 +94,8 @@ export class ExecUtil {
93
94
  static getResult(proc: ChildProcess, options: { catch?: boolean, binary?: false }): Promise<ExecutionResult<string>>;
94
95
  static getResult(proc: ChildProcess, options: { catch?: boolean, binary: true }): Promise<ExecutionResult<Buffer>>;
95
96
  static getResult<T extends string | Buffer>(proc: ChildProcess, options: { catch?: boolean, binary?: boolean } = {}): Promise<ExecutionResult<T>> {
96
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
97
- const res = (proc as unknown as { [RESULT]: Promise<ExecutionResult> })[RESULT] ??= new Promise<ExecutionResult>(resolve => {
97
+ const _proc: ChildProcess & { [RESULT]?: Promise<ExecutionResult> } = proc;
98
+ const res = _proc[RESULT] ??= new Promise<ExecutionResult>(resolve => {
98
99
  const stdout: Buffer[] = [];
99
100
  const stderr: Buffer[] = [];
100
101
  let done = false;
@@ -135,14 +136,13 @@ export class ExecUtil {
135
136
  }
136
137
  });
137
138
 
138
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
139
- return (options.catch ? res : res.then(v => {
139
+ return castTo(options.catch ? res : res.then(v => {
140
140
  if (v.valid) {
141
141
  return v;
142
142
  } else {
143
143
  throw new Error(v.message);
144
144
  }
145
- })) as Promise<ExecutionResult<T>>;
145
+ }));
146
146
  }
147
147
 
148
148
  /**
package/src/function.ts CHANGED
@@ -56,6 +56,6 @@ export function flushPendingFunctions(): Function[] {
56
56
  */
57
57
  export function describeFunction(fn: Function): FunctionMetadata;
58
58
  export function describeFunction(fn?: Function): FunctionMetadata | undefined {
59
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
60
- return (fn as unknown as { [METADATA]: FunctionMetadata })?.[METADATA];
59
+ const _fn: (Function & { [METADATA]?: FunctionMetadata }) | undefined = fn;
60
+ return _fn?.[METADATA];
61
61
  }
package/src/time.ts CHANGED
@@ -35,10 +35,9 @@ export class TimeUtil {
35
35
  if (amount instanceof Date) {
36
36
  return amount.getTime();
37
37
  } else if (typeof amount === 'string') {
38
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
39
- const { groups } = (amount.match(this.#timePattern) as { groups: { amount?: string, unit?: TimeUnit } });
40
- const amountStr = groups?.amount ?? `${amount}`;
41
- unit = groups?.unit ?? unit ?? 'ms';
38
+ const groups: { amount?: string, unit?: TimeUnit } = amount.match(this.#timePattern)?.groups ?? {};
39
+ const amountStr = groups.amount ?? `${amount}`;
40
+ unit = groups.unit ?? unit ?? 'ms';
42
41
  if (!TIME_UNITS[unit]) {
43
42
  return NaN;
44
43
  }
package/src/types.ts CHANGED
@@ -1,23 +1,42 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- export type Class<T = any> = abstract new (...args: any[]) => T;
3
- export type ConcreteClass<T = any> = new (...args: any[]) => T;
4
- export type ClassInstance<T = any> = T & {
5
- constructor: ConcreteClass<T> & { Ⲑid: string };
6
- };
1
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2
+ export type Any = any;
7
3
 
8
- export type AnyMap = {
9
- [key: string]: any
4
+ export type AnyMap = { [key: string]: Any };
5
+ export type Class<T = Any> = abstract new (...args: Any[]) => T;
6
+ export type ClassInstance<T = Any> = T & {
7
+ constructor: Class<T> & { Ⲑid: string };
10
8
  };
11
9
 
10
+ export type TypedFunction<R = Any, V = unknown> = (this: V, ...args: Any[]) => R;
11
+
12
+ export type MethodDescriptor<V = Any, R = Any> = TypedPropertyDescriptor<TypedFunction<R, V>>;
13
+ export type AsyncMethodDescriptor<V = Any, R = Any> = TypedPropertyDescriptor<TypedFunction<Promise<R>, V>>;
14
+ export type AsyncItrMethodDescriptor<V = Any, R = Any> = TypedPropertyDescriptor<TypedFunction<AsyncIterable<R>, V>>;
15
+ export type ClassTDecorator<T extends Class = Class> = (target: T) => T | void;
16
+
12
17
  export type Primitive = number | bigint | boolean | string | Date;
13
18
 
14
19
  export type DeepPartial<T> = {
15
20
  [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]>));
21
+ (T[P] extends Any[] ? (DeepPartial<T[P][number]> | null | undefined)[] : DeepPartial<T[P]>));
17
22
  };
18
23
 
19
24
  export const TypedObject: {
20
- keys<T = unknown, K extends keyof T = keyof T>(o: T): K[];
25
+ keys<T = unknown, K extends keyof T = keyof T & string>(o: T): K[];
21
26
  fromEntries<K extends string | symbol, V>(items: ([K, V] | readonly [K, V])[]): Record<K, V>;
22
27
  entries<K extends Record<symbol | string, unknown>>(record: K): [keyof K, K[keyof K]][];
23
28
  } & ObjectConstructor = Object;
29
+
30
+ export function castTo<T>(input: unknown): T {
31
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
32
+ return input as T;
33
+ }
34
+
35
+ export const castKey = <T>(input: string | number | symbol): keyof T => castTo(input);
36
+ export const asFull = <T>(input: Partial<T>): T => castTo(input);
37
+ export const asConstructable = <Z = unknown>(input: Class | unknown): { constructor: Class<Z> } => castTo(input);
38
+
39
+ export function classConstruct<T>(cls: Class<T>, args: unknown[] = []): ClassInstance<T> {
40
+ const cons: { new(..._args: Any[]): T } = castTo(cls);
41
+ return castTo(new cons(...args));
42
+ }
package/src/util.ts CHANGED
@@ -3,6 +3,7 @@ import timers from 'node:timers/promises';
3
3
  import fs from 'node:fs/promises';
4
4
  import path from 'node:path';
5
5
  import os from 'node:os';
6
+ import { castTo } from './types';
6
7
 
7
8
  type PromiseWithResolvers<T> = {
8
9
  resolve: (v: T) => void;
@@ -64,8 +65,7 @@ export class Util {
64
65
  idx += 1;
65
66
  let m = el;
66
67
  for (const fn of fns) {
67
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
68
- m = (await fn(m, idx)) as typeof m;
68
+ m = castTo(await fn(m, idx));
69
69
  }
70
70
  yield m;
71
71
  }
@@ -104,7 +104,7 @@ export class Util {
104
104
  }
105
105
 
106
106
  /**
107
- * Queue new macrotask
107
+ * Queue new macro task
108
108
  */
109
109
  static queueMacroTask(): Promise<void> {
110
110
  return timers.setImmediate(undefined);
@@ -22,8 +22,7 @@ const VALID_LEVELS: Record<string, string> = {
22
22
  };
23
23
 
24
24
  /**
25
- * Allows for removal of debug log messages depending on whether app is running
26
- * in prod mode.
25
+ * Logging support with code-location aware messages.
27
26
  */
28
27
  export class ConsoleLogTransformer {
29
28
 
@@ -2,7 +2,7 @@ import ts from 'typescript';
2
2
 
3
3
  import {
4
4
  TransformerState, OnMethod, OnClass, AfterClass,
5
- AfterFunction, CoreUtil, SystemUtil, Import
5
+ CoreUtil, SystemUtil, Import, OnFunction
6
6
  } from '@travetto/transformer';
7
7
 
8
8
  import type { FunctionMetadataTag } from '../src/function';
@@ -40,7 +40,7 @@ export class RegisterTransformer {
40
40
  }
41
41
  }
42
42
  return { hash, lines: range };
43
- } catch (err) {
43
+ } catch {
44
44
  return { hash, lines: [0, 0] };
45
45
  }
46
46
  }
@@ -118,7 +118,7 @@ export class RegisterTransformer {
118
118
  /**
119
119
  * Give proper functions a file name
120
120
  */
121
- @AfterFunction()
121
+ @OnFunction()
122
122
  static registerFunctionMetadata(state: TransformerState & MetadataInfo, node: ts.FunctionDeclaration | ts.FunctionExpression): typeof node {
123
123
  if (!this.#valid(state)) {
124
124
  return node;
@@ -0,0 +1,25 @@
1
+ import ts from 'typescript';
2
+
3
+ import { TransformerState, OnCall } from '@travetto/transformer';
4
+
5
+ const SRC = '@travetto/runtime/src/types.ts';
6
+
7
+ /**
8
+ * Allows for removal of type helpers at compile time
9
+ */
10
+ export class TypeHelpersTransformer {
11
+ @OnCall()
12
+ static onTypeHelper(state: TransformerState, node: ts.CallExpression): ts.Node {
13
+ if (
14
+ ts.isIdentifier(node.expression) &&
15
+ node.arguments.length === 1 &&
16
+ /as(Class|Constructable|Full)|cast(To|Key)/.test(node.expression.escapedText.toString())
17
+ ) {
18
+ const type = state.resolveType(node.expression);
19
+ if (type.key === 'unknown' && 'importName' in type && type.importName === SRC) {
20
+ // return node.arguments[0];
21
+ }
22
+ }
23
+ return node;
24
+ }
25
+ }