@travetto/transformer 5.0.0-rc.4 → 5.0.0-rc.6

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
@@ -105,7 +105,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
105
105
  exports.TEST = void 0;
106
106
  const tslib_1 = require("tslib");
107
107
  const Ⲑ_function_1 = tslib_1.__importStar(require("@travetto/runtime/src/function.js"));
108
- var ᚕm = ["@travetto/transformer", "doc/upper"];
108
+ var ᚕm = ["@travetto/transformer", "doc/upper.ts"];
109
109
  class TEST {
110
110
  static Ⲑinit = Ⲑ_function_1.registerFunction(TEST, ᚕm, { hash: 649563175, lines: [1, 9] }, { COMPUTEAGE: { hash: 1286718349, lines: [6, 8, 7] } }, false, false);
111
111
  NAME;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/transformer",
3
- "version": "5.0.0-rc.4",
3
+ "version": "5.0.0-rc.6",
4
4
  "description": "Functionality for AST transformations, with transformer registration, and general utils",
5
5
  "keywords": [
6
6
  "typescript",
@@ -24,7 +24,7 @@
24
24
  "directory": "module/transformer"
25
25
  },
26
26
  "dependencies": {
27
- "@travetto/manifest": "^5.0.0-rc.3",
27
+ "@travetto/manifest": "^5.0.0-rc.5",
28
28
  "tslib": "^2.6.3",
29
29
  "typescript": "^5.5.3"
30
30
  },
package/src/importer.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import ts from 'typescript';
2
2
 
3
- import { PackageUtil, path } from '@travetto/manifest';
3
+ import { ManifestModuleUtil, PackageUtil, path } from '@travetto/manifest';
4
4
 
5
5
  import { AnyType, TransformResolver, ManagedType } from './resolver/types';
6
6
  import { ImportUtil } from './util/import';
@@ -104,6 +104,10 @@ export class ImportManager {
104
104
  importFile(file: string, name?: string): Import {
105
105
  file = this.#resolver.getFileImportName(file);
106
106
 
107
+ if (file.endsWith('.ts') && !file.endsWith('.d.ts')) {
108
+ file = ManifestModuleUtil.withOutputExtension(file);
109
+ }
110
+
107
111
  // Allow for node classes to be imported directly
108
112
  if (/@types\/node/.test(file)) {
109
113
  file = PackageUtil.resolveImport(file.replace(/.*@types\/node\//, '').replace(D_OR_D_TS_EXT_RE, ''));
package/src/manager.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import ts from 'typescript';
2
2
 
3
- import { ManifestIndex } from '@travetto/manifest';
3
+ import { ManifestIndex, ManifestModuleUtil } from '@travetto/manifest';
4
4
 
5
5
  import { NodeTransformer } from './types/visitor';
6
6
  import { VisitorFactory } from './visitor';
@@ -25,7 +25,7 @@ export class TransformerManager {
25
25
 
26
26
  for (const file of transformerFiles) { // Exclude based on blacklist
27
27
  const entry = manifestIndex.getEntry(file)!;
28
- transformers.push(...getAllTransformers(await import(entry.import), entry.module));
28
+ transformers.push(...getAllTransformers(await import(ManifestModuleUtil.withOutputExtension(entry.import)), entry.module));
29
29
  }
30
30
 
31
31
  for (const x of transformers) {
@@ -7,7 +7,7 @@ import { DocUtil } from '../util/doc';
7
7
  import { CoreUtil } from '../util/core';
8
8
  import { DeclarationUtil } from '../util/declaration';
9
9
  import { LiteralUtil } from '../util/literal';
10
- import { TemplateLiteralPart } from '../types/shared';
10
+ import { transformCast, TemplateLiteralPart } from '../types/shared';
11
11
 
12
12
  import { Type, AnyType, UnionType, TransformResolver, TemplateType } from './types';
13
13
  import { CoerceUtil } from './coerce';
@@ -165,8 +165,7 @@ export const TypeBuilder: {
165
165
 
166
166
  if (name in GLOBAL_SIMPLE) {
167
167
  const cons = GLOBAL_SIMPLE[name];
168
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
169
- const ret = LiteralUtil.isLiteralType(type) ? CoerceUtil.coerce(type.value, cons as typeof String, false) :
168
+ const ret = LiteralUtil.isLiteralType(type) ? CoerceUtil.coerce(type.value, transformCast(cons), false) :
170
169
  undefined;
171
170
 
172
171
  return {
@@ -225,8 +224,7 @@ export const TypeBuilder: {
225
224
  ctor: String,
226
225
  nullable: type.nullable,
227
226
  undefinable: type.undefinable,
228
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
229
- template: { op: 'or', values: subTypes.map(x => (x as TemplateType).template!) }
227
+ template: { op: 'or', values: subTypes.map(x => transformCast<TemplateType>(x).template!) }
230
228
  };
231
229
  } else if (subTypes.length === 1) {
232
230
  return { undefinable, nullable, ...first };
@@ -50,8 +50,7 @@ export class CoerceUtil {
50
50
  switch (type) {
51
51
  case Date: {
52
52
  const res = typeof input === 'number' || /^[-]?\d+$/.test(`${input}`) ?
53
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
54
- new Date(parseInt(input as string, 10)) : new Date(input as Date);
53
+ new Date(parseInt(`${input}`, 10)) : new Date(`${input}`);
55
54
  if (strict && Number.isNaN(res.getTime())) {
56
55
  throw new Error(`Invalid date value: ${input}`);
57
56
  }
@@ -7,6 +7,7 @@ import { TypeCategorize, TypeBuilder } from './builder';
7
7
  import { VisitCache } from './cache';
8
8
  import { DocUtil } from '../util/doc';
9
9
  import { DeclarationUtil } from '../util/declaration';
10
+ import { transformCast } from '../types/shared';
10
11
 
11
12
  /**
12
13
  * Implementation of TransformResolver
@@ -41,14 +42,15 @@ export class SimpleResolver implements TransformResolver {
41
42
  }
42
43
 
43
44
  return this.#manifestIndex.getEntry(ManifestModuleUtil.getFileType(sourceFile) === 'ts' ? sourceFile : `${sourceFile}.js`) ??
44
- this.#manifestIndex.getFromImport(ManifestModuleUtil.sourceToBlankExt(sourceFile).replace(/^.*node_modules\//, ''));
45
+ this.#manifestIndex.getFromImport(ManifestModuleUtil.withoutSourceExtension(sourceFile).replace(/^.*node_modules\//, ''));
45
46
  }
47
+
46
48
  /**
47
49
  * Resolve an import name (e.g. @module/path/file) for a file
48
50
  */
49
51
  getFileImportName(file: string, removeExt?: boolean): string {
50
52
  const imp = this.getFileImport(file)?.import ?? file;
51
- return removeExt ? ManifestModuleUtil.sourceToBlankExt(imp) : imp;
53
+ return removeExt ? ManifestModuleUtil.withoutSourceExtension(imp) : imp;
52
54
  }
53
55
 
54
56
  /**
@@ -79,8 +81,7 @@ export class SimpleResolver implements TransformResolver {
79
81
  * Fetch all type arguments for a give type
80
82
  */
81
83
  getAllTypeArguments(ref: ts.Type): ts.Type[] {
82
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
83
- return this.#tsChecker.getTypeArguments(ref as ts.TypeReference) as ts.Type[];
84
+ return transformCast(this.#tsChecker.getTypeArguments(transformCast(ref)));
84
85
  }
85
86
 
86
87
  /**
@@ -147,8 +148,7 @@ export class SimpleResolver implements TransformResolver {
147
148
  delete result.tsSubTypes;
148
149
  }
149
150
  if (finalize) {
150
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
151
- result = finalize(result as never);
151
+ result = finalize(transformCast(result));
152
152
  }
153
153
  }
154
154
 
package/src/state.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import ts from 'typescript';
2
2
 
3
- import { path, ManifestIndex, ManifestModuleUtil } from '@travetto/manifest';
3
+ import { path, ManifestIndex } from '@travetto/manifest';
4
4
 
5
5
  import { ManagedType, AnyType, ForeignType } from './resolver/types';
6
6
  import { State, DecoratorMeta, Transformer, ModuleNameⲐ } from './types/visitor';
@@ -15,14 +15,12 @@ import { CoreUtil } from './util/core';
15
15
  import { LiteralUtil } from './util/literal';
16
16
  import { SystemUtil } from './util/system';
17
17
 
18
- function hasOriginal(n: unknown): n is { original: ts.Node } {
19
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
20
- return !!n && !(n as { parent?: unknown }).parent && !!(n as { original: unknown }).original;
18
+ function hasOriginal(n: ts.Node): n is ts.Node & { original: ts.Node } {
19
+ return !!n && !n.parent && 'original' in n && !!n.original;
21
20
  }
22
21
 
23
- function hasEscapedName(n: unknown): n is { name: { escapedText: string } } {
24
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
25
- return !!n && !!(n as { name?: { escapedText?: string } }).name?.escapedText;
22
+ function hasEscapedName(n: ts.Node): n is ts.Node & { name: { escapedText: string } } {
23
+ return !!n && 'name' in n && typeof n.name === 'object' && !!n.name && 'escapedText' in n.name && !!n.name.escapedText;
26
24
  }
27
25
 
28
26
  /**
@@ -151,8 +149,7 @@ export class TransformerState implements State {
151
149
  const targets = DocUtil.readAugments(this.#resolver.getType(ident));
152
150
  const module = file ? mod : undefined;
153
151
  const name = ident ?
154
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
155
- ident.escapedText! as string :
152
+ ident.escapedText?.toString()! :
156
153
  undefined;
157
154
 
158
155
  if (ident && name) {
@@ -193,10 +190,11 @@ export class TransformerState implements State {
193
190
  while (n && !ts.isSourceFile(n.parent) && n !== n.parent) {
194
191
  n = n.parent;
195
192
  }
196
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
197
- const nStmt: ts.Statement = n as ts.Statement;
198
- if (n && ts.isSourceFile(n.parent) && stmts.indexOf(nStmt) >= 0) {
199
- idx = stmts.indexOf(nStmt) - 1;
193
+ if (!ts.isStatement(n)) {
194
+ throw new Error('Unable to find statement at top level');
195
+ }
196
+ if (n && ts.isSourceFile(n.parent) && stmts.indexOf(n) >= 0) {
197
+ idx = stmts.indexOf(n) - 1;
200
198
  }
201
199
  } else if (before !== undefined) {
202
200
  idx = before;
@@ -225,8 +223,7 @@ export class TransformerState implements State {
225
223
  fromLiteral(val: unknown[]): ts.ArrayLiteralExpression;
226
224
  fromLiteral(val: string | boolean | number): ts.LiteralExpression;
227
225
  fromLiteral(val: unknown): ts.Node {
228
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
229
- return LiteralUtil.fromLiteral(this.factory, val as object);
226
+ return LiteralUtil.fromLiteral(this.factory, val!);
230
227
  }
231
228
 
232
229
  /**
@@ -266,7 +263,7 @@ export class TransformerState implements State {
266
263
  this.#modIdent = this.createIdentifier('ᚕm');
267
264
  const entry = this.#resolver.getFileImport(this.source.fileName);
268
265
  const decl = this.factory.createVariableDeclaration(this.#modIdent, undefined, undefined,
269
- this.fromLiteral([entry?.module, ManifestModuleUtil.sourceToBlankExt(entry?.relativeFile ?? '')])
266
+ this.fromLiteral([entry?.module, entry?.relativeFile ?? ''])
270
267
  );
271
268
  this.addStatements([
272
269
  this.factory.createVariableStatement([], this.factory.createVariableDeclarationList([decl]))
@@ -30,3 +30,8 @@ export type Import = {
30
30
  /** Template Literal Types */
31
31
  export type TemplateLiteralPart = string | NumberConstructor | StringConstructor | BooleanConstructor;
32
32
  export type TemplateLiteral = { op: 'and' | 'or', values: (TemplateLiteralPart | TemplateLiteral)[] };
33
+
34
+ export function transformCast<T>(input: unknown): T {
35
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
36
+ return input as T;
37
+ }
@@ -42,6 +42,6 @@ export interface NodeTransformer<S extends State = State, T extends TransformerT
42
42
  type: T;
43
43
  key: string;
44
44
  target?: string[];
45
- before?(state: S, node: N, dm?: DecoratorMeta): ts.Node | undefined;
46
- after?(state: S, node: N, dm?: DecoratorMeta): ts.Node | undefined;
45
+ before?<Z extends ts.Node = ts.Node>(state: S, node: N, dm?: DecoratorMeta): Z | undefined;
46
+ after?<Z extends ts.Node = ts.Node>(state: S, node: N, dm?: DecoratorMeta): Z | undefined;
47
47
  }
package/src/util/core.ts CHANGED
@@ -9,16 +9,14 @@ export class CoreUtil {
9
9
  * See if inbound node has an original property
10
10
  */
11
11
  static hasOriginal(o: ts.Node): o is (ts.Node & { original: ts.Node }) {
12
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
13
- return 'original' in o && !!(o as { original?: ts.Node }).original;
12
+ return 'original' in o && !!o.original;
14
13
  }
15
14
 
16
15
  /**
17
16
  * See if type has target
18
17
  */
19
18
  static hasTarget(o: ts.Type): o is (ts.Type & { target: ts.Type }) {
20
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
21
- return 'target' in o && !!(o as { target?: ts.Type }).target;
19
+ return 'target' in o && !!o.target;
22
20
  }
23
21
 
24
22
  /**
@@ -36,12 +34,19 @@ export class CoreUtil {
36
34
  /**
37
35
  * Find the primary argument of a call expression, or decorator.
38
36
  */
39
- static getArgument<T extends ts.Expression = ts.Expression>(node: ts.CallExpression | undefined, position = 0): T | undefined {
40
- if (node && node!.arguments && node!.arguments.length >= position + 1) {
41
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
42
- return node.arguments[position] as T;
37
+ static findArgument<T extends ts.Expression = ts.Expression>(node: ts.CallExpression | undefined, pred: (x: ts.Expression) => x is T): T | undefined {
38
+ if (node && node.arguments && node.arguments.length) {
39
+ return node.arguments.find(pred);
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Find the first argument of a call expression, or decorator.
45
+ */
46
+ static firstArgument(node: ts.CallExpression | undefined): ts.Expression | undefined {
47
+ if (node && node!.arguments && node!.arguments.length) {
48
+ return node.arguments[0];
43
49
  }
44
- return;
45
50
  }
46
51
 
47
52
  /**
@@ -57,8 +57,9 @@ export class DeclarationUtil {
57
57
  * Resolve the `ts.ObjectFlags`
58
58
  */
59
59
  static getObjectFlags(type: ts.Type): ts.ObjectFlags {
60
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions, no-bitwise
61
- return (ts as unknown as { getObjectFlags(t: ts.Type): ts.ObjectFlags }).getObjectFlags(type) & ~(ts.NodeFlags.ThisNodeOrAnySubNodesHasError);
60
+ const _ts: typeof ts & { getObjectFlags?(t: ts.Type): ts.ObjectFlags } = ts;
61
+ // eslint-disable-next-line no-bitwise
62
+ return _ts.getObjectFlags!(type) & ~(ts.NodeFlags.ThisNodeOrAnySubNodesHasError);
62
63
  }
63
64
 
64
65
  /**
@@ -56,15 +56,14 @@ export class DecoratorUtil {
56
56
  /**
57
57
  * Find the primary argument of a call expression, or decorator.
58
58
  */
59
- static getPrimaryArgument<T extends ts.Expression = ts.Expression>(node: ts.Decorator | undefined): T | undefined {
60
- return CoreUtil.getArgument(node && ts.isCallExpression(node.expression) ? node.expression : undefined);
59
+ static getPrimaryArgument(node: ts.Decorator | undefined): ts.Expression | undefined {
60
+ return CoreUtil.firstArgument(node && ts.isCallExpression(node.expression) ? node.expression : undefined);
61
61
  }
62
62
 
63
63
  /**
64
64
  * Find the primary argument of a call expression, or decorator.
65
65
  */
66
- static getArguments<T extends ts.Expression = ts.Expression>(node: ts.Decorator | undefined): T[] | undefined {
67
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
68
- return node && ts.isCallExpression(node.expression) ? [...node.expression.arguments] as T[] : undefined;
66
+ static getArguments(node: ts.Decorator | undefined): ts.Expression[] | undefined {
67
+ return node && ts.isCallExpression(node.expression) ? [...node.expression.arguments] : undefined;
69
68
  }
70
69
  }
package/src/util/doc.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import ts from 'typescript';
2
2
 
3
- import { DeclDocumentation } from '../types/shared';
3
+ import { transformCast, DeclDocumentation } from '../types/shared';
4
4
  import { CoreUtil } from './core';
5
5
  import { DeclarationUtil } from './declaration';
6
6
 
@@ -38,8 +38,7 @@ export class DocUtil {
38
38
  if (node) {
39
39
  const tags = ts.getJSDocTags(node);
40
40
  while (!this.hasJSDoc(node) && CoreUtil.hasOriginal(node)) {
41
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
42
- node = node.original as ts.Declaration;
41
+ node = transformCast<ts.Declaration>(node.original);
43
42
  }
44
43
 
45
44
  const docs = this.hasJSDoc(node) ? node.jsDoc : undefined;
@@ -1,6 +1,20 @@
1
1
  import ts from 'typescript';
2
2
 
3
- import { TemplateLiteral } from '../types/shared';
3
+ import { transformCast, TemplateLiteral } from '../types/shared';
4
+
5
+ const TypedObject: {
6
+ keys<T = unknown, K extends keyof T = keyof T>(o: T): K[];
7
+ } & ObjectConstructor = Object;
8
+
9
+ function isNode(n: unknown): n is ts.Node {
10
+ return !!n && typeof n === 'object' && 'kind' in n;
11
+ }
12
+
13
+ const KNOWN_FNS = new Set<unknown>([String, Number, Boolean, Date, RegExp]);
14
+
15
+ function isKnownFn(n: unknown): n is Function {
16
+ return KNOWN_FNS.has(n);
17
+ }
4
18
 
5
19
  /**
6
20
  * Utilities for dealing with literals
@@ -27,10 +41,8 @@ export class LiteralUtil {
27
41
  static fromLiteral(factory: ts.NodeFactory, val: unknown[]): ts.ArrayLiteralExpression;
28
42
  static fromLiteral(factory: ts.NodeFactory, val: string | boolean | number): ts.LiteralExpression;
29
43
  static fromLiteral(factory: ts.NodeFactory, val: unknown): ts.Node {
30
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
31
- if (val && (val as ts.Expression).kind) { // If already a node
32
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
33
- return val as ts.Node;
44
+ if (isNode(val)) { // If already a node
45
+ return val;
34
46
  } else if (Array.isArray(val)) {
35
47
  val = factory.createArrayLiteralExpression(val.map(v => this.fromLiteral(factory, v)));
36
48
  } else if (val === undefined) {
@@ -45,15 +57,12 @@ export class LiteralUtil {
45
57
  val = val ? factory.createTrue() : factory.createFalse();
46
58
  } else if (val instanceof RegExp) {
47
59
  val = factory.createRegularExpressionLiteral(`/${val.source}/${val.flags ?? ''}`);
48
- } else if (val === String || val === Number || val === Boolean || val === Date || val === RegExp) {
49
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
50
- val = factory.createIdentifier((val as Function).name);
60
+ } else if (isKnownFn(val)) {
61
+ val = factory.createIdentifier(val.name);
51
62
  } else {
52
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
53
- const ov = val as object;
63
+ const ov = val;
54
64
  const pairs: ts.PropertyAssignment[] = [];
55
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
56
- for (const k of Object.keys(ov) as (keyof typeof ov)[]) {
65
+ for (const k of TypedObject.keys(ov)) {
57
66
  if (ov[k] !== undefined) {
58
67
  pairs.push(
59
68
  factory.createPropertyAssignment(k, this.fromLiteral(factory, ov[k]))
@@ -62,8 +71,7 @@ export class LiteralUtil {
62
71
  }
63
72
  return factory.createObjectLiteralExpression(pairs);
64
73
  }
65
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
66
- return val as ts.Expression;
74
+ return transformCast(val);
67
75
  }
68
76
 
69
77
  /**
@@ -164,8 +172,7 @@ export class LiteralUtil {
164
172
  } else if (typeof el === 'string' || typeof el === 'number' || typeof el === 'boolean') {
165
173
  out.push(`${el}`);
166
174
  } else {
167
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
168
- out.push(`(?:${this.templateLiteralToRegex(el as TemplateLiteral, false)})`);
175
+ out.push(`(?:${this.templateLiteralToRegex(transformCast(el), false)})`);
169
176
  }
170
177
  }
171
178
  const body = out.join(template.op === 'and' ? '' : '|');
package/src/util/log.ts CHANGED
@@ -5,6 +5,8 @@ const exclude = new Set([
5
5
  'nextContainer', 'modifierFlagsCache', 'declaredProperties'
6
6
  ]);
7
7
 
8
+ const TypedObject: { keys<T = unknown, K extends keyof T = keyof T>(o: T): K[] } & ObjectConstructor = Object;
9
+
8
10
  /**
9
11
  * Utilities for logging typescript nodes
10
12
  */
@@ -33,11 +35,9 @@ export class LogUtil {
33
35
  if (Array.isArray(x)) {
34
36
  return x.map(v => this.collapseNode(v, cache));
35
37
  } else {
36
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
37
- const ox = x as object;
38
+ const ox = x;
38
39
  const out: Record<string, unknown> = {};
39
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
40
- for (const key of Object.keys(ox) as (keyof typeof ox)[]) {
40
+ for (const key of TypedObject.keys(ox)) {
41
41
  if (Object.getPrototypeOf(ox[key]) === Function.prototype || exclude.has(key) || ox[key] === undefined) {
42
42
  continue;
43
43
  }
package/src/visitor.ts CHANGED
@@ -126,8 +126,7 @@ export class VisitorFactory<S extends State = State> {
126
126
  }
127
127
 
128
128
  for (const all of set[phase]!.get('ALL') ?? []) {
129
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
130
- node = (all[phase]!(state, node) as T) ?? node;
129
+ node = all[phase]!<T>(state, node) ?? node;
131
130
  }
132
131
  return node;
133
132
  }
@@ -160,8 +159,7 @@ export class VisitorFactory<S extends State = State> {
160
159
 
161
160
  // For all matching handlers, execute
162
161
  for (const item of values) {
163
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
164
- node = (item[phase]!(state, node, dec) as T) ?? node;
162
+ node = item[phase]!<T>(state, node, dec) ?? node;
165
163
  }
166
164
  }
167
165
  return node;