@esportsplus/typescript 0.26.3 → 0.27.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/build/compiler/ast.d.ts +17 -0
- package/build/compiler/ast.js +42 -0
- package/build/compiler/coordinator.js +22 -26
- package/build/compiler/imports.d.ts +2 -2
- package/build/compiler/imports.js +28 -14
- package/build/compiler/index.d.ts +1 -1
- package/build/compiler/index.js +1 -1
- package/build/compiler/uid.d.ts +1 -1
- package/build/compiler/uid.js +4 -12
- package/package.json +1 -1
- package/src/compiler/ast.ts +65 -0
- package/src/compiler/coordinator.ts +33 -43
- package/src/compiler/imports.ts +38 -21
- package/src/compiler/index.ts +2 -2
- package/src/compiler/uid.ts +5 -16
- package/build/compiler/ast/expression.d.ts +0 -4
- package/build/compiler/ast/expression.js +0 -23
- package/build/compiler/ast/index.d.ts +0 -3
- package/build/compiler/ast/index.js +0 -3
- package/build/compiler/ast/range.d.ts +0 -7
- package/build/compiler/ast/range.js +0 -10
- package/build/compiler/ast/visitor.d.ts +0 -3
- package/build/compiler/ast/visitor.js +0 -8
- package/src/compiler/ast/expression.ts +0 -34
- package/src/compiler/ast/index.ts +0 -3
- package/src/compiler/ast/range.ts +0 -21
- package/src/compiler/ast/visitor.ts +0 -13
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
type Range = {
|
|
3
|
+
end: number;
|
|
4
|
+
start: number;
|
|
5
|
+
};
|
|
6
|
+
declare const _default: {
|
|
7
|
+
expression: {
|
|
8
|
+
name: (node: ts.Expression) => string | null;
|
|
9
|
+
};
|
|
10
|
+
inRange: (ranges: Range[], start: number, end: number) => boolean;
|
|
11
|
+
property: {
|
|
12
|
+
path: (node: ts.Expression) => string | null;
|
|
13
|
+
};
|
|
14
|
+
test: (node: ts.Node, fn: (n: ts.Node) => boolean) => boolean;
|
|
15
|
+
};
|
|
16
|
+
export default _default;
|
|
17
|
+
export type { Range };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
const expression = {
|
|
3
|
+
name: (node) => {
|
|
4
|
+
if (ts.isIdentifier(node)) {
|
|
5
|
+
return node.text;
|
|
6
|
+
}
|
|
7
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
8
|
+
return property.path(node);
|
|
9
|
+
}
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
const inRange = (ranges, start, end) => {
|
|
14
|
+
for (let i = 0, n = ranges.length; i < n; i++) {
|
|
15
|
+
let r = ranges[i];
|
|
16
|
+
if (start >= r.start && end <= r.end) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
21
|
+
};
|
|
22
|
+
const property = {
|
|
23
|
+
path: (node) => {
|
|
24
|
+
let current = node, parts = [];
|
|
25
|
+
while (ts.isPropertyAccessExpression(current)) {
|
|
26
|
+
parts.push(current.name.text);
|
|
27
|
+
current = current.expression;
|
|
28
|
+
}
|
|
29
|
+
if (ts.isIdentifier(current)) {
|
|
30
|
+
parts.push(current.text);
|
|
31
|
+
return parts.reverse().join('.');
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
const test = (node, fn) => {
|
|
37
|
+
if (fn(node)) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
return !!ts.forEachChild(node, child => test(child, fn) || undefined);
|
|
41
|
+
};
|
|
42
|
+
export default { expression, inRange, property, test };
|
|
@@ -28,7 +28,7 @@ function applyPrepend(code, file, prepend) {
|
|
|
28
28
|
if (prepend.length === 0) {
|
|
29
29
|
return code;
|
|
30
30
|
}
|
|
31
|
-
let position = 0
|
|
31
|
+
let position = 0;
|
|
32
32
|
for (let i = 0, n = file.statements.length; i < n; i++) {
|
|
33
33
|
let stmt = file.statements[i];
|
|
34
34
|
if (ts.isImportDeclaration(stmt)) {
|
|
@@ -39,9 +39,9 @@ function applyPrepend(code, file, prepend) {
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
if (position === 0) {
|
|
42
|
-
return
|
|
42
|
+
return prepend.join('\n') + code;
|
|
43
43
|
}
|
|
44
|
-
return code.slice(0, position) + '\n' +
|
|
44
|
+
return code.slice(0, position) + prepend.join('\n') + code.slice(position);
|
|
45
45
|
}
|
|
46
46
|
function hasPattern(code, patterns) {
|
|
47
47
|
for (let i = 0, n = patterns.length; i < n; i++) {
|
|
@@ -52,11 +52,10 @@ function hasPattern(code, patterns) {
|
|
|
52
52
|
return false;
|
|
53
53
|
}
|
|
54
54
|
function modify(code, file, pkg, options) {
|
|
55
|
-
let { namespace } = options;
|
|
56
55
|
if (!options.add && !options.namespace && !options.remove) {
|
|
57
56
|
return code;
|
|
58
57
|
}
|
|
59
|
-
let add = options.add ? new Set(options.add) : null, found = imports.
|
|
58
|
+
let { namespace } = options, add = options.add ? new Set(options.add) : null, found = imports.all(file, pkg);
|
|
60
59
|
if (found.length === 0) {
|
|
61
60
|
let statements = [];
|
|
62
61
|
if (namespace) {
|
|
@@ -70,7 +69,7 @@ function modify(code, file, pkg, options) {
|
|
|
70
69
|
}
|
|
71
70
|
return statements.join('\n') + '\n' + code;
|
|
72
71
|
}
|
|
73
|
-
let specifiers = new Set();
|
|
72
|
+
let remove = options.remove ? new Set(options.remove) : null, specifiers = new Set();
|
|
74
73
|
for (let i = 0, n = found.length; i < n; i++) {
|
|
75
74
|
for (let [name, alias] of found[i].specifiers) {
|
|
76
75
|
if (!remove || (!remove.has(name) && !remove.has(alias))) {
|
|
@@ -118,39 +117,36 @@ const transform = (plugins, code, file, program, shared) => {
|
|
|
118
117
|
if (plugins.length === 0) {
|
|
119
118
|
return { changed: false, code, sourceFile: file };
|
|
120
119
|
}
|
|
121
|
-
let
|
|
120
|
+
let currentCode = code, currentFile = file;
|
|
122
121
|
for (let i = 0, n = plugins.length; i < n; i++) {
|
|
123
122
|
let plugin = plugins[i];
|
|
124
123
|
if (plugin.patterns && !hasPattern(currentCode, plugin.patterns)) {
|
|
125
124
|
continue;
|
|
126
125
|
}
|
|
127
|
-
let
|
|
126
|
+
let { imports, prepend, replacements } = plugin.transform({
|
|
128
127
|
checker: program.getTypeChecker(),
|
|
129
128
|
code: currentCode,
|
|
130
129
|
program,
|
|
131
130
|
shared,
|
|
132
|
-
sourceFile:
|
|
131
|
+
sourceFile: currentFile
|
|
133
132
|
});
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
(
|
|
137
|
-
if (!hasChanges) {
|
|
138
|
-
continue;
|
|
139
|
-
}
|
|
140
|
-
changed = true;
|
|
141
|
-
if (result.replacements && result.replacements.length > 0) {
|
|
142
|
-
currentCode = applyIntents(currentCode, currentSourceFile, result.replacements);
|
|
143
|
-
currentSourceFile = ts.createSourceFile(currentSourceFile.fileName, currentCode, currentSourceFile.languageVersion, true);
|
|
133
|
+
if (replacements?.length) {
|
|
134
|
+
currentCode = applyIntents(currentCode, currentFile, replacements);
|
|
135
|
+
currentFile = ts.createSourceFile(currentFile.fileName, currentCode, currentFile.languageVersion, true);
|
|
144
136
|
}
|
|
145
|
-
if (
|
|
146
|
-
currentCode = applyPrepend(currentCode,
|
|
147
|
-
|
|
137
|
+
if (prepend?.length) {
|
|
138
|
+
currentCode = applyPrepend(currentCode, currentFile, prepend);
|
|
139
|
+
currentFile = ts.createSourceFile(currentFile.fileName, currentCode, currentFile.languageVersion, true);
|
|
148
140
|
}
|
|
149
|
-
if (
|
|
150
|
-
currentCode = applyImports(currentCode,
|
|
151
|
-
|
|
141
|
+
if (imports?.length) {
|
|
142
|
+
currentCode = applyImports(currentCode, currentFile, imports);
|
|
143
|
+
currentFile = ts.createSourceFile(currentFile.fileName, currentCode, currentFile.languageVersion, true);
|
|
152
144
|
}
|
|
153
145
|
}
|
|
154
|
-
return {
|
|
146
|
+
return {
|
|
147
|
+
changed: currentCode !== code,
|
|
148
|
+
code: currentCode,
|
|
149
|
+
sourceFile: currentFile
|
|
150
|
+
};
|
|
155
151
|
};
|
|
156
152
|
export default { transform };
|
|
@@ -10,8 +10,8 @@ type ModifyOptions = {
|
|
|
10
10
|
remove?: Iterable<string>;
|
|
11
11
|
};
|
|
12
12
|
declare const _default: {
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
all: (file: ts.SourceFile, pkg: string) => ImportInfo[];
|
|
14
|
+
includes: (checker: ts.TypeChecker, node: ts.Node, pkg: string, symbolName?: string) => boolean;
|
|
15
15
|
};
|
|
16
16
|
export default _default;
|
|
17
17
|
export type { ImportInfo, ModifyOptions };
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { ts } from '../index.js';
|
|
2
|
-
|
|
2
|
+
let cache = new WeakMap();
|
|
3
|
+
const all = (file, pkg) => {
|
|
3
4
|
let imports = [];
|
|
4
|
-
for (let i = 0, n =
|
|
5
|
-
let stmt =
|
|
5
|
+
for (let i = 0, n = file.statements.length; i < n; i++) {
|
|
6
|
+
let stmt = file.statements[i];
|
|
6
7
|
if (!ts.isImportDeclaration(stmt)) {
|
|
7
8
|
continue;
|
|
8
9
|
}
|
|
9
10
|
let moduleSpecifier = stmt.moduleSpecifier;
|
|
10
|
-
if (!ts.isStringLiteral(moduleSpecifier) || moduleSpecifier.text !==
|
|
11
|
+
if (!ts.isStringLiteral(moduleSpecifier) || moduleSpecifier.text !== pkg) {
|
|
11
12
|
continue;
|
|
12
13
|
}
|
|
13
14
|
let bindings = stmt.importClause?.namedBindings, specifiers = new Map();
|
|
@@ -17,19 +18,32 @@ const find = (sourceFile, packageName) => {
|
|
|
17
18
|
specifiers.set(propertyName, name);
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
|
-
imports.push({ end: stmt.end, specifiers, start: stmt.getStart(
|
|
21
|
+
imports.push({ end: stmt.end, specifiers, start: stmt.getStart(file) });
|
|
21
22
|
}
|
|
22
23
|
return imports;
|
|
23
24
|
};
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
const includes = (checker, node, pkg, symbolName) => {
|
|
26
|
+
let file = node.getSourceFile(), imports = cache.get(file);
|
|
27
|
+
if (!imports) {
|
|
28
|
+
imports = new Map();
|
|
29
|
+
cache.set(file, imports);
|
|
30
|
+
}
|
|
31
|
+
let varnames = imports.get(pkg);
|
|
32
|
+
if (!varnames) {
|
|
33
|
+
varnames = new Set();
|
|
34
|
+
for (let info of all(file, pkg)) {
|
|
35
|
+
for (let [, varname] of info.specifiers) {
|
|
36
|
+
varnames.add(varname);
|
|
37
|
+
}
|
|
28
38
|
}
|
|
39
|
+
imports.set(pkg, varnames);
|
|
40
|
+
}
|
|
41
|
+
if (ts.isIdentifier(node) && varnames.has(node.text) && (!symbolName || node.text === symbolName)) {
|
|
42
|
+
return true;
|
|
29
43
|
}
|
|
30
44
|
let symbol = checker.getSymbolAtLocation(node);
|
|
31
45
|
if (!symbol) {
|
|
32
|
-
if (
|
|
46
|
+
if (ts.isIdentifier(node) && varnames.has(node.text)) {
|
|
33
47
|
return true;
|
|
34
48
|
}
|
|
35
49
|
return false;
|
|
@@ -38,17 +52,17 @@ const inPackage = (checker, node, pkg, symbolName, packageImports) => {
|
|
|
38
52
|
symbol = checker.getAliasedSymbol(symbol);
|
|
39
53
|
}
|
|
40
54
|
if (symbolName && symbol.name !== symbolName) {
|
|
41
|
-
return
|
|
55
|
+
return ts.isIdentifier(node) && varnames.has(node.text);
|
|
42
56
|
}
|
|
43
57
|
let declarations = symbol.getDeclarations();
|
|
44
58
|
if (!declarations || declarations.length === 0) {
|
|
45
|
-
return
|
|
59
|
+
return ts.isIdentifier(node) && varnames.has(node.text);
|
|
46
60
|
}
|
|
47
61
|
for (let i = 0, n = declarations.length; i < n; i++) {
|
|
48
62
|
if (declarations[i].getSourceFile().fileName.includes(pkg)) {
|
|
49
63
|
return true;
|
|
50
64
|
}
|
|
51
65
|
}
|
|
52
|
-
return
|
|
66
|
+
return ts.isIdentifier(node) && varnames.has(node.text);
|
|
53
67
|
};
|
|
54
|
-
export default {
|
|
68
|
+
export default { all, includes };
|
package/build/compiler/index.js
CHANGED
package/build/compiler/uid.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: (
|
|
1
|
+
declare const _default: (name: string) => string;
|
|
2
2
|
export default _default;
|
package/build/compiler/uid.js
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
let
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
for (let i = 0, n = str.length; i < n; i++) {
|
|
6
|
-
h ^= str.charCodeAt(i);
|
|
7
|
-
h = Math.imul(h, 0x01000193);
|
|
8
|
-
}
|
|
9
|
-
return ((h >>> 0).toString(36) + Math.abs(h).toString(36)).replace(INVALID_CHARS, '');
|
|
10
|
-
}
|
|
11
|
-
export default (prefix) => {
|
|
12
|
-
return prefix + '_' + hash(prefix) + (counter++).toString(36);
|
|
1
|
+
import { uuid } from '@esportsplus/utilities';
|
|
2
|
+
let i = 0, namespace = uuid().replace(/[^A-Za-z0-9]/g, '');
|
|
3
|
+
export default (name) => {
|
|
4
|
+
return name + '_' + namespace + (i++).toString(36);
|
|
13
5
|
};
|
package/package.json
CHANGED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
type Range = {
|
|
5
|
+
end: number;
|
|
6
|
+
start: number;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
const expression = {
|
|
11
|
+
name: (node: ts.Expression): string | null => {
|
|
12
|
+
if (ts.isIdentifier(node)) {
|
|
13
|
+
return node.text;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
17
|
+
return property.path(node);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const inRange = (ranges: Range[], start: number, end: number): boolean => {
|
|
25
|
+
for (let i = 0, n = ranges.length; i < n; i++) {
|
|
26
|
+
let r = ranges[i];
|
|
27
|
+
|
|
28
|
+
if (start >= r.start && end <= r.end) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return false;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const property = {
|
|
37
|
+
path: (node: ts.Expression): string | null => {
|
|
38
|
+
let current: ts.Node = node,
|
|
39
|
+
parts: string[] = [];
|
|
40
|
+
|
|
41
|
+
while (ts.isPropertyAccessExpression(current)) {
|
|
42
|
+
parts.push(current.name.text);
|
|
43
|
+
current = current.expression;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (ts.isIdentifier(current)) {
|
|
47
|
+
parts.push(current.text);
|
|
48
|
+
return parts.reverse().join('.');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const test = (node: ts.Node, fn: (n: ts.Node) => boolean): boolean => {
|
|
56
|
+
if (fn(node)) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return !!ts.forEachChild(node, child => test(child, fn) || undefined);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
export default { expression, inRange, property, test };
|
|
65
|
+
export type { Range };
|
|
@@ -53,8 +53,7 @@ function applyPrepend(code: string, file: ts.SourceFile, prepend: string[]): str
|
|
|
53
53
|
return code;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
let position = 0
|
|
57
|
-
text = prepend.join('\n') + '\n';
|
|
56
|
+
let position = 0;
|
|
58
57
|
|
|
59
58
|
for (let i = 0, n = file.statements.length; i < n; i++) {
|
|
60
59
|
let stmt = file.statements[i];
|
|
@@ -68,10 +67,10 @@ function applyPrepend(code: string, file: ts.SourceFile, prepend: string[]): str
|
|
|
68
67
|
}
|
|
69
68
|
|
|
70
69
|
if (position === 0) {
|
|
71
|
-
return
|
|
70
|
+
return prepend.join('\n') + code;
|
|
72
71
|
}
|
|
73
72
|
|
|
74
|
-
return code.slice(0, position) + '\n' +
|
|
73
|
+
return code.slice(0, position) + prepend.join('\n') + code.slice(position);
|
|
75
74
|
}
|
|
76
75
|
|
|
77
76
|
function hasPattern(code: string, patterns: string[]): boolean {
|
|
@@ -85,16 +84,13 @@ function hasPattern(code: string, patterns: string[]): boolean {
|
|
|
85
84
|
}
|
|
86
85
|
|
|
87
86
|
function modify(code: string, file: ts.SourceFile, pkg: string, options: ModifyOptions): string {
|
|
88
|
-
let { namespace } = options;
|
|
89
|
-
|
|
90
|
-
// Fast path: nothing to change
|
|
91
87
|
if (!options.add && !options.namespace && !options.remove) {
|
|
92
88
|
return code;
|
|
93
89
|
}
|
|
94
90
|
|
|
95
|
-
let
|
|
96
|
-
|
|
97
|
-
|
|
91
|
+
let { namespace } = options,
|
|
92
|
+
add = options.add ? new Set(options.add) : null,
|
|
93
|
+
found = imports.all(file, pkg);
|
|
98
94
|
|
|
99
95
|
if (found.length === 0) {
|
|
100
96
|
let statements: string[] = [];
|
|
@@ -114,8 +110,9 @@ function modify(code: string, file: ts.SourceFile, pkg: string, options: ModifyO
|
|
|
114
110
|
return statements.join('\n') + '\n' + code;
|
|
115
111
|
}
|
|
116
112
|
|
|
117
|
-
|
|
118
|
-
|
|
113
|
+
let remove = options.remove ? new Set(options.remove) : null,
|
|
114
|
+
// Collect all non-removed specifiers from existing imports
|
|
115
|
+
specifiers = new Set<string>();
|
|
119
116
|
|
|
120
117
|
for (let i = 0, n = found.length; i < n; i++) {
|
|
121
118
|
for (let [name, alias] of found[i].specifiers) {
|
|
@@ -190,9 +187,8 @@ const transform = (
|
|
|
190
187
|
return { changed: false, code, sourceFile: file };
|
|
191
188
|
}
|
|
192
189
|
|
|
193
|
-
let
|
|
194
|
-
|
|
195
|
-
currentSourceFile = file;
|
|
190
|
+
let currentCode = code,
|
|
191
|
+
currentFile = file;
|
|
196
192
|
|
|
197
193
|
for (let i = 0, n = plugins.length; i < n; i++) {
|
|
198
194
|
let plugin = plugins[i];
|
|
@@ -201,56 +197,50 @@ const transform = (
|
|
|
201
197
|
continue;
|
|
202
198
|
}
|
|
203
199
|
|
|
204
|
-
let
|
|
200
|
+
let { imports, prepend, replacements } = plugin.transform({
|
|
205
201
|
checker: program.getTypeChecker(),
|
|
206
202
|
code: currentCode,
|
|
207
203
|
program,
|
|
208
204
|
shared,
|
|
209
|
-
sourceFile:
|
|
205
|
+
sourceFile: currentFile
|
|
210
206
|
});
|
|
211
207
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if (!hasChanges) {
|
|
217
|
-
continue;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
changed = true;
|
|
221
|
-
|
|
222
|
-
if (result.replacements && result.replacements.length > 0) {
|
|
223
|
-
currentCode = applyIntents(currentCode, currentSourceFile, result.replacements);
|
|
224
|
-
currentSourceFile = ts.createSourceFile(
|
|
225
|
-
currentSourceFile.fileName,
|
|
208
|
+
if (replacements?.length) {
|
|
209
|
+
currentCode = applyIntents(currentCode, currentFile, replacements);
|
|
210
|
+
currentFile = ts.createSourceFile(
|
|
211
|
+
currentFile.fileName,
|
|
226
212
|
currentCode,
|
|
227
|
-
|
|
213
|
+
currentFile.languageVersion,
|
|
228
214
|
true
|
|
229
215
|
);
|
|
230
216
|
}
|
|
231
217
|
|
|
232
|
-
if (
|
|
233
|
-
currentCode = applyPrepend(currentCode,
|
|
234
|
-
|
|
235
|
-
|
|
218
|
+
if (prepend?.length) {
|
|
219
|
+
currentCode = applyPrepend(currentCode, currentFile, prepend);
|
|
220
|
+
currentFile = ts.createSourceFile(
|
|
221
|
+
currentFile.fileName,
|
|
236
222
|
currentCode,
|
|
237
|
-
|
|
223
|
+
currentFile.languageVersion,
|
|
238
224
|
true
|
|
239
225
|
);
|
|
240
226
|
}
|
|
241
227
|
|
|
242
|
-
if (
|
|
243
|
-
currentCode = applyImports(currentCode,
|
|
244
|
-
|
|
245
|
-
|
|
228
|
+
if (imports?.length) {
|
|
229
|
+
currentCode = applyImports(currentCode, currentFile, imports);
|
|
230
|
+
currentFile = ts.createSourceFile(
|
|
231
|
+
currentFile.fileName,
|
|
246
232
|
currentCode,
|
|
247
|
-
|
|
233
|
+
currentFile.languageVersion,
|
|
248
234
|
true
|
|
249
235
|
);
|
|
250
236
|
}
|
|
251
237
|
}
|
|
252
238
|
|
|
253
|
-
return {
|
|
239
|
+
return {
|
|
240
|
+
changed: currentCode !== code,
|
|
241
|
+
code: currentCode,
|
|
242
|
+
sourceFile: currentFile
|
|
243
|
+
};
|
|
254
244
|
};
|
|
255
245
|
|
|
256
246
|
|
package/src/compiler/imports.ts
CHANGED
|
@@ -14,12 +14,15 @@ type ModifyOptions = {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
|
|
17
|
+
let cache = new WeakMap<ts.SourceFile, Map<string, Set<string>>>();
|
|
18
|
+
|
|
19
|
+
|
|
17
20
|
// Find all named imports from a specific package
|
|
18
|
-
const
|
|
21
|
+
const all = (file: ts.SourceFile, pkg: string): ImportInfo[] => {
|
|
19
22
|
let imports: ImportInfo[] = [];
|
|
20
23
|
|
|
21
|
-
for (let i = 0, n =
|
|
22
|
-
let stmt =
|
|
24
|
+
for (let i = 0, n = file.statements.length; i < n; i++) {
|
|
25
|
+
let stmt = file.statements[i];
|
|
23
26
|
|
|
24
27
|
if (!ts.isImportDeclaration(stmt)) {
|
|
25
28
|
continue;
|
|
@@ -27,7 +30,7 @@ const find = (sourceFile: ts.SourceFile, packageName: string): ImportInfo[] => {
|
|
|
27
30
|
|
|
28
31
|
let moduleSpecifier = stmt.moduleSpecifier;
|
|
29
32
|
|
|
30
|
-
if (!ts.isStringLiteral(moduleSpecifier) || moduleSpecifier.text !==
|
|
33
|
+
if (!ts.isStringLiteral(moduleSpecifier) || moduleSpecifier.text !== pkg) {
|
|
31
34
|
continue;
|
|
32
35
|
}
|
|
33
36
|
|
|
@@ -44,32 +47,46 @@ const find = (sourceFile: ts.SourceFile, packageName: string): ImportInfo[] => {
|
|
|
44
47
|
}
|
|
45
48
|
}
|
|
46
49
|
|
|
47
|
-
imports.push({ end: stmt.end, specifiers, start: stmt.getStart(
|
|
50
|
+
imports.push({ end: stmt.end, specifiers, start: stmt.getStart(file) });
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
return imports;
|
|
51
54
|
};
|
|
52
55
|
|
|
53
56
|
// Check if node's symbol originates from a specific package (with optional symbol name validation)
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
57
|
+
const includes = (checker: ts.TypeChecker, node: ts.Node, pkg: string, symbolName?: string): boolean => {
|
|
58
|
+
let file = node.getSourceFile(),
|
|
59
|
+
imports = cache.get(file);
|
|
60
|
+
|
|
61
|
+
if (!imports) {
|
|
62
|
+
imports = new Map();
|
|
63
|
+
cache.set(file, imports);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let varnames = imports.get(pkg);
|
|
67
|
+
|
|
68
|
+
if (!varnames) {
|
|
69
|
+
varnames = new Set();
|
|
70
|
+
|
|
71
|
+
for (let info of all(file, pkg)) {
|
|
72
|
+
for (let [, varname] of info.specifiers) {
|
|
73
|
+
varnames.add(varname);
|
|
74
|
+
}
|
|
65
75
|
}
|
|
76
|
+
|
|
77
|
+
imports.set(pkg, varnames);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Fast path: identifier matches known import and expected name
|
|
81
|
+
if (ts.isIdentifier(node) && varnames.has(node.text) && (!symbolName || node.text === symbolName)) {
|
|
82
|
+
return true;
|
|
66
83
|
}
|
|
67
84
|
|
|
68
85
|
let symbol = checker.getSymbolAtLocation(node);
|
|
69
86
|
|
|
70
87
|
if (!symbol) {
|
|
71
88
|
// Fallback: aliased import - check if local name is in imports
|
|
72
|
-
if (
|
|
89
|
+
if (ts.isIdentifier(node) && varnames.has(node.text)) {
|
|
73
90
|
return true;
|
|
74
91
|
}
|
|
75
92
|
|
|
@@ -83,13 +100,13 @@ const inPackage = (
|
|
|
83
100
|
|
|
84
101
|
// Check symbol name if specified
|
|
85
102
|
if (symbolName && symbol.name !== symbolName) {
|
|
86
|
-
return
|
|
103
|
+
return ts.isIdentifier(node) && varnames.has(node.text);
|
|
87
104
|
}
|
|
88
105
|
|
|
89
106
|
let declarations = symbol.getDeclarations();
|
|
90
107
|
|
|
91
108
|
if (!declarations || declarations.length === 0) {
|
|
92
|
-
return
|
|
109
|
+
return ts.isIdentifier(node) && varnames.has(node.text);
|
|
93
110
|
}
|
|
94
111
|
|
|
95
112
|
// Check if any declaration is from the expected package
|
|
@@ -99,9 +116,9 @@ const inPackage = (
|
|
|
99
116
|
}
|
|
100
117
|
}
|
|
101
118
|
|
|
102
|
-
return
|
|
119
|
+
return ts.isIdentifier(node) && varnames.has(node.text);
|
|
103
120
|
};
|
|
104
121
|
|
|
105
122
|
|
|
106
|
-
export default {
|
|
123
|
+
export default { all, includes };
|
|
107
124
|
export type { ImportInfo, ModifyOptions };
|
package/src/compiler/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { default as ast } from './ast';
|
|
2
2
|
export { default as code } from './code';
|
|
3
3
|
export { default as coordinator } from './coordinator';
|
|
4
4
|
export { default as imports } from './imports';
|
|
5
|
-
export { default as plugin } from './plugins
|
|
5
|
+
export { default as plugin } from './plugins';
|
|
6
6
|
export { default as uid } from './uid';
|
|
7
7
|
export type * from './types';
|
package/src/compiler/uid.ts
CHANGED
|
@@ -1,21 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import { uuid } from '@esportsplus/utilities';
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
let
|
|
4
|
+
let i = 0,
|
|
5
|
+
namespace = uuid().replace(/[^A-Za-z0-9]/g, '');
|
|
5
6
|
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
for (let i = 0, n = str.length; i < n; i++) {
|
|
11
|
-
h ^= str.charCodeAt(i);
|
|
12
|
-
h = Math.imul(h, 0x01000193);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
return ((h >>> 0).toString(36) + Math.abs(h).toString(36)).replace(INVALID_CHARS, '');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
export default (prefix: string): string => {
|
|
20
|
-
return prefix + '_' + hash(prefix) + (counter++).toString(36);
|
|
8
|
+
export default (name: string): string => {
|
|
9
|
+
return name + '_' + namespace + (i++).toString(36);
|
|
21
10
|
};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import ts from 'typescript';
|
|
2
|
-
const getExpressionName = (node) => {
|
|
3
|
-
if (ts.isIdentifier(node)) {
|
|
4
|
-
return node.text;
|
|
5
|
-
}
|
|
6
|
-
if (ts.isPropertyAccessExpression(node)) {
|
|
7
|
-
return getPropertyPath(node);
|
|
8
|
-
}
|
|
9
|
-
return null;
|
|
10
|
-
};
|
|
11
|
-
const getPropertyPath = (node) => {
|
|
12
|
-
let current = node, parts = [];
|
|
13
|
-
while (ts.isPropertyAccessExpression(current)) {
|
|
14
|
-
parts.push(current.name.text);
|
|
15
|
-
current = current.expression;
|
|
16
|
-
}
|
|
17
|
-
if (ts.isIdentifier(current)) {
|
|
18
|
-
parts.push(current.text);
|
|
19
|
-
return parts.reverse().join('.');
|
|
20
|
-
}
|
|
21
|
-
return null;
|
|
22
|
-
};
|
|
23
|
-
export { getExpressionName, getPropertyPath };
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import ts from 'typescript';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const getExpressionName = (node: ts.Expression): string | null => {
|
|
5
|
-
if (ts.isIdentifier(node)) {
|
|
6
|
-
return node.text;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
if (ts.isPropertyAccessExpression(node)) {
|
|
10
|
-
return getPropertyPath(node);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
return null;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const getPropertyPath = (node: ts.Expression): string | null => {
|
|
17
|
-
let current: ts.Node = node,
|
|
18
|
-
parts: string[] = [];
|
|
19
|
-
|
|
20
|
-
while (ts.isPropertyAccessExpression(current)) {
|
|
21
|
-
parts.push(current.name.text);
|
|
22
|
-
current = current.expression;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (ts.isIdentifier(current)) {
|
|
26
|
-
parts.push(current.text);
|
|
27
|
-
return parts.reverse().join('.');
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return null;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
export { getExpressionName, getPropertyPath };
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
type Range = {
|
|
2
|
-
end: number;
|
|
3
|
-
start: number;
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const inRange = (ranges: Range[], start: number, end: number): boolean => {
|
|
8
|
-
for (let i = 0, n = ranges.length; i < n; i++) {
|
|
9
|
-
let r = ranges[i];
|
|
10
|
-
|
|
11
|
-
if (start >= r.start && end <= r.end) {
|
|
12
|
-
return true;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
return false;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
export { inRange };
|
|
21
|
-
export type { Range };
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import ts from 'typescript';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const hasMatch = (node: ts.Node, predicate: (n: ts.Node) => boolean): boolean => {
|
|
5
|
-
if (predicate(node)) {
|
|
6
|
-
return true;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
return !!ts.forEachChild(node, child => hasMatch(child, predicate) || undefined);
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export { hasMatch };
|