@eventra_dev/eventra-cli 0.1.24 → 0.1.26
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/dist/commands/check.js +40 -16
- package/dist/commands/sync.js +40 -38
- package/dist/commands/watch.js +90 -36
- package/dist/engine/callResolver.js +52 -4
- package/dist/engine/engine.js +66 -32
- package/dist/engine/exportResolver.js +16 -4
- package/dist/engine/functionAnalyzer.js +66 -13
- package/dist/engine/graph.js +40 -4
- package/dist/engine/languageService.js +83 -20
- package/dist/engine/resolver.js +29 -21
- package/dist/engine/scanner.js +57 -46
- package/dist/engine/trackingDetector.js +68 -0
- package/dist/utils/getVirtualFile.js +8 -0
- package/dist/utils/processFile.js +0 -9
- package/dist/utils/universal.js +25 -87
- package/package.json +1 -1
- package/src/commands/check.ts +49 -29
- package/src/commands/sync.ts +48 -47
- package/src/commands/watch.ts +105 -37
- package/src/engine/callResolver.ts +77 -6
- package/src/engine/engine.ts +80 -33
- package/src/engine/exportResolver.ts +22 -5
- package/src/engine/functionAnalyzer.ts +76 -16
- package/src/engine/graph.ts +45 -6
- package/src/engine/languageService.ts +100 -29
- package/src/engine/resolver.ts +36 -27
- package/src/engine/scanner.ts +72 -50
- package/src/engine/trackingDetector.ts +94 -0
- package/src/types.ts +0 -3
- package/src/utils/getVirtualFile.ts +5 -0
- package/src/utils/processFile.ts +0 -9
- package/src/utils/universal.ts +26 -102
package/dist/commands/check.js
CHANGED
|
@@ -7,9 +7,11 @@ exports.check = check;
|
|
|
7
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
8
|
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
9
9
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
10
11
|
const config_1 = require("../utils/config");
|
|
11
12
|
const engine_1 = require("../engine/engine");
|
|
12
13
|
const processFile_1 = require("../utils/processFile");
|
|
14
|
+
const getVirtualFile_1 = require("../utils/getVirtualFile");
|
|
13
15
|
async function check({ fix = false }) {
|
|
14
16
|
const config = await (0, config_1.loadConfig)();
|
|
15
17
|
if (!config) {
|
|
@@ -19,37 +21,59 @@ async function check({ fix = false }) {
|
|
|
19
21
|
console.log(chalk_1.default.blue("Checking events..."));
|
|
20
22
|
const files = await (0, fast_glob_1.default)(config.sync.include, {
|
|
21
23
|
ignore: config.sync.exclude,
|
|
24
|
+
absolute: true,
|
|
22
25
|
});
|
|
23
26
|
const engine = new engine_1.EventraEngine(process.cwd());
|
|
27
|
+
const toScan = new Set();
|
|
28
|
+
const cache = new Map();
|
|
29
|
+
// COLLECT + CACHE
|
|
24
30
|
for (const file of files) {
|
|
25
31
|
try {
|
|
26
32
|
const raw = await promises_1.default.readFile(file, "utf-8");
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
catch { }
|
|
33
|
+
if (raw.length > 2_000_000)
|
|
34
|
+
continue;
|
|
35
|
+
const parsed = (0, processFile_1.processFile)(file, raw);
|
|
36
|
+
cache.set(file, parsed);
|
|
37
|
+
toScan.add(file);
|
|
38
|
+
for (const dep of parsed.deps) {
|
|
39
|
+
toScan.add(path_1.default.resolve(dep));
|
|
36
40
|
}
|
|
37
41
|
}
|
|
38
|
-
catch
|
|
39
|
-
|
|
42
|
+
catch { }
|
|
43
|
+
}
|
|
44
|
+
// PRELOAD
|
|
45
|
+
for (const file of toScan) {
|
|
46
|
+
try {
|
|
47
|
+
let parsed = cache.get(file);
|
|
48
|
+
if (!parsed) {
|
|
49
|
+
const raw = await promises_1.default.readFile(file, "utf-8");
|
|
50
|
+
parsed = (0, processFile_1.processFile)(file, raw);
|
|
51
|
+
cache.set(file, parsed);
|
|
52
|
+
}
|
|
53
|
+
const virtual = (0, getVirtualFile_1.getVirtualFile)(file);
|
|
54
|
+
engine.preloadFile(virtual, parsed.content);
|
|
55
|
+
}
|
|
56
|
+
catch { }
|
|
57
|
+
}
|
|
58
|
+
// SCAN
|
|
59
|
+
for (const file of toScan) {
|
|
60
|
+
try {
|
|
61
|
+
const parsed = cache.get(file);
|
|
62
|
+
if (!parsed)
|
|
63
|
+
continue;
|
|
64
|
+
const virtual = (0, getVirtualFile_1.getVirtualFile)(file);
|
|
65
|
+
engine.scanFile(virtual, parsed.content, config);
|
|
40
66
|
}
|
|
67
|
+
catch { }
|
|
41
68
|
}
|
|
69
|
+
// DIFF
|
|
42
70
|
const found = new Set(engine.getAllEvents());
|
|
43
71
|
const known = new Set(config.events ?? []);
|
|
44
72
|
const newEvents = [...found].filter(e => !known.has(e));
|
|
45
73
|
const removed = [...known].filter(e => !found.has(e));
|
|
46
74
|
// FIX MODE
|
|
47
75
|
if (fix) {
|
|
48
|
-
|
|
49
|
-
found.forEach(e => next.add(e));
|
|
50
|
-
newEvents.forEach(e => console.log(chalk_1.default.green(`+ ${e}`)));
|
|
51
|
-
removed.forEach(e => console.log(chalk_1.default.red(`- ${e}`)));
|
|
52
|
-
config.events = [...next].sort();
|
|
76
|
+
config.events = [...found].sort();
|
|
53
77
|
await (0, config_1.saveConfig)(config);
|
|
54
78
|
console.log(chalk_1.default.green(`\nSynced (${config.events.length} events)`));
|
|
55
79
|
return;
|
package/dist/commands/sync.js
CHANGED
|
@@ -7,9 +7,11 @@ exports.sync = sync;
|
|
|
7
7
|
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
8
8
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
9
9
|
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
10
11
|
const config_1 = require("../utils/config");
|
|
11
12
|
const engine_1 = require("../engine/engine");
|
|
12
13
|
const processFile_1 = require("../utils/processFile");
|
|
14
|
+
const getVirtualFile_1 = require("../utils/getVirtualFile");
|
|
13
15
|
async function sync() {
|
|
14
16
|
const config = await (0, config_1.loadConfig)();
|
|
15
17
|
if (!config)
|
|
@@ -17,73 +19,73 @@ async function sync() {
|
|
|
17
19
|
console.log(chalk_1.default.blue("Scanning..."));
|
|
18
20
|
const files = await (0, fast_glob_1.default)(config.sync.include, {
|
|
19
21
|
ignore: config.sync.exclude,
|
|
22
|
+
absolute: true,
|
|
20
23
|
});
|
|
21
24
|
if (!files.length) {
|
|
22
25
|
console.log(chalk_1.default.yellow("No files found"));
|
|
23
26
|
return;
|
|
24
27
|
}
|
|
25
28
|
const engine = new engine_1.EventraEngine(process.cwd());
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
+
const toScan = new Set();
|
|
30
|
+
const cache = new Map();
|
|
31
|
+
// COLLECT + CACHE
|
|
29
32
|
for (const file of files) {
|
|
30
33
|
try {
|
|
31
34
|
const raw = await promises_1.default.readFile(file, "utf-8");
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const { content: depContent, virtualFile: depVirtual, } = (0, processFile_1.processFile)(dep, depRaw);
|
|
40
|
-
engine["ts"].updateFile(depVirtual, depContent);
|
|
41
|
-
fileCache.push({ file: depVirtual, content: depContent });
|
|
42
|
-
}
|
|
43
|
-
catch { }
|
|
35
|
+
if (raw.length > 2_000_000)
|
|
36
|
+
continue;
|
|
37
|
+
const parsed = (0, processFile_1.processFile)(file, raw);
|
|
38
|
+
cache.set(file, parsed);
|
|
39
|
+
toScan.add(file);
|
|
40
|
+
for (const dep of parsed.deps) {
|
|
41
|
+
toScan.add(path_1.default.resolve(dep));
|
|
44
42
|
}
|
|
45
43
|
}
|
|
46
44
|
catch { }
|
|
47
45
|
}
|
|
48
|
-
|
|
46
|
+
// PRELOAD
|
|
47
|
+
for (const file of toScan) {
|
|
49
48
|
try {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
let parsed = cache.get(file);
|
|
50
|
+
if (!parsed) {
|
|
51
|
+
const raw = await promises_1.default.readFile(file, "utf-8");
|
|
52
|
+
parsed = (0, processFile_1.processFile)(file, raw);
|
|
53
|
+
cache.set(file, parsed);
|
|
53
54
|
}
|
|
55
|
+
const virtual = (0, getVirtualFile_1.getVirtualFile)(file);
|
|
56
|
+
engine.preloadFile(virtual, parsed.content);
|
|
57
|
+
}
|
|
58
|
+
catch { }
|
|
59
|
+
}
|
|
60
|
+
// SCAN
|
|
61
|
+
const detectedFn = new Set();
|
|
62
|
+
const detectedCmp = new Map();
|
|
63
|
+
for (const file of toScan) {
|
|
64
|
+
try {
|
|
65
|
+
const parsed = cache.get(file);
|
|
66
|
+
if (!parsed)
|
|
67
|
+
continue;
|
|
68
|
+
const virtual = (0, getVirtualFile_1.getVirtualFile)(file);
|
|
69
|
+
const res = engine.scanFile(virtual, parsed.content, config);
|
|
70
|
+
res.detectedFunctionWrappers.forEach(w => detectedFn.add(w));
|
|
54
71
|
for (const [k, v] of res.detectedComponentWrappers) {
|
|
55
72
|
detectedCmp.set(k, v);
|
|
56
73
|
}
|
|
57
74
|
}
|
|
58
|
-
catch
|
|
59
|
-
console.log(chalk_1.default.
|
|
60
|
-
if (err instanceof Error) {
|
|
61
|
-
console.log(chalk_1.default.gray(err.message));
|
|
62
|
-
}
|
|
75
|
+
catch {
|
|
76
|
+
console.log(chalk_1.default.gray(`skip: ${file}`));
|
|
63
77
|
}
|
|
64
78
|
}
|
|
65
|
-
//
|
|
79
|
+
// RESULT
|
|
66
80
|
const events = engine.getAllEvents().sort();
|
|
67
|
-
|
|
68
|
-
events.forEach(e => mergedEvents.add(e));
|
|
69
|
-
config.events = [...mergedEvents].sort();
|
|
70
|
-
// FUNCTION WRAPPERS
|
|
81
|
+
config.events = events;
|
|
71
82
|
config.functionWrappers = mergeUnique(config.functionWrappers ?? [], [...detectedFn].map(name => ({ name })), w => w.name);
|
|
72
|
-
// COMPONENT WRAPPERS
|
|
73
83
|
config.wrappers = mergeUnique(config.wrappers ?? [], [...detectedCmp.entries()].map(([name, prop]) => ({
|
|
74
84
|
name,
|
|
75
85
|
prop,
|
|
76
86
|
})), w => `${w.name}:${w.prop}`);
|
|
77
87
|
await (0, config_1.saveConfig)(config);
|
|
78
88
|
console.log(chalk_1.default.green(`Found ${events.length} events`));
|
|
79
|
-
if (detectedFn.size) {
|
|
80
|
-
console.log(chalk_1.default.blue("\nDetected function wrappers:"));
|
|
81
|
-
detectedFn.forEach(w => console.log(chalk_1.default.gray(`• ${w}`)));
|
|
82
|
-
}
|
|
83
|
-
if (detectedCmp.size) {
|
|
84
|
-
console.log(chalk_1.default.blue("\nDetected component wrappers:"));
|
|
85
|
-
detectedCmp.forEach((prop, name) => console.log(chalk_1.default.gray(`• ${name} (${prop})`)));
|
|
86
|
-
}
|
|
87
89
|
}
|
|
88
90
|
// HELPERS
|
|
89
91
|
function mergeUnique(a, b, key) {
|
package/dist/commands/watch.js
CHANGED
|
@@ -12,11 +12,9 @@ const path_1 = __importDefault(require("path"));
|
|
|
12
12
|
const config_1 = require("../utils/config");
|
|
13
13
|
const engine_1 = require("../engine/engine");
|
|
14
14
|
const processFile_1 = require("../utils/processFile");
|
|
15
|
-
|
|
16
|
-
function
|
|
17
|
-
return
|
|
18
|
-
? file + ".tsx"
|
|
19
|
-
: file;
|
|
15
|
+
const getVirtualFile_1 = require("../utils/getVirtualFile");
|
|
16
|
+
function normalize(file) {
|
|
17
|
+
return path_1.default.resolve(file).replace(/\\/g, "/");
|
|
20
18
|
}
|
|
21
19
|
async function watch() {
|
|
22
20
|
const config = await (0, config_1.loadConfig)();
|
|
@@ -25,58 +23,108 @@ async function watch() {
|
|
|
25
23
|
console.log(chalk_1.default.blue("Watching...\n"));
|
|
26
24
|
const files = await (0, fast_glob_1.default)(config.sync.include, {
|
|
27
25
|
ignore: config.sync.exclude,
|
|
26
|
+
absolute: true,
|
|
28
27
|
});
|
|
29
28
|
const engine = new engine_1.EventraEngine(process.cwd());
|
|
30
29
|
const watchedDeps = new Set();
|
|
31
|
-
|
|
30
|
+
const cache = new Map();
|
|
31
|
+
const toScan = new Set();
|
|
32
|
+
// COLLECT + CACHE
|
|
32
33
|
for (const file of files) {
|
|
33
34
|
try {
|
|
34
|
-
const abs =
|
|
35
|
+
const abs = normalize(file);
|
|
35
36
|
const raw = await promises_1.default.readFile(abs, "utf-8");
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
if (raw.length > 2_000_000)
|
|
38
|
+
continue;
|
|
39
|
+
const parsed = (0, processFile_1.processFile)(abs, raw);
|
|
40
|
+
cache.set(abs, parsed);
|
|
41
|
+
toScan.add(abs);
|
|
42
|
+
for (const dep of parsed.deps) {
|
|
43
|
+
toScan.add(normalize(dep));
|
|
42
44
|
}
|
|
43
45
|
}
|
|
44
46
|
catch {
|
|
45
47
|
console.log(chalk_1.default.gray(`skip: ${file}`));
|
|
46
48
|
}
|
|
47
49
|
}
|
|
50
|
+
// PRELOAD
|
|
51
|
+
for (const file of toScan) {
|
|
52
|
+
try {
|
|
53
|
+
let parsed = cache.get(file);
|
|
54
|
+
if (!parsed) {
|
|
55
|
+
const raw = await promises_1.default.readFile(file, "utf-8");
|
|
56
|
+
parsed = (0, processFile_1.processFile)(file, raw);
|
|
57
|
+
cache.set(file, parsed);
|
|
58
|
+
}
|
|
59
|
+
const virtual = (0, getVirtualFile_1.getVirtualFile)(file);
|
|
60
|
+
engine.preloadFile?.(virtual, parsed.content);
|
|
61
|
+
}
|
|
62
|
+
catch { }
|
|
63
|
+
}
|
|
64
|
+
// INITIAL SCAN
|
|
65
|
+
for (const file of toScan) {
|
|
66
|
+
try {
|
|
67
|
+
let parsed = cache.get(file);
|
|
68
|
+
if (!parsed) {
|
|
69
|
+
const raw = await promises_1.default.readFile(file, "utf-8");
|
|
70
|
+
parsed = (0, processFile_1.processFile)(file, raw);
|
|
71
|
+
}
|
|
72
|
+
const virtual = (0, getVirtualFile_1.getVirtualFile)(file);
|
|
73
|
+
engine.scanFile(virtual, parsed.content, config);
|
|
74
|
+
for (const dep of parsed.deps) {
|
|
75
|
+
watchedDeps.add(normalize(dep));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch { }
|
|
79
|
+
}
|
|
48
80
|
config.events = engine.getAllEvents().sort();
|
|
49
81
|
await (0, config_1.saveConfig)(config);
|
|
50
82
|
console.log(chalk_1.default.gray(`Initial: ${config.events.length} events\n`));
|
|
51
83
|
// QUEUE
|
|
52
84
|
let locked = false;
|
|
53
|
-
|
|
85
|
+
const queued = new Map();
|
|
54
86
|
let timer = null;
|
|
55
87
|
const run = async () => {
|
|
56
|
-
if (locked)
|
|
57
|
-
timer = setTimeout(run, 100);
|
|
88
|
+
if (locked)
|
|
58
89
|
return;
|
|
59
|
-
}
|
|
60
90
|
locked = true;
|
|
61
91
|
const batch = [...queued.values()];
|
|
62
92
|
queued.clear();
|
|
63
93
|
for (const item of batch) {
|
|
64
94
|
try {
|
|
65
95
|
const raw = await promises_1.default.readFile(item.real, "utf-8");
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
96
|
+
if (raw.length > 2_000_000)
|
|
97
|
+
continue;
|
|
98
|
+
const parsed = (0, processFile_1.processFile)(item.real, raw);
|
|
99
|
+
cache.set(item.real, parsed);
|
|
100
|
+
engine.updateFile(item.virtual, parsed.content, config);
|
|
101
|
+
// DEPENDENCY DIFF
|
|
102
|
+
const nextDeps = new Set();
|
|
103
|
+
for (const dep of parsed.deps) {
|
|
104
|
+
nextDeps.add(normalize(dep));
|
|
105
|
+
}
|
|
106
|
+
// add new deps
|
|
107
|
+
for (const dep of nextDeps) {
|
|
108
|
+
if (!watchedDeps.has(dep)) {
|
|
109
|
+
watcher.add(dep);
|
|
110
|
+
watchedDeps.add(dep);
|
|
74
111
|
}
|
|
112
|
+
}
|
|
113
|
+
// remove old deps
|
|
114
|
+
for (const dep of [...watchedDeps]) {
|
|
115
|
+
if (!nextDeps.has(dep)) {
|
|
116
|
+
watcher.unwatch(dep);
|
|
117
|
+
watchedDeps.delete(dep);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// preload deps
|
|
121
|
+
for (const dep of nextDeps) {
|
|
75
122
|
try {
|
|
76
|
-
const
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
123
|
+
const raw = await promises_1.default.readFile(dep, "utf-8");
|
|
124
|
+
const parsedDep = (0, processFile_1.processFile)(dep, raw);
|
|
125
|
+
cache.set(dep, parsedDep);
|
|
126
|
+
const virtual = (0, getVirtualFile_1.getVirtualFile)(dep);
|
|
127
|
+
engine.updateFile(virtual, parsedDep.content, config);
|
|
80
128
|
}
|
|
81
129
|
catch { }
|
|
82
130
|
}
|
|
@@ -85,7 +133,7 @@ async function watch() {
|
|
|
85
133
|
console.log(chalk_1.default.gray(`skip: ${item.real}`));
|
|
86
134
|
}
|
|
87
135
|
}
|
|
88
|
-
// EVENTS
|
|
136
|
+
// DIFF EVENTS
|
|
89
137
|
const next = engine.getAllEvents();
|
|
90
138
|
const added = next.filter(e => !config.events.includes(e));
|
|
91
139
|
const removed = config.events.filter(e => !next.includes(e));
|
|
@@ -100,33 +148,39 @@ async function watch() {
|
|
|
100
148
|
};
|
|
101
149
|
// SCHEDULER
|
|
102
150
|
const schedule = (file) => {
|
|
103
|
-
const abs =
|
|
104
|
-
const virtual = getVirtualFile(abs);
|
|
151
|
+
const abs = normalize(file);
|
|
152
|
+
const virtual = (0, getVirtualFile_1.getVirtualFile)(abs);
|
|
153
|
+
console.log(chalk_1.default.gray(`change: ${file}`));
|
|
105
154
|
queued.set(abs, { real: abs, virtual });
|
|
106
155
|
if (timer)
|
|
107
156
|
clearTimeout(timer);
|
|
108
|
-
timer = setTimeout(run,
|
|
157
|
+
timer = setTimeout(run, 200);
|
|
109
158
|
};
|
|
110
159
|
// WATCHER
|
|
111
160
|
const watcher = chokidar_1.default.watch(config.sync.include, {
|
|
112
161
|
ignored: config.sync.exclude,
|
|
113
162
|
ignoreInitial: true,
|
|
163
|
+
persistent: true,
|
|
114
164
|
});
|
|
115
165
|
watcher
|
|
116
166
|
.on("add", schedule)
|
|
117
167
|
.on("change", schedule)
|
|
118
168
|
.on("unlink", async (file) => {
|
|
119
|
-
const abs =
|
|
169
|
+
const abs = normalize(file);
|
|
120
170
|
console.log(chalk_1.default.gray(`remove: ${file}`));
|
|
121
|
-
const virtual = getVirtualFile(abs);
|
|
171
|
+
const virtual = (0, getVirtualFile_1.getVirtualFile)(abs);
|
|
122
172
|
engine.removeFile(virtual, config);
|
|
173
|
+
watcher.unwatch(abs);
|
|
123
174
|
watchedDeps.delete(abs);
|
|
124
175
|
const next = engine.getAllEvents();
|
|
125
176
|
config.events = next.sort();
|
|
126
177
|
await (0, config_1.saveConfig)(config);
|
|
127
178
|
console.log(chalk_1.default.gray(`Total: ${config.events.length} events\n`));
|
|
179
|
+
})
|
|
180
|
+
.on("error", (err) => {
|
|
181
|
+
console.error(chalk_1.default.red("Watcher error:"), err);
|
|
128
182
|
});
|
|
129
|
-
// WATCH DEPS
|
|
183
|
+
// WATCH DEPS INIT
|
|
130
184
|
for (const dep of watchedDeps) {
|
|
131
185
|
watcher.add(dep);
|
|
132
186
|
}
|
|
@@ -23,15 +23,37 @@ function resolveFromSymbol(symbol, checker, visited = new Set(), depth = 0) {
|
|
|
23
23
|
const aliased = checker.getAliasedSymbol(symbol);
|
|
24
24
|
return resolveFromSymbol(aliased, checker, visited, depth + 1);
|
|
25
25
|
}
|
|
26
|
+
// re-export support
|
|
27
|
+
if (symbol.exports) {
|
|
28
|
+
for (const exp of symbol.exports.values()) {
|
|
29
|
+
const resolved = resolveFromSymbol(exp, checker, visited, depth + 1);
|
|
30
|
+
if (resolved)
|
|
31
|
+
return resolved;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
26
34
|
const decls = symbol.getDeclarations() ?? [];
|
|
27
35
|
for (const decl of decls) {
|
|
36
|
+
// direct function
|
|
28
37
|
if (isFunctionLike(decl)) {
|
|
29
38
|
return decl;
|
|
30
39
|
}
|
|
31
|
-
//
|
|
40
|
+
// VARIABLE → FUNCTION
|
|
41
|
+
if (typescript_1.default.isVariableDeclaration(decl) && decl.initializer) {
|
|
42
|
+
if (isFunctionLike(decl.initializer)) {
|
|
43
|
+
return decl.initializer;
|
|
44
|
+
}
|
|
45
|
+
const innerSymbol = checker.getSymbolAtLocation(decl.initializer);
|
|
46
|
+
if (innerSymbol && innerSymbol !== symbol) {
|
|
47
|
+
const resolved = resolveFromSymbol(innerSymbol, checker, visited, depth + 1);
|
|
48
|
+
if (resolved)
|
|
49
|
+
return resolved;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// MethodSignature (interface / type)
|
|
32
53
|
if (typescript_1.default.isMethodSignature(decl)) {
|
|
33
54
|
const parent = decl.parent;
|
|
34
|
-
if (typescript_1.default.isInterfaceDeclaration(parent) ||
|
|
55
|
+
if (typescript_1.default.isInterfaceDeclaration(parent) ||
|
|
56
|
+
typescript_1.default.isTypeLiteralNode(parent)) {
|
|
35
57
|
const name = decl.name.getText();
|
|
36
58
|
const type = checker.getTypeAtLocation(parent);
|
|
37
59
|
const props = type.getProperties();
|
|
@@ -44,7 +66,7 @@ function resolveFromSymbol(symbol, checker, visited = new Set(), depth = 0) {
|
|
|
44
66
|
}
|
|
45
67
|
}
|
|
46
68
|
}
|
|
47
|
-
//
|
|
69
|
+
// fallback recursion
|
|
48
70
|
const s = checker.getSymbolAtLocation(decl);
|
|
49
71
|
if (s && s !== symbol) {
|
|
50
72
|
const resolved = resolveFromSymbol(s, checker, visited, depth + 1);
|
|
@@ -55,6 +77,28 @@ function resolveFromSymbol(symbol, checker, visited = new Set(), depth = 0) {
|
|
|
55
77
|
return null;
|
|
56
78
|
}
|
|
57
79
|
function resolveFunctionFromCall(expr, checker) {
|
|
80
|
+
// tracker.track
|
|
81
|
+
if (typescript_1.default.isPropertyAccessExpression(expr)) {
|
|
82
|
+
let symbol = checker.getSymbolAtLocation(expr.name);
|
|
83
|
+
if (symbol && (symbol.flags & typescript_1.default.SymbolFlags.Alias)) {
|
|
84
|
+
symbol = checker.getAliasedSymbol(symbol);
|
|
85
|
+
}
|
|
86
|
+
if (symbol) {
|
|
87
|
+
const resolved = resolveFromSymbol(symbol, checker);
|
|
88
|
+
if (resolved)
|
|
89
|
+
return resolved;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// tracker["track"]
|
|
93
|
+
if (typescript_1.default.isElementAccessExpression(expr)) {
|
|
94
|
+
const symbol = checker.getSymbolAtLocation(expr.argumentExpression);
|
|
95
|
+
if (symbol) {
|
|
96
|
+
const resolved = resolveFromSymbol(symbol, checker);
|
|
97
|
+
if (resolved)
|
|
98
|
+
return resolved;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// normal call signatures
|
|
58
102
|
const type = checker.getTypeAtLocation(expr);
|
|
59
103
|
const signatures = type.getCallSignatures();
|
|
60
104
|
for (const sig of signatures) {
|
|
@@ -64,7 +108,6 @@ function resolveFunctionFromCall(expr, checker) {
|
|
|
64
108
|
if (isFunctionLike(decl)) {
|
|
65
109
|
return decl;
|
|
66
110
|
}
|
|
67
|
-
// interface method
|
|
68
111
|
if (typescript_1.default.isMethodSignature(decl)) {
|
|
69
112
|
const symbol = checker.getSymbolAtLocation(decl.name);
|
|
70
113
|
if (symbol) {
|
|
@@ -74,5 +117,10 @@ function resolveFunctionFromCall(expr, checker) {
|
|
|
74
117
|
}
|
|
75
118
|
}
|
|
76
119
|
}
|
|
120
|
+
// fallback
|
|
121
|
+
const symbol = checker.getSymbolAtLocation(expr);
|
|
122
|
+
if (symbol) {
|
|
123
|
+
return resolveFromSymbol(symbol, checker);
|
|
124
|
+
}
|
|
77
125
|
return null;
|
|
78
126
|
}
|
package/dist/engine/engine.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.EventraEngine = void 0;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
4
9
|
const languageService_1 = require("./languageService");
|
|
5
10
|
const scanner_1 = require("./scanner");
|
|
6
11
|
const graph_1 = require("./graph");
|
|
@@ -16,28 +21,40 @@ class EventraEngine {
|
|
|
16
21
|
const { baseUrl, paths } = this.ts.getModuleResolutionConfig();
|
|
17
22
|
this.graph = new graph_1.DependencyGraph(baseUrl, paths);
|
|
18
23
|
}
|
|
24
|
+
normalize(file) {
|
|
25
|
+
return path_1.default.resolve(file).replace(/\\/g, "/");
|
|
26
|
+
}
|
|
27
|
+
empty() {
|
|
28
|
+
return {
|
|
29
|
+
events: new Set(),
|
|
30
|
+
detectedFunctionWrappers: new Set(),
|
|
31
|
+
detectedComponentWrappers: new Map(),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// PRELOAD
|
|
35
|
+
preloadFile(file, content) {
|
|
36
|
+
file = this.normalize(file);
|
|
37
|
+
this.ts.updateFile(file, content);
|
|
38
|
+
const source = this.ts.getSourceFile(file);
|
|
39
|
+
if (source) {
|
|
40
|
+
this.graph.update(file, source);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
19
43
|
// SCAN FILE
|
|
20
44
|
scanFile(file, content, config) {
|
|
45
|
+
file = this.normalize(file);
|
|
21
46
|
const h = (0, hash_1.hash)(content);
|
|
22
|
-
// skip unchanged
|
|
23
47
|
if (this.fileHash.get(file) === h) {
|
|
24
|
-
return
|
|
25
|
-
events: new Set(),
|
|
26
|
-
detectedFunctionWrappers: new Set(),
|
|
27
|
-
detectedComponentWrappers: new Map(),
|
|
28
|
-
});
|
|
48
|
+
return this.fileResults.get(file) ?? this.empty();
|
|
29
49
|
}
|
|
30
50
|
this.fileHash.set(file, h);
|
|
31
51
|
this.ts.updateFile(file, content);
|
|
32
52
|
const source = this.ts.getSourceFile(file);
|
|
33
53
|
const checker = this.ts.getChecker();
|
|
34
54
|
if (!source || !checker) {
|
|
35
|
-
return
|
|
36
|
-
events: new Set(),
|
|
37
|
-
detectedFunctionWrappers: new Set(),
|
|
38
|
-
detectedComponentWrappers: new Map(),
|
|
39
|
-
};
|
|
55
|
+
return this.empty();
|
|
40
56
|
}
|
|
57
|
+
// обновляем graph
|
|
41
58
|
this.graph.update(file, source);
|
|
42
59
|
const res = (0, scanner_1.scanSource)(source, checker, config);
|
|
43
60
|
this.fileResults.set(file, res);
|
|
@@ -45,27 +62,35 @@ class EventraEngine {
|
|
|
45
62
|
}
|
|
46
63
|
// UPDATE FILE (incremental)
|
|
47
64
|
updateFile(file, content, config) {
|
|
48
|
-
|
|
65
|
+
file = this.normalize(file);
|
|
49
66
|
const res = this.scanFile(file, content, config);
|
|
50
67
|
const dependents = this.graph.getAllDependentsDeep(file);
|
|
51
68
|
for (const dep of dependents) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const depContent = this.ts.getFileContent(dep);
|
|
55
|
-
if (!depContent)
|
|
69
|
+
const abs = this.normalize(dep);
|
|
70
|
+
if ((0, boundary_1.isExternalFile)(abs))
|
|
56
71
|
continue;
|
|
72
|
+
let depContent = this.ts.getFileContent(abs);
|
|
73
|
+
if (!depContent) {
|
|
74
|
+
try {
|
|
75
|
+
depContent = fs_1.default.readFileSync(abs, "utf-8");
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
57
81
|
const h = (0, hash_1.hash)(depContent);
|
|
58
|
-
if (this.fileHash.get(
|
|
82
|
+
if (this.fileHash.get(abs) === h) {
|
|
59
83
|
continue;
|
|
60
|
-
|
|
61
|
-
this.
|
|
62
|
-
|
|
84
|
+
}
|
|
85
|
+
this.fileHash.set(abs, h);
|
|
86
|
+
this.ts.updateFile(abs, depContent);
|
|
87
|
+
const source = this.ts.getSourceFile(abs);
|
|
63
88
|
const checker = this.ts.getChecker();
|
|
64
89
|
if (!source || !checker)
|
|
65
90
|
continue;
|
|
66
|
-
this.graph.update(
|
|
91
|
+
this.graph.update(abs, source);
|
|
67
92
|
const r = (0, scanner_1.scanSource)(source, checker, config);
|
|
68
|
-
this.fileResults.set(
|
|
93
|
+
this.fileResults.set(abs, r);
|
|
69
94
|
}
|
|
70
95
|
return res;
|
|
71
96
|
}
|
|
@@ -79,33 +104,42 @@ class EventraEngine {
|
|
|
79
104
|
}
|
|
80
105
|
// REMOVE FILE
|
|
81
106
|
removeFile(file, config) {
|
|
107
|
+
file = this.normalize(file);
|
|
108
|
+
const dependents = this.graph.getAllDependentsDeep(file);
|
|
82
109
|
this.ts.removeFile(file);
|
|
83
110
|
this.fileResults.delete(file);
|
|
84
111
|
this.fileHash.delete(file);
|
|
85
112
|
this.graph.remove(file);
|
|
86
|
-
const dependents = this.graph.getAllDependentsDeep(file);
|
|
87
113
|
for (const dep of dependents) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const content = this.ts.getFileContent(dep);
|
|
91
|
-
if (!content)
|
|
114
|
+
const abs = this.normalize(dep);
|
|
115
|
+
if ((0, boundary_1.isExternalFile)(abs))
|
|
92
116
|
continue;
|
|
117
|
+
let content = this.ts.getFileContent(abs);
|
|
118
|
+
if (!content) {
|
|
119
|
+
try {
|
|
120
|
+
content = fs_1.default.readFileSync(abs, "utf-8");
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
93
126
|
const h = (0, hash_1.hash)(content);
|
|
94
|
-
if (this.fileHash.get(
|
|
127
|
+
if (this.fileHash.get(abs) === h)
|
|
95
128
|
continue;
|
|
96
|
-
this.fileHash.set(
|
|
97
|
-
this.ts.updateFile(
|
|
98
|
-
const source = this.ts.getSourceFile(
|
|
129
|
+
this.fileHash.set(abs, h);
|
|
130
|
+
this.ts.updateFile(abs, content);
|
|
131
|
+
const source = this.ts.getSourceFile(abs);
|
|
99
132
|
const checker = this.ts.getChecker();
|
|
100
133
|
if (!source || !checker)
|
|
101
134
|
continue;
|
|
135
|
+
this.graph.update(abs, source);
|
|
102
136
|
const r = (0, scanner_1.scanSource)(source, checker, config ?? {
|
|
103
137
|
events: [],
|
|
104
138
|
wrappers: [],
|
|
105
139
|
functionWrappers: [],
|
|
106
140
|
sync: { include: [], exclude: [] },
|
|
107
141
|
});
|
|
108
|
-
this.fileResults.set(
|
|
142
|
+
this.fileResults.set(abs, r);
|
|
109
143
|
}
|
|
110
144
|
}
|
|
111
145
|
}
|