@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 +39 -34
- package/__index__.ts +16 -10
- package/package.json +13 -13
- package/src/importer.ts +40 -39
- package/src/manager.ts +9 -7
- package/src/register.ts +10 -4
- package/src/resolver/builder.ts +127 -66
- package/src/resolver/cache.ts +1 -0
- package/src/resolver/coerce.ts +12 -10
- package/src/resolver/service.ts +26 -19
- package/src/resolver/types.ts +17 -4
- package/src/state.ts +49 -36
- package/src/types/shared.ts +3 -3
- package/src/types/visitor.ts +13 -3
- package/src/util/core.ts +21 -16
- package/src/util/declaration.ts +69 -11
- package/src/util/decorator.ts +2 -2
- package/src/util/doc.ts +12 -11
- package/src/util/import.ts +2 -2
- package/src/util/literal.ts +11 -10
- package/src/util/log.ts +23 -5
- package/src/util/system.ts +2 -4
- package/src/visitor.ts +48 -48
package/src/state.ts
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { type ManifestIndex, path } from '@travetto/manifest';
|
|
4
4
|
|
|
5
|
-
import type { ManagedType, AnyType, ForeignType, MappedType } from './resolver/types.ts';
|
|
6
|
-
import { type State, type DecoratorMeta, type Transformer, ModuleNameSymbol } from './types/visitor.ts';
|
|
7
|
-
import { SimpleResolver } from './resolver/service.ts';
|
|
8
5
|
import { ImportManager } from './importer.ts';
|
|
6
|
+
import { SimpleResolver } from './resolver/service.ts';
|
|
7
|
+
import type { AnyType, ForeignType, ManagedType, MappedType } from './resolver/types.ts';
|
|
9
8
|
import type { Import } from './types/shared.ts';
|
|
10
|
-
|
|
11
|
-
import { DocUtil } from './util/doc.ts';
|
|
12
|
-
import { DecoratorUtil } from './util/decorator.ts';
|
|
13
|
-
import { DeclarationUtil } from './util/declaration.ts';
|
|
9
|
+
import { type DecoratorMeta, ModuleNameSymbol, type State, type Transformer } from './types/visitor.ts';
|
|
14
10
|
import { CoreUtil } from './util/core.ts';
|
|
11
|
+
import { DeclarationUtil } from './util/declaration.ts';
|
|
12
|
+
import { DecoratorUtil } from './util/decorator.ts';
|
|
13
|
+
import { DocUtil } from './util/doc.ts';
|
|
15
14
|
import { LiteralUtil } from './util/literal.ts';
|
|
16
15
|
import { SystemUtil } from './util/system.ts';
|
|
17
16
|
|
|
@@ -23,7 +22,7 @@ function hasEscapedName(node: ts.Node): node is ts.Node & { name: { escapedText:
|
|
|
23
22
|
return !!node && 'name' in node && typeof node.name === 'object' && !!node.name && 'escapedText' in node.name && !!node.name.escapedText;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
|
-
function
|
|
25
|
+
function canRedeclare(node: ts.Node): node is ts.InterfaceDeclaration | ts.ClassDeclaration | ts.FunctionDeclaration {
|
|
27
26
|
return ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node);
|
|
28
27
|
}
|
|
29
28
|
|
|
@@ -105,9 +104,12 @@ export class TransformerState implements State {
|
|
|
105
104
|
typeToIdentifier(node: ts.Type | AnyType): ts.Identifier | ts.PropertyAccessExpression | undefined {
|
|
106
105
|
const type = 'flags' in node ? this.resolveType(node) : node;
|
|
107
106
|
switch (type.key) {
|
|
108
|
-
case 'literal':
|
|
109
|
-
|
|
110
|
-
case '
|
|
107
|
+
case 'literal':
|
|
108
|
+
return this.factory.createIdentifier(type.ctor!.name);
|
|
109
|
+
case 'managed':
|
|
110
|
+
return this.getOrImport(type);
|
|
111
|
+
case 'shape':
|
|
112
|
+
return;
|
|
111
113
|
}
|
|
112
114
|
}
|
|
113
115
|
|
|
@@ -173,9 +175,7 @@ export class TransformerState implements State {
|
|
|
173
175
|
const targets = DocUtil.readAugments(type);
|
|
174
176
|
const example = DocUtil.readExample(type);
|
|
175
177
|
const module = file ? moduleImport : undefined;
|
|
176
|
-
const name = identifier ?
|
|
177
|
-
identifier.escapedText?.toString()! :
|
|
178
|
-
undefined;
|
|
178
|
+
const name = identifier ? identifier.escapedText?.toString() : undefined;
|
|
179
179
|
|
|
180
180
|
if (identifier && name) {
|
|
181
181
|
return { decorator, identifier, file, module, targets, name, options: example };
|
|
@@ -186,9 +186,9 @@ export class TransformerState implements State {
|
|
|
186
186
|
* Get list of all #decorators for a node
|
|
187
187
|
*/
|
|
188
188
|
getDecoratorList(node: ts.Node): DecoratorMeta[] {
|
|
189
|
-
return ts.canHaveDecorators(node)
|
|
190
|
-
.map(decorator => this.getDecoratorMeta(decorator))
|
|
191
|
-
|
|
189
|
+
return ts.canHaveDecorators(node)
|
|
190
|
+
? (ts.getDecorators(node) ?? []).map(decorator => this.getDecoratorMeta(decorator)).filter(metadata => !!metadata)
|
|
191
|
+
: [];
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
/**
|
|
@@ -257,7 +257,11 @@ export class TransformerState implements State {
|
|
|
257
257
|
/**
|
|
258
258
|
* Create property access
|
|
259
259
|
*/
|
|
260
|
-
createAccess(
|
|
260
|
+
createAccess(
|
|
261
|
+
first: string | ts.Expression,
|
|
262
|
+
second: string | ts.Identifier,
|
|
263
|
+
...items: (string | number | ts.Identifier)[]
|
|
264
|
+
): ts.Expression {
|
|
261
265
|
return CoreUtil.createAccess(this.factory, first, second, ...items);
|
|
262
266
|
}
|
|
263
267
|
|
|
@@ -298,12 +302,16 @@ export class TransformerState implements State {
|
|
|
298
302
|
getModuleIdentifier(): ts.Expression {
|
|
299
303
|
if (this.#moduleIdentifier === undefined) {
|
|
300
304
|
this.#moduleIdentifier = this.factory.createUniqueName('Δm');
|
|
301
|
-
const declaration = this.factory.createVariableDeclaration(
|
|
305
|
+
const declaration = this.factory.createVariableDeclaration(
|
|
306
|
+
this.#moduleIdentifier,
|
|
307
|
+
undefined,
|
|
308
|
+
undefined,
|
|
302
309
|
this.fromLiteral(this.getModuleIdentifierTarget())
|
|
303
310
|
);
|
|
304
|
-
this.addStatements(
|
|
305
|
-
this.factory.createVariableStatement([], this.factory.createVariableDeclarationList([declaration], ts.NodeFlags.Const))
|
|
306
|
-
|
|
311
|
+
this.addStatements(
|
|
312
|
+
[this.factory.createVariableStatement([], this.factory.createVariableDeclarationList([declaration], ts.NodeFlags.Const))],
|
|
313
|
+
-1
|
|
314
|
+
);
|
|
307
315
|
}
|
|
308
316
|
return this.#moduleIdentifier;
|
|
309
317
|
}
|
|
@@ -320,7 +328,7 @@ export class TransformerState implements State {
|
|
|
320
328
|
const targetScope = typeof input === 'string' ? input : input[ModuleNameSymbol]!;
|
|
321
329
|
const target = `${targetScope}:${name}`;
|
|
322
330
|
const list = this.getDecoratorList(node);
|
|
323
|
-
return list.find(item => item.targets?.includes(target) && (!module || item.name === name && item.module === module))?.decorator;
|
|
331
|
+
return list.find(item => item.targets?.includes(target) && (!module || (item.name === name && item.module === module)))?.decorator;
|
|
324
332
|
}
|
|
325
333
|
|
|
326
334
|
/**
|
|
@@ -341,10 +349,11 @@ export class TransformerState implements State {
|
|
|
341
349
|
const tgt = DeclarationUtil.getPrimaryDeclarationNode(type.original!);
|
|
342
350
|
const fileName = tgt.getSourceFile().fileName;
|
|
343
351
|
|
|
344
|
-
if (fileName === this.source.fileName) {
|
|
352
|
+
if (fileName === this.source.fileName) {
|
|
353
|
+
// if in same file suffix with location
|
|
345
354
|
let child: ts.Node = tgt;
|
|
346
355
|
while (child && !ts.isSourceFile(child)) {
|
|
347
|
-
if (
|
|
356
|
+
if (canRedeclare(child) || ts.isMethodDeclaration(child) || ts.isParameter(child)) {
|
|
348
357
|
if (child.name) {
|
|
349
358
|
unique.push(child.name.getText());
|
|
350
359
|
}
|
|
@@ -362,7 +371,8 @@ export class TransformerState implements State {
|
|
|
362
371
|
unique = [type.name ?? 'unknown']; // Type is only unique piece
|
|
363
372
|
}
|
|
364
373
|
|
|
365
|
-
if (unique.length) {
|
|
374
|
+
if (unique.length) {
|
|
375
|
+
// Make unique to file
|
|
366
376
|
unique.unshift(this.#resolver.getFileImportName(this.source.fileName));
|
|
367
377
|
return `${name}__${SystemUtil.naiveHashString(unique.join(':'), 12)}${suffix || ''}`;
|
|
368
378
|
} else {
|
|
@@ -390,7 +400,8 @@ export class TransformerState implements State {
|
|
|
390
400
|
findMethodByName(cls: ts.ClassLikeDeclaration | ts.Type, method: string): ts.MethodDeclaration | undefined {
|
|
391
401
|
if ('getSourceFile' in cls) {
|
|
392
402
|
return cls.members.find(
|
|
393
|
-
(value): value is ts.MethodDeclaration =>
|
|
403
|
+
(value): value is ts.MethodDeclaration =>
|
|
404
|
+
ts.isMethodDeclaration(value) && ts.isIdentifier(value.name) && value.name.escapedText === method
|
|
394
405
|
);
|
|
395
406
|
} else {
|
|
396
407
|
const properties = this.#resolver.getPropertiesOfType(cls);
|
|
@@ -416,12 +427,11 @@ export class TransformerState implements State {
|
|
|
416
427
|
*/
|
|
417
428
|
getForeignTarget(typeOrClassId: ForeignType | string): ts.Expression {
|
|
418
429
|
const file = this.importFile(FOREIGN_TYPE_REGISTRY_FILE);
|
|
419
|
-
return this.factory.createCallExpression(
|
|
420
|
-
file.identifier,
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
]);
|
|
430
|
+
return this.factory.createCallExpression(
|
|
431
|
+
this.createAccess(file.identifier, this.factory.createIdentifier('foreignType')),
|
|
432
|
+
[],
|
|
433
|
+
[this.fromLiteral(typeof typeOrClassId === 'string' ? typeOrClassId : typeOrClassId.classId)]
|
|
434
|
+
);
|
|
425
435
|
}
|
|
426
436
|
|
|
427
437
|
/**
|
|
@@ -456,7 +466,10 @@ export class TransformerState implements State {
|
|
|
456
466
|
*/
|
|
457
467
|
getApparentTypeOfField(value: ts.Type, field: string): AnyType | undefined {
|
|
458
468
|
const checker = this.#resolver.getChecker();
|
|
459
|
-
const properties = checker
|
|
469
|
+
const properties = checker
|
|
470
|
+
.getApparentType(value)
|
|
471
|
+
.getApparentProperties()
|
|
472
|
+
.find(property => property.escapedName === field);
|
|
460
473
|
return properties ? this.resolveType(checker.getTypeOfSymbol(properties)) : undefined;
|
|
461
474
|
}
|
|
462
|
-
}
|
|
475
|
+
}
|
package/src/types/shared.ts
CHANGED
|
@@ -14,6 +14,7 @@ export interface ParamDocumentation {
|
|
|
14
14
|
export interface DeclDocumentation {
|
|
15
15
|
return?: string;
|
|
16
16
|
description?: string;
|
|
17
|
+
examples?: string[];
|
|
17
18
|
params?: ParamDocumentation[];
|
|
18
19
|
}
|
|
19
20
|
|
|
@@ -28,9 +29,8 @@ export type Import = {
|
|
|
28
29
|
|
|
29
30
|
/** Template Literal Types */
|
|
30
31
|
export type TemplateLiteralPart = string | NumberConstructor | StringConstructor | BooleanConstructor | BigIntConstructor;
|
|
31
|
-
export type TemplateLiteral = { operation: 'and' | 'or'
|
|
32
|
+
export type TemplateLiteral = { operation: 'and' | 'or'; values: (TemplateLiteralPart | TemplateLiteral)[] };
|
|
32
33
|
|
|
33
34
|
export function transformCast<T>(input: unknown): T {
|
|
34
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
35
35
|
return input as T;
|
|
36
|
-
}
|
|
36
|
+
}
|
package/src/types/visitor.ts
CHANGED
|
@@ -24,8 +24,18 @@ export type State = {
|
|
|
24
24
|
export type TransformPhase = 'before' | 'after';
|
|
25
25
|
|
|
26
26
|
export type TransformerType =
|
|
27
|
-
|
|
28
|
-
| '
|
|
27
|
+
| 'class'
|
|
28
|
+
| 'method'
|
|
29
|
+
| 'property'
|
|
30
|
+
| 'getter'
|
|
31
|
+
| 'setter'
|
|
32
|
+
| 'parameter'
|
|
33
|
+
| 'static-method'
|
|
34
|
+
| 'call'
|
|
35
|
+
| 'function'
|
|
36
|
+
| 'file'
|
|
37
|
+
| 'type'
|
|
38
|
+
| 'interface'
|
|
29
39
|
| 'constructor';
|
|
30
40
|
|
|
31
41
|
export const ModuleNameSymbol = Symbol.for('@travetto/transformer:id');
|
|
@@ -43,4 +53,4 @@ export interface NodeTransformer<S extends State = State, T extends TransformerT
|
|
|
43
53
|
target?: string[];
|
|
44
54
|
before?<Z extends ts.Node = ts.Node>(state: S, node: N, dm?: DecoratorMeta): Z | undefined;
|
|
45
55
|
after?<Z extends ts.Node = ts.Node>(state: S, node: N, dm?: DecoratorMeta): Z | undefined;
|
|
46
|
-
}
|
|
56
|
+
}
|
package/src/util/core.ts
CHANGED
|
@@ -4,18 +4,17 @@ import ts from 'typescript';
|
|
|
4
4
|
* Core utilities util
|
|
5
5
|
*/
|
|
6
6
|
export class CoreUtil {
|
|
7
|
-
|
|
8
7
|
/**
|
|
9
8
|
* See if inbound node has an original property
|
|
10
9
|
*/
|
|
11
|
-
static hasOriginal(value: ts.Node): value is
|
|
10
|
+
static hasOriginal(value: ts.Node): value is ts.Node & { original: ts.Node } {
|
|
12
11
|
return 'original' in value && !!value.original;
|
|
13
12
|
}
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
15
|
* See if type has target
|
|
17
16
|
*/
|
|
18
|
-
static hasTarget(value: ts.Type): value is
|
|
17
|
+
static hasTarget(value: ts.Type): value is ts.Type & { target: ts.Type } {
|
|
19
18
|
return 'target' in value && !!value.target;
|
|
20
19
|
}
|
|
21
20
|
|
|
@@ -37,7 +36,7 @@ export class CoreUtil {
|
|
|
37
36
|
node: ts.CallExpression | undefined,
|
|
38
37
|
pred: (expr: ts.Expression) => expr is T
|
|
39
38
|
): T | undefined {
|
|
40
|
-
if (node
|
|
39
|
+
if (node?.arguments?.length) {
|
|
41
40
|
return node.arguments.find(pred);
|
|
42
41
|
}
|
|
43
42
|
}
|
|
@@ -46,7 +45,7 @@ export class CoreUtil {
|
|
|
46
45
|
* Find the first argument of a call expression, or decorator.
|
|
47
46
|
*/
|
|
48
47
|
static firstArgument(node: ts.CallExpression | undefined): ts.Expression | undefined {
|
|
49
|
-
if (node
|
|
48
|
+
if (node?.arguments?.length) {
|
|
50
49
|
return node.arguments[0];
|
|
51
50
|
}
|
|
52
51
|
}
|
|
@@ -55,10 +54,7 @@ export class CoreUtil {
|
|
|
55
54
|
* Create a static field for a class
|
|
56
55
|
*/
|
|
57
56
|
static createStaticField(factory: ts.NodeFactory, name: string, value: ts.Expression): ts.PropertyDeclaration {
|
|
58
|
-
return factory.createPropertyDeclaration(
|
|
59
|
-
[factory.createToken(ts.SyntaxKind.StaticKeyword)],
|
|
60
|
-
name, undefined, undefined, value
|
|
61
|
-
);
|
|
57
|
+
return factory.createPropertyDeclaration([factory.createToken(ts.SyntaxKind.StaticKeyword)], name, undefined, undefined, value);
|
|
62
58
|
}
|
|
63
59
|
|
|
64
60
|
/**
|
|
@@ -79,9 +75,18 @@ export class CoreUtil {
|
|
|
79
75
|
* @param source
|
|
80
76
|
* @param statements
|
|
81
77
|
*/
|
|
82
|
-
static updateSource(
|
|
78
|
+
static updateSource(
|
|
79
|
+
factory: ts.NodeFactory,
|
|
80
|
+
source: ts.SourceFile,
|
|
81
|
+
statements: ts.NodeArray<ts.Statement> | ts.Statement[]
|
|
82
|
+
): ts.SourceFile {
|
|
83
83
|
return factory.updateSourceFile(
|
|
84
|
-
source,
|
|
84
|
+
source,
|
|
85
|
+
statements,
|
|
86
|
+
source.isDeclarationFile,
|
|
87
|
+
source.referencedFiles,
|
|
88
|
+
source.typeReferenceDirectives,
|
|
89
|
+
source.hasNoDefaultLib
|
|
85
90
|
);
|
|
86
91
|
}
|
|
87
92
|
|
|
@@ -98,9 +103,10 @@ export class CoreUtil {
|
|
|
98
103
|
first = factory.createIdentifier(first);
|
|
99
104
|
}
|
|
100
105
|
return items.reduce<ts.Expression>(
|
|
101
|
-
(expr, value) =>
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
(expr, value) =>
|
|
107
|
+
typeof value === 'number'
|
|
108
|
+
? factory.createElementAccessExpression(expr, value)
|
|
109
|
+
: factory.createPropertyAccessExpression(expr, value),
|
|
104
110
|
factory.createPropertyAccessExpression(first, second)
|
|
105
111
|
);
|
|
106
112
|
}
|
|
@@ -122,7 +128,6 @@ export class CoreUtil {
|
|
|
122
128
|
* Is declaration abstract?
|
|
123
129
|
*/
|
|
124
130
|
static isAbstract(node: ts.Declaration): boolean {
|
|
125
|
-
// eslint-disable-next-line no-bitwise
|
|
126
131
|
return !!(ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Abstract);
|
|
127
132
|
}
|
|
128
|
-
}
|
|
133
|
+
}
|
package/src/util/declaration.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
|
+
|
|
2
3
|
import { CoreUtil } from './core.ts';
|
|
3
4
|
|
|
4
5
|
const isNamed = (value: ts.Declaration): value is ts.Declaration & { name: ts.Node } => 'name' in value && !!value.name;
|
|
@@ -7,7 +8,6 @@ const isNamed = (value: ts.Declaration): value is ts.Declaration & { name: ts.No
|
|
|
7
8
|
* Declaration utils
|
|
8
9
|
*/
|
|
9
10
|
export class DeclarationUtil {
|
|
10
|
-
|
|
11
11
|
/**
|
|
12
12
|
* Searches upward from the node until it finds the variable declaration list,
|
|
13
13
|
* and then checks the toString for `const `
|
|
@@ -24,9 +24,10 @@ export class DeclarationUtil {
|
|
|
24
24
|
* See if a declaration is public
|
|
25
25
|
*/
|
|
26
26
|
static isPublic(node: ts.Declaration): boolean {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
(!isNamed(node) || !ts.isPrivateIdentifier(node.name))
|
|
27
|
+
return (
|
|
28
|
+
!(ts.getCombinedModifierFlags(node) & ts.ModifierFlags.NonPublicAccessibilityModifier) &&
|
|
29
|
+
(!isNamed(node) || !ts.isPrivateIdentifier(node.name))
|
|
30
|
+
);
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
/**
|
|
@@ -65,8 +66,7 @@ export class DeclarationUtil {
|
|
|
65
66
|
*/
|
|
66
67
|
static getObjectFlags(type: ts.Type): ts.ObjectFlags {
|
|
67
68
|
const _ts: typeof ts & { getObjectFlags?(node: ts.Type): ts.ObjectFlags } = ts;
|
|
68
|
-
|
|
69
|
-
return _ts.getObjectFlags!(type) & ~(ts.NodeFlags.ThisNodeOrAnySubNodesHasError);
|
|
69
|
+
return _ts.getObjectFlags!(type) & ~ts.NodeFlags.ThisNodeOrAnySubNodesHasError;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
/**
|
|
@@ -75,10 +75,14 @@ export class DeclarationUtil {
|
|
|
75
75
|
* @param node
|
|
76
76
|
* @returns
|
|
77
77
|
*/
|
|
78
|
-
static getAccessorPair(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
static getAccessorPair(node: ts.GetAccessorDeclaration | ts.SetAccessorDeclaration): {
|
|
79
|
+
getter?: ts.GetAccessorDeclaration;
|
|
80
|
+
setter?: ts.SetAccessorDeclaration;
|
|
81
|
+
} {
|
|
82
|
+
const pair = {
|
|
83
|
+
getter: ts.isGetAccessorDeclaration(node) ? node : undefined,
|
|
84
|
+
setter: ts.isSetAccessorDeclaration(node) ? node : undefined
|
|
85
|
+
};
|
|
82
86
|
if (ts.isClassDeclaration(node.parent)) {
|
|
83
87
|
for (const member of node.parent.members) {
|
|
84
88
|
if (member.name && member.name.getText() === node.name.getText()) {
|
|
@@ -102,4 +106,58 @@ export class DeclarationUtil {
|
|
|
102
106
|
}
|
|
103
107
|
return false;
|
|
104
108
|
}
|
|
105
|
-
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Ensures a constructor exists in the class declaration, synthesizing one if necessary
|
|
112
|
+
*/
|
|
113
|
+
static ensureConstructor(factory: ts.NodeFactory, node: ts.ClassDeclaration): ts.ClassDeclaration {
|
|
114
|
+
const hasCons = node.members.some(member => ts.isConstructorDeclaration(member));
|
|
115
|
+
if (hasCons) {
|
|
116
|
+
return node;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const hasParent = node.heritageClauses?.some(clause => clause.token === ts.SyntaxKind.ExtendsKeyword);
|
|
120
|
+
const newConsStatements: ts.Statement[] = [];
|
|
121
|
+
let parameters: ts.ParameterDeclaration[] = [];
|
|
122
|
+
if (hasParent) {
|
|
123
|
+
parameters = [
|
|
124
|
+
factory.createParameterDeclaration(
|
|
125
|
+
undefined,
|
|
126
|
+
factory.createToken(ts.SyntaxKind.DotDotDotToken),
|
|
127
|
+
factory.createIdentifier('args'),
|
|
128
|
+
undefined,
|
|
129
|
+
factory.createArrayTypeNode(factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)),
|
|
130
|
+
undefined
|
|
131
|
+
)
|
|
132
|
+
];
|
|
133
|
+
newConsStatements.push(
|
|
134
|
+
factory.createExpressionStatement(
|
|
135
|
+
factory.createCallExpression(factory.createSuper(), undefined, [factory.createSpreadElement(factory.createIdentifier('args'))])
|
|
136
|
+
)
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
const newCons = factory.createConstructorDeclaration(undefined, parameters, factory.createBlock(newConsStatements, true));
|
|
140
|
+
return factory.updateClassDeclaration(node, node.modifiers, node.name, node.typeParameters, node.heritageClauses, [
|
|
141
|
+
...node.members,
|
|
142
|
+
newCons
|
|
143
|
+
]);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Calculates the insertion index for constructor statements (after super call, if exists)
|
|
148
|
+
*/
|
|
149
|
+
static getConstructorInsertIndex(node: ts.ConstructorDeclaration): number {
|
|
150
|
+
if (node.body) {
|
|
151
|
+
const first = node.body.statements[0];
|
|
152
|
+
if (
|
|
153
|
+
first &&
|
|
154
|
+
ts.isExpressionStatement(first) &&
|
|
155
|
+
ts.isCallExpression(first.expression) &&
|
|
156
|
+
first.expression.expression.kind === ts.SyntaxKind.SuperKeyword
|
|
157
|
+
) {
|
|
158
|
+
return 1;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return 0;
|
|
162
|
+
}
|
|
163
|
+
}
|
package/src/util/decorator.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
|
+
|
|
2
3
|
import { CoreUtil } from './core.ts';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Utilities for dealing with decorators
|
|
6
7
|
*/
|
|
7
8
|
export class DecoratorUtil {
|
|
8
|
-
|
|
9
9
|
static #getIdentFromExpression(expr: ts.Expression): ts.Identifier {
|
|
10
10
|
if (ts.isCallExpression(expr) && ts.isIdentifier(expr.expression)) {
|
|
11
11
|
return expr.expression;
|
|
@@ -66,4 +66,4 @@ export class DecoratorUtil {
|
|
|
66
66
|
static getArguments(node: ts.Decorator | undefined): ts.Expression[] | undefined {
|
|
67
67
|
return node && ts.isCallExpression(node.expression) ? [...node.expression.arguments] : undefined;
|
|
68
68
|
}
|
|
69
|
-
}
|
|
69
|
+
}
|
package/src/util/doc.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { type DeclDocumentation, transformCast } from '../types/shared.ts';
|
|
4
4
|
import { CoreUtil } from './core.ts';
|
|
5
5
|
import { DeclarationUtil } from './declaration.ts';
|
|
6
6
|
|
|
@@ -11,7 +11,7 @@ export class DocUtil {
|
|
|
11
11
|
/**
|
|
12
12
|
* See if node has js docs
|
|
13
13
|
*/
|
|
14
|
-
static hasJSDoc(node: ts.Node): node is
|
|
14
|
+
static hasJSDoc(node: ts.Node): node is ts.Node & { jsDoc: ts.JSDoc[] } {
|
|
15
15
|
return 'jsDoc' in node && node.jsDoc !== null && node.jsDoc !== undefined && Array.isArray(node.jsDoc) && node.jsDoc.length > 0;
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -26,21 +26,22 @@ export class DocUtil {
|
|
|
26
26
|
* Read JS Docs from a `ts.Declaration`
|
|
27
27
|
*/
|
|
28
28
|
static describeDocs(node: ts.Declaration | ts.Type): DeclDocumentation {
|
|
29
|
-
let toDescribe =
|
|
30
|
-
DeclarationUtil.getOptionalPrimaryDeclarationNode(node) : node;
|
|
29
|
+
let toDescribe = node && !('getSourceFile' in node) ? DeclarationUtil.getOptionalPrimaryDeclarationNode(node) : node;
|
|
31
30
|
|
|
32
31
|
const out: DeclDocumentation = {
|
|
33
32
|
description: undefined,
|
|
34
33
|
return: undefined,
|
|
34
|
+
examples: undefined,
|
|
35
35
|
params: []
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
if (toDescribe) {
|
|
39
|
-
const tags = ts.getJSDocTags(toDescribe);
|
|
40
39
|
while (!this.hasJSDoc(toDescribe) && CoreUtil.hasOriginal(toDescribe)) {
|
|
41
40
|
toDescribe = transformCast<ts.Declaration>(toDescribe.original);
|
|
42
41
|
}
|
|
43
42
|
|
|
43
|
+
const tags = ts.getJSDocTags(toDescribe);
|
|
44
|
+
|
|
44
45
|
const docs = this.hasJSDoc(toDescribe) ? toDescribe.jsDoc : undefined;
|
|
45
46
|
|
|
46
47
|
if (docs) {
|
|
@@ -50,15 +51,17 @@ export class DocUtil {
|
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
if (tags
|
|
54
|
+
if (tags?.length) {
|
|
54
55
|
for (const tag of tags) {
|
|
55
56
|
if (ts.isJSDocReturnTag(tag)) {
|
|
56
57
|
out.return = this.getDocComment(tag, out.return);
|
|
57
58
|
} else if (ts.isJSDocParameterTag(tag)) {
|
|
58
59
|
out.params!.push({
|
|
59
|
-
name: tag.name
|
|
60
|
+
name: tag.name?.getText(),
|
|
60
61
|
description: this.getDocComment(tag, '')!
|
|
61
62
|
});
|
|
63
|
+
} else if (tag.tagName.getText() === 'example') {
|
|
64
|
+
(out.examples ??= []).push(this.getDocComment(tag, '')!);
|
|
62
65
|
}
|
|
63
66
|
}
|
|
64
67
|
}
|
|
@@ -71,9 +74,7 @@ export class DocUtil {
|
|
|
71
74
|
*/
|
|
72
75
|
static readDocTag(type: ts.Type | ts.Symbol, name: string): string[] {
|
|
73
76
|
const tags = CoreUtil.getSymbol(type)?.getJsDocTags() ?? [];
|
|
74
|
-
return tags
|
|
75
|
-
.filter(tag => tag.name === name && !!tag.text)
|
|
76
|
-
.map(tag => tag.text!.map(part => part.text).join('')); // Join all text
|
|
77
|
+
return tags.filter(tag => tag.name === name && !!tag.text).map(tag => tag.text!.map(part => part.text).join('')); // Join all text
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
/**
|
|
@@ -99,4 +100,4 @@ export class DocUtil {
|
|
|
99
100
|
static readExample(type: ts.Type | ts.Symbol): string[] {
|
|
100
101
|
return this.readDocTag(type, 'example').map(line => line.replace(/^.*?([^` ]+).*?$/, (_, b) => b));
|
|
101
102
|
}
|
|
102
|
-
}
|
|
103
|
+
}
|
package/src/util/import.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { ManifestModuleUtil, PackageUtil, path } from '@travetto/manifest';
|
|
4
4
|
|
|
5
5
|
import type { Import } from '../types/shared.ts';
|
|
6
6
|
|
|
@@ -58,4 +58,4 @@ export class ImportUtil {
|
|
|
58
58
|
|
|
59
59
|
return imports;
|
|
60
60
|
}
|
|
61
|
-
}
|
|
61
|
+
}
|
package/src/util/literal.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { type TemplateLiteral, transformCast } from '../types/shared.ts';
|
|
4
4
|
|
|
5
5
|
const TypedObject: {
|
|
6
6
|
keys<T = unknown, K extends keyof T = keyof T>(value: T): K[];
|
|
@@ -20,14 +20,12 @@ function isKnownFn(value: unknown): value is Function {
|
|
|
20
20
|
* Utilities for dealing with literals
|
|
21
21
|
*/
|
|
22
22
|
export class LiteralUtil {
|
|
23
|
-
|
|
24
23
|
/**
|
|
25
24
|
* Determine if a type is a literal type
|
|
26
25
|
* @param type
|
|
27
26
|
*/
|
|
28
27
|
static isLiteralType(type: ts.Type): type is ts.LiteralType {
|
|
29
28
|
const flags = type.getFlags();
|
|
30
|
-
// eslint-disable-next-line no-bitwise
|
|
31
29
|
return (flags & (ts.TypeFlags.BooleanLiteral | ts.TypeFlags.NumberLiteral | ts.TypeFlags.StringLiteral)) > 0;
|
|
32
30
|
}
|
|
33
31
|
|
|
@@ -43,7 +41,8 @@ export class LiteralUtil {
|
|
|
43
41
|
static fromLiteral(factory: ts.NodeFactory, value: number): ts.NumericLiteral;
|
|
44
42
|
static fromLiteral(factory: ts.NodeFactory, value: boolean): ts.BooleanLiteral;
|
|
45
43
|
static fromLiteral(factory: ts.NodeFactory, value: unknown): ts.Node {
|
|
46
|
-
if (isNode(value)) {
|
|
44
|
+
if (isNode(value)) {
|
|
45
|
+
// If already a node
|
|
47
46
|
return value;
|
|
48
47
|
} else if (Array.isArray(value)) {
|
|
49
48
|
value = factory.createArrayLiteralExpression(value.map(element => this.fromLiteral(factory, element)));
|
|
@@ -69,9 +68,7 @@ export class LiteralUtil {
|
|
|
69
68
|
const pairs: ts.PropertyAssignment[] = [];
|
|
70
69
|
for (const key of TypedObject.keys(ov)) {
|
|
71
70
|
if (ov[key] !== undefined) {
|
|
72
|
-
pairs.push(
|
|
73
|
-
factory.createPropertyAssignment(key, this.fromLiteral(factory, ov[key]))
|
|
74
|
-
);
|
|
71
|
+
pairs.push(factory.createPropertyAssignment(key, this.fromLiteral(factory, ov[key])));
|
|
75
72
|
}
|
|
76
73
|
}
|
|
77
74
|
return factory.createObjectLiteralExpression(pairs);
|
|
@@ -142,12 +139,16 @@ export class LiteralUtil {
|
|
|
142
139
|
/**
|
|
143
140
|
* Extend object literal, whether JSON or ts.ObjectLiteralExpression
|
|
144
141
|
*/
|
|
145
|
-
static extendObjectLiteral(
|
|
142
|
+
static extendObjectLiteral(
|
|
143
|
+
factory: ts.NodeFactory,
|
|
144
|
+
source: object | ts.Expression,
|
|
145
|
+
...rest: (object | ts.Expression)[]
|
|
146
|
+
): ts.ObjectLiteralExpression {
|
|
146
147
|
let literal = this.fromLiteral(factory, source);
|
|
147
148
|
if (rest.find(item => !!item)) {
|
|
148
149
|
literal = factory.createObjectLiteralExpression([
|
|
149
150
|
factory.createSpreadAssignment(literal),
|
|
150
|
-
...
|
|
151
|
+
...rest.filter(item => !!item).map(expression => factory.createSpreadAssignment(this.fromLiteral(factory, expression)))
|
|
151
152
|
]);
|
|
152
153
|
}
|
|
153
154
|
return literal;
|
|
@@ -198,4 +199,4 @@ export class LiteralUtil {
|
|
|
198
199
|
return body;
|
|
199
200
|
}
|
|
200
201
|
}
|
|
201
|
-
}
|
|
202
|
+
}
|
package/src/util/log.ts
CHANGED
|
@@ -1,8 +1,26 @@
|
|
|
1
1
|
const exclude = new Set([
|
|
2
|
-
'parent',
|
|
3
|
-
'
|
|
4
|
-
'
|
|
5
|
-
'
|
|
2
|
+
'parent',
|
|
3
|
+
'checker',
|
|
4
|
+
'end',
|
|
5
|
+
'pos',
|
|
6
|
+
'id',
|
|
7
|
+
'source',
|
|
8
|
+
'sourceFile',
|
|
9
|
+
'getSourceFile',
|
|
10
|
+
'statements',
|
|
11
|
+
'stringIndexInfo',
|
|
12
|
+
'numberIndexInfo',
|
|
13
|
+
'instantiations',
|
|
14
|
+
'thisType',
|
|
15
|
+
'members',
|
|
16
|
+
'properties',
|
|
17
|
+
'outerTypeParameters',
|
|
18
|
+
'exports',
|
|
19
|
+
'transformFlags',
|
|
20
|
+
'flowNode',
|
|
21
|
+
'nextContainer',
|
|
22
|
+
'modifierFlagsCache',
|
|
23
|
+
'declaredProperties'
|
|
6
24
|
]);
|
|
7
25
|
|
|
8
26
|
const TypedObject: { keys<T = unknown, K extends keyof T = keyof T>(value: T): K[] } & ObjectConstructor = Object;
|
|
@@ -50,4 +68,4 @@ export class LogUtil {
|
|
|
50
68
|
return out;
|
|
51
69
|
}
|
|
52
70
|
}
|
|
53
|
-
}
|
|
71
|
+
}
|
package/src/util/system.ts
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
export class SystemUtil {
|
|
2
|
-
|
|
3
2
|
/**
|
|
4
3
|
* Naive hashing
|
|
5
4
|
*/
|
|
6
5
|
static naiveHash(text: string): number {
|
|
7
6
|
let hash = 5381;
|
|
8
7
|
|
|
9
|
-
for (let i = 0; i < text.length; i
|
|
10
|
-
// eslint-disable-next-line no-bitwise
|
|
8
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
11
9
|
hash = (hash * 33) ^ text.charCodeAt(i);
|
|
12
10
|
}
|
|
13
11
|
|
|
@@ -17,4 +15,4 @@ export class SystemUtil {
|
|
|
17
15
|
static naiveHashString(text: string, length: number): string {
|
|
18
16
|
return this.naiveHash(text).toString().padStart(length, '0').substring(0, length);
|
|
19
17
|
}
|
|
20
|
-
}
|
|
18
|
+
}
|