@eventra_dev/eventra-cli 0.1.34 → 0.2.1
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 +14 -30
- package/dist/commands/sync.js +9 -27
- package/dist/commands/watch.js +38 -121
- package/dist/engine/engine.js +14 -9
- package/dist/engine/scanner.js +41 -28
- package/dist/utils/universal.js +1 -1
- package/package.json +1 -1
- package/src/commands/check.ts +17 -48
- package/src/commands/sync.ts +14 -44
- package/src/commands/watch.ts +48 -158
- package/src/engine/engine.ts +20 -12
- package/src/engine/scanner.ts +67 -27
- package/src/utils/universal.ts +1 -1
package/dist/commands/check.js
CHANGED
|
@@ -24,9 +24,9 @@ async function check({ fix = false }) {
|
|
|
24
24
|
absolute: true,
|
|
25
25
|
});
|
|
26
26
|
const engine = new engine_1.EventraEngine(process.cwd());
|
|
27
|
-
const toScan = new Set();
|
|
28
27
|
const cache = new Map();
|
|
29
|
-
|
|
28
|
+
const toScan = new Set();
|
|
29
|
+
// COLLECT
|
|
30
30
|
for (const file of files) {
|
|
31
31
|
try {
|
|
32
32
|
const raw = await promises_1.default.readFile(file, "utf-8");
|
|
@@ -35,23 +35,17 @@ async function check({ fix = false }) {
|
|
|
35
35
|
const parsed = (0, processFile_1.processFile)(file, raw);
|
|
36
36
|
cache.set(file, parsed);
|
|
37
37
|
toScan.add(file);
|
|
38
|
-
|
|
39
|
-
toScan.add(path_1.default.resolve(dep));
|
|
40
|
-
}
|
|
38
|
+
parsed.deps.forEach(dep => toScan.add(path_1.default.resolve(dep)));
|
|
41
39
|
}
|
|
42
40
|
catch { }
|
|
43
41
|
}
|
|
44
42
|
// PRELOAD
|
|
45
43
|
for (const file of toScan) {
|
|
46
44
|
try {
|
|
47
|
-
|
|
48
|
-
if (!parsed)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
cache.set(file, parsed);
|
|
52
|
-
}
|
|
53
|
-
const virtual = (0, getVirtualFile_1.getVirtualFile)(file);
|
|
54
|
-
engine.preloadFile(virtual, parsed.content);
|
|
45
|
+
const parsed = cache.get(file);
|
|
46
|
+
if (!parsed)
|
|
47
|
+
continue;
|
|
48
|
+
engine.preloadFile((0, getVirtualFile_1.getVirtualFile)(file), parsed.content);
|
|
55
49
|
}
|
|
56
50
|
catch { }
|
|
57
51
|
}
|
|
@@ -61,34 +55,24 @@ async function check({ fix = false }) {
|
|
|
61
55
|
const parsed = cache.get(file);
|
|
62
56
|
if (!parsed)
|
|
63
57
|
continue;
|
|
64
|
-
|
|
65
|
-
engine.scanFile(virtual, parsed.content, config);
|
|
58
|
+
engine.scanFile((0, getVirtualFile_1.getVirtualFile)(file), parsed.content, config);
|
|
66
59
|
}
|
|
67
60
|
catch { }
|
|
68
61
|
}
|
|
69
|
-
// DIFF
|
|
70
62
|
const found = new Set(engine.getAllEvents());
|
|
71
63
|
const known = new Set(config.events ?? []);
|
|
72
|
-
const
|
|
64
|
+
const added = [...found].filter(e => !known.has(e));
|
|
73
65
|
const removed = [...known].filter(e => !found.has(e));
|
|
74
|
-
// FIX MODE
|
|
75
66
|
if (fix) {
|
|
76
67
|
config.events = [...found].sort();
|
|
77
68
|
await (0, config_1.saveConfig)(config);
|
|
78
|
-
console.log(chalk_1.default.green(
|
|
69
|
+
console.log(chalk_1.default.green("Synced"));
|
|
79
70
|
return;
|
|
80
71
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
console.log(chalk_1.default.red("\nNew events:"));
|
|
85
|
-
newEvents.forEach(e => console.log(chalk_1.default.red(`+ ${e}`)));
|
|
86
|
-
}
|
|
87
|
-
if (removed.length) {
|
|
88
|
-
console.log(chalk_1.default.yellow("\nRemoved events:"));
|
|
89
|
-
removed.forEach(e => console.log(chalk_1.default.yellow(`- ${e}`)));
|
|
90
|
-
}
|
|
72
|
+
if (added.length || removed.length) {
|
|
73
|
+
added.forEach(e => console.log(chalk_1.default.red(`+ ${e}`)));
|
|
74
|
+
removed.forEach(e => console.log(chalk_1.default.yellow(`- ${e}`)));
|
|
91
75
|
process.exit(1);
|
|
92
76
|
}
|
|
93
|
-
console.log(chalk_1.default.green("
|
|
77
|
+
console.log(chalk_1.default.green("All good"));
|
|
94
78
|
}
|
package/dist/commands/sync.js
CHANGED
|
@@ -21,14 +21,10 @@ async function sync() {
|
|
|
21
21
|
ignore: config.sync.exclude,
|
|
22
22
|
absolute: true,
|
|
23
23
|
});
|
|
24
|
-
if (!files.length) {
|
|
25
|
-
console.log(chalk_1.default.yellow("No files found"));
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
24
|
const engine = new engine_1.EventraEngine(process.cwd());
|
|
29
|
-
const toScan = new Set();
|
|
30
25
|
const cache = new Map();
|
|
31
|
-
|
|
26
|
+
const toScan = new Set();
|
|
27
|
+
// COLLECT
|
|
32
28
|
for (const file of files) {
|
|
33
29
|
try {
|
|
34
30
|
const raw = await promises_1.default.readFile(file, "utf-8");
|
|
@@ -37,9 +33,7 @@ async function sync() {
|
|
|
37
33
|
const parsed = (0, processFile_1.processFile)(file, raw);
|
|
38
34
|
cache.set(file, parsed);
|
|
39
35
|
toScan.add(file);
|
|
40
|
-
|
|
41
|
-
toScan.add(path_1.default.resolve(dep));
|
|
42
|
-
}
|
|
36
|
+
parsed.deps.forEach(dep => toScan.add(path_1.default.resolve(dep)));
|
|
43
37
|
}
|
|
44
38
|
catch { }
|
|
45
39
|
}
|
|
@@ -52,8 +46,7 @@ async function sync() {
|
|
|
52
46
|
parsed = (0, processFile_1.processFile)(file, raw);
|
|
53
47
|
cache.set(file, parsed);
|
|
54
48
|
}
|
|
55
|
-
|
|
56
|
-
engine.preloadFile(virtual, parsed.content);
|
|
49
|
+
engine.preloadFile((0, getVirtualFile_1.getVirtualFile)(file), parsed.content);
|
|
57
50
|
}
|
|
58
51
|
catch { }
|
|
59
52
|
}
|
|
@@ -65,33 +58,22 @@ async function sync() {
|
|
|
65
58
|
const parsed = cache.get(file);
|
|
66
59
|
if (!parsed)
|
|
67
60
|
continue;
|
|
68
|
-
const
|
|
69
|
-
const res = engine.scanFile(virtual, parsed.content, config);
|
|
61
|
+
const res = engine.updateFile((0, getVirtualFile_1.getVirtualFile)(file), parsed.content, config);
|
|
70
62
|
res.detectedFunctionWrappers.forEach(w => detectedFn.add(w));
|
|
71
|
-
|
|
72
|
-
detectedCmp.set(k, v);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
catch {
|
|
76
|
-
console.log(chalk_1.default.gray(`skip: ${file}`));
|
|
63
|
+
res.detectedComponentWrappers.forEach((v, k) => detectedCmp.set(k, v));
|
|
77
64
|
}
|
|
65
|
+
catch { }
|
|
78
66
|
}
|
|
79
67
|
// RESULT
|
|
80
68
|
const events = engine.getAllEvents().sort();
|
|
81
69
|
config.events = events;
|
|
82
70
|
config.functionWrappers = mergeUnique(config.functionWrappers ?? [], [...detectedFn].map(name => ({ name })), w => w.name);
|
|
83
|
-
config.wrappers = mergeUnique(config.wrappers ?? [], [...detectedCmp.entries()].map(([name, prop]) => ({
|
|
84
|
-
name,
|
|
85
|
-
prop,
|
|
86
|
-
})), w => `${w.name}:${w.prop}`);
|
|
71
|
+
config.wrappers = mergeUnique(config.wrappers ?? [], [...detectedCmp.entries()].map(([name, prop]) => ({ name, prop })), w => `${w.name}:${w.prop}`);
|
|
87
72
|
await (0, config_1.saveConfig)(config);
|
|
88
73
|
console.log(chalk_1.default.green(`Found ${events.length} events`));
|
|
89
74
|
}
|
|
90
|
-
// HELPERS
|
|
91
75
|
function mergeUnique(a, b, key) {
|
|
92
76
|
const map = new Map();
|
|
93
|
-
[...b, ...a].forEach(item =>
|
|
94
|
-
map.set(key(item), item);
|
|
95
|
-
});
|
|
77
|
+
[...b, ...a].forEach(item => map.set(key(item), item));
|
|
96
78
|
return [...map.values()];
|
|
97
79
|
}
|
package/dist/commands/watch.js
CHANGED
|
@@ -13,180 +13,97 @@ const config_1 = require("../utils/config");
|
|
|
13
13
|
const engine_1 = require("../engine/engine");
|
|
14
14
|
const processFile_1 = require("../utils/processFile");
|
|
15
15
|
const getVirtualFile_1 = require("../utils/getVirtualFile");
|
|
16
|
-
function normalize(file) {
|
|
17
|
-
return path_1.default.resolve(file).replace(/\\/g, "/");
|
|
18
|
-
}
|
|
19
16
|
async function watch() {
|
|
20
17
|
const config = await (0, config_1.loadConfig)();
|
|
21
18
|
if (!config)
|
|
22
19
|
return;
|
|
23
20
|
console.log(chalk_1.default.blue("Watching...\n"));
|
|
21
|
+
const engine = new engine_1.EventraEngine(process.cwd());
|
|
22
|
+
const fileDeps = new Map();
|
|
23
|
+
const cache = new Map();
|
|
24
|
+
const watchedDeps = new Set();
|
|
25
|
+
const normalize = (f) => path_1.default.resolve(f).replace(/\\/g, "/");
|
|
26
|
+
// INITIAL LOAD
|
|
24
27
|
const files = await (0, fast_glob_1.default)(config.sync.include, {
|
|
25
28
|
ignore: config.sync.exclude,
|
|
26
29
|
absolute: true,
|
|
27
30
|
});
|
|
28
|
-
const engine = new engine_1.EventraEngine(process.cwd());
|
|
29
|
-
const watchedDeps = new Set();
|
|
30
|
-
const cache = new Map();
|
|
31
|
-
const toScan = new Set();
|
|
32
|
-
// COLLECT + CACHE
|
|
33
31
|
for (const file of files) {
|
|
34
32
|
try {
|
|
35
33
|
const abs = normalize(file);
|
|
36
34
|
const raw = await promises_1.default.readFile(abs, "utf-8");
|
|
37
|
-
if (raw.length > 2_000_000)
|
|
38
|
-
continue;
|
|
39
35
|
const parsed = (0, processFile_1.processFile)(abs, raw);
|
|
40
36
|
cache.set(abs, parsed);
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
catch {
|
|
47
|
-
console.log(chalk_1.default.gray(`skip: ${file}`));
|
|
48
|
-
}
|
|
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
|
-
}
|
|
37
|
+
engine.preloadFile((0, getVirtualFile_1.getVirtualFile)(abs), parsed.content);
|
|
38
|
+
engine.updateFile((0, getVirtualFile_1.getVirtualFile)(abs), parsed.content, config);
|
|
39
|
+
fileDeps.set(abs, new Set(parsed.deps.map(d => normalize(d))));
|
|
77
40
|
}
|
|
78
41
|
catch { }
|
|
79
42
|
}
|
|
80
43
|
config.events = engine.getAllEvents().sort();
|
|
81
44
|
await (0, config_1.saveConfig)(config);
|
|
82
|
-
console.log(chalk_1.default.gray(`Initial: ${config.events.length}
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
const
|
|
45
|
+
console.log(chalk_1.default.gray(`Initial: ${config.events.length}\n`));
|
|
46
|
+
// WATCHER
|
|
47
|
+
const watcher = chokidar_1.default.watch([...files.map(normalize), ...watchedDeps], { ignoreInitial: true });
|
|
48
|
+
const queue = new Map();
|
|
86
49
|
let timer = null;
|
|
87
50
|
const run = async () => {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const batch = [...queued.values()];
|
|
92
|
-
queued.clear();
|
|
93
|
-
for (const item of batch) {
|
|
51
|
+
const batch = [...queue.keys()];
|
|
52
|
+
queue.clear();
|
|
53
|
+
for (const file of batch) {
|
|
94
54
|
try {
|
|
95
|
-
const raw = await promises_1.default.readFile(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const nextDeps = new Set();
|
|
103
|
-
for (const dep of parsed.deps) {
|
|
104
|
-
nextDeps.add(normalize(dep));
|
|
105
|
-
}
|
|
55
|
+
const raw = await promises_1.default.readFile(file, "utf-8");
|
|
56
|
+
const parsed = (0, processFile_1.processFile)(file, raw);
|
|
57
|
+
cache.set(file, parsed);
|
|
58
|
+
engine.updateFile((0, getVirtualFile_1.getVirtualFile)(file), parsed.content, config);
|
|
59
|
+
//dependency diff
|
|
60
|
+
const abs = normalize(file);
|
|
61
|
+
const prevDeps = fileDeps.get(abs) ?? new Set();
|
|
62
|
+
const nextDeps = new Set(parsed.deps.map(d => normalize(d)));
|
|
106
63
|
// add new deps
|
|
107
64
|
for (const dep of nextDeps) {
|
|
108
|
-
if (!
|
|
65
|
+
if (!prevDeps.has(dep)) {
|
|
109
66
|
watcher.add(dep);
|
|
110
67
|
watchedDeps.add(dep);
|
|
111
68
|
}
|
|
112
69
|
}
|
|
113
70
|
// remove old deps
|
|
114
|
-
for (const dep of
|
|
71
|
+
for (const dep of prevDeps) {
|
|
115
72
|
if (!nextDeps.has(dep)) {
|
|
116
73
|
watcher.unwatch(dep);
|
|
117
74
|
watchedDeps.delete(dep);
|
|
118
75
|
}
|
|
119
76
|
}
|
|
120
|
-
|
|
121
|
-
for (const dep of nextDeps) {
|
|
122
|
-
try {
|
|
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);
|
|
128
|
-
}
|
|
129
|
-
catch { }
|
|
130
|
-
}
|
|
77
|
+
fileDeps.set(abs, nextDeps);
|
|
131
78
|
}
|
|
132
79
|
catch {
|
|
133
|
-
console.log(chalk_1.default.gray(`skip: ${
|
|
80
|
+
console.log(chalk_1.default.gray(`skip: ${file}`));
|
|
134
81
|
}
|
|
135
82
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if (added.length || removed.length) {
|
|
141
|
-
added.forEach(e => console.log(chalk_1.default.green(`+ ${e}`)));
|
|
142
|
-
removed.forEach(e => console.log(chalk_1.default.red(`- ${e}`)));
|
|
143
|
-
config.events = next.sort();
|
|
144
|
-
await (0, config_1.saveConfig)(config);
|
|
145
|
-
console.log(chalk_1.default.gray(`Total: ${config.events.length} events\n`));
|
|
146
|
-
}
|
|
147
|
-
locked = false;
|
|
83
|
+
const next = engine.getAllEvents().sort();
|
|
84
|
+
config.events = next;
|
|
85
|
+
await (0, config_1.saveConfig)(config);
|
|
86
|
+
console.log(chalk_1.default.green(`Updated: ${next.length}`));
|
|
148
87
|
};
|
|
149
|
-
// SCHEDULER
|
|
150
88
|
const schedule = (file) => {
|
|
151
89
|
const abs = normalize(file);
|
|
152
|
-
|
|
153
|
-
console.log(chalk_1.default.gray(`change: ${file}`));
|
|
154
|
-
queued.set(abs, { real: abs, virtual });
|
|
90
|
+
queue.set(abs, true);
|
|
155
91
|
if (timer)
|
|
156
92
|
clearTimeout(timer);
|
|
157
93
|
timer = setTimeout(run, 200);
|
|
158
94
|
};
|
|
159
|
-
// WATCHER
|
|
160
|
-
const watcher = chokidar_1.default.watch(config.sync.include, {
|
|
161
|
-
ignored: config.sync.exclude,
|
|
162
|
-
ignoreInitial: true,
|
|
163
|
-
persistent: true,
|
|
164
|
-
});
|
|
165
95
|
watcher
|
|
166
|
-
.on("add", schedule)
|
|
167
96
|
.on("change", schedule)
|
|
97
|
+
.on("add", schedule)
|
|
168
98
|
.on("unlink", async (file) => {
|
|
169
99
|
const abs = normalize(file);
|
|
170
|
-
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
watcher.unwatch(abs);
|
|
174
|
-
watchedDeps.delete(abs);
|
|
175
|
-
const next = engine.getAllEvents();
|
|
176
|
-
config.events = next.sort();
|
|
100
|
+
engine.removeFile((0, getVirtualFile_1.getVirtualFile)(abs), config);
|
|
101
|
+
const next = engine.getAllEvents().sort();
|
|
102
|
+
config.events = next;
|
|
177
103
|
await (0, config_1.saveConfig)(config);
|
|
178
|
-
console.log(chalk_1.default.
|
|
179
|
-
})
|
|
180
|
-
.on("error", (err) => {
|
|
181
|
-
console.error(chalk_1.default.red("Watcher error:"), err);
|
|
104
|
+
console.log(chalk_1.default.red(`Removed → ${next.length}`));
|
|
182
105
|
});
|
|
183
|
-
// WATCH DEPS INIT
|
|
184
|
-
for (const dep of watchedDeps) {
|
|
185
|
-
watcher.add(dep);
|
|
186
|
-
}
|
|
187
|
-
// EXIT
|
|
188
106
|
process.on("SIGINT", async () => {
|
|
189
|
-
console.log(chalk_1.default.yellow("\nStopping watcher..."));
|
|
190
107
|
await watcher.close();
|
|
191
108
|
process.exit(0);
|
|
192
109
|
});
|
package/dist/engine/engine.js
CHANGED
|
@@ -41,7 +41,7 @@ class EventraEngine {
|
|
|
41
41
|
this.graph.update(file, source);
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
-
// SCAN FILE
|
|
44
|
+
// SCAN FILE (cached)
|
|
45
45
|
scanFile(file, content, config) {
|
|
46
46
|
file = this.normalize(file);
|
|
47
47
|
const h = (0, hash_1.hash)(content);
|
|
@@ -55,7 +55,6 @@ class EventraEngine {
|
|
|
55
55
|
if (!source || !checker) {
|
|
56
56
|
return this.empty();
|
|
57
57
|
}
|
|
58
|
-
// update graph
|
|
59
58
|
this.graph.update(file, source);
|
|
60
59
|
const res = (0, scanner_1.scanSource)(source, checker, config, new Set(), undefined, this.wrapperCache);
|
|
61
60
|
this.fileResults.set(file, res);
|
|
@@ -63,12 +62,19 @@ class EventraEngine {
|
|
|
63
62
|
}
|
|
64
63
|
// UPDATE FILE (incremental)
|
|
65
64
|
updateFile(file, content, config) {
|
|
66
|
-
this.wrapperCache.clear();
|
|
67
65
|
file = this.normalize(file);
|
|
66
|
+
// EARLY EXIT
|
|
67
|
+
if (this.fileHash.get(file) === (0, hash_1.hash)(content)) {
|
|
68
|
+
return this.fileResults.get(file) ?? this.empty();
|
|
69
|
+
}
|
|
70
|
+
// invalidate wrapper cache
|
|
71
|
+
this.wrapperCache.clear();
|
|
68
72
|
const res = this.scanFile(file, content, config);
|
|
69
73
|
const dependents = this.graph.getAllDependentsDeep(file);
|
|
70
74
|
for (const dep of dependents) {
|
|
71
75
|
const abs = this.normalize(dep);
|
|
76
|
+
if (abs === file)
|
|
77
|
+
continue; // self-skip
|
|
72
78
|
if ((0, boundary_1.isExternalFile)(abs))
|
|
73
79
|
continue;
|
|
74
80
|
let depContent = this.ts.getFileContent(abs);
|
|
@@ -106,15 +112,17 @@ class EventraEngine {
|
|
|
106
112
|
}
|
|
107
113
|
// REMOVE FILE
|
|
108
114
|
removeFile(file, config) {
|
|
109
|
-
this.wrapperCache.clear();
|
|
110
115
|
file = this.normalize(file);
|
|
116
|
+
this.wrapperCache.clear();
|
|
111
117
|
const dependents = this.graph.getAllDependentsDeep(file);
|
|
118
|
+
this.graph.remove(file);
|
|
112
119
|
this.ts.removeFile(file);
|
|
113
120
|
this.fileResults.delete(file);
|
|
114
121
|
this.fileHash.delete(file);
|
|
115
|
-
this.graph.remove(file);
|
|
116
122
|
for (const dep of dependents) {
|
|
117
123
|
const abs = this.normalize(dep);
|
|
124
|
+
if (abs === file)
|
|
125
|
+
continue;
|
|
118
126
|
if ((0, boundary_1.isExternalFile)(abs))
|
|
119
127
|
continue;
|
|
120
128
|
let content = this.ts.getFileContent(abs);
|
|
@@ -126,10 +134,7 @@ class EventraEngine {
|
|
|
126
134
|
continue;
|
|
127
135
|
}
|
|
128
136
|
}
|
|
129
|
-
|
|
130
|
-
if (this.fileHash.get(abs) === h)
|
|
131
|
-
continue;
|
|
132
|
-
this.fileHash.set(abs, h);
|
|
137
|
+
this.fileHash.delete(abs);
|
|
133
138
|
this.ts.updateFile(abs, content);
|
|
134
139
|
const source = this.ts.getSourceFile(abs);
|
|
135
140
|
const checker = this.ts.getChecker();
|
package/dist/engine/scanner.js
CHANGED
|
@@ -8,6 +8,7 @@ const typescript_1 = __importDefault(require("typescript"));
|
|
|
8
8
|
const resolver_1 = require("./resolver");
|
|
9
9
|
const callResolver_1 = require("./callResolver");
|
|
10
10
|
const exportResolver_1 = require("./exportResolver");
|
|
11
|
+
// HELPERS
|
|
11
12
|
function isValidEvent(v) {
|
|
12
13
|
return (v &&
|
|
13
14
|
v.length > 1 &&
|
|
@@ -36,6 +37,7 @@ function getJsxAttrName(name) {
|
|
|
36
37
|
return name.name.text;
|
|
37
38
|
return "";
|
|
38
39
|
}
|
|
40
|
+
// MAIN
|
|
39
41
|
function scanSource(source, checker, config, visited = new Set(), inheritedParamMap, wrapperCache = new Map()) {
|
|
40
42
|
const events = new Set();
|
|
41
43
|
const detectedFunctionWrappers = new Set();
|
|
@@ -44,30 +46,38 @@ function scanSource(source, checker, config, visited = new Set(), inheritedParam
|
|
|
44
46
|
return { events, detectedFunctionWrappers, detectedComponentWrappers };
|
|
45
47
|
}
|
|
46
48
|
visited.add(source.fileName);
|
|
49
|
+
// TRACK DETECTION
|
|
50
|
+
function isTrackCall(expr) {
|
|
51
|
+
if (typescript_1.default.isIdentifier(expr)) {
|
|
52
|
+
return expr.text === "track";
|
|
53
|
+
}
|
|
54
|
+
if (typescript_1.default.isPropertyAccessExpression(expr)) {
|
|
55
|
+
return expr.name.text === "track";
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
47
59
|
function extractTrackCall(node, paramMap) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
60
|
+
if (!isTrackCall(node.expression))
|
|
61
|
+
return;
|
|
62
|
+
const arg = node.arguments[0];
|
|
63
|
+
if (!arg)
|
|
64
|
+
return;
|
|
65
|
+
const res = (0, resolver_1.resolveNodeValue)(arg, checker, paramMap);
|
|
66
|
+
for (const v of res.values) {
|
|
67
|
+
if (isValidEvent(v)) {
|
|
68
|
+
events.add(v);
|
|
57
69
|
}
|
|
58
70
|
}
|
|
59
71
|
}
|
|
72
|
+
// WRAPPER DETECTION
|
|
60
73
|
function isWrapperFunction(fn) {
|
|
61
74
|
let found = false;
|
|
62
75
|
function walk(n) {
|
|
63
76
|
if (found)
|
|
64
77
|
return;
|
|
65
|
-
if (typescript_1.default.isCallExpression(n)) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
found = true;
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
78
|
+
if (typescript_1.default.isCallExpression(n) && isTrackCall(n.expression)) {
|
|
79
|
+
found = true;
|
|
80
|
+
return;
|
|
71
81
|
}
|
|
72
82
|
typescript_1.default.forEachChild(n, walk);
|
|
73
83
|
}
|
|
@@ -75,10 +85,12 @@ function scanSource(source, checker, config, visited = new Set(), inheritedParam
|
|
|
75
85
|
walk(fn.body);
|
|
76
86
|
return found;
|
|
77
87
|
}
|
|
88
|
+
// COMPONENT WRAPPER
|
|
78
89
|
function detectComponentWrapper(tag) {
|
|
79
90
|
const tagName = getJsxTagName(tag);
|
|
80
|
-
if (wrapperCache.has(tagName))
|
|
91
|
+
if (wrapperCache.has(tagName)) {
|
|
81
92
|
return wrapperCache.get(tagName);
|
|
93
|
+
}
|
|
82
94
|
let symbol = checker.getSymbolAtLocation(tag);
|
|
83
95
|
if (symbol && (symbol.flags & typescript_1.default.SymbolFlags.Alias)) {
|
|
84
96
|
symbol = checker.getAliasedSymbol(symbol);
|
|
@@ -104,14 +116,11 @@ function scanSource(source, checker, config, visited = new Set(), inheritedParam
|
|
|
104
116
|
function walk(n) {
|
|
105
117
|
if (prop)
|
|
106
118
|
return;
|
|
107
|
-
if (typescript_1.default.isCallExpression(n)) {
|
|
108
|
-
const
|
|
109
|
-
if (typescript_1.default.isPropertyAccessExpression(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
prop = arg.name.text;
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
119
|
+
if (typescript_1.default.isCallExpression(n) && isTrackCall(n.expression)) {
|
|
120
|
+
const arg = n.arguments[0];
|
|
121
|
+
if (typescript_1.default.isPropertyAccessExpression(arg)) {
|
|
122
|
+
prop = arg.name.text;
|
|
123
|
+
return;
|
|
115
124
|
}
|
|
116
125
|
}
|
|
117
126
|
typescript_1.default.forEachChild(n, walk);
|
|
@@ -126,6 +135,7 @@ function scanSource(source, checker, config, visited = new Set(), inheritedParam
|
|
|
126
135
|
wrapperCache.set(tagName, null);
|
|
127
136
|
return null;
|
|
128
137
|
}
|
|
138
|
+
// VISITOR
|
|
129
139
|
function visit(node) {
|
|
130
140
|
// JSX
|
|
131
141
|
if (typescript_1.default.isJsxSelfClosingElement(node) || typescript_1.default.isJsxOpeningElement(node)) {
|
|
@@ -183,9 +193,7 @@ function scanSource(source, checker, config, visited = new Set(), inheritedParam
|
|
|
183
193
|
}
|
|
184
194
|
});
|
|
185
195
|
}
|
|
186
|
-
// direct track
|
|
187
196
|
extractTrackCall(node, paramMap);
|
|
188
|
-
// wrapper
|
|
189
197
|
if (resolvedFn && isWrapperFunction(resolvedFn)) {
|
|
190
198
|
const name = getCallName(node.expression);
|
|
191
199
|
if (name && name !== "track") {
|
|
@@ -195,9 +203,14 @@ function scanSource(source, checker, config, visited = new Set(), inheritedParam
|
|
|
195
203
|
visit(resolvedFn.body);
|
|
196
204
|
}
|
|
197
205
|
}
|
|
198
|
-
|
|
199
|
-
|
|
206
|
+
if (resolvedFn && resolvedFn.body) {
|
|
207
|
+
const sf = resolvedFn.getSourceFile();
|
|
208
|
+
if (!visited.has(sf.fileName)) {
|
|
209
|
+
const res = scanSource(sf, checker, config, visited, paramMap, wrapperCache);
|
|
210
|
+
res.events.forEach(e => events.add(e));
|
|
211
|
+
}
|
|
200
212
|
}
|
|
213
|
+
node.arguments.forEach(visit);
|
|
201
214
|
visit(node.expression);
|
|
202
215
|
return;
|
|
203
216
|
}
|
package/dist/utils/universal.js
CHANGED