@travetto/transformer 3.0.0-rc.0 → 3.0.0-rc.10

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.
@@ -0,0 +1,103 @@
1
+ const REGEX_PAT = /[\/](.*)[\/](i|g|m|s)?/;
2
+
3
+ export class CoerceUtil {
4
+ /**
5
+ * Is a value a plain JS object, created using {}
6
+ */
7
+ static #isPlainObject(obj: unknown): obj is Record<string, unknown> {
8
+ return typeof obj === 'object' // separate from primitives
9
+ && obj !== undefined
10
+ && obj !== null // is obvious
11
+ && obj.constructor === Object // separate instances (Array, DOM, ...)
12
+ && Object.prototype.toString.call(obj) === '[object Object]'; // separate build-in like Math
13
+ }
14
+
15
+ /**
16
+ * Create regex from string, including flags
17
+ */
18
+ static #toRegex(input: string | RegExp): RegExp {
19
+ if (input instanceof RegExp) {
20
+ return input;
21
+ } else if (REGEX_PAT.test(input)) {
22
+ const [, pat, mod] = input.match(REGEX_PAT) ?? [];
23
+ return new RegExp(pat, mod);
24
+ } else {
25
+ return new RegExp(input);
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Coerce an input of any type to the class provided
31
+ * @param input Input value
32
+ * @param type Class to coerce to (String, Boolean, Number, Date, RegEx, Object)
33
+ * @param strict Should a failure to coerce throw an error?
34
+ */
35
+ static coerce(input: unknown, type: typeof String, strict?: boolean): string;
36
+ static coerce(input: unknown, type: typeof Number, strict?: boolean): number;
37
+ static coerce(input: unknown, type: typeof Boolean, strict?: boolean): boolean;
38
+ static coerce(input: unknown, type: typeof Date, strict?: boolean): Date;
39
+ static coerce(input: unknown, type: typeof RegExp, strict?: boolean): RegExp;
40
+ static coerce(input: unknown, type: Function, strict = true): unknown {
41
+ // Do nothing
42
+ if (input === null || input === undefined) {
43
+ return input;
44
+ } else if (!strict && type !== String && input === '') {
45
+ return undefined; // treat empty string as undefined for non-strings in non-strict mode
46
+ } else if (type && input instanceof type) {
47
+ return input;
48
+ }
49
+
50
+ switch (type) {
51
+ case Date: {
52
+ const res = typeof input === 'number' || /^[-]?\d+$/.test(`${input}`) ?
53
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
54
+ new Date(parseInt(input as string, 10)) : new Date(input as Date);
55
+ if (strict && Number.isNaN(res.getTime())) {
56
+ throw new Error(`Invalid date value: ${input}`);
57
+ }
58
+ return res;
59
+ }
60
+ case Number: {
61
+ const res = `${input}`.includes('.') ? parseFloat(`${input}`) : parseInt(`${input}`, 10);
62
+ if (strict && Number.isNaN(res)) {
63
+ throw new Error(`Invalid numeric value: ${input}`);
64
+ }
65
+ return res;
66
+ }
67
+ case Boolean: {
68
+ const match = `${input}`.match(/^((?<TRUE>true|yes|1|on)|false|no|off|0)$/i);
69
+ if (strict && !match) {
70
+ throw new Error(`Invalid boolean value: ${input}`);
71
+ }
72
+ return !!match?.groups?.TRUE;
73
+ }
74
+ case RegExp: {
75
+ if (typeof input === 'string') {
76
+ try {
77
+ return this.#toRegex(input);
78
+ } catch {
79
+ if (strict) {
80
+ throw new Error(`Invalid regex: ${input}`);
81
+ } else {
82
+ return;
83
+ }
84
+ }
85
+ } else if (strict) {
86
+ throw new Error('Invalid regex type');
87
+ } else {
88
+ return;
89
+ }
90
+ }
91
+ case Object: {
92
+ if (!strict || this.#isPlainObject(input)) {
93
+ return input;
94
+ } else {
95
+ throw new Error('Invalid object type');
96
+ }
97
+ }
98
+ case undefined:
99
+ case String: return `${input}`;
100
+ }
101
+ throw new Error(`Unknown type ${type.name}`);
102
+ }
103
+ }
@@ -1,9 +1,9 @@
1
- import * as ts from 'typescript';
1
+ import ts from 'typescript';
2
2
 
3
- import { AnyType, Checker } from './types';
3
+ import type { AnyType, Checker } from './types';
4
4
  import { TypeCategorize, TypeBuilder } from './builder';
5
5
  import { VisitCache } from './cache';
6
- import { DocUtil } from '../util';
6
+ import { DocUtil } from '../util/doc';
7
7
 
8
8
  /**
9
9
  * Type resolver
@@ -1,4 +1,4 @@
1
- import type * as ts from 'typescript';
1
+ import type ts from 'typescript';
2
2
 
3
3
  /**
4
4
  * Base type for a simplistic type structure
@@ -37,7 +37,7 @@ export interface ExternalType extends Type<'external'> {
37
37
  /**
38
38
  * Location the type came from, for class references
39
39
  */
40
- source: string;
40
+ importName: string;
41
41
  /**
42
42
  * Type arguments
43
43
  */
@@ -55,7 +55,7 @@ export interface ShapeType extends Type<'shape'> {
55
55
  /**
56
56
  * Location the type came from, for class references
57
57
  */
58
- source: string;
58
+ importName: string;
59
59
  /**
60
60
  * Does not include methods, used for shapes not concrete types
61
61
  */
package/src/state.ts CHANGED
@@ -1,18 +1,20 @@
1
- import * as ts from 'typescript';
1
+ import ts from 'typescript';
2
2
 
3
- import { SystemUtil } from '@travetto/boot/src/internal/system';
4
- import { ModuleUtil } from '@travetto/boot/src/internal/module-util';
5
- import { Util } from '@travetto/base';
3
+ import { path } from '@travetto/manifest';
6
4
 
7
5
  import { ExternalType, AnyType } from './resolver/types';
8
- import { State, DecoratorMeta, Transformer, TransformerId } from './types/visitor';
6
+ import { State, DecoratorMeta, Transformer, ModuleNameⲐ } from './types/visitor';
9
7
  import { TypeResolver } from './resolver/service';
10
8
  import { ImportManager } from './importer';
9
+ import { Import } from './types/shared';
10
+
11
11
  import { DocUtil } from './util/doc';
12
12
  import { DecoratorUtil } from './util/decorator';
13
13
  import { DeclarationUtil } from './util/declaration';
14
- import { CoreUtil, LiteralUtil } from './util';
15
- import { Import } from './types/shared';
14
+ import { CoreUtil } from './util/core';
15
+ import { LiteralUtil } from './util/literal';
16
+ import { SystemUtil } from './util/system';
17
+ import { TransformerIndex } from './manifest-index';
16
18
 
17
19
  function hasOriginal(n: unknown): n is { original: ts.Node } {
18
20
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
@@ -28,20 +30,22 @@ function hasEscapedName(n: unknown): n is { name: { escapedText: string } } {
28
30
  * Transformer runtime state
29
31
  */
30
32
  export class TransformerState implements State {
31
- static SYNTHETIC_EXT = 'syn';
33
+ static SYNTHETIC_EXT = 'syn';
32
34
 
33
35
  #resolver: TypeResolver;
34
36
  #imports: ImportManager;
37
+ #fileIdent: ts.Identifier;
35
38
  #syntheticIdentifiers = new Map<string, ts.Identifier>();
36
39
  #decorators = new Map<string, ts.PropertyAccessExpression>();
37
-
38
40
  added = new Map<number, ts.Statement[]>();
39
- module: string;
41
+ importName: string;
42
+ file: string;
40
43
 
41
44
  constructor(public source: ts.SourceFile, public factory: ts.NodeFactory, checker: ts.TypeChecker) {
42
45
  this.#imports = new ImportManager(source, factory);
43
46
  this.#resolver = new TypeResolver(checker);
44
- this.module = ModuleUtil.normalizePath(this.source.fileName);
47
+ this.file = path.toPosix(this.source.fileName);
48
+ this.importName = TransformerIndex.getImportName(this.file, true);
45
49
  }
46
50
 
47
51
  /**
@@ -62,8 +66,8 @@ export class TransformerState implements State {
62
66
  /**
63
67
  * Import a given file
64
68
  */
65
- importFile(file: string): Import {
66
- return this.#imports.importFile(file);
69
+ importFile(file: string, name?: string): Import {
70
+ return this.#imports.importFile(file, name);
67
71
  }
68
72
 
69
73
  /**
@@ -81,7 +85,9 @@ export class TransformerState implements State {
81
85
  resolveExternalType(node: ts.Node): ExternalType {
82
86
  const resolved = this.resolveType(node);
83
87
  if (resolved.key !== 'external') {
84
- throw new Error(`Unable to import non-external type: ${node.getText()} ${resolved.key}: ${node.getSourceFile().fileName}`);
88
+ const file = node.getSourceFile().fileName;
89
+ const src = TransformerIndex.getImportName(file);
90
+ throw new Error(`Unable to import non-external type: ${node.getText()} ${resolved.key}: ${src}`);
85
91
  }
86
92
  return resolved;
87
93
  }
@@ -141,32 +147,33 @@ export class TransformerState implements State {
141
147
  /**
142
148
  * Read a decorator's metadata
143
149
  */
144
- getDecoratorMeta(dec: ts.Decorator): DecoratorMeta {
150
+ getDecoratorMeta(dec: ts.Decorator): DecoratorMeta | undefined {
145
151
  const ident = DecoratorUtil.getDecoratorIdent(dec);
146
152
  const decl = DeclarationUtil.getPrimaryDeclarationNode(
147
153
  this.#resolver.getType(ident)
148
154
  );
149
-
150
- return {
151
- dec,
152
- ident,
153
- file: decl?.getSourceFile().fileName,
154
- module: decl ? ModuleUtil.normalizePath(decl.getSourceFile().fileName) : undefined, // All #decorators will be absolute
155
- targets: DocUtil.readAugments(this.#resolver.getType(ident)),
156
- name: ident ?
157
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
158
- ident.escapedText! as string :
159
- undefined
160
- };
155
+ const src = decl?.getSourceFile().fileName;
156
+ const mod = src ? TransformerIndex.getImportName(src, true) : undefined;
157
+ const file = TransformerIndex.getFromImport(mod ?? '')?.outputFile;
158
+ const targets = DocUtil.readAugments(this.#resolver.getType(ident));
159
+ const module = file ? mod : undefined;
160
+ const name = ident ?
161
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
162
+ ident.escapedText! as string :
163
+ undefined;
164
+
165
+ if (ident && name) {
166
+ return { dec, ident, file, module, targets, name };
167
+ }
161
168
  }
162
169
 
163
170
  /**
164
171
  * Get list of all #decorators for a node
165
172
  */
166
173
  getDecoratorList(node: ts.Node): DecoratorMeta[] {
167
- return (node.decorators ?? [])
174
+ return ts.canHaveDecorators(node) ? (ts.getDecorators(node) ?? [])
168
175
  .map(dec => this.getDecoratorMeta(dec))
169
- .filter(x => !!x.ident);
176
+ .filter((x): x is DecoratorMeta => !!x) : [];
170
177
  }
171
178
 
172
179
  /**
@@ -181,44 +188,40 @@ export class TransformerState implements State {
181
188
  * @param stmt
182
189
  * @param before
183
190
  */
184
- addStatement(stmt: ts.Statement, before?: ts.Node): void {
191
+ addStatements(added: ts.Statement[], before?: ts.Node | number): void {
185
192
  const stmts = this.source.statements.slice(0);
186
- let idx = stmts.length;
187
- let n = before;
188
- if (hasOriginal(n)) {
189
- n = n.original;
190
- }
191
- while (n && !ts.isSourceFile(n.parent)) {
192
- n = n.parent;
193
- }
194
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
195
- const nStmt: ts.Statement = n as ts.Statement;
196
- if (n && ts.isSourceFile(n.parent) && stmts.indexOf(nStmt) >= 0) {
197
- idx = stmts.indexOf(nStmt) - 1;
193
+ let idx = stmts.length + 1000;
194
+
195
+ if (before && typeof before !== 'number') {
196
+ let n = before;
197
+ if (hasOriginal(n)) {
198
+ n = n.original;
199
+ }
200
+ while (n && !ts.isSourceFile(n.parent) && n !== n.parent) {
201
+ n = n.parent;
202
+ }
203
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
204
+ const nStmt: ts.Statement = n as ts.Statement;
205
+ if (n && ts.isSourceFile(n.parent) && stmts.indexOf(nStmt) >= 0) {
206
+ idx = stmts.indexOf(nStmt) - 1;
207
+ }
208
+ } else if (before !== undefined) {
209
+ idx = before;
198
210
  }
199
211
  if (!this.added.has(idx)) {
200
212
  this.added.set(idx, []);
201
213
  }
202
- this.added.get(idx)!.push(stmt);
214
+ this.added.get(idx)!.push(...added);
203
215
  }
204
216
 
205
217
  /**
206
218
  * Finalize the source file for emission
207
219
  */
208
220
  finalize(ret: ts.SourceFile): ts.SourceFile {
209
- ret = this.#imports.finalize(ret);
221
+ ret = this.#imports.finalize(ret, this.#resolver.getChecker());
210
222
  return ret;
211
223
  }
212
224
 
213
- /**
214
- * Get Filename as ᚕsrc
215
- */
216
- getFilenameAsSrc(): ts.CallExpression {
217
- const ident = this.factory.createIdentifier('ᚕsrc');
218
- ident.getSourceFile = (): ts.SourceFile => this.source;
219
- return this.factory.createCallExpression(ident, [], [this.createIdentifier('__filename')]);
220
- }
221
-
222
225
  /**
223
226
  * From literal
224
227
  */
@@ -243,7 +246,7 @@ export class TransformerState implements State {
243
246
  /**
244
247
  * Create property access
245
248
  */
246
- createAccess(first: string | ts.Expression, second: string | ts.Identifier, ...items: (string | ts.Identifier)[]): ts.PropertyAccessExpression {
249
+ createAccess(first: string | ts.Expression, second: string | ts.Identifier, ...items: (string | number | ts.Identifier)[]): ts.Expression {
247
250
  return CoreUtil.createAccess(this.factory, first, second, ...items);
248
251
  }
249
252
 
@@ -262,6 +265,22 @@ export class TransformerState implements State {
262
265
  return this.factory.createIdentifier(typeof name === 'string' ? name : name.getText());
263
266
  }
264
267
 
268
+ /**
269
+ * Get filename identifier, regardless of module system
270
+ */
271
+ getFilenameIdentifier(): ts.Expression {
272
+ if (this.#fileIdent === undefined) {
273
+ this.#fileIdent = this.createIdentifier('ᚕf');
274
+ const decl = this.factory.createVariableDeclaration(this.#fileIdent, undefined, undefined,
275
+ this.fromLiteral(TransformerIndex.getImportName(this.source.fileName) ?? this.source.fileName)
276
+ );
277
+ this.addStatements([
278
+ this.factory.createVariableStatement([], this.factory.createVariableDeclarationList([decl]))
279
+ ], -1);
280
+ }
281
+ return this.#fileIdent;
282
+ }
283
+
265
284
  /**
266
285
  * Find decorator, relative to registered key
267
286
  * @param state
@@ -269,10 +288,11 @@ export class TransformerState implements State {
269
288
  * @param name
270
289
  * @param module
271
290
  */
272
- findDecorator(cls: Transformer, node: ts.Node, name: string, module?: string): ts.Decorator | undefined {
273
- const target = `${cls[TransformerId]}/${name}`;
274
- return this.getDecoratorList(node)
275
- .find(x => x.targets?.includes(target) && (!module || x.name === name && x.module === module))?.dec;
291
+ findDecorator(mod: string | Transformer, node: ts.Node, name: string, module?: string): ts.Decorator | undefined {
292
+ mod = typeof mod === 'string' ? mod : mod[ModuleNameⲐ]!;
293
+ const target = `${mod}:${name}`;
294
+ const list = this.getDecoratorList(node);
295
+ return list.find(x => x.targets?.includes(target) && (!module || x.name === name && x.module === module))?.dec;
276
296
  }
277
297
 
278
298
  /**
@@ -291,7 +311,7 @@ export class TransformerState implements State {
291
311
  }
292
312
  } catch {
293
313
  // Determine type unique ident
294
- unique = Util.uuid(type.name ? 5 : 10);
314
+ unique = SystemUtil.uuid(type.name ? 5 : 10);
295
315
  }
296
316
  // Otherwise read name with uuid
297
317
  let name = type.name && !type.name.startsWith('_') ? type.name : '';
@@ -1,4 +1,4 @@
1
- import * as ts from 'typescript';
1
+ import type ts from 'typescript';
2
2
 
3
3
  /**
4
4
  * Param documentation
@@ -1,4 +1,4 @@
1
- import * as ts from 'typescript';
1
+ import ts from 'typescript';
2
2
 
3
3
  /**
4
4
  * Decorator metadata
@@ -14,7 +14,7 @@ export type DecoratorMeta = {
14
14
 
15
15
  export type State = {
16
16
  source: ts.SourceFile;
17
- module: string;
17
+ importName: string;
18
18
  added: Map<number, ts.Statement[]>;
19
19
  getDecoratorList(node: ts.Node): DecoratorMeta[];
20
20
  finalize(src: ts.SourceFile): ts.SourceFile;
@@ -22,12 +22,14 @@ export type State = {
22
22
 
23
23
  export type TransformPhase = 'before' | 'after';
24
24
 
25
- export type TransformerType = 'class' | 'method' | 'property' | 'getter' | 'setter' | 'parameter' | 'static-method' | 'call' | 'function';
25
+ export type TransformerType =
26
+ 'class' | 'method' | 'property' | 'getter' | 'setter' | 'parameter' |
27
+ 'static-method' | 'call' | 'function' | 'file';
26
28
 
27
- export const TransformerId = Symbol.for('@trv:transformer/id');
29
+ export const ModuleNameⲐ = Symbol.for('@travetto/transformer:id');
28
30
 
29
31
  export type Transformer = {
30
- [TransformerId]: string;
32
+ [ModuleNameⲐ]?: string;
31
33
  name: string;
32
34
  };
33
35
 
package/src/util/core.ts CHANGED
@@ -1,9 +1,10 @@
1
- import * as ts from 'typescript';
1
+ import ts from 'typescript';
2
2
 
3
3
  /**
4
4
  * Core utilities util
5
5
  */
6
6
  export class CoreUtil {
7
+
7
8
  /**
8
9
  * See if inbound node has an original property
9
10
  */
@@ -51,7 +52,6 @@ export class CoreUtil {
51
52
  */
52
53
  static createStaticField(factory: ts.NodeFactory, name: string, val: ts.Expression): ts.PropertyDeclaration {
53
54
  return factory.createPropertyDeclaration(
54
- undefined,
55
55
  [factory.createToken(ts.SyntaxKind.StaticKeyword)],
56
56
  name, undefined, undefined, val
57
57
  );
@@ -88,13 +88,15 @@ export class CoreUtil {
88
88
  factory: ts.NodeFactory,
89
89
  first: string | ts.Expression,
90
90
  second: string | ts.Identifier,
91
- ...items: (string | ts.Identifier)[]
92
- ): ts.PropertyAccessExpression {
91
+ ...items: (string | number | ts.Identifier)[]
92
+ ): ts.Expression {
93
93
  if (typeof first === 'string') {
94
94
  first = factory.createIdentifier(first);
95
95
  }
96
- return items.reduce(
97
- (acc, p) => factory.createPropertyAccessExpression(acc, p),
96
+ return items.reduce<ts.Expression>(
97
+ (acc, p) => typeof p === 'number' ?
98
+ factory.createElementAccessExpression(acc, p) :
99
+ factory.createPropertyAccessExpression(acc, p),
98
100
  factory.createPropertyAccessExpression(first, second)
99
101
  );
100
102
  }
@@ -1,4 +1,4 @@
1
- import * as ts from 'typescript';
1
+ import ts from 'typescript';
2
2
  import { CoreUtil } from './core';
3
3
 
4
4
  /**
@@ -57,8 +57,8 @@ export class DeclarationUtil {
57
57
  * Resolve the `ts.ObjectFlags`
58
58
  */
59
59
  static getObjectFlags(type: ts.Type): ts.ObjectFlags {
60
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
61
- return (ts as unknown as { getObjectFlags(t: ts.Type): ts.ObjectFlags }).getObjectFlags(type);
60
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions, no-bitwise
61
+ return (ts as unknown as { getObjectFlags(t: ts.Type): ts.ObjectFlags }).getObjectFlags(type) & ~(ts.NodeFlags.ThisNodeOrAnySubNodesHasError);
62
62
  }
63
63
 
64
64
  /**
@@ -1,4 +1,4 @@
1
- import * as ts from 'typescript';
1
+ import ts from 'typescript';
2
2
  import { CoreUtil } from './core';
3
3
 
4
4
  /**
@@ -24,11 +24,14 @@ export class DecoratorUtil {
24
24
  /**
25
25
  * Replace or add a decorator to a list of decorators
26
26
  */
27
- static spliceDecorators(node: ts.Node, target: ts.Decorator | undefined, replacements: ts.Decorator[], idx = -1): ts.Decorator[] {
27
+ static spliceDecorators(node: ts.Node, target: ts.Decorator | undefined, replacements: ts.Decorator[], idx = -1): ts.ModifierLike[] {
28
+ if (!ts.canHaveDecorators(node)) {
29
+ return [];
30
+ }
28
31
  if (idx < 0 && target) {
29
- idx = node.decorators?.indexOf(target) ?? -1;
32
+ idx = node.modifiers?.indexOf(target) ?? -1;
30
33
  }
31
- const out = (node.decorators ?? []).filter(x => x !== target);
34
+ const out = (node.modifiers ?? []).filter(x => x !== target);
32
35
  if (idx < 0) {
33
36
  out.push(...replacements);
34
37
  } else {
package/src/util/doc.ts CHANGED
@@ -1,4 +1,4 @@
1
- import * as ts from 'typescript';
1
+ import ts from 'typescript';
2
2
 
3
3
  import { DeclDocumentation } from '../types/shared';
4
4
  import { CoreUtil } from './core';
@@ -1,7 +1,6 @@
1
- import * as ts from 'typescript';
2
- import { resolve as pathResolve } from 'path';
1
+ import ts from 'typescript';
3
2
 
4
- import { PathUtil } from '@travetto/boot';
3
+ import { PackageUtil, path } from '@travetto/manifest';
5
4
 
6
5
  import { Import } from '../types/shared';
7
6
 
@@ -13,9 +12,17 @@ export class ImportUtil {
13
12
  * useful for handling failed imports, but still transpiling
14
13
  */
15
14
  static optionalResolve(file: string, base?: string): string {
16
- file = base ? pathResolve(base, file) : file;
15
+ if (base?.endsWith('.ts')) {
16
+ base = path.dirname(base);
17
+ }
18
+ if (base && file.startsWith('.')) {
19
+ return path.resolve(base, file);
20
+ // TODO: Replace with manifest reverse lookup
21
+ } else if (file.startsWith('@')) {
22
+ return path.resolve('node_modules', file);
23
+ }
17
24
  try {
18
- return require.resolve(file);
25
+ return PackageUtil.resolveImport(file);
19
26
  } catch {
20
27
  return file;
21
28
  }
@@ -25,23 +32,23 @@ export class ImportUtil {
25
32
  * Collect all imports for a source file, as a hash map
26
33
  */
27
34
  static collectImports(src: ts.SourceFile): Map<string, Import> {
28
- const pth = require.resolve(src.fileName);
29
- const base = PathUtil.toUnix(pth);
35
+ // TODO: Replace with manifest reverse lookup
36
+ const base = path.toPosix(src.fileName);
30
37
 
31
38
  const imports = new Map<string, Import>();
32
39
 
33
40
  for (const stmt of src.statements) {
34
41
  if (ts.isImportDeclaration(stmt) && ts.isStringLiteral(stmt.moduleSpecifier)) {
35
- const path = this.optionalResolve(stmt.moduleSpecifier.text, base);
42
+ const resolved = this.optionalResolve(stmt.moduleSpecifier.text, base);
36
43
 
37
44
  if (stmt.importClause) {
38
45
  if (stmt.importClause.namedBindings) {
39
46
  const bindings = stmt.importClause.namedBindings;
40
47
  if (ts.isNamespaceImport(bindings)) {
41
- imports.set(bindings.name.text, { path, ident: bindings.name, stmt });
48
+ imports.set(bindings.name.text, { path: resolved, ident: bindings.name, stmt });
42
49
  } else if (ts.isNamedImports(bindings)) {
43
50
  for (const n of bindings.elements) {
44
- imports.set(n.name.text, { path, ident: n.name, stmt });
51
+ imports.set(n.name.text, { path: resolved, ident: n.name, stmt });
45
52
  }
46
53
  }
47
54
  }
@@ -1,4 +1,4 @@
1
- import * as ts from 'typescript';
1
+ import ts from 'typescript';
2
2
 
3
3
  /**
4
4
  * Utilities for dealing with literals
@@ -48,7 +48,8 @@ export class LiteralUtil {
48
48
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
49
49
  const ov = val as object;
50
50
  const pairs: ts.PropertyAssignment[] = [];
51
- for (const k of Object.keys(ov)) {
51
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
52
+ for (const k of Object.keys(ov) as (keyof typeof ov)[]) {
52
53
  if (ov[k] !== undefined) {
53
54
  pairs.push(
54
55
  factory.createPropertyAssignment(k, this.fromLiteral(factory, ov[k]))
package/src/util/log.ts CHANGED
@@ -1,5 +1,3 @@
1
- import { Util } from '@travetto/base';
2
-
3
1
  const exclude = new Set([
4
2
  'parent', 'checker', 'end', 'pos', 'id', 'source', 'sourceFile', 'getSourceFile',
5
3
  'statements', 'stringIndexInfo', 'numberIndexInfo', 'instantiations', 'thisType',
@@ -22,7 +20,7 @@ export class LogUtil {
22
20
  * Clean up `ts.Node` contents for logging
23
21
  */
24
22
  static collapseNode(x: unknown, cache: Set<unknown> = new Set()): unknown {
25
- if (!x || Util.isPrimitive(x)) {
23
+ if (!x || !(typeof x === 'object' || typeof x === 'function')) {
26
24
  return x;
27
25
  }
28
26
 
@@ -39,7 +37,7 @@ export class LogUtil {
39
37
  const ox = x as object;
40
38
  const out: Record<string, unknown> = {};
41
39
  for (const key of Object.keys(ox)) {
42
- if (Util.isFunction(ox[key]) || exclude.has(key) || ox[key] === undefined) {
40
+ if (Object.getPrototypeOf(ox[key]) === Function.prototype || exclude.has(key) || ox[key] === undefined) {
43
41
  continue;
44
42
  }
45
43
  try {
@@ -0,0 +1,31 @@
1
+ import crypto from 'crypto';
2
+
3
+ export class SystemUtil {
4
+
5
+ /**
6
+ * Generate a random UUID
7
+ * @param len The length of the uuid to generate
8
+ */
9
+ static uuid(len: number = 32): string {
10
+ const bytes = crypto.randomBytes(Math.ceil(len / 2));
11
+ // eslint-disable-next-line no-bitwise
12
+ bytes[6] = (bytes[6] & 0x0f) | 0x40;
13
+ // eslint-disable-next-line no-bitwise
14
+ bytes[8] = (bytes[8] & 0x3f) | 0x80;
15
+ return bytes.toString('hex').substring(0, len);
16
+ }
17
+
18
+ /**
19
+ * Naive hashing
20
+ */
21
+ static naiveHash(text: string): number {
22
+ let hash = 5381;
23
+
24
+ for (let i = 0; i < text.length; i++) {
25
+ // eslint-disable-next-line no-bitwise
26
+ hash = (hash * 33) ^ text.charCodeAt(i);
27
+ }
28
+
29
+ return Math.abs(hash);
30
+ }
31
+ }