@eventra_dev/eventra-cli 0.1.17 → 0.1.19
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 +17 -11
- package/dist/commands/sync.js +12 -4
- package/dist/commands/watch.js +10 -1
- package/dist/engine/scanner.js +4 -2
- package/dist/utils/parsers/astro.js +17 -10
- package/dist/utils/parsers/router.js +15 -8
- package/dist/utils/parsers/svelte.js +7 -3
- package/dist/utils/parsers/vue.js +21 -11
- package/dist/utils/processFile.js +6 -10
- package/package.json +1 -1
- package/src/commands/check.ts +37 -14
- package/src/commands/sync.ts +21 -4
- package/src/commands/watch.ts +17 -1
- package/src/engine/scanner.ts +4 -2
- package/src/types.ts +8 -5
- package/src/utils/parsers/astro.ts +17 -12
- package/src/utils/parsers/router.ts +16 -6
- package/src/utils/parsers/svelte.ts +11 -4
- package/src/utils/parsers/vue.ts +21 -11
- package/src/utils/processFile.ts +6 -7
package/dist/commands/check.js
CHANGED
|
@@ -24,31 +24,37 @@ async function check({ fix = false }) {
|
|
|
24
24
|
for (const file of files) {
|
|
25
25
|
try {
|
|
26
26
|
const raw = await promises_1.default.readFile(file, "utf-8");
|
|
27
|
-
const { content, virtualFile } = (0, processFile_1.processFile)(file, raw);
|
|
27
|
+
const { content, virtualFile, deps } = (0, processFile_1.processFile)(file, raw);
|
|
28
28
|
engine.scanFile(virtualFile, content, config);
|
|
29
|
+
for (const dep of deps) {
|
|
30
|
+
try {
|
|
31
|
+
const depRaw = await promises_1.default.readFile(dep, "utf-8");
|
|
32
|
+
const { content: depContent, virtualFile: depVirtual, } = (0, processFile_1.processFile)(dep, depRaw);
|
|
33
|
+
engine.scanFile(depVirtual, depContent, config);
|
|
34
|
+
}
|
|
35
|
+
catch { }
|
|
36
|
+
}
|
|
29
37
|
}
|
|
30
38
|
catch (err) {
|
|
31
39
|
console.log(chalk_1.default.yellow(`Skipped: ${file}`));
|
|
32
|
-
if (err instanceof Error) {
|
|
33
|
-
console.log(chalk_1.default.gray(err.message));
|
|
34
|
-
}
|
|
35
40
|
}
|
|
36
41
|
}
|
|
37
42
|
const found = new Set(engine.getAllEvents());
|
|
38
43
|
const known = new Set(config.events ?? []);
|
|
39
44
|
const newEvents = [...found].filter(e => !known.has(e));
|
|
40
45
|
const removed = [...known].filter(e => !found.has(e));
|
|
46
|
+
// FIX MODE
|
|
41
47
|
if (fix) {
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
config.events = [...merged].sort();
|
|
48
|
+
const next = new Set();
|
|
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();
|
|
48
53
|
await (0, config_1.saveConfig)(config);
|
|
49
|
-
console.log(chalk_1.default.green(
|
|
54
|
+
console.log(chalk_1.default.green(`\nSynced (${config.events.length} events)`));
|
|
50
55
|
return;
|
|
51
56
|
}
|
|
57
|
+
// CHECK MODE
|
|
52
58
|
if (newEvents.length || removed.length) {
|
|
53
59
|
if (newEvents.length) {
|
|
54
60
|
console.log(chalk_1.default.red("\nNew events:"));
|
package/dist/commands/sync.js
CHANGED
|
@@ -29,13 +29,21 @@ async function sync() {
|
|
|
29
29
|
for (const file of files) {
|
|
30
30
|
try {
|
|
31
31
|
const raw = await promises_1.default.readFile(file, "utf-8");
|
|
32
|
-
const { content, virtualFile } = (0, processFile_1.processFile)(file, raw);
|
|
32
|
+
const { content, virtualFile, deps } = (0, processFile_1.processFile)(file, raw);
|
|
33
33
|
engine["ts"].updateFile(virtualFile, content);
|
|
34
34
|
fileCache.push({ file: virtualFile, content });
|
|
35
|
+
// deps
|
|
36
|
+
for (const dep of deps) {
|
|
37
|
+
try {
|
|
38
|
+
const depRaw = await promises_1.default.readFile(dep, "utf-8");
|
|
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 { }
|
|
44
|
+
}
|
|
35
45
|
}
|
|
36
|
-
catch {
|
|
37
|
-
// ignore
|
|
38
|
-
}
|
|
46
|
+
catch { }
|
|
39
47
|
}
|
|
40
48
|
for (const { file, content } of fileCache) {
|
|
41
49
|
try {
|
package/dist/commands/watch.js
CHANGED
|
@@ -53,8 +53,17 @@ async function watch() {
|
|
|
53
53
|
for (const file of batch) {
|
|
54
54
|
try {
|
|
55
55
|
const raw = await promises_1.default.readFile(file, "utf-8");
|
|
56
|
-
const { content, virtualFile } = (0, processFile_1.processFile)(file, raw);
|
|
56
|
+
const { content, virtualFile, deps } = (0, processFile_1.processFile)(file, raw);
|
|
57
57
|
engine.updateFile(virtualFile, content, config);
|
|
58
|
+
// deps
|
|
59
|
+
for (const dep of deps) {
|
|
60
|
+
try {
|
|
61
|
+
const depRaw = await promises_1.default.readFile(dep, "utf-8");
|
|
62
|
+
const { content: depContent, virtualFile: depVirtual, } = (0, processFile_1.processFile)(dep, depRaw);
|
|
63
|
+
engine.updateFile(depVirtual, depContent, config);
|
|
64
|
+
}
|
|
65
|
+
catch { }
|
|
66
|
+
}
|
|
58
67
|
}
|
|
59
68
|
catch {
|
|
60
69
|
console.log(chalk_1.default.gray(`skip: ${file}`));
|
package/dist/engine/scanner.js
CHANGED
|
@@ -87,6 +87,7 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
|
|
|
87
87
|
const isAutoWrapper = resolvedFn && (0, functionAnalyzer_1.findTrackParamIndex)(resolvedFn) !== null;
|
|
88
88
|
const isTracking = isKnownWrapper ||
|
|
89
89
|
TRACKING_NAMES.has(name) ||
|
|
90
|
+
name.startsWith("$") || // NUXT FIX
|
|
90
91
|
(isAutoWrapper &&
|
|
91
92
|
resolvedFn &&
|
|
92
93
|
!(0, boundary_1.isExternalFile)(resolvedFn.getSourceFile().fileName));
|
|
@@ -97,7 +98,6 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
|
|
|
97
98
|
if (!isKnownWrapper && isAutoWrapper && !TRACKING_NAMES.has(name)) {
|
|
98
99
|
detectedFunctionWrappers.add(name);
|
|
99
100
|
}
|
|
100
|
-
// paramMap (chain support)
|
|
101
101
|
const paramMap = new Map(inheritedParamMap ?? []);
|
|
102
102
|
if (resolvedFn && typescript_1.default.isFunctionLike(resolvedFn)) {
|
|
103
103
|
resolvedFn.parameters.forEach((param, i) => {
|
|
@@ -110,6 +110,7 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
|
|
|
110
110
|
});
|
|
111
111
|
}
|
|
112
112
|
let handled = false;
|
|
113
|
+
// MAIN RESOLVE
|
|
113
114
|
if (resolvedFn) {
|
|
114
115
|
const idx = (0, functionAnalyzer_1.findTrackParamIndex)(resolvedFn);
|
|
115
116
|
if (idx !== null && node.arguments[idx]) {
|
|
@@ -121,6 +122,7 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
|
|
|
121
122
|
handled = true;
|
|
122
123
|
}
|
|
123
124
|
}
|
|
125
|
+
// FALLBACK
|
|
124
126
|
if (!handled) {
|
|
125
127
|
for (const arg of node.arguments) {
|
|
126
128
|
const res = (0, resolver_1.resolveNodeValue)(arg, checker, paramMap);
|
|
@@ -130,7 +132,7 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
|
|
|
130
132
|
});
|
|
131
133
|
}
|
|
132
134
|
}
|
|
133
|
-
//
|
|
135
|
+
// CROSS FILE
|
|
134
136
|
if (resolvedFn) {
|
|
135
137
|
const sf = resolvedFn.getSourceFile();
|
|
136
138
|
if (!visited.has(sf.fileName)) {
|
|
@@ -1,8 +1,13 @@
|
|
|
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.parseAstro = parseAstro;
|
|
4
|
-
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
function parseAstro(content, file) {
|
|
5
9
|
const parts = [];
|
|
10
|
+
const deps = [];
|
|
6
11
|
// frontmatter
|
|
7
12
|
const frontmatter = content.match(/^---([\s\S]*?)---/);
|
|
8
13
|
if (frontmatter?.[1]) {
|
|
@@ -13,20 +18,22 @@ function parseAstro(content) {
|
|
|
13
18
|
for (const m of scripts) {
|
|
14
19
|
const attrs = m[1];
|
|
15
20
|
const body = m[2];
|
|
21
|
+
// external script
|
|
16
22
|
if (attrs.includes("src")) {
|
|
17
23
|
const src = attrs.match(/src=["'](.+?)["']/)?.[1];
|
|
18
|
-
if (src)
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
if (!src)
|
|
25
|
+
continue;
|
|
26
|
+
const resolved = src.startsWith("/")
|
|
27
|
+
? path_1.default.resolve(process.cwd(), src.slice(1))
|
|
28
|
+
: path_1.default.resolve(path_1.default.dirname(file), src);
|
|
29
|
+
deps.push(resolved);
|
|
21
30
|
}
|
|
22
31
|
else {
|
|
23
32
|
parts.push(body);
|
|
24
33
|
}
|
|
25
34
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
return parts.join("\n");
|
|
35
|
+
return {
|
|
36
|
+
code: parts.join("\n"),
|
|
37
|
+
deps,
|
|
38
|
+
};
|
|
32
39
|
}
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.detectParser = detectParser;
|
|
4
|
+
const vue_1 = require("./vue");
|
|
5
|
+
const svelte_1 = require("./svelte");
|
|
6
|
+
const astro_1 = require("./astro");
|
|
7
|
+
const fallback = (content) => ({
|
|
8
|
+
code: content,
|
|
9
|
+
deps: [],
|
|
10
|
+
});
|
|
4
11
|
function detectParser(file) {
|
|
5
|
-
|
|
6
|
-
if (
|
|
7
|
-
return
|
|
8
|
-
if (
|
|
9
|
-
return
|
|
10
|
-
if (
|
|
11
|
-
return
|
|
12
|
-
return
|
|
12
|
+
const f = file.toLowerCase();
|
|
13
|
+
if (f.endsWith(".vue"))
|
|
14
|
+
return vue_1.parseVue;
|
|
15
|
+
if (f.endsWith(".svelte"))
|
|
16
|
+
return svelte_1.parseSvelte;
|
|
17
|
+
if (f.endsWith(".astro"))
|
|
18
|
+
return astro_1.parseAstro;
|
|
19
|
+
return fallback;
|
|
13
20
|
}
|
|
@@ -3,15 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.parseSvelte = parseSvelte;
|
|
4
4
|
function parseSvelte(content) {
|
|
5
5
|
const parts = [];
|
|
6
|
-
|
|
6
|
+
const deps = [];
|
|
7
|
+
// script
|
|
7
8
|
const scripts = content.matchAll(/<script[^>]*>([\s\S]*?)<\/script>/g);
|
|
8
9
|
for (const m of scripts) {
|
|
9
10
|
parts.push(m[1]);
|
|
10
11
|
}
|
|
11
|
-
// on:click
|
|
12
|
+
// on:click={...}
|
|
12
13
|
const handlers = content.matchAll(/on:\w+=\{([^}]+)\}/g);
|
|
13
14
|
for (const h of handlers) {
|
|
14
15
|
parts.push(h[1] + ";");
|
|
15
16
|
}
|
|
16
|
-
return
|
|
17
|
+
return {
|
|
18
|
+
code: parts.join("\n"),
|
|
19
|
+
deps,
|
|
20
|
+
};
|
|
17
21
|
}
|
|
@@ -1,41 +1,51 @@
|
|
|
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.parseVue = parseVue;
|
|
4
|
-
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
function parseVue(content, file) {
|
|
5
9
|
const parts = [];
|
|
6
|
-
|
|
10
|
+
const deps = [];
|
|
11
|
+
// SCRIPT
|
|
7
12
|
const scripts = content.matchAll(/<script([^>]*)>([\s\S]*?)<\/script>/g);
|
|
8
13
|
for (const m of scripts) {
|
|
9
14
|
const attrs = m[1];
|
|
10
15
|
const body = m[2];
|
|
11
16
|
if (attrs.includes("src")) {
|
|
12
17
|
const src = attrs.match(/src=["'](.+?)["']/)?.[1];
|
|
13
|
-
if (src)
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
if (!src)
|
|
19
|
+
continue;
|
|
20
|
+
const resolved = src.startsWith("/")
|
|
21
|
+
? path_1.default.resolve(process.cwd(), src.slice(1))
|
|
22
|
+
: path_1.default.resolve(path_1.default.dirname(file), src);
|
|
23
|
+
deps.push(resolved);
|
|
16
24
|
continue;
|
|
17
25
|
}
|
|
18
26
|
parts.push(body);
|
|
19
27
|
}
|
|
20
|
-
//
|
|
28
|
+
// TEMPLATE
|
|
21
29
|
const templateMatch = content.match(/<template[^>]*>([\s\S]*?)<\/template>/);
|
|
22
30
|
let template = templateMatch?.[1] ?? "";
|
|
23
|
-
// remove comments
|
|
24
31
|
template = template.replace(/<!--[\s\S]*?-->/g, "");
|
|
25
|
-
//
|
|
32
|
+
// @click
|
|
26
33
|
const handlers = template.matchAll(/@[\w-]+="([^"]+)"/g);
|
|
27
34
|
for (const h of handlers) {
|
|
28
35
|
parts.push(h[1] + ";");
|
|
29
36
|
}
|
|
30
|
-
//
|
|
37
|
+
// v-on
|
|
31
38
|
const vOn = template.matchAll(/v-on:[\w-]+="([^"]+)"/g);
|
|
32
39
|
for (const v of vOn) {
|
|
33
40
|
parts.push(v[1] + ";");
|
|
34
41
|
}
|
|
35
|
-
//
|
|
42
|
+
// :prop
|
|
36
43
|
const binds = template.matchAll(/:[\w-]+="([^"]+)"/g);
|
|
37
44
|
for (const b of binds) {
|
|
38
45
|
parts.push(b[1] + ";");
|
|
39
46
|
}
|
|
40
|
-
return
|
|
47
|
+
return {
|
|
48
|
+
code: parts.join("\n"),
|
|
49
|
+
deps,
|
|
50
|
+
};
|
|
41
51
|
}
|
|
@@ -2,21 +2,17 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.processFile = processFile;
|
|
4
4
|
const router_1 = require("./parsers/router");
|
|
5
|
-
const vue_1 = require("./parsers/vue");
|
|
6
|
-
const svelte_1 = require("./parsers/svelte");
|
|
7
|
-
const astro_1 = require("./parsers/astro");
|
|
8
5
|
function processFile(file, content) {
|
|
9
6
|
const parser = (0, router_1.detectParser)(file);
|
|
10
|
-
|
|
11
|
-
content = (0, vue_1.parseVue)(content);
|
|
12
|
-
if (parser === "svelte")
|
|
13
|
-
content = (0, svelte_1.parseSvelte)(content);
|
|
14
|
-
if (parser === "astro")
|
|
15
|
-
content = (0, astro_1.parseAstro)(content);
|
|
7
|
+
const res = parser(content, file);
|
|
16
8
|
const virtualFile = file.endsWith(".vue") ||
|
|
17
9
|
file.endsWith(".svelte") ||
|
|
18
10
|
file.endsWith(".astro")
|
|
19
11
|
? file + ".tsx"
|
|
20
12
|
: file;
|
|
21
|
-
return {
|
|
13
|
+
return {
|
|
14
|
+
content: res.code,
|
|
15
|
+
virtualFile,
|
|
16
|
+
deps: res.deps,
|
|
17
|
+
};
|
|
22
18
|
}
|
package/package.json
CHANGED
package/src/commands/check.ts
CHANGED
|
@@ -26,16 +26,25 @@ export async function check({ fix = false }: { fix?: boolean }) {
|
|
|
26
26
|
try {
|
|
27
27
|
const raw = await fs.readFile(file, "utf-8");
|
|
28
28
|
|
|
29
|
-
const { content, virtualFile } = processFile(file, raw);
|
|
29
|
+
const { content, virtualFile, deps } = processFile(file, raw);
|
|
30
30
|
|
|
31
31
|
engine.scanFile(virtualFile, content, config);
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
for (const dep of deps) {
|
|
34
|
+
try {
|
|
35
|
+
const depRaw = await fs.readFile(dep, "utf-8");
|
|
36
|
+
|
|
37
|
+
const {
|
|
38
|
+
content: depContent,
|
|
39
|
+
virtualFile: depVirtual,
|
|
40
|
+
} = processFile(dep, depRaw);
|
|
35
41
|
|
|
36
|
-
|
|
37
|
-
|
|
42
|
+
engine.scanFile(depVirtual, depContent, config);
|
|
43
|
+
} catch {}
|
|
38
44
|
}
|
|
45
|
+
|
|
46
|
+
} catch (err) {
|
|
47
|
+
console.log(chalk.yellow(`Skipped: ${file}`));
|
|
39
48
|
}
|
|
40
49
|
}
|
|
41
50
|
|
|
@@ -45,31 +54,45 @@ export async function check({ fix = false }: { fix?: boolean }) {
|
|
|
45
54
|
const newEvents = [...found].filter(e => !known.has(e));
|
|
46
55
|
const removed = [...known].filter(e => !found.has(e));
|
|
47
56
|
|
|
57
|
+
// FIX MODE
|
|
48
58
|
if (fix) {
|
|
49
|
-
const
|
|
59
|
+
const next = new Set<string>();
|
|
60
|
+
|
|
61
|
+
found.forEach(e => next.add(e));
|
|
50
62
|
|
|
51
|
-
newEvents.forEach(e =>
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
});
|
|
63
|
+
newEvents.forEach(e =>
|
|
64
|
+
console.log(chalk.green(`+ ${e}`))
|
|
65
|
+
);
|
|
55
66
|
|
|
56
|
-
|
|
67
|
+
removed.forEach(e =>
|
|
68
|
+
console.log(chalk.red(`- ${e}`))
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
config.events = [...next].sort();
|
|
57
72
|
|
|
58
73
|
await saveConfig(config);
|
|
59
74
|
|
|
60
|
-
console.log(
|
|
75
|
+
console.log(
|
|
76
|
+
chalk.green(`\nSynced (${config.events.length} events)`)
|
|
77
|
+
);
|
|
78
|
+
|
|
61
79
|
return;
|
|
62
80
|
}
|
|
63
81
|
|
|
82
|
+
// CHECK MODE
|
|
64
83
|
if (newEvents.length || removed.length) {
|
|
65
84
|
if (newEvents.length) {
|
|
66
85
|
console.log(chalk.red("\nNew events:"));
|
|
67
|
-
newEvents.forEach(e =>
|
|
86
|
+
newEvents.forEach(e =>
|
|
87
|
+
console.log(chalk.red(`+ ${e}`))
|
|
88
|
+
);
|
|
68
89
|
}
|
|
69
90
|
|
|
70
91
|
if (removed.length) {
|
|
71
92
|
console.log(chalk.yellow("\nRemoved events:"));
|
|
72
|
-
removed.forEach(e =>
|
|
93
|
+
removed.forEach(e =>
|
|
94
|
+
console.log(chalk.yellow(`- ${e}`))
|
|
95
|
+
);
|
|
73
96
|
}
|
|
74
97
|
|
|
75
98
|
process.exit(1);
|
package/src/commands/sync.ts
CHANGED
|
@@ -31,12 +31,29 @@ export async function sync() {
|
|
|
31
31
|
for (const file of files) {
|
|
32
32
|
try {
|
|
33
33
|
const raw = await fs.readFile(file, "utf-8");
|
|
34
|
-
|
|
34
|
+
|
|
35
|
+
const { content, virtualFile, deps } = processFile(file, raw);
|
|
36
|
+
|
|
35
37
|
engine["ts"].updateFile(virtualFile, content);
|
|
36
38
|
fileCache.push({ file: virtualFile, content });
|
|
37
|
-
|
|
38
|
-
//
|
|
39
|
-
|
|
39
|
+
|
|
40
|
+
// deps
|
|
41
|
+
for (const dep of deps) {
|
|
42
|
+
try {
|
|
43
|
+
const depRaw = await fs.readFile(dep, "utf-8");
|
|
44
|
+
|
|
45
|
+
const {
|
|
46
|
+
content: depContent,
|
|
47
|
+
virtualFile: depVirtual,
|
|
48
|
+
} = processFile(dep, depRaw);
|
|
49
|
+
|
|
50
|
+
engine["ts"].updateFile(depVirtual, depContent);
|
|
51
|
+
fileCache.push({ file: depVirtual, content: depContent });
|
|
52
|
+
|
|
53
|
+
} catch {}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
} catch {}
|
|
40
57
|
}
|
|
41
58
|
|
|
42
59
|
for (const { file, content } of fileCache) {
|
package/src/commands/watch.ts
CHANGED
|
@@ -60,10 +60,26 @@ export async function watch() {
|
|
|
60
60
|
for (const file of batch) {
|
|
61
61
|
try {
|
|
62
62
|
const raw = await fs.readFile(file, "utf-8");
|
|
63
|
-
|
|
63
|
+
|
|
64
|
+
const { content, virtualFile, deps } = processFile(file, raw);
|
|
64
65
|
|
|
65
66
|
engine.updateFile(virtualFile, content, config);
|
|
66
67
|
|
|
68
|
+
// deps
|
|
69
|
+
for (const dep of deps) {
|
|
70
|
+
try {
|
|
71
|
+
const depRaw = await fs.readFile(dep, "utf-8");
|
|
72
|
+
|
|
73
|
+
const {
|
|
74
|
+
content: depContent,
|
|
75
|
+
virtualFile: depVirtual,
|
|
76
|
+
} = processFile(dep, depRaw);
|
|
77
|
+
|
|
78
|
+
engine.updateFile(depVirtual, depContent, config);
|
|
79
|
+
|
|
80
|
+
} catch {}
|
|
81
|
+
}
|
|
82
|
+
|
|
67
83
|
} catch {
|
|
68
84
|
console.log(chalk.gray(`skip: ${file}`));
|
|
69
85
|
}
|
package/src/engine/scanner.ts
CHANGED
|
@@ -126,6 +126,7 @@ export function scanSource(
|
|
|
126
126
|
const isTracking =
|
|
127
127
|
isKnownWrapper ||
|
|
128
128
|
TRACKING_NAMES.has(name) ||
|
|
129
|
+
name.startsWith("$") || // NUXT FIX
|
|
129
130
|
(isAutoWrapper &&
|
|
130
131
|
resolvedFn &&
|
|
131
132
|
!isExternalFile(resolvedFn.getSourceFile().fileName));
|
|
@@ -139,7 +140,6 @@ export function scanSource(
|
|
|
139
140
|
detectedFunctionWrappers.add(name);
|
|
140
141
|
}
|
|
141
142
|
|
|
142
|
-
// paramMap (chain support)
|
|
143
143
|
const paramMap = new Map(inheritedParamMap ?? []);
|
|
144
144
|
|
|
145
145
|
if (resolvedFn && ts.isFunctionLike(resolvedFn)) {
|
|
@@ -155,6 +155,7 @@ export function scanSource(
|
|
|
155
155
|
|
|
156
156
|
let handled = false;
|
|
157
157
|
|
|
158
|
+
// MAIN RESOLVE
|
|
158
159
|
if (resolvedFn) {
|
|
159
160
|
const idx = findTrackParamIndex(resolvedFn);
|
|
160
161
|
|
|
@@ -173,6 +174,7 @@ export function scanSource(
|
|
|
173
174
|
}
|
|
174
175
|
}
|
|
175
176
|
|
|
177
|
+
// FALLBACK
|
|
176
178
|
if (!handled) {
|
|
177
179
|
for (const arg of node.arguments) {
|
|
178
180
|
const res = resolveNodeValue(arg, checker, paramMap);
|
|
@@ -183,7 +185,7 @@ export function scanSource(
|
|
|
183
185
|
}
|
|
184
186
|
}
|
|
185
187
|
|
|
186
|
-
//
|
|
188
|
+
// CROSS FILE
|
|
187
189
|
if (resolvedFn) {
|
|
188
190
|
const sf = resolvedFn.getSourceFile();
|
|
189
191
|
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
export type ScanMode = "strict" | "hybrid" | "discovery";
|
|
2
2
|
|
|
3
|
+
export type ParseResult = {
|
|
4
|
+
code: string;
|
|
5
|
+
deps: string[];
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export type Parser = (content: string, file: string) => ParseResult;
|
|
9
|
+
|
|
10
|
+
|
|
3
11
|
export type ComponentWrapper = {
|
|
4
12
|
name: string;
|
|
5
13
|
prop: string;
|
|
@@ -23,8 +31,3 @@ export type EventraConfig = {
|
|
|
23
31
|
exclude: string[];
|
|
24
32
|
};
|
|
25
33
|
};
|
|
26
|
-
|
|
27
|
-
export type ResolveResult = {
|
|
28
|
-
values: string[];
|
|
29
|
-
dynamic: boolean;
|
|
30
|
-
};
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { ParseResult } from "../../types";
|
|
3
|
+
|
|
4
|
+
export function parseAstro(content: string, file: string): ParseResult {
|
|
2
5
|
const parts: string[] = [];
|
|
6
|
+
const deps: string[] = [];
|
|
3
7
|
|
|
4
8
|
// frontmatter
|
|
5
9
|
const frontmatter = content.match(/^---([\s\S]*?)---/);
|
|
@@ -14,22 +18,23 @@ export function parseAstro(content: string) {
|
|
|
14
18
|
const attrs = m[1];
|
|
15
19
|
const body = m[2];
|
|
16
20
|
|
|
21
|
+
// external script
|
|
17
22
|
if (attrs.includes("src")) {
|
|
18
23
|
const src = attrs.match(/src=["'](.+?)["']/)?.[1];
|
|
19
|
-
if (src)
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
if (!src) continue;
|
|
25
|
+
|
|
26
|
+
const resolved = src.startsWith("/")
|
|
27
|
+
? path.resolve(process.cwd(), src.slice(1))
|
|
28
|
+
: path.resolve(path.dirname(file), src);
|
|
29
|
+
|
|
30
|
+
deps.push(resolved);
|
|
22
31
|
} else {
|
|
23
32
|
parts.push(body);
|
|
24
33
|
}
|
|
25
34
|
}
|
|
26
35
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
parts.push(m[1] + ";");
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return parts.join("\n");
|
|
36
|
+
return {
|
|
37
|
+
code: parts.join("\n"),
|
|
38
|
+
deps,
|
|
39
|
+
};
|
|
35
40
|
}
|
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { Parser } from "../../types";
|
|
2
|
+
import { parseVue } from "./vue";
|
|
3
|
+
import { parseSvelte } from "./svelte";
|
|
4
|
+
import { parseAstro } from "./astro";
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
const fallback: Parser = (content) => ({
|
|
7
|
+
code: content,
|
|
8
|
+
deps: [],
|
|
9
|
+
});
|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
export function detectParser(file: string): Parser {
|
|
12
|
+
const f = file.toLowerCase();
|
|
13
|
+
|
|
14
|
+
if (f.endsWith(".vue")) return parseVue;
|
|
15
|
+
if (f.endsWith(".svelte")) return parseSvelte;
|
|
16
|
+
if (f.endsWith(".astro")) return parseAstro;
|
|
17
|
+
|
|
18
|
+
return fallback;
|
|
9
19
|
}
|
|
@@ -1,17 +1,24 @@
|
|
|
1
|
-
|
|
1
|
+
import { ParseResult } from "../../types";
|
|
2
|
+
|
|
3
|
+
export function parseSvelte(content: string): ParseResult {
|
|
2
4
|
const parts: string[] = [];
|
|
5
|
+
const deps: string[] = [];
|
|
3
6
|
|
|
4
|
-
//
|
|
7
|
+
// script
|
|
5
8
|
const scripts = content.matchAll(/<script[^>]*>([\s\S]*?)<\/script>/g);
|
|
6
9
|
for (const m of scripts) {
|
|
7
10
|
parts.push(m[1]);
|
|
8
11
|
}
|
|
9
12
|
|
|
10
|
-
// on:click
|
|
13
|
+
// on:click={...}
|
|
11
14
|
const handlers = content.matchAll(/on:\w+=\{([^}]+)\}/g);
|
|
15
|
+
|
|
12
16
|
for (const h of handlers) {
|
|
13
17
|
parts.push(h[1] + ";");
|
|
14
18
|
}
|
|
15
19
|
|
|
16
|
-
return
|
|
20
|
+
return {
|
|
21
|
+
code: parts.join("\n"),
|
|
22
|
+
deps,
|
|
23
|
+
};
|
|
17
24
|
}
|
package/src/utils/parsers/vue.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { ParseResult } from "../../types";
|
|
3
|
+
|
|
4
|
+
export function parseVue(content: string, file: string): ParseResult {
|
|
2
5
|
const parts: string[] = [];
|
|
6
|
+
const deps: string[] = [];
|
|
3
7
|
|
|
4
|
-
//
|
|
8
|
+
// SCRIPT
|
|
5
9
|
const scripts = content.matchAll(/<script([^>]*)>([\s\S]*?)<\/script>/g);
|
|
6
10
|
|
|
7
11
|
for (const m of scripts) {
|
|
@@ -10,39 +14,45 @@ export function parseVue(content: string) {
|
|
|
10
14
|
|
|
11
15
|
if (attrs.includes("src")) {
|
|
12
16
|
const src = attrs.match(/src=["'](.+?)["']/)?.[1];
|
|
13
|
-
if (src)
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
if (!src) continue;
|
|
18
|
+
|
|
19
|
+
const resolved = src.startsWith("/")
|
|
20
|
+
? path.resolve(process.cwd(), src.slice(1))
|
|
21
|
+
: path.resolve(path.dirname(file), src);
|
|
22
|
+
|
|
23
|
+
deps.push(resolved);
|
|
16
24
|
continue;
|
|
17
25
|
}
|
|
18
26
|
|
|
19
27
|
parts.push(body);
|
|
20
28
|
}
|
|
21
29
|
|
|
22
|
-
//
|
|
30
|
+
// TEMPLATE
|
|
23
31
|
const templateMatch = content.match(/<template[^>]*>([\s\S]*?)<\/template>/);
|
|
24
32
|
let template = templateMatch?.[1] ?? "";
|
|
25
33
|
|
|
26
|
-
// remove comments
|
|
27
34
|
template = template.replace(/<!--[\s\S]*?-->/g, "");
|
|
28
35
|
|
|
29
|
-
//
|
|
36
|
+
// @click
|
|
30
37
|
const handlers = template.matchAll(/@[\w-]+="([^"]+)"/g);
|
|
31
38
|
for (const h of handlers) {
|
|
32
39
|
parts.push(h[1] + ";");
|
|
33
40
|
}
|
|
34
41
|
|
|
35
|
-
//
|
|
42
|
+
// v-on
|
|
36
43
|
const vOn = template.matchAll(/v-on:[\w-]+="([^"]+)"/g);
|
|
37
44
|
for (const v of vOn) {
|
|
38
45
|
parts.push(v[1] + ";");
|
|
39
46
|
}
|
|
40
47
|
|
|
41
|
-
//
|
|
48
|
+
// :prop
|
|
42
49
|
const binds = template.matchAll(/:[\w-]+="([^"]+)"/g);
|
|
43
50
|
for (const b of binds) {
|
|
44
51
|
parts.push(b[1] + ";");
|
|
45
52
|
}
|
|
46
53
|
|
|
47
|
-
return
|
|
54
|
+
return {
|
|
55
|
+
code: parts.join("\n"),
|
|
56
|
+
deps,
|
|
57
|
+
};
|
|
48
58
|
}
|
package/src/utils/processFile.ts
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import { detectParser } from "./parsers/router";
|
|
2
|
-
import { parseVue } from "./parsers/vue";
|
|
3
|
-
import { parseSvelte } from "./parsers/svelte";
|
|
4
|
-
import { parseAstro } from "./parsers/astro";
|
|
5
2
|
|
|
6
3
|
export function processFile(file: string, content: string) {
|
|
7
4
|
const parser = detectParser(file);
|
|
8
5
|
|
|
9
|
-
|
|
10
|
-
if (parser === "svelte") content = parseSvelte(content);
|
|
11
|
-
if (parser === "astro") content = parseAstro(content);
|
|
6
|
+
const res = parser(content, file);
|
|
12
7
|
|
|
13
8
|
const virtualFile =
|
|
14
9
|
file.endsWith(".vue") ||
|
|
@@ -17,5 +12,9 @@ export function processFile(file: string, content: string) {
|
|
|
17
12
|
? file + ".tsx"
|
|
18
13
|
: file;
|
|
19
14
|
|
|
20
|
-
return {
|
|
15
|
+
return {
|
|
16
|
+
content: res.code,
|
|
17
|
+
virtualFile,
|
|
18
|
+
deps: res.deps,
|
|
19
|
+
};
|
|
21
20
|
}
|