@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/src/state.ts CHANGED
@@ -1,17 +1,16 @@
1
1
  import ts from 'typescript';
2
2
 
3
- import { path, type ManifestIndex } from '@travetto/manifest';
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 isRedefinableDeclaration(node: ts.Node): node is ts.InterfaceDeclaration | ts.ClassDeclaration | ts.FunctionDeclaration {
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': return this.factory.createIdentifier(type.ctor!.name);
109
- case 'managed': return this.getOrImport(type);
110
- case 'shape': return;
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) ? (ts.getDecorators(node) ?? [])
190
- .map(decorator => this.getDecoratorMeta(decorator))
191
- .filter(metadata => !!metadata) : [];
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(first: string | ts.Expression, second: string | ts.Identifier, ...items: (string | number | ts.Identifier)[]): ts.Expression {
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(this.#moduleIdentifier, undefined, undefined,
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
- ], -1);
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) { // if in same file suffix with location
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 (isRedefinableDeclaration(child) || ts.isMethodDeclaration(child) || ts.isParameter(child)) {
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) { // Make unique to file
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 => ts.isMethodDeclaration(value) && ts.isIdentifier(value.name) && value.name.escapedText === method
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(this.createAccess(
420
- file.identifier,
421
- this.factory.createIdentifier('foreignType'),
422
- ), [], [
423
- this.fromLiteral(typeof typeOrClassId === 'string' ? typeOrClassId : typeOrClassId.classId)
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.getApparentType(value).getApparentProperties().find(property => property.escapedName === field);
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
+ }
@@ -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', values: (TemplateLiteralPart | TemplateLiteral)[] };
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
+ }
@@ -24,8 +24,18 @@ export type State = {
24
24
  export type TransformPhase = 'before' | 'after';
25
25
 
26
26
  export type TransformerType =
27
- 'class' | 'method' | 'property' | 'getter' | 'setter' | 'parameter'
28
- | 'static-method' | 'call' | 'function' | 'file' | 'type' | 'interface'
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 (ts.Node & { original: ts.Node }) {
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 (ts.Type & { target: ts.Type }) {
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 && node.arguments && node.arguments.length) {
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 && node!.arguments && node!.arguments.length) {
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(factory: ts.NodeFactory, source: ts.SourceFile, statements: ts.NodeArray<ts.Statement> | ts.Statement[]): ts.SourceFile {
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, statements, source.isDeclarationFile, source.referencedFiles, source.typeReferenceDirectives, source.hasNoDefaultLib
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) => typeof value === 'number' ?
102
- factory.createElementAccessExpression(expr, value) :
103
- factory.createPropertyAccessExpression(expr, value),
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
+ }
@@ -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
- // eslint-disable-next-line no-bitwise
28
- return !(ts.getCombinedModifierFlags(node) & ts.ModifierFlags.NonPublicAccessibilityModifier) &&
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
- // eslint-disable-next-line no-bitwise
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
- node: ts.GetAccessorDeclaration | ts.SetAccessorDeclaration
80
- ): { getter?: ts.GetAccessorDeclaration, setter?: ts.SetAccessorDeclaration } {
81
- const pair = { getter: ts.isGetAccessorDeclaration(node) ? node : undefined, setter: ts.isSetAccessorDeclaration(node) ? node : undefined };
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
+ }
@@ -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 { transformCast, type DeclDocumentation } from '../types/shared.ts';
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 (ts.Node & { jsDoc: ts.JSDoc[] }) {
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 = (node && !('getSourceFile' in node)) ?
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 && tags.length) {
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 && tag.name.getText(),
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
+ }
@@ -1,6 +1,6 @@
1
1
  import ts from 'typescript';
2
2
 
3
- import { path, ManifestModuleUtil, PackageUtil } from '@travetto/manifest';
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
+ }
@@ -1,6 +1,6 @@
1
1
  import ts from 'typescript';
2
2
 
3
- import { transformCast, type TemplateLiteral } from '../types/shared.ts';
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)) { // If already a node
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(factory: ts.NodeFactory, source: object | ts.Expression, ...rest: (object | ts.Expression)[]): ts.ObjectLiteralExpression {
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
- ...(rest.filter(item => !!item).map(expression => factory.createSpreadAssignment(this.fromLiteral(factory, expression))))
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', 'checker', 'end', 'pos', 'id', 'source', 'sourceFile', 'getSourceFile',
3
- 'statements', 'stringIndexInfo', 'numberIndexInfo', 'instantiations', 'thisType',
4
- 'members', 'properties', 'outerTypeParameters', 'exports', 'transformFlags', 'flowNode',
5
- 'nextContainer', 'modifierFlagsCache', 'declaredProperties'
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
+ }
@@ -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
+ }