@travetto/transformer 8.0.0-alpha.9 → 8.0.0

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
@@ -15,15 +15,15 @@ yarn add @travetto/transformer
15
15
 
16
16
  This module provides support for enhanced AST transformations, and declarative transformer registration, with common patterns to support all the transformers used throughout the framework. Transformations are located by `support/transformer.<name>.ts` as the filename.
17
17
 
18
- The module is primarily aimed at extremely advanced usages for things that cannot be detected at runtime. The [Registry](https://github.com/travetto/travetto/tree/main/module/registry#readme "Patterns and utilities for handling registration of metadata and functionality for run-time use") module already has knowledge of all `class`es and `field`s, and is able to listen to changes there. Many of the modules build upon work by some of the foundational transformers defined in [Manifest](https://github.com/travetto/travetto/tree/main/module/manifest#readme "Support for project indexing, manifesting, along with file watching"), [Registry](https://github.com/travetto/travetto/tree/main/module/registry#readme "Patterns and utilities for handling registration of metadata and functionality for run-time use"), [Schema](https://github.com/travetto/travetto/tree/main/module/schema#readme "Data type registry for runtime validation, reflection and binding.") and [Dependency Injection](https://github.com/travetto/travetto/tree/main/module/di#readme "Dependency registration/management and injection support."). These all center around defining a registry of classes, and associated type information.
18
+ The module is primarily aimed at extremely advanced usages for things that cannot be detected at runtime. The [Registry](https://github.com/travetto/travetto/tree/main/module/registry#readme "Patterns and utilities for handling registration of metadata and functionality for run-time use") module already has knowledge of all `class`es and `field`s, and is able to listen to changes there. Many of the modules build upon work by some of the foundational transformers defined in [Manifest](https://github.com/travetto/travetto/tree/main/module/manifest#readme "Support for project indexing, manifesting, along with file watching"), [Registry](https://github.com/travetto/travetto/tree/main/module/registry#readme "Patterns and utilities for handling registration of metadata and functionality for run-time use"), [Schema](https://github.com/travetto/travetto/tree/main/module/schema#readme "Data type registry for runtime validation, reflection and binding.") and [Dependency Injection](https://github.com/travetto/travetto/tree/main/module/di#readme "Dependency registration/management and injection support."). These all center around defining a registry of classes, and associated type information.
19
19
 
20
20
  Because working with the [Typescript](https://typescriptlang.org) API can be delicate (and open to breaking changes), creating new transformers should be done cautiously.
21
21
 
22
22
  ## Monorepos and Idempotency
23
- Within the framework, any build or compile step will target the entire workspace, and for mono-repo projects, will include all modules. The optimization this provides is great, but comes with a strict requirement that all compilation processes need to be idempotent. This means that compiling a module directly, versus as a dependency should always produce the same output. This produces a requirement that all transformers are opt-in by the source code, and which transformers are needed in a file should be code-evident. This also means that no transformers are optional, as that could produce different output depending on the dependency graph for a given module.
23
+ Within the framework, any build or compile step will target the entire workspace, and for mono-repo projects, will include all modules. The optimization this provides is great, but comes with a strict requirement that all compilation processes need to be idempotent. This means that compiling a module directly, versus as a dependency should always produce the same output. This produces a requirement that all transformers are opt-in by the source code, and which transformers are needed in a file should be code-evident. This also means that no transformers are optional, as that could produce different output depending on the dependency graph for a given module.
24
24
 
25
25
  ## Custom Transformer
26
- Below is an example of a transformer that upper cases all `class`, `method` and `param` declarations. This will break any code that depends upon it as we are redefining all the identifiers at compile time.
26
+ Below is an example of a transformer that upper cases all `class`, `method` and `param` declarations. This will break any code that depends upon it as we are redefining all the identifiers at compile time.
27
27
 
28
28
  **Code: Sample Transformer - Upper case all declarations**
29
29
  ```typescript
@@ -32,7 +32,6 @@ import type ts from 'typescript';
32
32
  import { TransformerHandler, type TransformerState } from '@travetto/transformer';
33
33
 
34
34
  export class MakeUpper {
35
-
36
35
  static isValid(state: TransformerState): boolean {
37
36
  return state.importName !== '@travetto/transformer/doc/upper.ts';
38
37
  }
@@ -44,39 +43,45 @@ export class MakeUpper {
44
43
  }
45
44
 
46
45
  static handleProperty(state: TransformerState, node: ts.PropertyDeclaration): ts.PropertyDeclaration {
47
- return !this.isValid(state) ? node : state.factory.updatePropertyDeclaration(
48
- node,
49
- node.modifiers,
50
- node.name.getText().toUpperCase(),
51
- undefined,
52
- node.type,
53
- node.initializer ?? state.createIdentifier('undefined')
54
- );
46
+ return !this.isValid(state)
47
+ ? node
48
+ : state.factory.updatePropertyDeclaration(
49
+ node,
50
+ node.modifiers,
51
+ node.name.getText().toUpperCase(),
52
+ undefined,
53
+ node.type,
54
+ node.initializer ?? state.createIdentifier('undefined')
55
+ );
55
56
  }
56
57
 
57
58
  static handleClass(state: TransformerState, node: ts.ClassDeclaration): ts.ClassDeclaration {
58
- return !this.isValid(state) ? node : state.factory.updateClassDeclaration(
59
- node,
60
- node.modifiers,
61
- state.createIdentifier(node.name!.getText().toUpperCase()),
62
- node.typeParameters,
63
- node.heritageClauses,
64
- node.members
65
- );
59
+ return !this.isValid(state)
60
+ ? node
61
+ : state.factory.updateClassDeclaration(
62
+ node,
63
+ node.modifiers,
64
+ state.createIdentifier(node.name!.getText().toUpperCase()),
65
+ node.typeParameters,
66
+ node.heritageClauses,
67
+ node.members
68
+ );
66
69
  }
67
70
 
68
71
  static handleMethod(state: TransformerState, node: ts.MethodDeclaration): ts.MethodDeclaration {
69
- return !this.isValid(state) ? node : state.factory.updateMethodDeclaration(
70
- node,
71
- node.modifiers,
72
- undefined,
73
- state.createIdentifier(node.name.getText().toUpperCase()),
74
- undefined,
75
- node.typeParameters,
76
- node.parameters,
77
- node.type,
78
- node.body
79
- );
72
+ return !this.isValid(state)
73
+ ? node
74
+ : state.factory.updateMethodDeclaration(
75
+ node,
76
+ node.modifiers,
77
+ undefined,
78
+ state.createIdentifier(node.name.getText().toUpperCase()),
79
+ undefined,
80
+ node.typeParameters,
81
+ node.parameters,
82
+ node.type,
83
+ node.body
84
+ );
80
85
  }
81
86
  }
82
87
  ```
@@ -91,7 +96,7 @@ export class Test {
91
96
  dob: Date;
92
97
 
93
98
  computeAge(): void {
94
- this['age'] = (Date.now() - this.dob.getTime());
99
+ this.age = Date.now() - this.dob.getTime();
95
100
  }
96
101
  }
97
102
  ```
@@ -101,12 +106,12 @@ export class Test {
101
106
  import * as Δfunction from "@travetto/runtime/src/function.js";
102
107
  const Δm_1 = ["@travetto/transformer", "doc/upper.ts"];
103
108
  export class TEST {
104
- static { Δfunction.registerFunction(TEST, Δm_1, { hash: 649563175, lines: [1, 9] }, { COMPUTEAGE: { hash: 1286718349, lines: [6, 8, 7] } }, false); }
109
+ static { Δfunction.registerFunction(TEST, Δm_1, { hash: 2002713074, lines: [1, 9] }, { COMPUTEAGE: { hash: 731903366, lines: [6, 8, 7] } }, false); }
105
110
  NAME;
106
111
  AGE;
107
112
  DOB;
108
113
  COMPUTEAGE() {
109
- this['AGE'] = (Date.now() - this.DOB.getTime());
114
+ this.AGE = Date.now() - this.DOB.getTime();
110
115
  }
111
116
  }
112
117
  ```
package/__index__.ts CHANGED
@@ -1,10 +1,20 @@
1
- export * from './src/state.ts';
2
- export * from './src/visitor.ts';
1
+ export * from './src/manager.ts';
3
2
  export * from './src/register.ts';
4
- export * from './src/types/visitor.ts';
3
+ export type {
4
+ AnyType,
5
+ CompositionType,
6
+ ForeignType,
7
+ LiteralType,
8
+ ManagedType,
9
+ PointerType,
10
+ ShapeType,
11
+ TemplateType,
12
+ TupleType,
13
+ UnknownType
14
+ } from './src/resolver/types.ts';
15
+ export * from './src/state.ts';
5
16
  export * from './src/types/shared.ts';
6
- export * from './src/manager.ts';
7
-
17
+ export * from './src/types/visitor.ts';
8
18
  export * from './src/util/core.ts';
9
19
  export * from './src/util/declaration.ts';
10
20
  export * from './src/util/decorator.ts';
@@ -12,8 +22,4 @@ export * from './src/util/doc.ts';
12
22
  export * from './src/util/literal.ts';
13
23
  export * from './src/util/log.ts';
14
24
  export * from './src/util/system.ts';
15
-
16
- export type {
17
- AnyType, ForeignType, ManagedType, PointerType, LiteralType, ShapeType,
18
- CompositionType, TupleType, UnknownType, TemplateType
19
- } from './src/resolver/types.ts';
25
+ export * from './src/visitor.ts';
package/package.json CHANGED
@@ -1,31 +1,34 @@
1
1
  {
2
2
  "name": "@travetto/transformer",
3
- "version": "8.0.0-alpha.9",
4
- "type": "module",
3
+ "version": "8.0.0",
5
4
  "description": "Functionality for AST transformations, with transformer registration, and general utils",
6
5
  "keywords": [
7
- "typescript",
8
6
  "ast-transformations",
9
- "travetto"
7
+ "travetto",
8
+ "typescript"
10
9
  ],
11
10
  "homepage": "https://travetto.io",
12
11
  "license": "MIT",
13
12
  "author": {
14
- "email": "travetto.framework@gmail.com",
15
- "name": "Travetto Framework"
13
+ "name": "Travetto Framework",
14
+ "email": "travetto.framework@gmail.com"
15
+ },
16
+ "repository": {
17
+ "url": "git+https://github.com/travetto/travetto.git",
18
+ "directory": "module/transformer"
16
19
  },
17
20
  "files": [
18
21
  "__index__.ts",
19
22
  "src",
20
23
  "support"
21
24
  ],
25
+ "type": "module",
22
26
  "main": "__index__.ts",
23
- "repository": {
24
- "url": "git+https://github.com/travetto/travetto.git",
25
- "directory": "module/transformer"
27
+ "publishConfig": {
28
+ "access": "public"
26
29
  },
27
30
  "dependencies": {
28
- "@travetto/manifest": "^8.0.0-alpha.7",
31
+ "@travetto/manifest": "^8.0.0",
29
32
  "tslib": "^2.8.1",
30
33
  "typescript": "^6.0.2"
31
34
  },
@@ -34,8 +37,5 @@
34
37
  "roles": [
35
38
  "compile"
36
39
  ]
37
- },
38
- "publishConfig": {
39
- "access": "public"
40
40
  }
41
41
  }
package/src/importer.ts CHANGED
@@ -2,12 +2,12 @@ import ts from 'typescript';
2
2
 
3
3
  import { ManifestModuleUtil, PackageUtil, path } from '@travetto/manifest';
4
4
 
5
- import type { AnyType, TransformResolver, ManagedType, MappedType } from './resolver/types.ts';
6
- import { ImportUtil } from './util/import.ts';
7
- import { CoreUtil } from './util/core.ts';
5
+ import type { AnyType, ManagedType, MappedType, TransformResolver } from './resolver/types.ts';
8
6
  import type { Import } from './types/shared.ts';
9
- import { LiteralUtil } from './util/literal.ts';
7
+ import { CoreUtil } from './util/core.ts';
10
8
  import { DeclarationUtil } from './util/declaration.ts';
9
+ import { ImportUtil } from './util/import.ts';
10
+ import { LiteralUtil } from './util/literal.ts';
11
11
 
12
12
  const D_OR_D_TS_EXT_REGEX = /[.]d([.]ts)?$/;
13
13
 
@@ -15,7 +15,6 @@ const D_OR_D_TS_EXT_REGEX = /[.]d([.]ts)?$/;
15
15
  * Manages imports within a ts.SourceFile
16
16
  */
17
17
  export class ImportManager {
18
-
19
18
  #newImports = new Map<string, Import>();
20
19
  #imports: Map<string, Import>;
21
20
  #idx: Record<string, number> = {};
@@ -51,19 +50,13 @@ export class ImportManager {
51
50
  const type = this.#resolver.getType(element.name);
52
51
  const objFlags = DeclarationUtil.getObjectFlags(type);
53
52
  const typeFlags = type.getFlags();
54
- // eslint-disable-next-line no-bitwise
55
53
  if (!(objFlags & (ts.SymbolFlags.Type | ts.SymbolFlags.Interface)) || !(typeFlags & ts.TypeFlags.Any)) {
56
54
  newBindings.push(element);
57
55
  }
58
56
  }
59
57
  }
60
58
  if (newBindings.length !== bindings.elements.length) {
61
- return this.factory.updateImportClause(
62
- clause,
63
- clause.isTypeOnly,
64
- clause.name,
65
- this.factory.createNamedImports(newBindings)
66
- );
59
+ return this.factory.updateImportClause(clause, clause.isTypeOnly, clause.name, this.factory.createNamedImports(newBindings));
67
60
  } else {
68
61
  return clause;
69
62
  }
@@ -82,9 +75,7 @@ export class ImportManager {
82
75
  }
83
76
  }
84
77
 
85
- return fileOrImport ?
86
- (fileOrImport.startsWith('.') || this.#resolver.isKnownFile(fileOrImport)) :
87
- false;
78
+ return fileOrImport ? fileOrImport.startsWith('.') || this.#resolver.isKnownFile(fileOrImport) : false;
88
79
  }
89
80
 
90
81
  /**
@@ -96,10 +87,8 @@ export class ImportManager {
96
87
 
97
88
  const type = ManifestModuleUtil.getFileType(specText);
98
89
  if (type === 'js' || type === 'ts') {
99
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
100
90
  return LiteralUtil.fromLiteral(this.factory, ManifestModuleUtil.withOutputExtension(specText)) as unknown as T;
101
91
  } else {
102
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
103
92
  return LiteralUtil.fromLiteral(this.factory, `${specText}${ManifestModuleUtil.OUTPUT_EXT}`) as unknown as T;
104
93
  }
105
94
  }
@@ -115,7 +104,7 @@ export class ImportManager {
115
104
  return this.factory.createIdentifier(name);
116
105
  } else {
117
106
  const key = path.basename(file, path.extname(file)).replace(/\W+/g, '_');
118
- const suffix = this.#idx[key] = (this.#idx[key] ?? -1) + 1;
107
+ const suffix = (this.#idx[key] = (this.#idx[key] ?? -1) + 1);
119
108
  return this.factory.createIdentifier(`Δ${key}${suffix ? suffix : ''}`);
120
109
  }
121
110
  });
@@ -140,7 +129,8 @@ export class ImportManager {
140
129
  const identifier = this.getIdentifier(file, name);
141
130
  const uniqueName = identifier.text;
142
131
 
143
- if (this.#imports.has(uniqueName)) { // Already imported, be cool
132
+ if (this.#imports.has(uniqueName)) {
133
+ // Already imported, be cool
144
134
  return this.#imports.get(uniqueName)!;
145
135
  }
146
136
 
@@ -161,10 +151,16 @@ export class ImportManager {
161
151
  }
162
152
  switch (type.key) {
163
153
  case 'managed':
164
- case 'literal': this.importFromResolved(...type.typeArguments || []); break;
154
+ case 'literal':
155
+ this.importFromResolved(...(type.typeArguments || []));
156
+ break;
165
157
  case 'composition':
166
- case 'tuple': this.importFromResolved(...type.subTypes || []); break;
167
- case 'shape': this.importFromResolved(...Object.values(type.fieldTypes)); break;
158
+ case 'tuple':
159
+ this.importFromResolved(...(type.subTypes || []));
160
+ break;
161
+ case 'shape':
162
+ this.importFromResolved(...Object.values(type.fieldTypes));
163
+ break;
168
164
  }
169
165
  }
170
166
  }
@@ -191,7 +187,8 @@ export class ImportManager {
191
187
  ...importStmts,
192
188
  ...file.statements.filter((node: ts.Statement & { remove?: boolean }) => !node.remove) // Exclude culled imports
193
189
  ]);
194
- } catch (error) { // Missing import
190
+ } catch (error) {
191
+ // Missing import
195
192
  if (!(error instanceof Error)) {
196
193
  throw error;
197
194
  }
@@ -207,24 +204,28 @@ export class ImportManager {
207
204
  for (const statement of source.statements) {
208
205
  if (ts.isExportDeclaration(statement)) {
209
206
  if (!statement.isTypeOnly) {
210
- toAdd.push(this.factory.updateExportDeclaration(
211
- statement,
212
- statement.modifiers,
213
- statement.isTypeOnly,
214
- statement.exportClause,
215
- this.normalizeModuleSpecifier(statement.moduleSpecifier),
216
- statement.attributes
217
- ));
207
+ toAdd.push(
208
+ this.factory.updateExportDeclaration(
209
+ statement,
210
+ statement.modifiers,
211
+ statement.isTypeOnly,
212
+ statement.exportClause,
213
+ this.normalizeModuleSpecifier(statement.moduleSpecifier),
214
+ statement.attributes
215
+ )
216
+ );
218
217
  }
219
218
  } else if (ts.isImportDeclaration(statement)) {
220
219
  if (statement.importClause?.phaseModifier !== ts.SyntaxKind.TypeKeyword) {
221
- toAdd.push(this.factory.updateImportDeclaration(
222
- statement,
223
- statement.modifiers,
224
- this.#rewriteImportClause(statement.moduleSpecifier, statement.importClause)!,
225
- this.normalizeModuleSpecifier(statement.moduleSpecifier)!,
226
- statement.attributes
227
- ));
220
+ toAdd.push(
221
+ this.factory.updateImportDeclaration(
222
+ statement,
223
+ statement.modifiers,
224
+ this.#rewriteImportClause(statement.moduleSpecifier, statement.importClause)!,
225
+ this.normalizeModuleSpecifier(statement.moduleSpecifier)!,
226
+ statement.attributes
227
+ )
228
+ );
228
229
  }
229
230
  } else {
230
231
  toAdd.push(statement);
@@ -255,4 +256,4 @@ export class ImportManager {
255
256
  return factory.createPropertyAccessExpression(identifier, targetName);
256
257
  }
257
258
  }
258
- }
259
+ }
package/src/manager.ts CHANGED
@@ -2,16 +2,15 @@ import type ts from 'typescript';
2
2
 
3
3
  import type { ManifestIndex } from '@travetto/manifest';
4
4
 
5
+ import { getAllTransformers } from './register.ts';
6
+ import { TransformerState } from './state.ts';
5
7
  import type { NodeTransformer } from './types/visitor.ts';
6
8
  import { VisitorFactory } from './visitor.ts';
7
- import { TransformerState } from './state.ts';
8
- import { getAllTransformers } from './register.ts';
9
9
 
10
10
  /**
11
11
  * Manages the typescript transformers
12
12
  */
13
13
  export class TransformerManager {
14
-
15
14
  /**
16
15
  * Create transformer manager
17
16
  * @param transformerFiles
@@ -23,16 +22,19 @@ export class TransformerManager {
23
22
 
24
23
  const transformers: NodeTransformer<TransformerState>[] = [];
25
24
 
26
- for (const file of transformerFiles) { // Exclude based on blacklist
25
+ for (const file of transformerFiles) {
26
+ // Exclude based on blacklist
27
27
  const entry = manifestIndex.getEntry(file)!;
28
28
  transformers.push(...getAllTransformers(await import(entry.import), entry.module));
29
29
  }
30
30
 
31
31
  for (const transformer of transformers) {
32
32
  process.send?.({
33
- type: 'log', payload: {
33
+ type: 'log',
34
+ payload: {
34
35
  level: 'debug',
35
- message: `Loaded Transformer: ${transformer.key}#${transformer.type}`, scope: 'transformers'
36
+ message: `Loaded Transformer: ${transformer.key}#${transformer.type}`,
37
+ scope: 'transformers'
36
38
  }
37
39
  });
38
40
  }
@@ -72,4 +74,4 @@ export class TransformerManager {
72
74
  get(): ts.CustomTransformers | undefined {
73
75
  return this.#cached!;
74
76
  }
75
- }
77
+ }
package/src/register.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type NodeTransformer, type TransformPhase, type TransformerType, type Transformer, ModuleNameSymbol } from './types/visitor.ts';
1
+ import { ModuleNameSymbol, type NodeTransformer, type Transformer, type TransformerType, type TransformPhase } from './types/visitor.ts';
2
2
 
3
3
  const HandlersSymbol = Symbol();
4
4
 
@@ -18,7 +18,7 @@ export function getAllTransformers(inputs: Record<string, { [HandlersSymbol]?: N
18
18
  if (isTransformer(value)) {
19
19
  value[ModuleNameSymbol] = module;
20
20
  }
21
- return (value[HandlersSymbol] ?? []);
21
+ return value[HandlersSymbol] ?? [];
22
22
  })
23
23
  .map(handler => ({
24
24
  ...handler,
@@ -28,6 +28,12 @@ export function getAllTransformers(inputs: Record<string, { [HandlersSymbol]?: N
28
28
  }
29
29
 
30
30
  // Store handlers in class
31
- export function TransformerHandler(cls: TransformerWithHandlers, fn: Function, phase: TransformPhase, type: TransformerType, target?: string[]): void {
31
+ export function TransformerHandler(
32
+ cls: TransformerWithHandlers,
33
+ fn: Function,
34
+ phase: TransformPhase,
35
+ type: TransformerType,
36
+ target?: string[]
37
+ ): void {
32
38
  (cls[HandlersSymbol] ??= []).push({ key: fn.name, [phase]: fn.bind(cls), type, target });
33
- }
39
+ }