@travetto/transformer 5.0.11 → 5.0.13
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 +3 -3
- package/package.json +3 -3
- package/src/importer.ts +14 -13
- package/src/register.ts +2 -2
- package/src/resolver/builder.ts +14 -10
- package/src/resolver/types.ts +6 -2
- package/src/state.ts +14 -21
- package/src/types/shared.ts +0 -1
- package/src/types/visitor.ts +2 -2
package/README.md
CHANGED
|
@@ -104,10 +104,10 @@ export class Test {
|
|
|
104
104
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
105
105
|
exports.TEST = void 0;
|
|
106
106
|
const tslib_1 = require("tslib");
|
|
107
|
-
const
|
|
108
|
-
var
|
|
107
|
+
const Δfunction = tslib_1.__importStar(require("@travetto/runtime/src/function.js"));
|
|
108
|
+
var mod_1 = ["@travetto/transformer", "doc/upper.ts"];
|
|
109
109
|
class TEST {
|
|
110
|
-
static
|
|
110
|
+
static { Δfunction.registerFunction(TEST, mod_1, { hash: 649563175, lines: [1, 9] }, { COMPUTEAGE: { hash: 1286718349, lines: [6, 8, 7] } }, false); }
|
|
111
111
|
NAME;
|
|
112
112
|
AGE;
|
|
113
113
|
DOB;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/transformer",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.13",
|
|
4
4
|
"description": "Functionality for AST transformations, with transformer registration, and general utils",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
],
|
|
21
21
|
"main": "__index__.ts",
|
|
22
22
|
"repository": {
|
|
23
|
-
"url": "https://github.com/travetto/travetto.git",
|
|
23
|
+
"url": "git+https://github.com/travetto/travetto.git",
|
|
24
24
|
"directory": "module/transformer"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@travetto/manifest": "^5.0.
|
|
27
|
+
"@travetto/manifest": "^5.0.12",
|
|
28
28
|
"tslib": "^2.8.1",
|
|
29
29
|
"typescript": "^5.7.2"
|
|
30
30
|
},
|
package/src/importer.ts
CHANGED
|
@@ -19,7 +19,7 @@ export class ImportManager {
|
|
|
19
19
|
#newImports = new Map<string, Import>();
|
|
20
20
|
#imports: Map<string, Import>;
|
|
21
21
|
#idx: Record<string, number> = {};
|
|
22
|
-
#ids = new Map<string,
|
|
22
|
+
#ids = new Map<string, ts.Identifier>();
|
|
23
23
|
#importName: string;
|
|
24
24
|
#resolver: TransformResolver;
|
|
25
25
|
|
|
@@ -89,7 +89,6 @@ export class ImportManager {
|
|
|
89
89
|
false;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
|
|
93
92
|
/**
|
|
94
93
|
* Is a file or import an untyped file access
|
|
95
94
|
* @param fileOrImport
|
|
@@ -101,15 +100,17 @@ export class ImportManager {
|
|
|
101
100
|
}
|
|
102
101
|
|
|
103
102
|
/**
|
|
104
|
-
* Produces a unique ID for a given file
|
|
103
|
+
* Produces a unique ID for a given file
|
|
105
104
|
*/
|
|
106
|
-
getId(file: string, name?: string):
|
|
105
|
+
getId(file: string, name?: string): ts.Identifier {
|
|
107
106
|
if (!this.#ids.has(file)) {
|
|
108
107
|
if (name) {
|
|
109
|
-
this.#ids.set(file, name);
|
|
108
|
+
this.#ids.set(file, this.factory.createIdentifier(name));
|
|
110
109
|
} else {
|
|
111
|
-
const key = path.basename(file, path.extname(file)).replace(
|
|
112
|
-
|
|
110
|
+
const key = path.basename(file, path.extname(file)).replace(/\W+/g, '_');
|
|
111
|
+
const suffix = this.#idx[key] = (this.#idx[key] ?? -1) + 1;
|
|
112
|
+
// eslint-disable-next-line no-bitwise
|
|
113
|
+
this.#ids.set(file, this.factory.createIdentifier(`Δ${key}${suffix ? suffix : ''}`));
|
|
113
114
|
}
|
|
114
115
|
}
|
|
115
116
|
return this.#ids.get(file)!;
|
|
@@ -131,15 +132,15 @@ export class ImportManager {
|
|
|
131
132
|
}
|
|
132
133
|
|
|
133
134
|
if (!D_OR_D_TS_EXT_RE.test(file) && !this.#newImports.has(file)) {
|
|
134
|
-
const
|
|
135
|
+
const ident = this.getId(file, name);
|
|
136
|
+
const uniqueName = ident.text;
|
|
135
137
|
|
|
136
|
-
if (this.#imports.has(
|
|
137
|
-
return this.#imports.get(
|
|
138
|
+
if (this.#imports.has(uniqueName)) { // Already imported, be cool
|
|
139
|
+
return this.#imports.get(uniqueName)!;
|
|
138
140
|
}
|
|
139
141
|
|
|
140
|
-
const ident = this.factory.createIdentifier(id);
|
|
141
142
|
const newImport = { path: file, ident };
|
|
142
|
-
this.#imports.set(
|
|
143
|
+
this.#imports.set(uniqueName, newImport);
|
|
143
144
|
this.#newImports.set(file, newImport);
|
|
144
145
|
}
|
|
145
146
|
return this.#newImports.get(file)!;
|
|
@@ -156,7 +157,7 @@ export class ImportManager {
|
|
|
156
157
|
switch (type.key) {
|
|
157
158
|
case 'managed':
|
|
158
159
|
case 'literal': this.importFromResolved(...type.typeArguments || []); break;
|
|
159
|
-
case '
|
|
160
|
+
case 'composition':
|
|
160
161
|
case 'tuple': this.importFromResolved(...type.subTypes || []); break;
|
|
161
162
|
case 'shape': this.importFromResolved(...Object.values(type.fieldTypes)); break;
|
|
162
163
|
}
|
package/src/register.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
2
|
|
|
3
|
-
import { DecoratorMeta, NodeTransformer, State, TransformPhase, TransformerType, Transformer,
|
|
3
|
+
import { DecoratorMeta, NodeTransformer, State, TransformPhase, TransformerType, Transformer, ModuleNameSymbol } from './types/visitor';
|
|
4
4
|
|
|
5
5
|
const HandlersProp = Symbol.for('@travetto/transformer:handlers');
|
|
6
6
|
|
|
@@ -18,7 +18,7 @@ export function getAllTransformers(obj: Record<string, { [HandlersProp]?: NodeTr
|
|
|
18
18
|
return Object.values(obj)
|
|
19
19
|
.flatMap(x => {
|
|
20
20
|
if (isTransformer(x)) {
|
|
21
|
-
x[
|
|
21
|
+
x[ModuleNameSymbol] = module;
|
|
22
22
|
}
|
|
23
23
|
return (x[HandlersProp] ?? []);
|
|
24
24
|
})
|
package/src/resolver/builder.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { DeclarationUtil } from '../util/declaration';
|
|
|
9
9
|
import { LiteralUtil } from '../util/literal';
|
|
10
10
|
import { transformCast, TemplateLiteralPart } from '../types/shared';
|
|
11
11
|
|
|
12
|
-
import { Type, AnyType,
|
|
12
|
+
import { Type, AnyType, CompositionType, TransformResolver, TemplateType } from './types';
|
|
13
13
|
import { CoerceUtil } from './coerce';
|
|
14
14
|
|
|
15
15
|
const TYPINGS_RE = /[.]d[.][cm]?ts$/;
|
|
@@ -39,7 +39,7 @@ const GLOBAL_SIMPLE: Record<string, Function> = {
|
|
|
39
39
|
type Category =
|
|
40
40
|
'void' | 'undefined' | 'concrete' | 'unknown' |
|
|
41
41
|
'tuple' | 'shape' | 'literal' | 'template' | 'managed' |
|
|
42
|
-
'
|
|
42
|
+
'composition' | 'foreign';
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
45
|
* Type categorizer, input for builder
|
|
@@ -98,12 +98,14 @@ export function TypeCategorize(resolver: TransformResolver, type: ts.Type): { ca
|
|
|
98
98
|
ts.TypeFlags.Void | ts.TypeFlags.Undefined
|
|
99
99
|
)) {
|
|
100
100
|
return { category: 'literal', type };
|
|
101
|
-
} else if (type.
|
|
102
|
-
return { category: '
|
|
101
|
+
} else if (type.isUnionOrIntersection()) {
|
|
102
|
+
return { category: 'composition', type };
|
|
103
103
|
} else if (objectFlags & ts.ObjectFlags.Tuple) {
|
|
104
104
|
return { category: 'tuple', type };
|
|
105
105
|
} else if (type.isLiteral()) {
|
|
106
106
|
return { category: 'shape', type };
|
|
107
|
+
} else if ((objectFlags & ts.ObjectFlags.Mapped)) { // Mapped types: Pick, Omit, Exclude, Retain
|
|
108
|
+
return { category: 'shape', type };
|
|
107
109
|
}
|
|
108
110
|
return { category: 'literal', type };
|
|
109
111
|
}
|
|
@@ -207,21 +209,21 @@ export const TypeBuilder: {
|
|
|
207
209
|
return { key: 'managed', name, importName, tsTypeArguments };
|
|
208
210
|
}
|
|
209
211
|
},
|
|
210
|
-
|
|
211
|
-
build: (resolver, uType: ts.
|
|
212
|
+
composition: {
|
|
213
|
+
build: (resolver, uType: ts.UnionOrIntersectionType) => {
|
|
212
214
|
let undefinable = false;
|
|
213
215
|
let nullable = false;
|
|
214
216
|
const remainder = uType.types.filter(ut => {
|
|
215
217
|
const u = (ut.getFlags() & (ts.TypeFlags.Undefined)) > 0;
|
|
216
218
|
const n = (ut.getFlags() & (ts.TypeFlags.Null)) > 0;
|
|
217
|
-
undefinable
|
|
218
|
-
nullable
|
|
219
|
+
undefinable ||= u;
|
|
220
|
+
nullable ||= n;
|
|
219
221
|
return !(u || n);
|
|
220
222
|
});
|
|
221
223
|
const name = CoreUtil.getSymbol(uType)?.getName();
|
|
222
|
-
return { key: '
|
|
224
|
+
return { key: 'composition', name, undefinable, nullable, tsSubTypes: remainder, subTypes: [], operation: uType.isUnion() ? 'or' : 'and' };
|
|
223
225
|
},
|
|
224
|
-
finalize: (type:
|
|
226
|
+
finalize: (type: CompositionType) => {
|
|
225
227
|
const { undefinable, nullable, subTypes } = type;
|
|
226
228
|
const [first] = subTypes;
|
|
227
229
|
|
|
@@ -237,6 +239,8 @@ export const TypeBuilder: {
|
|
|
237
239
|
return { undefinable, nullable, ...first };
|
|
238
240
|
} else if (first.key === 'literal' && subTypes.every(el => el.name === first.name)) { // We have a common
|
|
239
241
|
type.commonType = first;
|
|
242
|
+
} else if (type.operation === 'and' && first.key === 'shape' && subTypes.every(el => el.key === 'shape')) { // All shapes
|
|
243
|
+
return { importName: first.importName, name: first.name, key: 'shape', fieldTypes: subTypes.reduce((acc, x) => ({ ...acc, ...x.fieldTypes }), {}) };
|
|
240
244
|
}
|
|
241
245
|
return type;
|
|
242
246
|
}
|
package/src/resolver/types.ts
CHANGED
|
@@ -117,7 +117,7 @@ export interface TemplateType extends Type<'template'> {
|
|
|
117
117
|
/**
|
|
118
118
|
* Union type
|
|
119
119
|
*/
|
|
120
|
-
export interface
|
|
120
|
+
export interface CompositionType extends Type<'composition'> {
|
|
121
121
|
/**
|
|
122
122
|
* A common type if derivable, e.g. 'a'|'b' will have a common type of string
|
|
123
123
|
*/
|
|
@@ -130,6 +130,10 @@ export interface UnionType extends Type<'union'> {
|
|
|
130
130
|
* Type Info
|
|
131
131
|
*/
|
|
132
132
|
tsSubTypes?: ts.Type[];
|
|
133
|
+
/**
|
|
134
|
+
* Operation to perform
|
|
135
|
+
*/
|
|
136
|
+
operation?: 'and' | 'or';
|
|
133
137
|
}
|
|
134
138
|
|
|
135
139
|
/**
|
|
@@ -177,7 +181,7 @@ export interface ForeignType extends Type<'foreign'> {
|
|
|
177
181
|
export interface UnknownType extends Type<'unknown'> { }
|
|
178
182
|
|
|
179
183
|
export type AnyType =
|
|
180
|
-
TupleType | ShapeType |
|
|
184
|
+
TupleType | ShapeType | CompositionType | LiteralType |
|
|
181
185
|
ManagedType | PointerType | UnknownType | ForeignType | TemplateType;
|
|
182
186
|
|
|
183
187
|
/**
|
package/src/state.ts
CHANGED
|
@@ -2,8 +2,8 @@ import ts from 'typescript';
|
|
|
2
2
|
|
|
3
3
|
import { path, ManifestIndex } from '@travetto/manifest';
|
|
4
4
|
|
|
5
|
-
import { ManagedType, AnyType
|
|
6
|
-
import { State, DecoratorMeta, Transformer,
|
|
5
|
+
import { ManagedType, AnyType } from './resolver/types';
|
|
6
|
+
import { State, DecoratorMeta, Transformer, ModuleNameSymbol } from './types/visitor';
|
|
7
7
|
import { SimpleResolver } from './resolver/service';
|
|
8
8
|
import { ImportManager } from './importer';
|
|
9
9
|
import { Import } from './types/shared';
|
|
@@ -23,12 +23,14 @@ function hasEscapedName(n: ts.Node): n is ts.Node & { name: { escapedText: strin
|
|
|
23
23
|
return !!n && 'name' in n && typeof n.name === 'object' && !!n.name && 'escapedText' in n.name && !!n.name.escapedText;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
function isRedefinableDeclaration(x: ts.Node): x is ts.InterfaceDeclaration | ts.ClassDeclaration | ts.FunctionDeclaration {
|
|
27
|
+
return ts.isFunctionDeclaration(x) || ts.isClassDeclaration(x) || ts.isInterfaceDeclaration(x);
|
|
28
|
+
}
|
|
29
|
+
|
|
26
30
|
/**
|
|
27
31
|
* Transformer runtime state
|
|
28
32
|
*/
|
|
29
33
|
export class TransformerState implements State {
|
|
30
|
-
static SYNTHETIC_EXT = 'Ⲑsyn';
|
|
31
|
-
|
|
32
34
|
#resolver: SimpleResolver;
|
|
33
35
|
#imports: ImportManager;
|
|
34
36
|
#modIdent: ts.Identifier;
|
|
@@ -268,7 +270,7 @@ export class TransformerState implements State {
|
|
|
268
270
|
*/
|
|
269
271
|
getModuleIdentifier(): ts.Expression {
|
|
270
272
|
if (this.#modIdent === undefined) {
|
|
271
|
-
this.#modIdent = this.
|
|
273
|
+
this.#modIdent = this.factory.createUniqueName('mod');
|
|
272
274
|
const entry = this.#resolver.getFileImport(this.source.fileName);
|
|
273
275
|
const decl = this.factory.createVariableDeclaration(this.#modIdent, undefined, undefined,
|
|
274
276
|
this.fromLiteral([entry?.module, entry?.relativeFile ?? ''])
|
|
@@ -288,7 +290,7 @@ export class TransformerState implements State {
|
|
|
288
290
|
* @param module
|
|
289
291
|
*/
|
|
290
292
|
findDecorator(mod: string | Transformer, node: ts.Node, name: string, module?: string): ts.Decorator | undefined {
|
|
291
|
-
mod = typeof mod === 'string' ? mod : mod[
|
|
293
|
+
mod = typeof mod === 'string' ? mod : mod[ModuleNameSymbol]!;
|
|
292
294
|
const target = `${mod}:${name}`;
|
|
293
295
|
const list = this.getDecoratorList(node);
|
|
294
296
|
return list.find(x => x.targets?.includes(target) && (!module || x.name === name && x.module === module))?.dec;
|
|
@@ -299,7 +301,7 @@ export class TransformerState implements State {
|
|
|
299
301
|
* @param node
|
|
300
302
|
* @param type
|
|
301
303
|
*/
|
|
302
|
-
generateUniqueIdentifier(node: ts.Node, type: AnyType): string {
|
|
304
|
+
generateUniqueIdentifier(node: ts.Node, type: AnyType, suffix?: string): string {
|
|
303
305
|
let unique: string[] = [];
|
|
304
306
|
let name = type.name && !type.name.startsWith('_') ? type.name : '';
|
|
305
307
|
if (!name && hasEscapedName(node)) {
|
|
@@ -315,14 +317,15 @@ export class TransformerState implements State {
|
|
|
315
317
|
if (fileName === this.source.fileName) { // if in same file suffix with location
|
|
316
318
|
let child: ts.Node = tgt;
|
|
317
319
|
while (child && !ts.isSourceFile(child)) {
|
|
318
|
-
if (
|
|
320
|
+
if (isRedefinableDeclaration(child) || ts.isMethodDeclaration(child) || ts.isParameter(child)) {
|
|
319
321
|
if (child.name) {
|
|
320
322
|
unique.push(child.name.getText());
|
|
321
323
|
}
|
|
322
324
|
}
|
|
323
325
|
child = child.parent;
|
|
324
326
|
}
|
|
325
|
-
|
|
327
|
+
|
|
328
|
+
if (!unique.length) {
|
|
326
329
|
unique.push(ts.getLineAndCharacterOfPosition(tgt.getSourceFile(), tgt.getStart()).line.toString());
|
|
327
330
|
}
|
|
328
331
|
} else {
|
|
@@ -334,7 +337,7 @@ export class TransformerState implements State {
|
|
|
334
337
|
|
|
335
338
|
if (unique.length) { // Make unique to file
|
|
336
339
|
unique.unshift(this.#resolver.getFileImportName(this.source.fileName));
|
|
337
|
-
return `${name}__${SystemUtil.naiveHashString(unique.join(':'), 12)}`;
|
|
340
|
+
return `${name}__${SystemUtil.naiveHashString(unique.join(':'), 12)}${suffix || ''}`;
|
|
338
341
|
} else {
|
|
339
342
|
return name;
|
|
340
343
|
}
|
|
@@ -343,8 +346,7 @@ export class TransformerState implements State {
|
|
|
343
346
|
/**
|
|
344
347
|
* Register synthetic identifier
|
|
345
348
|
*/
|
|
346
|
-
|
|
347
|
-
id = `${id}${TransformerState.SYNTHETIC_EXT}`;
|
|
349
|
+
registerIdentifier(id: string): [identifier: ts.Identifier, exists: boolean] {
|
|
348
350
|
let exists = true;
|
|
349
351
|
if (!this.#syntheticIdentifiers.has(id)) {
|
|
350
352
|
this.#syntheticIdentifiers.set(id, this.factory.createIdentifier(id));
|
|
@@ -381,13 +383,4 @@ export class TransformerState implements State {
|
|
|
381
383
|
getFileImportName(file: string): string {
|
|
382
384
|
return this.#resolver.getFileImportName(file);
|
|
383
385
|
}
|
|
384
|
-
|
|
385
|
-
/**
|
|
386
|
-
* Get foreign target
|
|
387
|
-
*/
|
|
388
|
-
getForeignTarget(state: TransformerState, ret: ForeignType): ts.Expression {
|
|
389
|
-
return state.fromLiteral({
|
|
390
|
-
Ⲑid: `${ret.source.split('node_modules/')[1]}+${ret.name}`
|
|
391
|
-
});
|
|
392
|
-
}
|
|
393
386
|
}
|
package/src/types/shared.ts
CHANGED
|
@@ -26,7 +26,6 @@ export type Import = {
|
|
|
26
26
|
stmt?: ts.ImportDeclaration;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
|
|
30
29
|
/** Template Literal Types */
|
|
31
30
|
export type TemplateLiteralPart = string | NumberConstructor | StringConstructor | BooleanConstructor;
|
|
32
31
|
export type TemplateLiteral = { op: 'and' | 'or', values: (TemplateLiteralPart | TemplateLiteral)[] };
|
package/src/types/visitor.ts
CHANGED
|
@@ -26,10 +26,10 @@ export type TransformerType =
|
|
|
26
26
|
'class' | 'method' | 'property' | 'getter' | 'setter' | 'parameter' |
|
|
27
27
|
'static-method' | 'call' | 'function' | 'file';
|
|
28
28
|
|
|
29
|
-
export const
|
|
29
|
+
export const ModuleNameSymbol = Symbol.for('@travetto/transformer:id');
|
|
30
30
|
|
|
31
31
|
export type Transformer = {
|
|
32
|
-
[
|
|
32
|
+
[ModuleNameSymbol]?: string;
|
|
33
33
|
name: string;
|
|
34
34
|
};
|
|
35
35
|
|