@eventra_dev/eventra-cli 0.1.24 → 0.1.25
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 +65 -29
- package/dist/engine/engine.js +3 -1
- package/dist/utils/getVirtualFile.js +8 -0
- package/package.json +1 -1
- package/src/commands/check.ts +49 -29
- package/src/commands/sync.ts +48 -47
- package/src/commands/watch.ts +78 -30
- package/src/engine/engine.ts +3 -1
- package/src/utils/getVirtualFile.ts +5 -0
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,12 +12,7 @@ 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 getVirtualFile(file) {
|
|
17
|
-
return /\.(vue|svelte|astro|html)$/i.test(file)
|
|
18
|
-
? file + ".tsx"
|
|
19
|
-
: file;
|
|
20
|
-
}
|
|
15
|
+
const getVirtualFile_1 = require("../utils/getVirtualFile");
|
|
21
16
|
async function watch() {
|
|
22
17
|
const config = await (0, config_1.loadConfig)();
|
|
23
18
|
if (!config)
|
|
@@ -25,48 +20,82 @@ async function watch() {
|
|
|
25
20
|
console.log(chalk_1.default.blue("Watching...\n"));
|
|
26
21
|
const files = await (0, fast_glob_1.default)(config.sync.include, {
|
|
27
22
|
ignore: config.sync.exclude,
|
|
23
|
+
absolute: true,
|
|
28
24
|
});
|
|
29
25
|
const engine = new engine_1.EventraEngine(process.cwd());
|
|
30
26
|
const watchedDeps = new Set();
|
|
31
|
-
|
|
27
|
+
const cache = new Map();
|
|
28
|
+
const toScan = new Set();
|
|
29
|
+
// COLLECT + CACHE
|
|
32
30
|
for (const file of files) {
|
|
33
31
|
try {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
for (const dep of deps) {
|
|
41
|
-
|
|
32
|
+
const raw = await promises_1.default.readFile(file, "utf-8");
|
|
33
|
+
if (raw.length > 2_000_000)
|
|
34
|
+
continue; // safeguard
|
|
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
|
+
const absDep = path_1.default.resolve(dep);
|
|
40
|
+
toScan.add(absDep);
|
|
42
41
|
}
|
|
43
42
|
}
|
|
44
43
|
catch {
|
|
45
44
|
console.log(chalk_1.default.gray(`skip: ${file}`));
|
|
46
45
|
}
|
|
47
46
|
}
|
|
47
|
+
// PRELOAD (TS PROGRAM)
|
|
48
|
+
for (const file of toScan) {
|
|
49
|
+
try {
|
|
50
|
+
let parsed = cache.get(file);
|
|
51
|
+
if (!parsed) {
|
|
52
|
+
const raw = await promises_1.default.readFile(file, "utf-8");
|
|
53
|
+
parsed = (0, processFile_1.processFile)(file, raw);
|
|
54
|
+
}
|
|
55
|
+
const virtual = (0, getVirtualFile_1.getVirtualFile)(file);
|
|
56
|
+
engine.preloadFile?.(virtual, parsed.content);
|
|
57
|
+
}
|
|
58
|
+
catch { }
|
|
59
|
+
}
|
|
60
|
+
// INITIAL SCAN
|
|
61
|
+
for (const file of toScan) {
|
|
62
|
+
try {
|
|
63
|
+
let parsed = cache.get(file);
|
|
64
|
+
if (!parsed) {
|
|
65
|
+
const raw = await promises_1.default.readFile(file, "utf-8");
|
|
66
|
+
parsed = (0, processFile_1.processFile)(file, raw);
|
|
67
|
+
}
|
|
68
|
+
const virtual = (0, getVirtualFile_1.getVirtualFile)(file);
|
|
69
|
+
engine.scanFile(virtual, parsed.content, config);
|
|
70
|
+
for (const dep of parsed.deps) {
|
|
71
|
+
watchedDeps.add(path_1.default.resolve(dep));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch { }
|
|
75
|
+
}
|
|
48
76
|
config.events = engine.getAllEvents().sort();
|
|
49
77
|
await (0, config_1.saveConfig)(config);
|
|
50
78
|
console.log(chalk_1.default.gray(`Initial: ${config.events.length} events\n`));
|
|
51
79
|
// QUEUE
|
|
52
80
|
let locked = false;
|
|
53
|
-
|
|
81
|
+
const queued = new Map();
|
|
54
82
|
let timer = null;
|
|
55
83
|
const run = async () => {
|
|
56
|
-
if (locked)
|
|
57
|
-
timer = setTimeout(run, 100);
|
|
84
|
+
if (locked)
|
|
58
85
|
return;
|
|
59
|
-
}
|
|
60
86
|
locked = true;
|
|
61
87
|
const batch = [...queued.values()];
|
|
62
88
|
queued.clear();
|
|
63
89
|
for (const item of batch) {
|
|
64
90
|
try {
|
|
65
91
|
const raw = await promises_1.default.readFile(item.real, "utf-8");
|
|
66
|
-
|
|
67
|
-
|
|
92
|
+
if (raw.length > 2_000_000)
|
|
93
|
+
continue;
|
|
94
|
+
const parsed = (0, processFile_1.processFile)(item.real, raw);
|
|
95
|
+
cache.set(item.real, parsed);
|
|
96
|
+
engine.updateFile(item.virtual, parsed.content, config);
|
|
68
97
|
// DEPS
|
|
69
|
-
for (const dep of deps) {
|
|
98
|
+
for (const dep of parsed.deps) {
|
|
70
99
|
const absDep = path_1.default.resolve(dep);
|
|
71
100
|
if (!watchedDeps.has(absDep)) {
|
|
72
101
|
watcher.add(absDep);
|
|
@@ -74,9 +103,10 @@ async function watch() {
|
|
|
74
103
|
}
|
|
75
104
|
try {
|
|
76
105
|
const depRaw = await promises_1.default.readFile(absDep, "utf-8");
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
106
|
+
const depParsed = (0, processFile_1.processFile)(absDep, depRaw);
|
|
107
|
+
cache.set(absDep, depParsed);
|
|
108
|
+
const depVirtual = (0, getVirtualFile_1.getVirtualFile)(absDep);
|
|
109
|
+
engine.updateFile(depVirtual, depParsed.content, config);
|
|
80
110
|
}
|
|
81
111
|
catch { }
|
|
82
112
|
}
|
|
@@ -85,7 +115,7 @@ async function watch() {
|
|
|
85
115
|
console.log(chalk_1.default.gray(`skip: ${item.real}`));
|
|
86
116
|
}
|
|
87
117
|
}
|
|
88
|
-
// EVENTS
|
|
118
|
+
// DIFF EVENTS
|
|
89
119
|
const next = engine.getAllEvents();
|
|
90
120
|
const added = next.filter(e => !config.events.includes(e));
|
|
91
121
|
const removed = config.events.filter(e => !next.includes(e));
|
|
@@ -101,16 +131,18 @@ async function watch() {
|
|
|
101
131
|
// SCHEDULER
|
|
102
132
|
const schedule = (file) => {
|
|
103
133
|
const abs = path_1.default.resolve(file);
|
|
104
|
-
const virtual = getVirtualFile(abs);
|
|
134
|
+
const virtual = (0, getVirtualFile_1.getVirtualFile)(abs);
|
|
135
|
+
console.log(chalk_1.default.gray(`change: ${file}`));
|
|
105
136
|
queued.set(abs, { real: abs, virtual });
|
|
106
137
|
if (timer)
|
|
107
138
|
clearTimeout(timer);
|
|
108
|
-
timer = setTimeout(run,
|
|
139
|
+
timer = setTimeout(run, 250);
|
|
109
140
|
};
|
|
110
141
|
// WATCHER
|
|
111
142
|
const watcher = chokidar_1.default.watch(config.sync.include, {
|
|
112
143
|
ignored: config.sync.exclude,
|
|
113
144
|
ignoreInitial: true,
|
|
145
|
+
persistent: true,
|
|
114
146
|
});
|
|
115
147
|
watcher
|
|
116
148
|
.on("add", schedule)
|
|
@@ -118,13 +150,17 @@ async function watch() {
|
|
|
118
150
|
.on("unlink", async (file) => {
|
|
119
151
|
const abs = path_1.default.resolve(file);
|
|
120
152
|
console.log(chalk_1.default.gray(`remove: ${file}`));
|
|
121
|
-
const virtual = getVirtualFile(abs);
|
|
153
|
+
const virtual = (0, getVirtualFile_1.getVirtualFile)(abs);
|
|
122
154
|
engine.removeFile(virtual, config);
|
|
155
|
+
watcher.unwatch(abs);
|
|
123
156
|
watchedDeps.delete(abs);
|
|
124
157
|
const next = engine.getAllEvents();
|
|
125
158
|
config.events = next.sort();
|
|
126
159
|
await (0, config_1.saveConfig)(config);
|
|
127
160
|
console.log(chalk_1.default.gray(`Total: ${config.events.length} events\n`));
|
|
161
|
+
})
|
|
162
|
+
.on("error", (err) => {
|
|
163
|
+
console.error(chalk_1.default.red("Watcher error:"), err);
|
|
128
164
|
});
|
|
129
165
|
// WATCH DEPS
|
|
130
166
|
for (const dep of watchedDeps) {
|
package/dist/engine/engine.js
CHANGED
|
@@ -16,6 +16,9 @@ class EventraEngine {
|
|
|
16
16
|
const { baseUrl, paths } = this.ts.getModuleResolutionConfig();
|
|
17
17
|
this.graph = new graph_1.DependencyGraph(baseUrl, paths);
|
|
18
18
|
}
|
|
19
|
+
preloadFile(file, content) {
|
|
20
|
+
this.ts.updateFile(file, content);
|
|
21
|
+
}
|
|
19
22
|
// SCAN FILE
|
|
20
23
|
scanFile(file, content, config) {
|
|
21
24
|
const h = (0, hash_1.hash)(content);
|
|
@@ -45,7 +48,6 @@ class EventraEngine {
|
|
|
45
48
|
}
|
|
46
49
|
// UPDATE FILE (incremental)
|
|
47
50
|
updateFile(file, content, config) {
|
|
48
|
-
// сначала обновляем текущий файл
|
|
49
51
|
const res = this.scanFile(file, content, config);
|
|
50
52
|
const dependents = this.graph.getAllDependentsDeep(file);
|
|
51
53
|
for (const dep of dependents) {
|
package/package.json
CHANGED
package/src/commands/check.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import fg from "fast-glob";
|
|
3
3
|
import fs from "fs/promises";
|
|
4
|
+
import path from "path";
|
|
4
5
|
|
|
5
6
|
import { loadConfig, saveConfig } from "../utils/config";
|
|
6
7
|
import { EventraEngine } from "../engine/engine";
|
|
7
8
|
import { processFile } from "../utils/processFile";
|
|
9
|
+
import { getVirtualFile } from "../utils/getVirtualFile";
|
|
8
10
|
|
|
9
11
|
export async function check({ fix = false }: { fix?: boolean }) {
|
|
10
12
|
const config = await loadConfig();
|
|
@@ -18,36 +20,68 @@ export async function check({ fix = false }: { fix?: boolean }) {
|
|
|
18
20
|
|
|
19
21
|
const files = await fg(config.sync.include, {
|
|
20
22
|
ignore: config.sync.exclude,
|
|
23
|
+
absolute: true,
|
|
21
24
|
});
|
|
22
25
|
|
|
23
26
|
const engine = new EventraEngine(process.cwd());
|
|
24
27
|
|
|
28
|
+
const toScan = new Set<string>();
|
|
29
|
+
|
|
30
|
+
const cache = new Map<
|
|
31
|
+
string,
|
|
32
|
+
{ content: string; deps: string[] }
|
|
33
|
+
>();
|
|
34
|
+
|
|
35
|
+
// COLLECT + CACHE
|
|
25
36
|
for (const file of files) {
|
|
26
37
|
try {
|
|
27
38
|
const raw = await fs.readFile(file, "utf-8");
|
|
28
39
|
|
|
29
|
-
|
|
40
|
+
if (raw.length > 2_000_000) continue;
|
|
41
|
+
|
|
42
|
+
const parsed = processFile(file, raw);
|
|
30
43
|
|
|
31
|
-
|
|
44
|
+
cache.set(file, parsed);
|
|
45
|
+
toScan.add(file);
|
|
32
46
|
|
|
33
|
-
for (const dep of deps) {
|
|
34
|
-
|
|
35
|
-
|
|
47
|
+
for (const dep of parsed.deps) {
|
|
48
|
+
toScan.add(path.resolve(dep));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
} catch {}
|
|
52
|
+
}
|
|
36
53
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
54
|
+
// PRELOAD
|
|
55
|
+
for (const file of toScan) {
|
|
56
|
+
try {
|
|
57
|
+
let parsed = cache.get(file);
|
|
41
58
|
|
|
42
|
-
|
|
43
|
-
|
|
59
|
+
if (!parsed) {
|
|
60
|
+
const raw = await fs.readFile(file, "utf-8");
|
|
61
|
+
parsed = processFile(file, raw);
|
|
62
|
+
cache.set(file, parsed);
|
|
44
63
|
}
|
|
45
64
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
65
|
+
const virtual = getVirtualFile(file);
|
|
66
|
+
engine.preloadFile(virtual, parsed.content);
|
|
67
|
+
|
|
68
|
+
} catch {}
|
|
49
69
|
}
|
|
50
70
|
|
|
71
|
+
// SCAN
|
|
72
|
+
for (const file of toScan) {
|
|
73
|
+
try {
|
|
74
|
+
const parsed = cache.get(file);
|
|
75
|
+
if (!parsed) continue;
|
|
76
|
+
|
|
77
|
+
const virtual = getVirtualFile(file);
|
|
78
|
+
|
|
79
|
+
engine.scanFile(virtual, parsed.content, config);
|
|
80
|
+
|
|
81
|
+
} catch {}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// DIFF
|
|
51
85
|
const found = new Set(engine.getAllEvents());
|
|
52
86
|
const known = new Set(config.events ?? []);
|
|
53
87
|
|
|
@@ -56,26 +90,12 @@ export async function check({ fix = false }: { fix?: boolean }) {
|
|
|
56
90
|
|
|
57
91
|
// FIX MODE
|
|
58
92
|
if (fix) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
found.forEach(e => next.add(e));
|
|
62
|
-
|
|
63
|
-
newEvents.forEach(e =>
|
|
64
|
-
console.log(chalk.green(`+ ${e}`))
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
removed.forEach(e =>
|
|
68
|
-
console.log(chalk.red(`- ${e}`))
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
config.events = [...next].sort();
|
|
72
|
-
|
|
93
|
+
config.events = [...found].sort();
|
|
73
94
|
await saveConfig(config);
|
|
74
95
|
|
|
75
96
|
console.log(
|
|
76
97
|
chalk.green(`\nSynced (${config.events.length} events)`)
|
|
77
98
|
);
|
|
78
|
-
|
|
79
99
|
return;
|
|
80
100
|
}
|
|
81
101
|
|
package/src/commands/sync.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import fg from "fast-glob";
|
|
2
2
|
import fs from "fs/promises";
|
|
3
3
|
import chalk from "chalk";
|
|
4
|
+
import path from "path";
|
|
4
5
|
|
|
5
6
|
import { loadConfig, saveConfig } from "../utils/config";
|
|
6
7
|
import { EventraEngine } from "../engine/engine";
|
|
7
8
|
import { processFile } from "../utils/processFile";
|
|
9
|
+
import { getVirtualFile } from "../utils/getVirtualFile";
|
|
8
10
|
|
|
9
11
|
export async function sync() {
|
|
10
12
|
const config = await loadConfig();
|
|
@@ -14,6 +16,7 @@ export async function sync() {
|
|
|
14
16
|
|
|
15
17
|
const files = await fg(config.sync.include, {
|
|
16
18
|
ignore: config.sync.exclude,
|
|
19
|
+
absolute: true,
|
|
17
20
|
});
|
|
18
21
|
|
|
19
22
|
if (!files.length) {
|
|
@@ -23,76 +26,86 @@ export async function sync() {
|
|
|
23
26
|
|
|
24
27
|
const engine = new EventraEngine(process.cwd());
|
|
25
28
|
|
|
26
|
-
const
|
|
27
|
-
const detectedCmp = new Map<string, string>();
|
|
29
|
+
const toScan = new Set<string>();
|
|
28
30
|
|
|
29
|
-
const
|
|
31
|
+
const cache = new Map<
|
|
32
|
+
string,
|
|
33
|
+
{ content: string; deps: string[] }
|
|
34
|
+
>();
|
|
30
35
|
|
|
36
|
+
// COLLECT + CACHE
|
|
31
37
|
for (const file of files) {
|
|
32
38
|
try {
|
|
33
39
|
const raw = await fs.readFile(file, "utf-8");
|
|
34
40
|
|
|
35
|
-
|
|
41
|
+
if (raw.length > 2_000_000) continue;
|
|
36
42
|
|
|
37
|
-
|
|
38
|
-
fileCache.push({ file: virtualFile, content });
|
|
43
|
+
const parsed = processFile(file, raw);
|
|
39
44
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
try {
|
|
43
|
-
const depRaw = await fs.readFile(dep, "utf-8");
|
|
45
|
+
cache.set(file, parsed);
|
|
46
|
+
toScan.add(file);
|
|
44
47
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
} = processFile(dep, depRaw);
|
|
48
|
+
for (const dep of parsed.deps) {
|
|
49
|
+
toScan.add(path.resolve(dep));
|
|
50
|
+
}
|
|
49
51
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
} catch {}
|
|
53
|
+
}
|
|
52
54
|
|
|
53
|
-
|
|
55
|
+
// PRELOAD
|
|
56
|
+
for (const file of toScan) {
|
|
57
|
+
try {
|
|
58
|
+
let parsed = cache.get(file);
|
|
59
|
+
|
|
60
|
+
if (!parsed) {
|
|
61
|
+
const raw = await fs.readFile(file, "utf-8");
|
|
62
|
+
parsed = processFile(file, raw);
|
|
63
|
+
cache.set(file, parsed);
|
|
54
64
|
}
|
|
55
65
|
|
|
66
|
+
const virtual = getVirtualFile(file);
|
|
67
|
+
engine.preloadFile(virtual, parsed.content);
|
|
68
|
+
|
|
56
69
|
} catch {}
|
|
57
70
|
}
|
|
58
71
|
|
|
59
|
-
|
|
72
|
+
// SCAN
|
|
73
|
+
const detectedFn = new Set<string>();
|
|
74
|
+
const detectedCmp = new Map<string, string>();
|
|
75
|
+
|
|
76
|
+
for (const file of toScan) {
|
|
60
77
|
try {
|
|
61
|
-
const
|
|
78
|
+
const parsed = cache.get(file);
|
|
79
|
+
if (!parsed) continue;
|
|
62
80
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
81
|
+
const virtual = getVirtualFile(file);
|
|
82
|
+
|
|
83
|
+
const res = engine.scanFile(virtual, parsed.content, config);
|
|
84
|
+
|
|
85
|
+
res.detectedFunctionWrappers.forEach(w =>
|
|
86
|
+
detectedFn.add(w)
|
|
87
|
+
);
|
|
66
88
|
|
|
67
89
|
for (const [k, v] of res.detectedComponentWrappers) {
|
|
68
90
|
detectedCmp.set(k, v);
|
|
69
91
|
}
|
|
70
92
|
|
|
71
|
-
} catch
|
|
72
|
-
console.log(chalk.
|
|
73
|
-
|
|
74
|
-
if (err instanceof Error) {
|
|
75
|
-
console.log(chalk.gray(err.message));
|
|
76
|
-
}
|
|
93
|
+
} catch {
|
|
94
|
+
console.log(chalk.gray(`skip: ${file}`));
|
|
77
95
|
}
|
|
78
96
|
}
|
|
79
97
|
|
|
80
|
-
//
|
|
98
|
+
// RESULT
|
|
81
99
|
const events = engine.getAllEvents().sort();
|
|
82
100
|
|
|
83
|
-
|
|
84
|
-
events.forEach(e => mergedEvents.add(e));
|
|
101
|
+
config.events = events;
|
|
85
102
|
|
|
86
|
-
config.events = [...mergedEvents].sort();
|
|
87
|
-
|
|
88
|
-
// FUNCTION WRAPPERS
|
|
89
103
|
config.functionWrappers = mergeUnique(
|
|
90
104
|
config.functionWrappers ?? [],
|
|
91
105
|
[...detectedFn].map(name => ({ name })),
|
|
92
106
|
w => w.name
|
|
93
107
|
);
|
|
94
108
|
|
|
95
|
-
// COMPONENT WRAPPERS
|
|
96
109
|
config.wrappers = mergeUnique(
|
|
97
110
|
config.wrappers ?? [],
|
|
98
111
|
[...detectedCmp.entries()].map(([name, prop]) => ({
|
|
@@ -105,18 +118,6 @@ export async function sync() {
|
|
|
105
118
|
await saveConfig(config);
|
|
106
119
|
|
|
107
120
|
console.log(chalk.green(`Found ${events.length} events`));
|
|
108
|
-
|
|
109
|
-
if (detectedFn.size) {
|
|
110
|
-
console.log(chalk.blue("\nDetected function wrappers:"));
|
|
111
|
-
detectedFn.forEach(w => console.log(chalk.gray(`• ${w}`)));
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (detectedCmp.size) {
|
|
115
|
-
console.log(chalk.blue("\nDetected component wrappers:"));
|
|
116
|
-
detectedCmp.forEach((prop, name) =>
|
|
117
|
-
console.log(chalk.gray(`• ${name} (${prop})`))
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
121
|
}
|
|
121
122
|
|
|
122
123
|
// HELPERS
|
package/src/commands/watch.ts
CHANGED
|
@@ -7,19 +7,13 @@ import path from "path";
|
|
|
7
7
|
import { loadConfig, saveConfig } from "../utils/config";
|
|
8
8
|
import { EventraEngine } from "../engine/engine";
|
|
9
9
|
import { processFile } from "../utils/processFile";
|
|
10
|
+
import { getVirtualFile } from "../utils/getVirtualFile";
|
|
10
11
|
|
|
11
12
|
type QueueItem = {
|
|
12
13
|
real: string;
|
|
13
14
|
virtual: string;
|
|
14
15
|
};
|
|
15
16
|
|
|
16
|
-
// stabile virtual mapping
|
|
17
|
-
function getVirtualFile(file: string) {
|
|
18
|
-
return /\.(vue|svelte|astro|html)$/i.test(file)
|
|
19
|
-
? file + ".tsx"
|
|
20
|
-
: file;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
17
|
export async function watch() {
|
|
24
18
|
const config = await loadConfig();
|
|
25
19
|
if (!config) return;
|
|
@@ -28,26 +22,33 @@ export async function watch() {
|
|
|
28
22
|
|
|
29
23
|
const files = await fg(config.sync.include, {
|
|
30
24
|
ignore: config.sync.exclude,
|
|
25
|
+
absolute: true,
|
|
31
26
|
});
|
|
32
27
|
|
|
33
28
|
const engine = new EventraEngine(process.cwd());
|
|
34
|
-
|
|
35
29
|
const watchedDeps = new Set<string>();
|
|
30
|
+
const cache = new Map<
|
|
31
|
+
string,
|
|
32
|
+
{ content: string; deps: string[] }
|
|
33
|
+
>();
|
|
36
34
|
|
|
37
|
-
|
|
35
|
+
const toScan = new Set<string>();
|
|
36
|
+
|
|
37
|
+
// COLLECT + CACHE
|
|
38
38
|
for (const file of files) {
|
|
39
39
|
try {
|
|
40
|
-
const
|
|
41
|
-
const raw = await fs.readFile(abs, "utf-8");
|
|
40
|
+
const raw = await fs.readFile(file, "utf-8");
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
const virtual = getVirtualFile(abs);
|
|
42
|
+
if (raw.length > 2_000_000) continue; // safeguard
|
|
45
43
|
|
|
46
|
-
|
|
44
|
+
const parsed = processFile(file, raw);
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
cache.set(file, parsed);
|
|
47
|
+
toScan.add(file);
|
|
48
|
+
|
|
49
|
+
for (const dep of parsed.deps) {
|
|
50
|
+
const absDep = path.resolve(dep);
|
|
51
|
+
toScan.add(absDep);
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
} catch {
|
|
@@ -55,6 +56,44 @@ export async function watch() {
|
|
|
55
56
|
}
|
|
56
57
|
}
|
|
57
58
|
|
|
59
|
+
// PRELOAD (TS PROGRAM)
|
|
60
|
+
for (const file of toScan) {
|
|
61
|
+
try {
|
|
62
|
+
let parsed = cache.get(file);
|
|
63
|
+
|
|
64
|
+
if (!parsed) {
|
|
65
|
+
const raw = await fs.readFile(file, "utf-8");
|
|
66
|
+
parsed = processFile(file, raw);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const virtual = getVirtualFile(file);
|
|
70
|
+
|
|
71
|
+
engine.preloadFile?.(virtual, parsed.content);
|
|
72
|
+
|
|
73
|
+
} catch {}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// INITIAL SCAN
|
|
77
|
+
for (const file of toScan) {
|
|
78
|
+
try {
|
|
79
|
+
let parsed = cache.get(file);
|
|
80
|
+
|
|
81
|
+
if (!parsed) {
|
|
82
|
+
const raw = await fs.readFile(file, "utf-8");
|
|
83
|
+
parsed = processFile(file, raw);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const virtual = getVirtualFile(file);
|
|
87
|
+
|
|
88
|
+
engine.scanFile(virtual, parsed.content, config);
|
|
89
|
+
|
|
90
|
+
for (const dep of parsed.deps) {
|
|
91
|
+
watchedDeps.add(path.resolve(dep));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
} catch {}
|
|
95
|
+
}
|
|
96
|
+
|
|
58
97
|
config.events = engine.getAllEvents().sort();
|
|
59
98
|
await saveConfig(config);
|
|
60
99
|
|
|
@@ -64,15 +103,11 @@ export async function watch() {
|
|
|
64
103
|
|
|
65
104
|
// QUEUE
|
|
66
105
|
let locked = false;
|
|
67
|
-
|
|
106
|
+
const queued = new Map<string, QueueItem>();
|
|
68
107
|
let timer: NodeJS.Timeout | null = null;
|
|
69
108
|
|
|
70
109
|
const run = async () => {
|
|
71
|
-
if (locked)
|
|
72
|
-
timer = setTimeout(run, 100);
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
|
|
110
|
+
if (locked) return;
|
|
76
111
|
locked = true;
|
|
77
112
|
|
|
78
113
|
const batch = [...queued.values()];
|
|
@@ -82,12 +117,16 @@ export async function watch() {
|
|
|
82
117
|
try {
|
|
83
118
|
const raw = await fs.readFile(item.real, "utf-8");
|
|
84
119
|
|
|
85
|
-
|
|
120
|
+
if (raw.length > 2_000_000) continue;
|
|
86
121
|
|
|
87
|
-
|
|
122
|
+
const parsed = processFile(item.real, raw);
|
|
123
|
+
|
|
124
|
+
cache.set(item.real, parsed);
|
|
125
|
+
|
|
126
|
+
engine.updateFile(item.virtual, parsed.content, config);
|
|
88
127
|
|
|
89
128
|
// DEPS
|
|
90
|
-
for (const dep of deps) {
|
|
129
|
+
for (const dep of parsed.deps) {
|
|
91
130
|
const absDep = path.resolve(dep);
|
|
92
131
|
|
|
93
132
|
if (!watchedDeps.has(absDep)) {
|
|
@@ -97,11 +136,13 @@ export async function watch() {
|
|
|
97
136
|
|
|
98
137
|
try {
|
|
99
138
|
const depRaw = await fs.readFile(absDep, "utf-8");
|
|
100
|
-
const
|
|
139
|
+
const depParsed = processFile(absDep, depRaw);
|
|
140
|
+
|
|
141
|
+
cache.set(absDep, depParsed);
|
|
101
142
|
|
|
102
143
|
const depVirtual = getVirtualFile(absDep);
|
|
103
144
|
|
|
104
|
-
engine.updateFile(depVirtual,
|
|
145
|
+
engine.updateFile(depVirtual, depParsed.content, config);
|
|
105
146
|
} catch {}
|
|
106
147
|
}
|
|
107
148
|
|
|
@@ -110,7 +151,7 @@ export async function watch() {
|
|
|
110
151
|
}
|
|
111
152
|
}
|
|
112
153
|
|
|
113
|
-
// EVENTS
|
|
154
|
+
// DIFF EVENTS
|
|
114
155
|
const next = engine.getAllEvents();
|
|
115
156
|
|
|
116
157
|
const added = next.filter(e => !config.events.includes(e));
|
|
@@ -136,16 +177,19 @@ export async function watch() {
|
|
|
136
177
|
const abs = path.resolve(file);
|
|
137
178
|
const virtual = getVirtualFile(abs);
|
|
138
179
|
|
|
180
|
+
console.log(chalk.gray(`change: ${file}`));
|
|
181
|
+
|
|
139
182
|
queued.set(abs, { real: abs, virtual });
|
|
140
183
|
|
|
141
184
|
if (timer) clearTimeout(timer);
|
|
142
|
-
timer = setTimeout(run,
|
|
185
|
+
timer = setTimeout(run, 250);
|
|
143
186
|
};
|
|
144
187
|
|
|
145
188
|
// WATCHER
|
|
146
189
|
const watcher = chokidar.watch(config.sync.include, {
|
|
147
190
|
ignored: config.sync.exclude,
|
|
148
191
|
ignoreInitial: true,
|
|
192
|
+
persistent: true,
|
|
149
193
|
});
|
|
150
194
|
|
|
151
195
|
watcher
|
|
@@ -160,6 +204,7 @@ export async function watch() {
|
|
|
160
204
|
|
|
161
205
|
engine.removeFile(virtual, config);
|
|
162
206
|
|
|
207
|
+
watcher.unwatch(abs);
|
|
163
208
|
watchedDeps.delete(abs);
|
|
164
209
|
|
|
165
210
|
const next = engine.getAllEvents();
|
|
@@ -170,6 +215,9 @@ export async function watch() {
|
|
|
170
215
|
console.log(
|
|
171
216
|
chalk.gray(`Total: ${config.events.length} events\n`)
|
|
172
217
|
);
|
|
218
|
+
})
|
|
219
|
+
.on("error", (err) => {
|
|
220
|
+
console.error(chalk.red("Watcher error:"), err);
|
|
173
221
|
});
|
|
174
222
|
|
|
175
223
|
// WATCH DEPS
|
package/src/engine/engine.ts
CHANGED
|
@@ -18,6 +18,9 @@ export class EventraEngine {
|
|
|
18
18
|
const { baseUrl, paths } = this.ts.getModuleResolutionConfig();
|
|
19
19
|
this.graph = new DependencyGraph(baseUrl, paths);
|
|
20
20
|
}
|
|
21
|
+
preloadFile(file: string, content: string) {
|
|
22
|
+
this.ts.updateFile(file, content);
|
|
23
|
+
}
|
|
21
24
|
|
|
22
25
|
// SCAN FILE
|
|
23
26
|
scanFile(
|
|
@@ -66,7 +69,6 @@ export class EventraEngine {
|
|
|
66
69
|
content: string,
|
|
67
70
|
config: EventraConfig
|
|
68
71
|
) {
|
|
69
|
-
// сначала обновляем текущий файл
|
|
70
72
|
const res = this.scanFile(file, content, config);
|
|
71
73
|
|
|
72
74
|
const dependents = this.graph.getAllDependentsDeep(file);
|