@travetto/runtime 5.0.0-rc.2
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/LICENSE +21 -0
- package/README.md +304 -0
- package/__index__.ts +16 -0
- package/package.json +48 -0
- package/src/console.ts +137 -0
- package/src/context.ts +100 -0
- package/src/env.ts +109 -0
- package/src/error.ts +66 -0
- package/src/exec.ts +156 -0
- package/src/file-loader.ts +59 -0
- package/src/function.ts +42 -0
- package/src/global.d.ts +3 -0
- package/src/manifest-index.ts +4 -0
- package/src/resources.ts +26 -0
- package/src/shutdown.ts +65 -0
- package/src/time.ts +101 -0
- package/src/trv.d.ts +59 -0
- package/src/types.ts +12 -0
- package/src/util.ts +104 -0
- package/src/watch.ts +38 -0
- package/support/transformer.console-log.ts +113 -0
- package/support/transformer.function-metadata.ts +137 -0
- package/support/transformer.rewrite-path-import.ts +39 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
export type Class<T = any> = abstract new (...args: any[]) => T;
|
|
3
|
+
export type ConcreteClass<T = any> = new (...args: any[]) => T;
|
|
4
|
+
export type ClassInstance<T = any> = T & {
|
|
5
|
+
constructor: ConcreteClass<T> & { Ⲑid: string };
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export const TypedObject: {
|
|
9
|
+
keys<T = unknown, K extends keyof T = keyof T>(o: T): K[];
|
|
10
|
+
fromEntries<K extends string | symbol, V>(items: ([K, V] | readonly [K, V])[]): Record<K, V>;
|
|
11
|
+
entries<K extends Record<symbol | string, unknown>>(record: K): [keyof K, K[keyof K]][];
|
|
12
|
+
} & ObjectConstructor = Object;
|
package/src/util.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import timers from 'node:timers/promises';
|
|
3
|
+
import fs from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
|
|
6
|
+
type PromiseWithResolvers<T> = {
|
|
7
|
+
resolve: (v: T) => void;
|
|
8
|
+
reject: (err?: unknown) => void;
|
|
9
|
+
promise: Promise<T>;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
type MapFn<T, U> = (val: T, i: number) => U | Promise<U>;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Grab bag of common utilities
|
|
16
|
+
*/
|
|
17
|
+
export class Util {
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Generate a random UUID
|
|
21
|
+
* @param len The length of the uuid to generate
|
|
22
|
+
*/
|
|
23
|
+
static uuid(len: number = 32): string {
|
|
24
|
+
const bytes = crypto.randomBytes(Math.ceil(len / 2));
|
|
25
|
+
// eslint-disable-next-line no-bitwise
|
|
26
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
|
27
|
+
// eslint-disable-next-line no-bitwise
|
|
28
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
29
|
+
return bytes.toString('hex').substring(0, len);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Generate a proper sha512 hash from a src value
|
|
34
|
+
* @param src The seed value to build the hash from
|
|
35
|
+
* @param len The optional length of the hash to generate
|
|
36
|
+
*/
|
|
37
|
+
static hash(src: string, len: number = -1): string {
|
|
38
|
+
const hash = crypto.createHash('sha512');
|
|
39
|
+
hash.update(src);
|
|
40
|
+
const ret = hash.digest('hex');
|
|
41
|
+
return len > 0 ? ret.substring(0, len) : ret;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Produce a promise that is externally resolvable
|
|
46
|
+
*/
|
|
47
|
+
static resolvablePromise<T = void>(): PromiseWithResolvers<T> {
|
|
48
|
+
let ops: Pick<PromiseWithResolvers<T>, 'reject' | 'resolve'>;
|
|
49
|
+
const prom = new Promise<T>((resolve, reject) => ops = { resolve, reject });
|
|
50
|
+
return { ...ops!, promise: prom };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Map an async iterable with various mapping functions
|
|
55
|
+
*/
|
|
56
|
+
static mapAsyncItr<T, U, V, W>(source: AsyncIterable<T>, fn1: MapFn<T, U>, fn2: MapFn<U, V>, fn3: MapFn<V, W>): AsyncIterable<W>;
|
|
57
|
+
static mapAsyncItr<T, U, V>(source: AsyncIterable<T>, fn1: MapFn<T, U>, fn2: MapFn<U, V>): AsyncIterable<V>;
|
|
58
|
+
static mapAsyncItr<T, U>(source: AsyncIterable<T>, fn: MapFn<T, U>): AsyncIterable<U>;
|
|
59
|
+
static async * mapAsyncItr<T>(source: AsyncIterable<T>, ...fns: MapFn<unknown, unknown>[]): AsyncIterable<unknown> {
|
|
60
|
+
let idx = -1;
|
|
61
|
+
for await (const el of source) {
|
|
62
|
+
if (el !== undefined) {
|
|
63
|
+
idx += 1;
|
|
64
|
+
let m = el;
|
|
65
|
+
for (const fn of fns) {
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
67
|
+
m = (await fn(m, idx)) as typeof m;
|
|
68
|
+
}
|
|
69
|
+
yield m;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Write file and copy over when ready
|
|
76
|
+
*/
|
|
77
|
+
static async bufferedFileWrite(file: string, content: string): Promise<void> {
|
|
78
|
+
const temp = path.resolve(path.dirname(file), `.${process.hrtime()[0]}.${path.basename(file)}`);
|
|
79
|
+
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
80
|
+
await fs.writeFile(temp, content, 'utf8');
|
|
81
|
+
await fs.rename(temp, file);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Non-blocking timeout
|
|
86
|
+
*/
|
|
87
|
+
static nonBlockingTimeout(time: number): Promise<void> {
|
|
88
|
+
return timers.setTimeout(time, undefined, { ref: false }).catch(() => { });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Blocking timeout
|
|
93
|
+
*/
|
|
94
|
+
static blockingTimeout(time: number): Promise<void> {
|
|
95
|
+
return timers.setTimeout(time, undefined, { ref: true }).catch(() => { });
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Queue new macrotask
|
|
100
|
+
*/
|
|
101
|
+
static queueMacroTask(): Promise<void> {
|
|
102
|
+
return timers.setImmediate(undefined);
|
|
103
|
+
}
|
|
104
|
+
}
|
package/src/watch.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { RuntimeIndex } from './manifest-index';
|
|
2
|
+
import { ExecUtil } from './exec';
|
|
3
|
+
import { ShutdownManager } from './shutdown';
|
|
4
|
+
import { Util } from './util';
|
|
5
|
+
|
|
6
|
+
export type WatchEvent = { file: string, action: 'create' | 'update' | 'delete', output: string, module: string, time: number };
|
|
7
|
+
|
|
8
|
+
export async function* watchCompiler(cfg?: { restartOnExit?: boolean, signal?: AbortSignal }): AsyncIterable<WatchEvent> {
|
|
9
|
+
// Load at runtime
|
|
10
|
+
const { CompilerClient } = await import('@travetto/compiler/support/server/client');
|
|
11
|
+
|
|
12
|
+
const client = new CompilerClient(RuntimeIndex.manifest, {
|
|
13
|
+
warn(message, ...args): void { console.error('warn', message, ...args); },
|
|
14
|
+
debug(message, ...args): void { console.error('debug', message, ...args); },
|
|
15
|
+
error(message, ...args): void { console.error('error', message, ...args); },
|
|
16
|
+
info(message, ...args): void { console.error('info', message, ...args); },
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const ctrl = new AbortController();
|
|
20
|
+
const remove = ShutdownManager.onGracefulShutdown(async () => ctrl.abort(), watchCompiler);
|
|
21
|
+
|
|
22
|
+
await client.waitForState(['compile-end', 'watch-start'], undefined, ctrl.signal);
|
|
23
|
+
|
|
24
|
+
if (!await client.isWatching()) { // If we get here, without a watch
|
|
25
|
+
while (!await client.isWatching()) { // Wait until watch starts
|
|
26
|
+
await Util.nonBlockingTimeout(1000 * 60);
|
|
27
|
+
}
|
|
28
|
+
} else {
|
|
29
|
+
yield* client.fetchEvents('change', { signal: ctrl.signal, enforceIteration: true });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
remove();
|
|
33
|
+
|
|
34
|
+
if (cfg?.restartOnExit) {
|
|
35
|
+
// We are done, request restart
|
|
36
|
+
await ShutdownManager.gracefulShutdown(ExecUtil.RESTART_EXIT_CODE);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
TransformerState, OnCall, LiteralUtil,
|
|
5
|
+
OnClass, AfterClass, OnMethod, AfterMethod, AfterFunction, OnFunction
|
|
6
|
+
} from '@travetto/transformer';
|
|
7
|
+
|
|
8
|
+
const CONSOLE_IMPORT = '@travetto/runtime/src/console';
|
|
9
|
+
const MANIFEST_MOD = '@travetto/manifest';
|
|
10
|
+
|
|
11
|
+
type CustomState = TransformerState & {
|
|
12
|
+
scope: { type: 'method' | 'class' | 'function', name: string }[];
|
|
13
|
+
imported?: ts.Identifier;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const VALID_LEVELS: Record<string, string> = {
|
|
17
|
+
log: 'info',
|
|
18
|
+
info: 'info',
|
|
19
|
+
debug: 'debug',
|
|
20
|
+
warn: 'warn',
|
|
21
|
+
error: 'error'
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Allows for removal of debug log messages depending on whether app is running
|
|
26
|
+
* in prod mode.
|
|
27
|
+
*/
|
|
28
|
+
export class ConsoleLogTransformer {
|
|
29
|
+
|
|
30
|
+
static initState(state: CustomState): void {
|
|
31
|
+
state.scope = state.scope ?? [];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@OnClass()
|
|
35
|
+
static startClassForLog(state: CustomState, node: ts.ClassDeclaration): typeof node {
|
|
36
|
+
this.initState(state);
|
|
37
|
+
state.scope.push({ type: 'class', name: node.name?.text ?? 'unknown' });
|
|
38
|
+
return node;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@AfterClass()
|
|
42
|
+
static leaveClassForLog(state: CustomState, node: ts.ClassDeclaration): typeof node {
|
|
43
|
+
state.scope.pop();
|
|
44
|
+
return node;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@OnMethod()
|
|
48
|
+
static startMethodForLog(state: CustomState, node: ts.MethodDeclaration): typeof node {
|
|
49
|
+
this.initState(state);
|
|
50
|
+
let name = 'unknown';
|
|
51
|
+
if (ts.isIdentifier(node.name) || ts.isPrivateIdentifier(node.name)) {
|
|
52
|
+
name = node.name?.text ?? name;
|
|
53
|
+
}
|
|
54
|
+
state.scope.push({ type: 'method', name });
|
|
55
|
+
return node;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@AfterMethod()
|
|
59
|
+
static leaveMethodForLog(state: CustomState, node: ts.MethodDeclaration): typeof node {
|
|
60
|
+
state.scope.pop();
|
|
61
|
+
return node;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@OnFunction()
|
|
65
|
+
static startFunctionForLog(state: CustomState, node: ts.FunctionDeclaration | ts.FunctionExpression): typeof node {
|
|
66
|
+
this.initState(state);
|
|
67
|
+
state.scope.push({ type: 'function', name: node.name?.text ?? 'unknown' });
|
|
68
|
+
return node;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@AfterFunction()
|
|
72
|
+
static leaveFunctionForLog(state: CustomState, node: ts.FunctionDeclaration | ts.FunctionExpression): typeof node {
|
|
73
|
+
state.scope.pop();
|
|
74
|
+
return node;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@OnCall()
|
|
78
|
+
static onLogCall(state: CustomState, node: ts.CallExpression): typeof node | ts.Identifier {
|
|
79
|
+
if (!ts.isPropertyAccessExpression(node.expression) || state.importName.startsWith(MANIFEST_MOD)) {
|
|
80
|
+
return node;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const chain = node.expression;
|
|
84
|
+
const name = chain.name;
|
|
85
|
+
const prop = chain.expression;
|
|
86
|
+
|
|
87
|
+
if (!ts.isIdentifier(prop) || prop.escapedText !== 'console' || !ts.isIdentifier(name)) {
|
|
88
|
+
return node;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const level = name.escapedText!;
|
|
92
|
+
|
|
93
|
+
if (VALID_LEVELS[level]) {
|
|
94
|
+
const ident = state.imported ??= state.importFile(CONSOLE_IMPORT, 'ᚕ_c').ident;
|
|
95
|
+
return state.factory.updateCallExpression(
|
|
96
|
+
node,
|
|
97
|
+
state.createAccess(ident, 'log'),
|
|
98
|
+
node.typeArguments,
|
|
99
|
+
[
|
|
100
|
+
LiteralUtil.fromLiteral(state.factory, {
|
|
101
|
+
level: state.factory.createStringLiteral(VALID_LEVELS[level]),
|
|
102
|
+
import: state.getModuleIdentifier(),
|
|
103
|
+
line: state.source.getLineAndCharacterOfPosition(node.getStart(state.source)).line + 1,
|
|
104
|
+
scope: state.scope?.map(x => x.name).join(':'),
|
|
105
|
+
args: node.arguments.slice(0)
|
|
106
|
+
}),
|
|
107
|
+
]
|
|
108
|
+
);
|
|
109
|
+
} else {
|
|
110
|
+
return node;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
TransformerState, OnMethod, OnClass, AfterClass,
|
|
5
|
+
AfterFunction, CoreUtil, SystemUtil, Import
|
|
6
|
+
} from '@travetto/transformer';
|
|
7
|
+
|
|
8
|
+
import type { FunctionMetadataTag } from '../src/function';
|
|
9
|
+
|
|
10
|
+
const RUNTIME_MOD = '@travetto/runtime';
|
|
11
|
+
const RUNTIME_MOD_SRC = `${RUNTIME_MOD}/src`;
|
|
12
|
+
const REGISTER_IMPORT = `${RUNTIME_MOD_SRC}/function`;
|
|
13
|
+
|
|
14
|
+
const methods = Symbol.for(`${RUNTIME_MOD}:methods`);
|
|
15
|
+
const cls = Symbol.for(`${RUNTIME_MOD}:class`);
|
|
16
|
+
const fn = Symbol.for(`${RUNTIME_MOD}:function`);
|
|
17
|
+
const registerImport = Symbol.for(`${RUNTIME_MOD}:registerImport`);
|
|
18
|
+
|
|
19
|
+
interface MetadataInfo {
|
|
20
|
+
[registerImport]?: Import;
|
|
21
|
+
[methods]?: Record<string, FunctionMetadataTag>;
|
|
22
|
+
[cls]?: FunctionMetadataTag;
|
|
23
|
+
[fn]?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Providing metadata for classes
|
|
28
|
+
*/
|
|
29
|
+
export class RegisterTransformer {
|
|
30
|
+
|
|
31
|
+
static #tag(state: TransformerState, node: ts.Node): FunctionMetadataTag {
|
|
32
|
+
const hash = SystemUtil.naiveHash(node.getText());
|
|
33
|
+
try {
|
|
34
|
+
const range = CoreUtil.getRangeOf(state.source, node) ?? [0, 0];
|
|
35
|
+
return { hash, lines: range };
|
|
36
|
+
} catch (err) {
|
|
37
|
+
return { hash, lines: [0, 0] };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static #valid({ importName: imp }: TransformerState): boolean {
|
|
42
|
+
return !imp.startsWith(REGISTER_IMPORT);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Hash each class
|
|
47
|
+
*/
|
|
48
|
+
@OnClass()
|
|
49
|
+
static collectClassMetadata(state: TransformerState & MetadataInfo, node: ts.ClassDeclaration): ts.ClassDeclaration {
|
|
50
|
+
if (!this.#valid(state)) {
|
|
51
|
+
return node; // Exclude self
|
|
52
|
+
}
|
|
53
|
+
state[cls] = this.#tag(state, node);
|
|
54
|
+
return node;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Hash each method
|
|
59
|
+
*/
|
|
60
|
+
@OnMethod()
|
|
61
|
+
static collectMethodMetadata(state: TransformerState & MetadataInfo, node: ts.MethodDeclaration): ts.MethodDeclaration {
|
|
62
|
+
if (state[cls] && ts.isIdentifier(node.name) && !CoreUtil.isAbstract(node) && ts.isClassDeclaration(node.parent)) {
|
|
63
|
+
state[methods] ??= {};
|
|
64
|
+
state[methods]![node.name.escapedText.toString()] = this.#tag(state, node);
|
|
65
|
+
}
|
|
66
|
+
return node;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* After visiting each class, register all the collected metadata
|
|
71
|
+
*/
|
|
72
|
+
@AfterClass()
|
|
73
|
+
static registerClassMetadata(state: TransformerState & MetadataInfo, node: ts.ClassDeclaration): ts.ClassDeclaration {
|
|
74
|
+
if (!state[cls]) {
|
|
75
|
+
return node;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
state[registerImport] ??= state.importFile(REGISTER_IMPORT);
|
|
79
|
+
|
|
80
|
+
const name = node.name?.escapedText.toString() ?? '';
|
|
81
|
+
|
|
82
|
+
const meta = state.factory.createCallExpression(
|
|
83
|
+
state.createAccess(state[registerImport].ident, 'register'),
|
|
84
|
+
[],
|
|
85
|
+
[
|
|
86
|
+
state.createIdentifier(name),
|
|
87
|
+
state.getModuleIdentifier(),
|
|
88
|
+
state.fromLiteral(state[cls]),
|
|
89
|
+
state.extendObjectLiteral(state[methods] || {}),
|
|
90
|
+
state.fromLiteral(CoreUtil.isAbstract(node)),
|
|
91
|
+
state.fromLiteral(name.endsWith(TransformerState.SYNTHETIC_EXT))
|
|
92
|
+
]
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
state[methods] = {};
|
|
96
|
+
delete state[cls];
|
|
97
|
+
|
|
98
|
+
return state.factory.updateClassDeclaration(
|
|
99
|
+
node,
|
|
100
|
+
node.modifiers,
|
|
101
|
+
node.name,
|
|
102
|
+
node.typeParameters,
|
|
103
|
+
node.heritageClauses,
|
|
104
|
+
[
|
|
105
|
+
state.createStaticField('Ⲑinit', meta),
|
|
106
|
+
...node.members
|
|
107
|
+
]
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Give proper functions a file name
|
|
113
|
+
*/
|
|
114
|
+
@AfterFunction()
|
|
115
|
+
static registerFunctionMetadata(state: TransformerState & MetadataInfo, node: ts.FunctionDeclaration | ts.FunctionExpression): typeof node {
|
|
116
|
+
if (!this.#valid(state)) {
|
|
117
|
+
return node;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (ts.isFunctionDeclaration(node) && node.name && node.parent && ts.isSourceFile(node.parent)) {
|
|
121
|
+
// If we have a class like function
|
|
122
|
+
state[registerImport] ??= state.importFile(REGISTER_IMPORT);
|
|
123
|
+
const tag = this.#tag(state, node);
|
|
124
|
+
const meta = state.factory.createCallExpression(
|
|
125
|
+
state.createAccess(state[registerImport].ident, 'register'),
|
|
126
|
+
[],
|
|
127
|
+
[
|
|
128
|
+
state.createIdentifier(node.name),
|
|
129
|
+
state.getModuleIdentifier(),
|
|
130
|
+
state.fromLiteral(tag),
|
|
131
|
+
]
|
|
132
|
+
);
|
|
133
|
+
state.addStatements([state.factory.createExpressionStatement(meta)]);
|
|
134
|
+
}
|
|
135
|
+
return node;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
|
|
3
|
+
import { TransformerState, OnFile } from '@travetto/transformer';
|
|
4
|
+
|
|
5
|
+
const PATH_REGEX = /^['"](node:)?path['"]$/;
|
|
6
|
+
const PATH_TARGET = '@travetto/manifest/src/path';
|
|
7
|
+
const SKIP_SRC = /^@travetto\/manifest\/(src|support)/;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Rewriting path imports to use manifest's path
|
|
11
|
+
*/
|
|
12
|
+
export class PathImportTransformer {
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Hash each class
|
|
16
|
+
*/
|
|
17
|
+
@OnFile()
|
|
18
|
+
static rewritePathImport(state: TransformerState, node: ts.SourceFile): ts.SourceFile {
|
|
19
|
+
if (SKIP_SRC.test(state.importName)) {
|
|
20
|
+
return node;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const stmt = node.statements.find((x): x is ts.ImportDeclaration =>
|
|
24
|
+
ts.isImportDeclaration(x) && PATH_REGEX.test(x.moduleSpecifier?.getText() ?? ''));
|
|
25
|
+
if (stmt) {
|
|
26
|
+
const updated = state.factory.updateImportDeclaration(
|
|
27
|
+
stmt,
|
|
28
|
+
stmt.modifiers,
|
|
29
|
+
stmt.importClause,
|
|
30
|
+
state.factory.createStringLiteral(PATH_TARGET),
|
|
31
|
+
stmt.attributes
|
|
32
|
+
);
|
|
33
|
+
return state.factory.updateSourceFile(node, node.statements.map(x =>
|
|
34
|
+
x === stmt ? updated : x
|
|
35
|
+
));
|
|
36
|
+
}
|
|
37
|
+
return node;
|
|
38
|
+
}
|
|
39
|
+
}
|