@travetto/transformer 6.0.1 → 7.0.0-rc.1
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/package.json +2 -2
- package/src/importer.ts +6 -4
- package/src/register.ts +18 -0
- package/src/resolver/builder.ts +50 -7
- package/src/resolver/service.ts +7 -5
- package/src/resolver/types.ts +23 -5
- package/src/state.ts +16 -10
- package/src/types/visitor.ts +4 -2
- package/src/util/declaration.ts +19 -5
- package/src/util/doc.ts +16 -8
- package/src/util/log.ts +1 -1
- package/src/visitor.ts +3 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/transformer",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0-rc.1",
|
|
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": "^
|
|
27
|
+
"@travetto/manifest": "^7.0.0-rc.0",
|
|
28
28
|
"tslib": "^2.8.1",
|
|
29
29
|
"typescript": "^5.9.3"
|
|
30
30
|
},
|
package/src/importer.ts
CHANGED
|
@@ -2,7 +2,7 @@ import ts from 'typescript';
|
|
|
2
2
|
|
|
3
3
|
import { ManifestModuleUtil, PackageUtil, path } from '@travetto/manifest';
|
|
4
4
|
|
|
5
|
-
import { AnyType, TransformResolver, ManagedType } from './resolver/types.ts';
|
|
5
|
+
import { AnyType, TransformResolver, ManagedType, MappedType } from './resolver/types.ts';
|
|
6
6
|
import { ImportUtil } from './util/import.ts';
|
|
7
7
|
import { CoreUtil } from './util/core.ts';
|
|
8
8
|
import { Import } from './types/shared.ts';
|
|
@@ -246,12 +246,14 @@ export class ImportManager {
|
|
|
246
246
|
/**
|
|
247
247
|
* Get the identifier and import if needed
|
|
248
248
|
*/
|
|
249
|
-
getOrImport(factory: ts.NodeFactory, type: ManagedType): ts.Identifier | ts.PropertyAccessExpression {
|
|
249
|
+
getOrImport(factory: ts.NodeFactory, type: ManagedType | MappedType): ts.Identifier | ts.PropertyAccessExpression {
|
|
250
|
+
const targetName = type.key === 'managed' ? type.name! : type.mappedClassName!;
|
|
251
|
+
// In same file already
|
|
250
252
|
if (type.importName === this.#importName) {
|
|
251
|
-
return factory.createIdentifier(
|
|
253
|
+
return factory.createIdentifier(targetName);
|
|
252
254
|
} else {
|
|
253
255
|
const { ident } = this.#imports.get(type.importName) ?? this.importFile(type.importName);
|
|
254
|
-
return factory.createPropertyAccessExpression(ident,
|
|
256
|
+
return factory.createPropertyAccessExpression(ident, targetName);
|
|
255
257
|
}
|
|
256
258
|
}
|
|
257
259
|
}
|
package/src/register.ts
CHANGED
|
@@ -115,6 +115,15 @@ export function OnMethod(...target: string[]) {
|
|
|
115
115
|
): void => storeHandler(inst, d.value!, 'before', 'method', target);
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Listens for a `ts.ConstructorDeclaration`, on descent
|
|
120
|
+
*/
|
|
121
|
+
export function OnConstructor(...target: string[]) {
|
|
122
|
+
return <S extends State = State, R extends ts.Node = ts.Node>(
|
|
123
|
+
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.ConstructorDeclaration, dm?: DecoratorMeta) => R>
|
|
124
|
+
): void => storeHandler(inst, d.value!, 'before', 'constructor', target);
|
|
125
|
+
}
|
|
126
|
+
|
|
118
127
|
/**
|
|
119
128
|
* Listens for a static `ts.MethodDeclaration`, on descent
|
|
120
129
|
*/
|
|
@@ -214,6 +223,15 @@ export function AfterMethod(...target: string[]) {
|
|
|
214
223
|
): void => storeHandler(inst, d.value!, 'after', 'method', target);
|
|
215
224
|
}
|
|
216
225
|
|
|
226
|
+
/**
|
|
227
|
+
* Listens for a `ts.ConstructorDeclaration`, on ascent
|
|
228
|
+
*/
|
|
229
|
+
export function AfterConstructor(...target: string[]) {
|
|
230
|
+
return <S extends State = State, R extends ts.Node = ts.Node>(
|
|
231
|
+
inst: Transformer, __: unknown, d: TypedPropertyDescriptor<(state: S, node: ts.ConstructorDeclaration, dm?: DecoratorMeta) => R>
|
|
232
|
+
): void => storeHandler(inst, d.value!, 'after', 'constructor', target);
|
|
233
|
+
}
|
|
234
|
+
|
|
217
235
|
/**
|
|
218
236
|
* Listens for a static `ts.MethodDeclaration`, on ascent
|
|
219
237
|
*/
|
package/src/resolver/builder.ts
CHANGED
|
@@ -9,11 +9,21 @@ import { DeclarationUtil } from '../util/declaration.ts';
|
|
|
9
9
|
import { LiteralUtil } from '../util/literal.ts';
|
|
10
10
|
import { transformCast, TemplateLiteralPart } from '../types/shared.ts';
|
|
11
11
|
|
|
12
|
-
import { Type, AnyType, CompositionType, TransformResolver, TemplateType } from './types.ts';
|
|
12
|
+
import { Type, AnyType, CompositionType, TransformResolver, TemplateType, MappedType } from './types.ts';
|
|
13
13
|
import { CoerceUtil } from './coerce.ts';
|
|
14
14
|
|
|
15
15
|
const UNDEFINED = Symbol();
|
|
16
16
|
|
|
17
|
+
const MAPPED_TYPE_SET = new Set(['Omit', 'Pick', 'Required', 'Partial']);
|
|
18
|
+
const isMappedType = (type: string | undefined): type is MappedType['operation'] => MAPPED_TYPE_SET.has(type!);
|
|
19
|
+
const getMappedFields = (type: ts.Type): string[] | undefined => {
|
|
20
|
+
if (type.isStringLiteral()) {
|
|
21
|
+
return [type.value];
|
|
22
|
+
} else if (type.isUnion() && type.types.every(t => t.isStringLiteral())) {
|
|
23
|
+
return type.types.map(t => t.value);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
17
27
|
/**
|
|
18
28
|
* List of global types that can be parameterized
|
|
19
29
|
*/
|
|
@@ -39,7 +49,7 @@ const GLOBAL_SIMPLE: Record<string, Function> = {
|
|
|
39
49
|
|
|
40
50
|
type Category =
|
|
41
51
|
'tuple' | 'shape' | 'literal' | 'template' | 'managed' |
|
|
42
|
-
'composition' | 'foreign' | 'concrete' | 'unknown';
|
|
52
|
+
'composition' | 'foreign' | 'concrete' | 'unknown' | 'mapped';
|
|
43
53
|
|
|
44
54
|
/**
|
|
45
55
|
* Type categorizer, input for builder
|
|
@@ -102,9 +112,9 @@ export function TypeCategorize(resolver: TransformResolver, type: ts.Type): { ca
|
|
|
102
112
|
return { category: 'tuple', type };
|
|
103
113
|
} else if (type.isLiteral()) {
|
|
104
114
|
return { category: 'shape', type };
|
|
105
|
-
} else if (
|
|
115
|
+
} else if (objectFlags & ts.ObjectFlags.Mapped) { // Mapped types
|
|
106
116
|
if (type.getProperties().some(x => x.declarations || x.valueDeclaration)) {
|
|
107
|
-
return { category: '
|
|
117
|
+
return { category: 'mapped', type };
|
|
108
118
|
}
|
|
109
119
|
}
|
|
110
120
|
return { category: 'literal', type };
|
|
@@ -115,7 +125,7 @@ export function TypeCategorize(resolver: TransformResolver, type: ts.Type): { ca
|
|
|
115
125
|
*/
|
|
116
126
|
export const TypeBuilder: {
|
|
117
127
|
[K in Category]: {
|
|
118
|
-
build(resolver: TransformResolver, type: ts.Type, alias?: ts.Symbol): AnyType | undefined;
|
|
128
|
+
build(resolver: TransformResolver, type: ts.Type, context: { alias?: ts.Symbol, node?: ts.Node }): AnyType | undefined;
|
|
119
129
|
finalize?(type: Type<K>): AnyType;
|
|
120
130
|
}
|
|
121
131
|
} = {
|
|
@@ -249,10 +259,43 @@ export const TypeBuilder: {
|
|
|
249
259
|
return type;
|
|
250
260
|
}
|
|
251
261
|
},
|
|
262
|
+
mapped: {
|
|
263
|
+
build: (resolver, type, context) => {
|
|
264
|
+
let mainType: ts.Type | undefined;
|
|
265
|
+
let fields: string[] | undefined;
|
|
266
|
+
let operation: string | undefined;
|
|
267
|
+
let name: string | undefined;
|
|
268
|
+
|
|
269
|
+
const decls = DeclarationUtil.getDeclarations(type).filter(x => ts.isTypeAliasDeclaration(x));
|
|
270
|
+
const ref = decls[0]?.type;
|
|
271
|
+
|
|
272
|
+
if (ref && ts.isTypeReferenceNode(ref) && ref.typeArguments && ref.typeArguments.length > 0) {
|
|
273
|
+
const [first, second] = ref.typeArguments;
|
|
274
|
+
mainType = resolver.getType(first);
|
|
275
|
+
operation = ref.typeName.getText();
|
|
276
|
+
name = resolver.getTypeAsString(type)!;
|
|
277
|
+
fields = !second ? [] : getMappedFields(resolver.getType(second));
|
|
278
|
+
} else if (type.aliasTypeArguments && type.aliasSymbol) {
|
|
279
|
+
mainType = type.aliasTypeArguments[0];
|
|
280
|
+
operation = type.aliasSymbol.escapedName.toString();
|
|
281
|
+
fields = (type.aliasTypeArguments.length > 1) ? getMappedFields(type.aliasTypeArguments[1]) : [];
|
|
282
|
+
name = `${resolver.getTypeAsString(mainType)!}_${operation}_${fields?.join('_')}`;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (!isMappedType(operation) || fields === undefined || !mainType || !mainType.isClass()) {
|
|
286
|
+
return TypeBuilder.shape.build(resolver, type, context);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const importName = resolver.getTypeImportName(mainType) ?? '<unknown>';
|
|
290
|
+
const mappedClassName = resolver.getTypeAsString(mainType)!;
|
|
291
|
+
|
|
292
|
+
return { key: 'mapped', name, original: mainType, operation, importName, mappedClassName, fields };
|
|
293
|
+
}
|
|
294
|
+
},
|
|
252
295
|
shape: {
|
|
253
|
-
build: (resolver, type,
|
|
296
|
+
build: (resolver, type, context) => {
|
|
254
297
|
const tsFieldTypes: Record<string, ts.Type> = {};
|
|
255
|
-
const name = CoreUtil.getSymbol(alias ?? type)?.getName();
|
|
298
|
+
const name = CoreUtil.getSymbol(context?.alias ?? type)?.getName();
|
|
256
299
|
const importName = resolver.getTypeImportName(type) ?? '<unknown>';
|
|
257
300
|
const tsTypeArguments = resolver.getAllTypeArguments(type);
|
|
258
301
|
const props = resolver.getPropertiesOfType(type);
|
package/src/resolver/service.ts
CHANGED
|
@@ -59,7 +59,7 @@ export class SimpleResolver implements TransformResolver {
|
|
|
59
59
|
* Resolve an import name (e.g. @module/path/file) for a type
|
|
60
60
|
*/
|
|
61
61
|
getTypeImportName(type: ts.Type, removeExt?: boolean): string | undefined {
|
|
62
|
-
const ogSource = DeclarationUtil.
|
|
62
|
+
const ogSource = DeclarationUtil.getOptionalPrimaryDeclarationNode(type)?.getSourceFile()?.fileName;
|
|
63
63
|
return ogSource ? this.getFileImportName(ogSource, removeExt) : undefined;
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -106,7 +106,7 @@ export class SimpleResolver implements TransformResolver {
|
|
|
106
106
|
* Get list of properties
|
|
107
107
|
*/
|
|
108
108
|
getPropertiesOfType(type: ts.Type): ts.Symbol[] {
|
|
109
|
-
return this.#tsChecker.getPropertiesOfType(type);
|
|
109
|
+
return this.#tsChecker.getPropertiesOfType(type).filter(x => x.getName() !== '__proto__' && x.getName() !== 'prototype');
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
/**
|
|
@@ -117,13 +117,13 @@ export class SimpleResolver implements TransformResolver {
|
|
|
117
117
|
const resolve = (resType: ts.Type, alias?: ts.Symbol, depth = 0): AnyType => {
|
|
118
118
|
|
|
119
119
|
if (depth > 20) { // Max depth is 20
|
|
120
|
-
throw new Error(
|
|
120
|
+
throw new Error(`Object structure too nested: ${'getText' in node ? node.getText() : ''}`);
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
const { category, type } = TypeCategorize(this, resType);
|
|
124
124
|
const { build, finalize } = TypeBuilder[category];
|
|
125
125
|
|
|
126
|
-
let result = build(this, type, alias);
|
|
126
|
+
let result = build(this, type, { alias, node: node && 'kind' in node ? node : undefined });
|
|
127
127
|
|
|
128
128
|
// Convert via cache if needed
|
|
129
129
|
result = visited.getOrSet(type, result);
|
|
@@ -131,7 +131,9 @@ export class SimpleResolver implements TransformResolver {
|
|
|
131
131
|
// Recurse
|
|
132
132
|
if (result) {
|
|
133
133
|
result.original = resType;
|
|
134
|
-
|
|
134
|
+
try {
|
|
135
|
+
result.comment = DocUtil.describeDocs(type).description;
|
|
136
|
+
} catch { }
|
|
135
137
|
|
|
136
138
|
if ('tsTypeArguments' in result) {
|
|
137
139
|
result.typeArguments = result.tsTypeArguments!.map((elType) => resolve(elType, type.aliasSymbol, depth + 1));
|
package/src/resolver/types.ts
CHANGED
|
@@ -61,23 +61,42 @@ export interface ShapeType extends Type<'shape'> {
|
|
|
61
61
|
* Does not include methods, used for shapes not concrete types
|
|
62
62
|
*/
|
|
63
63
|
fieldTypes: Record<string, AnyType>;
|
|
64
|
-
|
|
65
64
|
/**
|
|
66
65
|
* Type Info
|
|
67
66
|
*/
|
|
68
67
|
tsFieldTypes?: Record<string, ts.Type>;
|
|
69
|
-
|
|
70
68
|
/**
|
|
71
69
|
* Type arguments
|
|
72
70
|
*/
|
|
73
71
|
typeArguments?: AnyType[];
|
|
74
|
-
|
|
75
72
|
/**
|
|
76
73
|
* Type Arguments
|
|
77
74
|
*/
|
|
78
75
|
tsTypeArguments?: ts.Type[];
|
|
79
76
|
}
|
|
80
77
|
|
|
78
|
+
/**
|
|
79
|
+
* A type that is mapped
|
|
80
|
+
*/
|
|
81
|
+
export interface MappedType extends Type<'mapped'> {
|
|
82
|
+
/**
|
|
83
|
+
* Location the type came from, for class references
|
|
84
|
+
*/
|
|
85
|
+
importName: string;
|
|
86
|
+
/**
|
|
87
|
+
* Mapped class name
|
|
88
|
+
*/
|
|
89
|
+
mappedClassName: string;
|
|
90
|
+
/**
|
|
91
|
+
* The type of mapping operation
|
|
92
|
+
*/
|
|
93
|
+
operation: 'Omit' | 'Pick' | 'Partial' | 'Required';
|
|
94
|
+
/**
|
|
95
|
+
* The fields being provided for the mapping
|
|
96
|
+
*/
|
|
97
|
+
fields: string[];
|
|
98
|
+
}
|
|
99
|
+
|
|
81
100
|
/**
|
|
82
101
|
* A literal type, with an optional real value
|
|
83
102
|
*/
|
|
@@ -168,7 +187,6 @@ export interface ForeignType extends Type<'foreign'> {
|
|
|
168
187
|
* Identifier for type
|
|
169
188
|
*/
|
|
170
189
|
name: string;
|
|
171
|
-
|
|
172
190
|
/**
|
|
173
191
|
* Primary source file
|
|
174
192
|
*/
|
|
@@ -181,7 +199,7 @@ export interface ForeignType extends Type<'foreign'> {
|
|
|
181
199
|
export interface UnknownType extends Type<'unknown'> { }
|
|
182
200
|
|
|
183
201
|
export type AnyType =
|
|
184
|
-
TupleType | ShapeType | CompositionType | LiteralType |
|
|
202
|
+
TupleType | ShapeType | CompositionType | LiteralType | MappedType |
|
|
185
203
|
ManagedType | PointerType | UnknownType | ForeignType | TemplateType;
|
|
186
204
|
|
|
187
205
|
/**
|
package/src/state.ts
CHANGED
|
@@ -2,7 +2,7 @@ import ts from 'typescript';
|
|
|
2
2
|
|
|
3
3
|
import { path, ManifestIndex } from '@travetto/manifest';
|
|
4
4
|
|
|
5
|
-
import { ManagedType, AnyType, ForeignType } from './resolver/types.ts';
|
|
5
|
+
import { ManagedType, AnyType, ForeignType, MappedType } from './resolver/types.ts';
|
|
6
6
|
import { State, DecoratorMeta, Transformer, ModuleNameSymbol } from './types/visitor.ts';
|
|
7
7
|
import { SimpleResolver } from './resolver/service.ts';
|
|
8
8
|
import { ImportManager } from './importer.ts';
|
|
@@ -27,6 +27,8 @@ function isRedefinableDeclaration(x: ts.Node): x is ts.InterfaceDeclaration | ts
|
|
|
27
27
|
return ts.isFunctionDeclaration(x) || ts.isClassDeclaration(x) || ts.isInterfaceDeclaration(x);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
const FOREIGN_TYPE_REGISTRY_FILE = '@travetto/runtime/src/function';
|
|
31
|
+
|
|
30
32
|
/**
|
|
31
33
|
* Transformer runtime state
|
|
32
34
|
*/
|
|
@@ -64,7 +66,7 @@ export class TransformerState implements State {
|
|
|
64
66
|
/**
|
|
65
67
|
* Get or import the node or external type
|
|
66
68
|
*/
|
|
67
|
-
getOrImport(type: ManagedType): ts.Identifier | ts.PropertyAccessExpression {
|
|
69
|
+
getOrImport(type: ManagedType | MappedType): ts.Identifier | ts.PropertyAccessExpression {
|
|
68
70
|
return this.#imports.getOrImport(this.factory, type);
|
|
69
71
|
}
|
|
70
72
|
|
|
@@ -164,20 +166,20 @@ export class TransformerState implements State {
|
|
|
164
166
|
*/
|
|
165
167
|
getDecoratorMeta(dec: ts.Decorator): DecoratorMeta | undefined {
|
|
166
168
|
const ident = DecoratorUtil.getDecoratorIdent(dec);
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
);
|
|
169
|
+
const type = this.#resolver.getType(ident);
|
|
170
|
+
const decl = DeclarationUtil.getOptionalPrimaryDeclarationNode(type);
|
|
170
171
|
const src = decl?.getSourceFile().fileName;
|
|
171
172
|
const mod = src ? this.#resolver.getFileImportName(src, true) : undefined;
|
|
172
173
|
const file = this.#manifestIndex.getFromImport(mod ?? '')?.outputFile;
|
|
173
|
-
const targets = DocUtil.readAugments(
|
|
174
|
+
const targets = DocUtil.readAugments(type);
|
|
175
|
+
const example = DocUtil.readExample(type);
|
|
174
176
|
const module = file ? mod : undefined;
|
|
175
177
|
const name = ident ?
|
|
176
178
|
ident.escapedText?.toString()! :
|
|
177
179
|
undefined;
|
|
178
180
|
|
|
179
181
|
if (ident && name) {
|
|
180
|
-
return { dec, ident, file, module, targets, name };
|
|
182
|
+
return { dec, ident, file, module, targets, name, options: example };
|
|
181
183
|
}
|
|
182
184
|
}
|
|
183
185
|
|
|
@@ -402,9 +404,13 @@ export class TransformerState implements State {
|
|
|
402
404
|
* Produce a foreign target type
|
|
403
405
|
*/
|
|
404
406
|
getForeignTarget(ret: ForeignType): ts.Expression {
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
407
|
+
const file = this.importFile(FOREIGN_TYPE_REGISTRY_FILE);
|
|
408
|
+
return this.factory.createCallExpression(this.createAccess(
|
|
409
|
+
file.ident,
|
|
410
|
+
this.factory.createIdentifier('foreignType'),
|
|
411
|
+
), [], [
|
|
412
|
+
this.fromLiteral(`${ret.source.split('node_modules/')[1]}+${ret.name}`)
|
|
413
|
+
]);
|
|
408
414
|
}
|
|
409
415
|
|
|
410
416
|
/**
|
package/src/types/visitor.ts
CHANGED
|
@@ -10,6 +10,7 @@ export type DecoratorMeta = {
|
|
|
10
10
|
file?: string;
|
|
11
11
|
targets?: string[];
|
|
12
12
|
name?: string;
|
|
13
|
+
options?: string[];
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
export type State = {
|
|
@@ -23,8 +24,9 @@ export type State = {
|
|
|
23
24
|
export type TransformPhase = 'before' | 'after';
|
|
24
25
|
|
|
25
26
|
export type TransformerType =
|
|
26
|
-
'class' | 'method' | 'property' | 'getter' | 'setter' | 'parameter'
|
|
27
|
-
'static-method' | 'call' | 'function' | 'file' | 'type' | 'interface'
|
|
27
|
+
'class' | 'method' | 'property' | 'getter' | 'setter' | 'parameter'
|
|
28
|
+
| 'static-method' | 'call' | 'function' | 'file' | 'type' | 'interface'
|
|
29
|
+
| 'constructor';
|
|
28
30
|
|
|
29
31
|
export const ModuleNameSymbol = Symbol.for('@travetto/transformer:id');
|
|
30
32
|
|
package/src/util/declaration.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
2
|
import { CoreUtil } from './core.ts';
|
|
3
3
|
|
|
4
|
+
const isNamed = (o: ts.Declaration): o is ts.Declaration & { name: ts.Node } => 'name' in o && !!o.name;
|
|
5
|
+
|
|
4
6
|
/**
|
|
5
7
|
* Declaration utils
|
|
6
8
|
*/
|
|
@@ -23,7 +25,8 @@ export class DeclarationUtil {
|
|
|
23
25
|
*/
|
|
24
26
|
static isPublic(node: ts.Declaration): boolean {
|
|
25
27
|
// eslint-disable-next-line no-bitwise
|
|
26
|
-
return !(ts.getCombinedModifierFlags(node) & ts.ModifierFlags.NonPublicAccessibilityModifier)
|
|
28
|
+
return !(ts.getCombinedModifierFlags(node) & ts.ModifierFlags.NonPublicAccessibilityModifier) &&
|
|
29
|
+
(!isNamed(node) || !ts.isPrivateIdentifier(node.name));
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
/**
|
|
@@ -42,15 +45,19 @@ export class DeclarationUtil {
|
|
|
42
45
|
/**
|
|
43
46
|
* Find primary declaration out of a list of declarations
|
|
44
47
|
*/
|
|
45
|
-
static
|
|
46
|
-
|
|
48
|
+
static getPrimaryDeclarationNode(node: ts.Type | ts.Symbol): ts.Declaration {
|
|
49
|
+
const decls = this.getDeclarations(node);
|
|
50
|
+
if (!decls.length) {
|
|
51
|
+
throw new Error('No declarations found for type');
|
|
52
|
+
}
|
|
53
|
+
return decls[0];
|
|
47
54
|
}
|
|
48
55
|
|
|
49
56
|
/**
|
|
50
57
|
* Find primary declaration out of a list of declarations
|
|
51
58
|
*/
|
|
52
|
-
static
|
|
53
|
-
return this.
|
|
59
|
+
static getOptionalPrimaryDeclarationNode(node: ts.Type | ts.Symbol): ts.Declaration | undefined {
|
|
60
|
+
return this.getDeclarations(node)[0];
|
|
54
61
|
}
|
|
55
62
|
|
|
56
63
|
/**
|
|
@@ -88,4 +95,11 @@ export class DeclarationUtil {
|
|
|
88
95
|
}
|
|
89
96
|
return acc;
|
|
90
97
|
}
|
|
98
|
+
|
|
99
|
+
static isStatic(node: ts.Declaration): boolean {
|
|
100
|
+
if ('modifiers' in node && Array.isArray(node.modifiers)) {
|
|
101
|
+
return node.modifiers?.some(x => x.kind === ts.SyntaxKind.StaticKeyword) ?? false;
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
91
105
|
}
|
package/src/util/doc.ts
CHANGED
|
@@ -26,22 +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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
let toDescribe = (node && !('getSourceFile' in node)) ?
|
|
30
|
+
DeclarationUtil.getOptionalPrimaryDeclarationNode(node) : node;
|
|
31
|
+
|
|
32
32
|
const out: DeclDocumentation = {
|
|
33
33
|
description: undefined,
|
|
34
34
|
return: undefined,
|
|
35
35
|
params: []
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
if (
|
|
39
|
-
const tags = ts.getJSDocTags(
|
|
40
|
-
while (!this.hasJSDoc(
|
|
41
|
-
|
|
38
|
+
if (toDescribe) {
|
|
39
|
+
const tags = ts.getJSDocTags(toDescribe);
|
|
40
|
+
while (!this.hasJSDoc(toDescribe) && CoreUtil.hasOriginal(toDescribe)) {
|
|
41
|
+
toDescribe = transformCast<ts.Declaration>(toDescribe.original);
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
const docs = this.hasJSDoc(
|
|
44
|
+
const docs = this.hasJSDoc(toDescribe) ? toDescribe.jsDoc : undefined;
|
|
45
45
|
|
|
46
46
|
if (docs) {
|
|
47
47
|
const top = docs.at(-1)!;
|
|
@@ -92,4 +92,12 @@ export class DocUtil {
|
|
|
92
92
|
static readAugments(type: ts.Type | ts.Symbol): string[] {
|
|
93
93
|
return this.readDocTag(type, 'augments').map(x => x.replace(/^.*?([^` ]+).*?$/, (_, b) => b));
|
|
94
94
|
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Read example information
|
|
98
|
+
* @param type
|
|
99
|
+
*/
|
|
100
|
+
static readExample(type: ts.Type | ts.Symbol): string[] {
|
|
101
|
+
return this.readDocTag(type, 'example').map(x => x.replace(/^.*?([^` ]+).*?$/, (_, b) => b));
|
|
102
|
+
}
|
|
95
103
|
}
|
package/src/util/log.ts
CHANGED
|
@@ -38,7 +38,7 @@ export class LogUtil {
|
|
|
38
38
|
const ox = x;
|
|
39
39
|
const out: Record<string, unknown> = {};
|
|
40
40
|
for (const key of TypedObject.keys(ox)) {
|
|
41
|
-
if (Object.getPrototypeOf(ox[key]) === Function.prototype || exclude.has(key)
|
|
41
|
+
if (ox[key] === null || ox[key] === undefined || Object.getPrototypeOf(ox[key]) === Function.prototype || exclude.has(key)) {
|
|
42
42
|
continue;
|
|
43
43
|
}
|
|
44
44
|
try {
|
package/src/visitor.ts
CHANGED
|
@@ -16,7 +16,9 @@ export class VisitorFactory<S extends State = State> {
|
|
|
16
16
|
* Get the type of transformer from a given a ts.node
|
|
17
17
|
*/
|
|
18
18
|
static nodeToType(node: ts.Node): TransformerType | undefined {
|
|
19
|
-
if (ts.
|
|
19
|
+
if (ts.isConstructorDeclaration(node)) {
|
|
20
|
+
return 'constructor';
|
|
21
|
+
} else if (ts.isMethodDeclaration(node)) {
|
|
20
22
|
// eslint-disable-next-line no-bitwise
|
|
21
23
|
return (ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Static) ? 'static-method' : 'method';
|
|
22
24
|
} else if (ts.isPropertyDeclaration(node)) {
|