@travetto/transformer 8.0.0-alpha.8 → 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.
@@ -1,16 +1,24 @@
1
- /* eslint-disable no-bitwise */
2
1
  import ts from 'typescript';
3
2
 
4
- import { path, ManifestModuleUtil } from '@travetto/manifest';
3
+ import { ManifestModuleUtil, path } from '@travetto/manifest';
5
4
 
6
- import { DocUtil } from '../util/doc.ts';
5
+ import { type TemplateLiteralPart, transformCast } from '../types/shared.ts';
7
6
  import { CoreUtil } from '../util/core.ts';
8
7
  import { DeclarationUtil } from '../util/declaration.ts';
8
+ import { DocUtil } from '../util/doc.ts';
9
9
  import { LiteralUtil } from '../util/literal.ts';
10
- import { transformCast, type TemplateLiteralPart } from '../types/shared.ts';
11
-
12
- import type { Type, AnyType, CompositionType, TransformResolver, TemplateType, MappedType, ShapeType, ResolverContext, ManagedType } from './types.ts';
13
10
  import { CoerceUtil } from './coerce.ts';
11
+ import type {
12
+ AnyType,
13
+ CompositionType,
14
+ ManagedType,
15
+ MappedType,
16
+ ResolverContext,
17
+ ShapeType,
18
+ TemplateType,
19
+ TransformResolver,
20
+ Type
21
+ } from './types.ts';
14
22
 
15
23
  const UNDEFINED = Symbol();
16
24
 
@@ -29,11 +37,15 @@ const getMappedFields = (type: ts.Type): string[] | undefined => {
29
37
  * List of global types that can be parameterized
30
38
  */
31
39
  const GLOBAL_COMPLEX: Record<string, Function> = {
32
- Array, Promise, Set, Map, ReadonlyArray: Array,
33
- Iterator: function Iterator() { },
34
- Iterable: function Iterable() { },
35
- IterableIterator: function IterableIterator() { },
36
- AsyncIterator: function AsyncIterator() { },
40
+ Array,
41
+ Promise,
42
+ Set,
43
+ Map,
44
+ ReadonlyArray: Array,
45
+ Iterator: function Iterator() {},
46
+ Iterable: function Iterable() {},
47
+ IterableIterator: function IterableIterator() {},
48
+ AsyncIterator: function AsyncIterator() {},
37
49
  PropertyDescriptor: Object,
38
50
  TypedPropertyDescriptor: Object
39
51
  };
@@ -44,12 +56,29 @@ const GLOBAL_COMPLEX: Record<string, Function> = {
44
56
  const UNDEFINED_GLOBAL = { undefined: 1, void: 1, null: 1 };
45
57
  const SIMPLE_NAMES: Record<string, string> = { String: 'string', Number: 'number', Boolean: 'boolean', Object: 'object' };
46
58
  const GLOBAL_SIMPLE: Record<string, Function> = {
47
- RegExp, Date, Number, Boolean, String, Function, Object, Error, BigInt,
48
- ArrayBuffer, SharedArrayBuffer,
49
- Uint8Array, Uint16Array, Uint32Array,
50
- Int8Array, Int16Array, Int32Array,
51
- Uint8ClampedArray, BigInt64Array, BigUint64Array,
52
- Float16Array, Float32Array, Float64Array,
59
+ RegExp,
60
+ Date,
61
+ Number,
62
+ Boolean,
63
+ String,
64
+ Function,
65
+ Object,
66
+ Error,
67
+ BigInt,
68
+ ArrayBuffer,
69
+ SharedArrayBuffer,
70
+ Uint8Array,
71
+ Uint16Array,
72
+ Uint32Array,
73
+ Int8Array,
74
+ Int16Array,
75
+ Int32Array,
76
+ Uint8ClampedArray,
77
+ BigInt64Array,
78
+ BigUint64Array,
79
+ Float16Array,
80
+ Float32Array,
81
+ Float64Array,
53
82
  PromiseConstructor: Promise.constructor
54
83
  };
55
84
 
@@ -58,27 +87,30 @@ type Category = Exclude<AnyType['key'], 'pointer'> | 'concrete';
58
87
  /**
59
88
  * Type categorizer, input for builder
60
89
  */
61
- export function TypeCategorize(resolver: TransformResolver, type: ts.Type): { category: Category, type: ts.Type } {
90
+ export function TypeCategorize(resolver: TransformResolver, type: ts.Type): { category: Category; type: ts.Type } {
62
91
  const flags = type.getFlags();
63
92
  const objectFlags = DeclarationUtil.getObjectFlags(type) ?? 0;
64
93
 
65
- if (flags & (ts.TypeFlags.TemplateLiteral)) {
94
+ if (flags & ts.TypeFlags.TemplateLiteral) {
66
95
  return { category: 'template', type };
67
- } else if (flags & (
68
- ts.TypeFlags.BigIntLike |
69
- ts.TypeFlags.BooleanLike |
70
- ts.TypeFlags.NumberLike |
71
- ts.TypeFlags.StringLike |
72
- ts.TypeFlags.Null |
73
- ts.TypeFlags.Undefined |
74
- ts.TypeFlags.Void
75
- )) {
96
+ } else if (
97
+ flags &
98
+ (ts.TypeFlags.BigIntLike |
99
+ ts.TypeFlags.BooleanLike |
100
+ ts.TypeFlags.NumberLike |
101
+ ts.TypeFlags.StringLike |
102
+ ts.TypeFlags.Null |
103
+ ts.TypeFlags.Undefined |
104
+ ts.TypeFlags.Void)
105
+ ) {
76
106
  return { category: 'literal', type };
77
107
  } else if (DocUtil.hasDocTag(type, 'concrete')) {
78
108
  return { category: 'concrete', type };
79
- } else if (flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown | ts.TypeFlags.Never)) { // Any or unknown
109
+ } else if (flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown | ts.TypeFlags.Never)) {
110
+ // Any or unknown
80
111
  return { category: 'unknown', type };
81
- } else if (objectFlags & ts.ObjectFlags.Reference && !CoreUtil.getSymbol(type)) { // Tuple type?
112
+ } else if (objectFlags & ts.ObjectFlags.Reference && !CoreUtil.getSymbol(type)) {
113
+ // Tuple type?
82
114
  return { category: 'tuple', type };
83
115
  } else if (type.isUnionOrIntersection()) {
84
116
  return { category: 'composition', type };
@@ -89,12 +121,10 @@ export function TypeCategorize(resolver: TransformResolver, type: ts.Type): { ca
89
121
  if (sourceFile && ManifestModuleUtil.TYPINGS_EXT_REGEX.test(sourceFile) && !resolver.isKnownFile(sourceFile)) {
90
122
  return { category: 'foreign', type };
91
123
  }
92
- } catch { }
124
+ } catch {}
93
125
 
94
126
  const text = resolver.getTypeAsString(type);
95
- if (flags & (ts.SymbolFlags.TypeAlias | ts.SymbolFlags.ExportValue)
96
- && text?.startsWith('typeof')
97
- ) {
127
+ if (flags & (ts.SymbolFlags.TypeAlias | ts.SymbolFlags.ExportValue) && text?.startsWith('typeof')) {
98
128
  return { category: 'managed', type };
99
129
  }
100
130
  return { category: 'shape', type };
@@ -114,7 +144,8 @@ export function TypeCategorize(resolver: TransformResolver, type: ts.Type): { ca
114
144
  return { category: 'literal', type };
115
145
  } else if (sourceFile && ManifestModuleUtil.TYPINGS_EXT_REGEX.test(sourceFile) && !resolver.isKnownFile(sourceFile)) {
116
146
  return { category: 'foreign', type: resolvedType };
117
- } else if (!resolvedType.isClass()) { // Not a real type
147
+ } else if (!resolvedType.isClass()) {
148
+ // Not a real type
118
149
  return { category: 'shape', type: resolvedType };
119
150
  } else {
120
151
  return { category: 'managed', type: resolvedType };
@@ -123,7 +154,8 @@ export function TypeCategorize(resolver: TransformResolver, type: ts.Type): { ca
123
154
  return { category: 'tuple', type };
124
155
  } else if (type.isLiteral()) {
125
156
  return { category: 'shape', type };
126
- } else if (objectFlags & ts.ObjectFlags.Mapped) { // Mapped types
157
+ } else if (objectFlags & ts.ObjectFlags.Mapped) {
158
+ // Mapped types
127
159
  if (type.getProperties().some(property => property.declarations || property.valueDeclaration)) {
128
160
  return { category: 'mapped', type };
129
161
  }
@@ -138,7 +170,7 @@ export const TypeBuilder: {
138
170
  [K in Category]: {
139
171
  build(resolver: TransformResolver, type: ts.Type, context: ResolverContext): AnyType | undefined;
140
172
  finalize?(type: Type<K>): AnyType;
141
- }
173
+ };
142
174
  } = {
143
175
  unknown: {
144
176
  build: (resolver, type) => {
@@ -154,8 +186,8 @@ export const TypeBuilder: {
154
186
  // If we are have a template literal type, we need to make our own type node
155
187
  if (type.flags & ts.TypeFlags.TemplateLiteral) {
156
188
  const values: TemplateLiteralPart[] = [];
157
- const texts = 'texts' in type && (typeof type.texts === 'object') && Array.isArray(type.texts) ? type.texts : undefined;
158
- const types = 'types' in type && (typeof type.types === 'object') && Array.isArray(type.types) ? type.types : undefined;
189
+ const texts = 'texts' in type && typeof type.texts === 'object' && Array.isArray(type.texts) ? type.texts : undefined;
190
+ const types = 'types' in type && typeof type.types === 'object' && Array.isArray(type.types) ? type.types : undefined;
159
191
  if (texts?.length && types?.length) {
160
192
  for (let i = 0; i < texts?.length; i += 1) {
161
193
  if (texts[i] && texts[i] !== 'undefined') {
@@ -163,15 +195,23 @@ export const TypeBuilder: {
163
195
  }
164
196
  if (types[i]) {
165
197
  switch (types[i].intrinsicName) {
166
- case 'number': values.push(Number); break;
167
- case 'string': values.push(String); break;
168
- case 'boolean': values.push(Boolean); break;
169
- case 'undefined': values.push(''); break;
198
+ case 'number':
199
+ values.push(Number);
200
+ break;
201
+ case 'string':
202
+ values.push(String);
203
+ break;
204
+ case 'boolean':
205
+ values.push(Boolean);
206
+ break;
207
+ case 'undefined':
208
+ values.push('');
209
+ break;
170
210
  }
171
211
  }
172
212
  }
173
213
  if (values.length > 0) {
174
- return ({ key: 'template', template: { operation: 'and', values }, ctor: String });
214
+ return { key: 'template', template: { operation: 'and', values }, ctor: String };
175
215
  }
176
216
  }
177
217
  }
@@ -188,8 +228,7 @@ export const TypeBuilder: {
188
228
  return { key: 'literal', ctor: undefined, name };
189
229
  } else if (name in GLOBAL_SIMPLE) {
190
230
  const cons = GLOBAL_SIMPLE[name];
191
- const literal = LiteralUtil.isLiteralType(type) ? CoerceUtil.coerce(type.value, transformCast(cons), false) :
192
- undefined;
231
+ const literal = LiteralUtil.isLiteralType(type) ? CoerceUtil.coerce(type.value, transformCast(cons), false) : undefined;
193
232
 
194
233
  return {
195
234
  key: 'literal',
@@ -233,8 +272,8 @@ export const TypeBuilder: {
233
272
 
234
273
  // Detect managed, but shapeable
235
274
  if (tsTypeArguments.length > 0) {
236
- const hasEmptyConstructor = type.getConstructSignatures().some(signature => signature.parameters.length === 0)
237
- || type.getConstructSignatures().length === 0; // If no constructor, we can assume it's shapeable
275
+ const hasEmptyConstructor =
276
+ type.getConstructSignatures().some(signature => signature.parameters.length === 0) || type.getConstructSignatures().length === 0; // If no constructor, we can assume it's shapeable
238
277
  const hasMethods = type.getProperties().some(property => property.getFlags() & ts.SymbolFlags.Method);
239
278
  if (hasEmptyConstructor && !hasMethods && allowsVirtualTemplate(type)) {
240
279
  return TypeBuilder.shape.build(resolver, type, {
@@ -246,26 +285,35 @@ export const TypeBuilder: {
246
285
  }
247
286
 
248
287
  return managedType;
249
- },
288
+ }
250
289
  },
251
290
  composition: {
252
291
  build: (resolver, uType: ts.UnionOrIntersectionType) => {
253
292
  let undefinable = false;
254
293
  let nullable = false;
255
294
  const remainder = uType.types.filter(ut => {
256
- const isUndefined = (ut.getFlags() & (ts.TypeFlags.Undefined)) > 0;
257
- const isNull = (ut.getFlags() & (ts.TypeFlags.Null)) > 0;
295
+ const isUndefined = (ut.getFlags() & ts.TypeFlags.Undefined) > 0;
296
+ const isNull = (ut.getFlags() & ts.TypeFlags.Null) > 0;
258
297
  undefinable ||= isUndefined;
259
298
  nullable ||= isNull;
260
299
  return !(isUndefined || isNull);
261
300
  });
262
301
  const name = CoreUtil.getSymbol(uType)?.getName();
263
- return { key: 'composition', name, undefinable, nullable, tsSubTypes: remainder, subTypes: [], operation: uType.isUnion() ? 'or' : 'and' };
302
+ return {
303
+ key: 'composition',
304
+ name,
305
+ undefinable,
306
+ nullable,
307
+ tsSubTypes: remainder,
308
+ subTypes: [],
309
+ operation: uType.isUnion() ? 'or' : 'and'
310
+ };
264
311
  },
265
312
  finalize: (type: CompositionType) => {
266
313
  const { undefinable, nullable, subTypes } = type;
267
314
 
268
- if (subTypes.length === 0) { // We have an unknown type?
315
+ if (subTypes.length === 0) {
316
+ // We have an unknown type?
269
317
  return { key: 'unknown', nullable, undefinable };
270
318
  }
271
319
 
@@ -281,14 +329,16 @@ export const TypeBuilder: {
281
329
  };
282
330
  } else if (subTypes.length === 1) {
283
331
  return { undefinable, nullable, ...first };
284
- } else if (first.key === 'literal' && subTypes.every(item => item.name === first.name)) { // We have a common
332
+ } else if (first.key === 'literal' && subTypes.every(item => item.name === first.name)) {
333
+ // We have a common
285
334
  type.commonType = first;
286
- } else if (type.operation === 'and' && first.key === 'shape' && subTypes.every(item => item.key === 'shape')) { // All shapes
335
+ } else if (type.operation === 'and' && first.key === 'shape' && subTypes.every(item => item.key === 'shape')) {
336
+ // All shapes
287
337
  return {
288
338
  importName: first.importName,
289
339
  name: first.name,
290
340
  key: 'shape',
291
- fieldTypes: subTypes.reduce((map, subType) => ({ ...map, ...subType.fieldTypes }), {})
341
+ fieldTypes: subTypes.reduce((map, subType) => Object.assign(map, { ...subType.fieldTypes }), {})
292
342
  };
293
343
  }
294
344
  return type;
@@ -313,7 +363,7 @@ export const TypeBuilder: {
313
363
  } else if (type.aliasTypeArguments && type.aliasSymbol) {
314
364
  mainType = type.aliasTypeArguments[0];
315
365
  operation = type.aliasSymbol.escapedName.toString();
316
- fields = (type.aliasTypeArguments.length > 1) ? getMappedFields(type.aliasTypeArguments[1]) : [];
366
+ fields = type.aliasTypeArguments.length > 1 ? getMappedFields(type.aliasTypeArguments[1]) : [];
317
367
  name = `${resolver.getTypeAsString(mainType)!}_${operation}_${fields?.join('_')}`;
318
368
  }
319
369
 
@@ -341,13 +391,14 @@ export const TypeBuilder: {
341
391
 
342
392
  for (const member of properties) {
343
393
  const declaration = DeclarationUtil.getPrimaryDeclarationNode(member);
344
- if (DeclarationUtil.isPublic(declaration)) { // IF public
394
+ if (DeclarationUtil.isPublic(declaration)) {
395
+ // IF public
345
396
  const memberType = resolver.getType(declaration);
346
397
  if (
347
398
  !member.getName().includes('@') && // if not a symbol
348
399
  !memberType.getCallSignatures().length // if not a function
349
400
  ) {
350
- if ((ts.isPropertySignature(declaration) || ts.isPropertyDeclaration(declaration)) && !!declaration.questionToken) {
401
+ if ((ts.isPropertySignature(declaration) || ts.isPropertyDeclaration(declaration)) && declaration.questionToken) {
351
402
  Object.defineProperty(memberType, UNDEFINED, { value: true });
352
403
  }
353
404
  tsFieldTypes[member.getName()] = memberType;
@@ -355,8 +406,14 @@ export const TypeBuilder: {
355
406
  }
356
407
  }
357
408
  return {
358
- key: 'shape', name, importName, tsFieldTypes, tsTypeArguments,
359
- fieldTypes: {}, extendsFrom: context.extendsFrom, canTemplate: allowsVirtualTemplate(type)
409
+ key: 'shape',
410
+ name,
411
+ importName,
412
+ tsFieldTypes,
413
+ tsTypeArguments,
414
+ fieldTypes: {},
415
+ extendsFrom: context.extendsFrom,
416
+ canTemplate: allowsVirtualTemplate(type)
360
417
  };
361
418
  },
362
419
  finalize: (type: ShapeType) => {
@@ -390,9 +447,12 @@ export const TypeBuilder: {
390
447
 
391
448
  // Resolving relative to source file
392
449
  if (!importName || importName.startsWith('.')) {
393
- const rawSourceFile: string = DeclarationUtil.getDeclarations(type)
394
- ?.find(declaration => ts.getAllJSDocTags(declaration, (node): node is ts.JSDocTag => node.tagName.getText() === 'concrete').length)
395
- ?.getSourceFile().fileName ?? '';
450
+ const rawSourceFile: string =
451
+ DeclarationUtil.getDeclarations(type)
452
+ ?.find(
453
+ declaration => ts.getAllJSDocTags(declaration, (node): node is ts.JSDocTag => node.tagName.getText() === 'concrete').length
454
+ )
455
+ ?.getSourceFile().fileName ?? '';
396
456
 
397
457
  if (!importName || importName === '.') {
398
458
  importName = resolver.getFileImportName(rawSourceFile);
@@ -404,8 +464,9 @@ export const TypeBuilder: {
404
464
 
405
465
  // Convert name to $Concrete suffix if not provided
406
466
  if (!name) {
407
- const [primaryDeclaration] = DeclarationUtil.getDeclarations(type)
408
- .filter(declaration => ts.isInterfaceDeclaration(declaration) || ts.isTypeAliasDeclaration(declaration));
467
+ const [primaryDeclaration] = DeclarationUtil.getDeclarations(type).filter(
468
+ declaration => ts.isInterfaceDeclaration(declaration) || ts.isTypeAliasDeclaration(declaration)
469
+ );
409
470
  name = `${primaryDeclaration.name.text}$Concrete`;
410
471
  }
411
472
 
@@ -1,4 +1,5 @@
1
1
  import type ts from 'typescript';
2
+
2
3
  import type { AnyType } from './types.ts';
3
4
 
4
5
  /**
@@ -1,15 +1,17 @@
1
- const REGEX_PATTERN = /[\/](.*)[\/](i|g|m|s)?/;
1
+ const REGEX_PATTERN = /[/](.*)[/](i|g|m|s)?/;
2
2
 
3
3
  export class CoerceUtil {
4
4
  /**
5
5
  * Is a value a plain JS object, created using {}
6
6
  */
7
7
  static #isPlainObject(value: unknown): value is Record<string, unknown> {
8
- return typeof value === 'object' // separate from primitives
9
- && value !== undefined
10
- && value !== null // is obvious
11
- && value.constructor === Object // separate instances (Array, DOM, ...)
12
- && Object.prototype.toString.call(value) === '[object Object]'; // separate build-in like Math
8
+ return (
9
+ typeof value === 'object' && // separate from primitives
10
+ value !== undefined &&
11
+ value !== null && // is obvious
12
+ value.constructor === Object && // separate instances (Array, DOM, ...)
13
+ Object.prototype.toString.call(value) === '[object Object]'
14
+ ); // separate build-in like Math
13
15
  }
14
16
 
15
17
  /**
@@ -50,8 +52,7 @@ export class CoerceUtil {
50
52
 
51
53
  switch (type) {
52
54
  case Date: {
53
- const value = typeof input === 'number' || /^[-]?\d+$/.test(`${input}`) ?
54
- new Date(parseInt(`${input}`, 10)) : new Date(`${input}`);
55
+ const value = typeof input === 'number' || /^[-]?\d+$/.test(`${input}`) ? new Date(parseInt(`${input}`, 10)) : new Date(`${input}`);
55
56
  if (strict && Number.isNaN(value.getTime())) {
56
57
  throw new Error(`Invalid date value: ${input}`);
57
58
  }
@@ -106,8 +107,9 @@ export class CoerceUtil {
106
107
  }
107
108
  }
108
109
  case undefined:
109
- case String: return `${input}`;
110
+ case String:
111
+ return `${input}`;
110
112
  }
111
113
  throw new Error(`Unknown type ${type.name}`);
112
114
  }
113
- }
115
+ }
@@ -1,13 +1,13 @@
1
1
  import ts from 'typescript';
2
2
 
3
- import { path, type ManifestIndex, ManifestModuleUtil, type IndexedFile } from '@travetto/manifest';
3
+ import { type IndexedFile, type ManifestIndex, ManifestModuleUtil, path } from '@travetto/manifest';
4
4
 
5
- import type { AnyType, ResolverContext, TransformResolver } from './types.ts';
6
- import { TypeCategorize, TypeBuilder } from './builder.ts';
7
- import { VisitCache } from './cache.ts';
8
- import { DocUtil } from '../util/doc.ts';
9
- import { DeclarationUtil } from '../util/declaration.ts';
10
5
  import { transformCast } from '../types/shared.ts';
6
+ import { DeclarationUtil } from '../util/declaration.ts';
7
+ import { DocUtil } from '../util/doc.ts';
8
+ import { TypeBuilder, TypeCategorize } from './builder.ts';
9
+ import { VisitCache } from './cache.ts';
10
+ import type { AnyType, ResolverContext, TransformResolver } from './types.ts';
11
11
 
12
12
  const isFinalizeType = (key: string): key is keyof typeof TypeBuilder => key in TypeBuilder;
13
13
 
@@ -45,8 +45,10 @@ export class SimpleResolver implements TransformResolver {
45
45
 
46
46
  const sourceType = ManifestModuleUtil.getFileType(sourceFile);
47
47
 
48
- return this.#manifestIndex.getEntry((sourceType === 'ts' || sourceType === 'js') ? sourceFile : undefined!) ??
49
- this.#manifestIndex.getFromImport(ManifestModuleUtil.withoutSourceExtension(sourceFile).replace(/^.*node_modules\//, ''));
48
+ return (
49
+ this.#manifestIndex.getEntry(sourceType === 'ts' || sourceType === 'js' ? sourceFile : undefined!) ??
50
+ this.#manifestIndex.getFromImport(ManifestModuleUtil.withoutSourceExtension(sourceFile).replace(/^.*node_modules\//, ''))
51
+ );
50
52
  }
51
53
 
52
54
  /**
@@ -69,8 +71,7 @@ export class SimpleResolver implements TransformResolver {
69
71
  * Is the file/import known to the index, helpful for determine ownership
70
72
  */
71
73
  isKnownFile(fileOrImport: string): boolean {
72
- return (this.#manifestIndex.getFromSource(fileOrImport) !== undefined) ||
73
- (this.#manifestIndex.getFromImport(fileOrImport) !== undefined);
74
+ return this.#manifestIndex.getFromSource(fileOrImport) !== undefined || this.#manifestIndex.getFromImport(fileOrImport) !== undefined;
74
75
  }
75
76
 
76
77
  /**
@@ -116,7 +117,8 @@ export class SimpleResolver implements TransformResolver {
116
117
  * Get list of properties
117
118
  */
118
119
  getPropertiesOfType(type: ts.Type): ts.Symbol[] {
119
- return this.#tsChecker.getPropertiesOfType(type)
120
+ return this.#tsChecker
121
+ .getPropertiesOfType(type)
120
122
  .filter(property => property.getName() !== '__proto__' && property.getName() !== 'prototype');
121
123
  }
122
124
 
@@ -128,7 +130,8 @@ export class SimpleResolver implements TransformResolver {
128
130
  const resolve = (resType: ts.Type, context?: Omit<ResolverContext, 'node' | 'importName'>): AnyType => {
129
131
  const { depth = 0 } = context ?? {};
130
132
 
131
- if (depth > 20) { // Max depth is 20
133
+ if (depth > 20) {
134
+ // Max depth is 20
132
135
  throw new Error(`Object structure too nested: ${'getText' in node ? node.getText() : ''}`);
133
136
  }
134
137
 
@@ -137,7 +140,7 @@ export class SimpleResolver implements TransformResolver {
137
140
  const typeArguments: ts.Type[] =
138
141
  'resolvedTypeArguments' in resType && resType.resolvedTypeArguments ? transformCast(resType.resolvedTypeArguments) : [];
139
142
 
140
- let result = TypeBuilder[category].build(this, type, { ...context, node: (node && 'kind' in node) ? node : undefined, importName });
143
+ let result = TypeBuilder[category].build(this, type, { ...context, node: node && 'kind' in node ? node : undefined, importName });
141
144
 
142
145
  // Convert via cache if needed
143
146
  result = visited.getOrSet(type, result);
@@ -148,15 +151,19 @@ export class SimpleResolver implements TransformResolver {
148
151
  result.templateTypeName = context?.templateTypeName;
149
152
 
150
153
  try {
151
- result.comment = DocUtil.describeDocs(type).description;
152
- } catch { }
154
+ result.description = DocUtil.describeDocs(type).description;
155
+ } catch {}
153
156
 
154
157
  if ('tsTypeArguments' in result) {
155
158
  const tsTypeArguments = result.tsTypeArguments!;
156
159
  if (typeArguments.length) {
157
- result.typeArguments = typeArguments.map((item, i) => resolve(item, { alias: type.aliasSymbol, templateTypeName: tsTypeArguments[i][0], depth: depth + 1 }));
160
+ result.typeArguments = typeArguments.map((item, i) =>
161
+ resolve(item, { alias: type.aliasSymbol, templateTypeName: tsTypeArguments[i][0], depth: depth + 1 })
162
+ );
158
163
  } else {
159
- result.typeArguments = tsTypeArguments.map((item) => resolve(item[1], { alias: type.aliasSymbol, templateTypeName: item[0], depth: depth + 1 }));
164
+ result.typeArguments = tsTypeArguments.map(item =>
165
+ resolve(item[1], { alias: type.aliasSymbol, templateTypeName: item[0], depth: depth + 1 })
166
+ );
160
167
  }
161
168
  delete result.tsTypeArguments;
162
169
  }
@@ -169,7 +176,7 @@ export class SimpleResolver implements TransformResolver {
169
176
  delete result.tsFieldTypes;
170
177
  }
171
178
  if ('tsSubTypes' in result) {
172
- result.subTypes = result.tsSubTypes!.map((item) => resolve(item, { alias: type.aliasSymbol, depth: depth + 1 }));
179
+ result.subTypes = result.tsSubTypes!.map(item => resolve(item, { alias: type.aliasSymbol, depth: depth + 1 }));
173
180
  delete result.tsSubTypes;
174
181
  }
175
182
  if (isFinalizeType(result.key)) {
@@ -190,4 +197,4 @@ export class SimpleResolver implements TransformResolver {
190
197
  return { key: 'literal', ctor: Object, name: 'object' };
191
198
  }
192
199
  }
193
- }
200
+ }
@@ -1,4 +1,5 @@
1
1
  import type ts from 'typescript';
2
+
2
3
  import type { TemplateLiteral } from '../types/shared.ts';
3
4
 
4
5
  type TemplateArgument = [templateName: string, type: ts.Type];
@@ -18,7 +19,11 @@ export interface Type<K extends string> {
18
19
  /**
19
20
  * JS Doc comment
20
21
  */
21
- comment?: string;
22
+ description?: string;
23
+ /**
24
+ * JS Doc examples
25
+ */
26
+ examples?: string[];
22
27
  /**
23
28
  * Can be undefined
24
29
  */
@@ -218,11 +223,19 @@ export interface ForeignType extends Type<'foreign'> {
218
223
  /**
219
224
  * Unknown type, should default to object
220
225
  */
221
- export interface UnknownType extends Type<'unknown'> { }
226
+ export interface UnknownType extends Type<'unknown'> {}
222
227
 
223
228
  export type AnyType =
224
- TupleType | ShapeType | CompositionType | LiteralType | MappedType |
225
- ManagedType | PointerType | UnknownType | ForeignType | TemplateType;
229
+ | TupleType
230
+ | ShapeType
231
+ | CompositionType
232
+ | LiteralType
233
+ | MappedType
234
+ | ManagedType
235
+ | PointerType
236
+ | UnknownType
237
+ | ForeignType
238
+ | TemplateType;
226
239
 
227
240
  /**
228
241
  * Simple interface for checked methods