@eventra_dev/eventra-cli 0.1.20 → 0.1.22
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/engine/resolver.js +15 -13
- package/dist/engine/scanner.js +12 -8
- package/dist/utils/processFile.js +11 -9
- package/dist/utils/universal.js +179 -0
- package/package.json +1 -1
- package/src/engine/resolver.ts +19 -12
- package/src/engine/scanner.ts +10 -6
- package/src/utils/processFile.ts +8 -9
- package/src/utils/universal.ts +217 -0
- package/dist/utils/parsers/astro.js +0 -49
- package/dist/utils/parsers/router.js +0 -20
- package/dist/utils/parsers/svelte.js +0 -30
- package/dist/utils/parsers/utils.js +0 -21
- package/dist/utils/parsers/vue.js +0 -59
- package/src/utils/parsers/astro.ts +0 -53
- package/src/utils/parsers/router.ts +0 -19
- package/src/utils/parsers/svelte.ts +0 -36
- package/src/utils/parsers/utils.ts +0 -18
- package/src/utils/parsers/vue.ts +0 -67
package/dist/engine/resolver.js
CHANGED
|
@@ -7,10 +7,10 @@ exports.resolveNodeValue = resolveNodeValue;
|
|
|
7
7
|
const typescript_1 = __importDefault(require("typescript"));
|
|
8
8
|
const exportResolver_1 = require("./exportResolver");
|
|
9
9
|
function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
10
|
-
if (seen.has(node))
|
|
11
|
-
return
|
|
10
|
+
if (seen.has(node)) {
|
|
11
|
+
return { values: [], dynamic: true };
|
|
12
|
+
}
|
|
12
13
|
seen.add(node);
|
|
13
|
-
// param mapping
|
|
14
14
|
if (typescript_1.default.isIdentifier(node) && paramMap?.has(node.text)) {
|
|
15
15
|
return resolveNodeValue(paramMap.get(node.text), checker, paramMap, seen);
|
|
16
16
|
}
|
|
@@ -29,15 +29,14 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
29
29
|
const a = resolveNodeValue(node.whenTrue, checker, paramMap, seen);
|
|
30
30
|
const b = resolveNodeValue(node.whenFalse, checker, paramMap, seen);
|
|
31
31
|
return {
|
|
32
|
-
values: [...new Set([...(a
|
|
32
|
+
values: [...new Set([...(a.values ?? []), ...(b.values ?? [])])],
|
|
33
33
|
dynamic: true,
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
36
|
if (typescript_1.default.isIdentifier(node)) {
|
|
37
37
|
let symbol = checker.getSymbolAtLocation(node);
|
|
38
38
|
if (!symbol)
|
|
39
|
-
return
|
|
40
|
-
// variable inline resolve FIRST
|
|
39
|
+
return { values: [], dynamic: true };
|
|
41
40
|
for (const decl of symbol.getDeclarations() ?? []) {
|
|
42
41
|
if (typescript_1.default.isVariableDeclaration(decl) && decl.initializer) {
|
|
43
42
|
return resolveNodeValue(decl.initializer, checker, paramMap, seen);
|
|
@@ -45,7 +44,6 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
45
44
|
}
|
|
46
45
|
const original = symbol;
|
|
47
46
|
symbol = (0, exportResolver_1.resolveExportedSymbol)(symbol, checker) ?? symbol;
|
|
48
|
-
// avoid alias loop
|
|
49
47
|
if (symbol !== original && (symbol.flags & typescript_1.default.SymbolFlags.Alias)) {
|
|
50
48
|
symbol = checker.getAliasedSymbol(symbol);
|
|
51
49
|
}
|
|
@@ -62,6 +60,7 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
62
60
|
}
|
|
63
61
|
}
|
|
64
62
|
}
|
|
63
|
+
return { values: [], dynamic: true };
|
|
65
64
|
}
|
|
66
65
|
if (typescript_1.default.isPropertyAccessExpression(node)) {
|
|
67
66
|
const symbol = checker.getSymbolAtLocation(node);
|
|
@@ -70,7 +69,6 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
70
69
|
if (s.flags & typescript_1.default.SymbolFlags.Alias) {
|
|
71
70
|
s = checker.getAliasedSymbol(s);
|
|
72
71
|
}
|
|
73
|
-
// ENUM support
|
|
74
72
|
for (const decl of s.getDeclarations() ?? []) {
|
|
75
73
|
if (typescript_1.default.isEnumMember(decl) && decl.initializer) {
|
|
76
74
|
if (typescript_1.default.isStringLiteral(decl.initializer)) {
|
|
@@ -82,7 +80,6 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
82
80
|
}
|
|
83
81
|
}
|
|
84
82
|
}
|
|
85
|
-
// OBJECT support
|
|
86
83
|
if (typescript_1.default.isIdentifier(node.expression)) {
|
|
87
84
|
const objSymbol = checker.getSymbolAtLocation(node.expression);
|
|
88
85
|
if (objSymbol) {
|
|
@@ -102,6 +99,7 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
102
99
|
}
|
|
103
100
|
}
|
|
104
101
|
}
|
|
102
|
+
return { values: [], dynamic: true };
|
|
105
103
|
}
|
|
106
104
|
if (typescript_1.default.isObjectLiteralExpression(node)) {
|
|
107
105
|
const values = [];
|
|
@@ -111,8 +109,7 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
111
109
|
const name = prop.name.getText();
|
|
112
110
|
if (name === "event") {
|
|
113
111
|
const res = resolveNodeValue(prop.initializer, checker, paramMap, seen);
|
|
114
|
-
|
|
115
|
-
values.push(...res.values);
|
|
112
|
+
values.push(...res.values);
|
|
116
113
|
}
|
|
117
114
|
}
|
|
118
115
|
return { values, dynamic: true };
|
|
@@ -123,11 +120,16 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
123
120
|
const right = resolveNodeValue(node.right, checker, paramMap, seen);
|
|
124
121
|
if (left && right) {
|
|
125
122
|
return {
|
|
126
|
-
values: left.values.flatMap(l => right.values.
|
|
123
|
+
values: left.values.flatMap(l => right.values.length
|
|
124
|
+
? right.values.map(r => l + r)
|
|
125
|
+
: [l + "*"]),
|
|
127
126
|
dynamic: true,
|
|
128
127
|
};
|
|
129
128
|
}
|
|
130
129
|
}
|
|
131
130
|
}
|
|
132
|
-
|
|
131
|
+
if (typescript_1.default.isCallExpression(node)) {
|
|
132
|
+
return { values: [], dynamic: true };
|
|
133
|
+
}
|
|
134
|
+
return { values: [], dynamic: true };
|
|
133
135
|
}
|
package/dist/engine/scanner.js
CHANGED
|
@@ -115,10 +115,12 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
|
|
|
115
115
|
const idx = (0, functionAnalyzer_1.findTrackParamIndex)(resolvedFn);
|
|
116
116
|
if (idx !== null && node.arguments[idx]) {
|
|
117
117
|
const res = (0, resolver_1.resolveNodeValue)(node.arguments[idx], checker, paramMap);
|
|
118
|
-
res
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
118
|
+
if (res && res.values.length) {
|
|
119
|
+
res.values.forEach(v => {
|
|
120
|
+
if (isValidEvent(v))
|
|
121
|
+
events.add(v);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
122
124
|
handled = true;
|
|
123
125
|
}
|
|
124
126
|
}
|
|
@@ -126,10 +128,12 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
|
|
|
126
128
|
if (!handled) {
|
|
127
129
|
for (const arg of node.arguments) {
|
|
128
130
|
const res = (0, resolver_1.resolveNodeValue)(arg, checker, paramMap);
|
|
129
|
-
res
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
if (res && res.values.length) {
|
|
132
|
+
res.values.forEach(v => {
|
|
133
|
+
if (isValidEvent(v))
|
|
134
|
+
events.add(v);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
133
137
|
}
|
|
134
138
|
}
|
|
135
139
|
// CROSS FILE
|
|
@@ -1,18 +1,20 @@
|
|
|
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.processFile = processFile;
|
|
4
|
-
const
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const universal_1 = require("./universal");
|
|
5
9
|
function processFile(file, content) {
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const virtualFile =
|
|
9
|
-
file.
|
|
10
|
-
file.endsWith(".astro")
|
|
11
|
-
? file + ".tsx"
|
|
10
|
+
const { code, deps } = (0, universal_1.parseUniversal)(content, file);
|
|
11
|
+
const ext = path_1.default.extname(file);
|
|
12
|
+
const virtualFile = /\.(vue|svelte|astro|html)$/i.test(file)
|
|
13
|
+
? file.replace(ext, "") + ".tsx"
|
|
12
14
|
: file;
|
|
13
15
|
return {
|
|
14
|
-
content:
|
|
16
|
+
content: code || "",
|
|
15
17
|
virtualFile,
|
|
16
|
-
deps:
|
|
18
|
+
deps: [...new Set(deps.filter(Boolean))],
|
|
17
19
|
};
|
|
18
20
|
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.parseUniversal = parseUniversal;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
/**
|
|
9
|
+
* exact JS:
|
|
10
|
+
* - {...}
|
|
11
|
+
* - attr="..."
|
|
12
|
+
* - Vue / Svelte handlers
|
|
13
|
+
*/
|
|
14
|
+
function extractJS(input) {
|
|
15
|
+
const result = [];
|
|
16
|
+
let i = 0;
|
|
17
|
+
const len = input.length;
|
|
18
|
+
let inString = null;
|
|
19
|
+
let escape = false;
|
|
20
|
+
while (i < len) {
|
|
21
|
+
const ch = input[i];
|
|
22
|
+
// STRING
|
|
23
|
+
if (inString) {
|
|
24
|
+
if (escape)
|
|
25
|
+
escape = false;
|
|
26
|
+
else if (ch === "\\")
|
|
27
|
+
escape = true;
|
|
28
|
+
else if (ch === inString)
|
|
29
|
+
inString = null;
|
|
30
|
+
i++;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
34
|
+
inString = ch;
|
|
35
|
+
i++;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
// { ... }
|
|
39
|
+
if (ch === "{") {
|
|
40
|
+
let depth = 1;
|
|
41
|
+
let j = i + 1;
|
|
42
|
+
let innerStr = null;
|
|
43
|
+
let innerEsc = false;
|
|
44
|
+
while (j < len && depth > 0) {
|
|
45
|
+
const c = input[j];
|
|
46
|
+
if (innerStr) {
|
|
47
|
+
if (innerEsc)
|
|
48
|
+
innerEsc = false;
|
|
49
|
+
else if (c === "\\")
|
|
50
|
+
innerEsc = true;
|
|
51
|
+
else if (c === innerStr)
|
|
52
|
+
innerStr = null;
|
|
53
|
+
j++;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
57
|
+
innerStr = c;
|
|
58
|
+
j++;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (c === "{")
|
|
62
|
+
depth++;
|
|
63
|
+
else if (c === "}")
|
|
64
|
+
depth--;
|
|
65
|
+
j++;
|
|
66
|
+
}
|
|
67
|
+
if (depth === 0) {
|
|
68
|
+
const expr = input.slice(i + 1, j - 1).trim();
|
|
69
|
+
if (expr)
|
|
70
|
+
result.push(expr);
|
|
71
|
+
i = j;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// attr="..."
|
|
76
|
+
if (ch === "=" && (input[i + 1] === '"' || input[i + 1] === "'")) {
|
|
77
|
+
const quote = input[i + 1];
|
|
78
|
+
let j = i + 2;
|
|
79
|
+
let val = "";
|
|
80
|
+
while (j < len) {
|
|
81
|
+
const c = input[j];
|
|
82
|
+
if (c === "\\" && input[j + 1]) {
|
|
83
|
+
val += c + input[j + 1];
|
|
84
|
+
j += 2;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (c === quote)
|
|
88
|
+
break;
|
|
89
|
+
val += c;
|
|
90
|
+
j++;
|
|
91
|
+
}
|
|
92
|
+
if (val.trim())
|
|
93
|
+
result.push(val.trim());
|
|
94
|
+
i = j + 1;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
i++;
|
|
98
|
+
}
|
|
99
|
+
// Vue / Svelte / JSX handlers
|
|
100
|
+
const extra = [
|
|
101
|
+
/@[\w-]+\s*=\s*["']([\s\S]*?)["']/g,
|
|
102
|
+
/v-on:[\w-]+\s*=\s*["']([\s\S]*?)["']/g,
|
|
103
|
+
/on:[\w-]+\s*=\s*{([\s\S]*?)}/g,
|
|
104
|
+
/on\w+\s*=\s*{([\s\S]*?)}/g,
|
|
105
|
+
];
|
|
106
|
+
for (const r of extra) {
|
|
107
|
+
const m = input.matchAll(r);
|
|
108
|
+
for (const x of m) {
|
|
109
|
+
const v = x[1]?.trim();
|
|
110
|
+
if (v)
|
|
111
|
+
result.push(v);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
function extractLooseJS(input) {
|
|
117
|
+
const result = [];
|
|
118
|
+
const lines = input.split("\n");
|
|
119
|
+
for (const line of lines) {
|
|
120
|
+
const l = line.trim();
|
|
121
|
+
if (!l)
|
|
122
|
+
continue;
|
|
123
|
+
if (l.startsWith("<"))
|
|
124
|
+
continue;
|
|
125
|
+
if (l.includes("(") ||
|
|
126
|
+
l.includes("=") ||
|
|
127
|
+
l.includes("=>") ||
|
|
128
|
+
l.includes("function") ||
|
|
129
|
+
l.includes("track")) {
|
|
130
|
+
result.push(l);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Universal:
|
|
137
|
+
* - Astro
|
|
138
|
+
* - Vue
|
|
139
|
+
* - Svelte
|
|
140
|
+
* - React / JSX
|
|
141
|
+
* - Node / backend
|
|
142
|
+
*/
|
|
143
|
+
function parseUniversal(content, file) {
|
|
144
|
+
const parts = [];
|
|
145
|
+
const deps = [];
|
|
146
|
+
// Astro frontmatter ---
|
|
147
|
+
const fm = content.match(/^---([\s\S]*?)---/);
|
|
148
|
+
if (fm?.[1])
|
|
149
|
+
parts.push(fm[1]);
|
|
150
|
+
// <script src="">
|
|
151
|
+
const scriptSrc = content.matchAll(/<script\b[^>]*?\bsrc=["'](.+?)["'][^>]*>/g);
|
|
152
|
+
for (const s of scriptSrc) {
|
|
153
|
+
const src = s[1];
|
|
154
|
+
const resolved = src.startsWith("/")
|
|
155
|
+
? path_1.default.resolve(process.cwd(), "." + src)
|
|
156
|
+
: path_1.default.resolve(path_1.default.dirname(file), src);
|
|
157
|
+
deps.push(resolved);
|
|
158
|
+
}
|
|
159
|
+
// inline <script>
|
|
160
|
+
const scripts = content.matchAll(/<script\b[^>]*>([\s\S]*?)<\/script>/g);
|
|
161
|
+
for (const m of scripts) {
|
|
162
|
+
if (m[1].trim())
|
|
163
|
+
parts.push(m[1]);
|
|
164
|
+
}
|
|
165
|
+
const noScripts = content.replace(/<script[\s\S]*?<\/script>/g, "");
|
|
166
|
+
const loose = extractLooseJS(noScripts);
|
|
167
|
+
for (const l of loose) {
|
|
168
|
+
parts.push(l);
|
|
169
|
+
}
|
|
170
|
+
// expressions
|
|
171
|
+
const extracted = extractJS(content);
|
|
172
|
+
for (const e of extracted) {
|
|
173
|
+
parts.push(e + ";");
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
code: [...new Set(parts)].join("\n"),
|
|
177
|
+
deps,
|
|
178
|
+
};
|
|
179
|
+
}
|
package/package.json
CHANGED
package/src/engine/resolver.ts
CHANGED
|
@@ -11,12 +11,13 @@ export function resolveNodeValue(
|
|
|
11
11
|
checker: ts.TypeChecker,
|
|
12
12
|
paramMap?: Map<string, ts.Expression>,
|
|
13
13
|
seen = new Set<ts.Node>()
|
|
14
|
-
): ResolveResult
|
|
14
|
+
): ResolveResult {
|
|
15
15
|
|
|
16
|
-
if (seen.has(node))
|
|
16
|
+
if (seen.has(node)) {
|
|
17
|
+
return { values: [], dynamic: true };
|
|
18
|
+
}
|
|
17
19
|
seen.add(node);
|
|
18
20
|
|
|
19
|
-
// param mapping
|
|
20
21
|
if (ts.isIdentifier(node) && paramMap?.has(node.text)) {
|
|
21
22
|
return resolveNodeValue(
|
|
22
23
|
paramMap.get(node.text)!,
|
|
@@ -46,16 +47,15 @@ export function resolveNodeValue(
|
|
|
46
47
|
const b = resolveNodeValue(node.whenFalse, checker, paramMap, seen);
|
|
47
48
|
|
|
48
49
|
return {
|
|
49
|
-
values: [...new Set([...(a
|
|
50
|
+
values: [...new Set([...(a.values ?? []), ...(b.values ?? [])])],
|
|
50
51
|
dynamic: true,
|
|
51
52
|
};
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
if (ts.isIdentifier(node)) {
|
|
55
56
|
let symbol = checker.getSymbolAtLocation(node);
|
|
56
|
-
if (!symbol) return
|
|
57
|
+
if (!symbol) return { values: [], dynamic: true };
|
|
57
58
|
|
|
58
|
-
// variable inline resolve FIRST
|
|
59
59
|
for (const decl of symbol.getDeclarations() ?? []) {
|
|
60
60
|
if (ts.isVariableDeclaration(decl) && decl.initializer) {
|
|
61
61
|
return resolveNodeValue(
|
|
@@ -71,7 +71,6 @@ export function resolveNodeValue(
|
|
|
71
71
|
|
|
72
72
|
symbol = resolveExportedSymbol(symbol, checker) ?? symbol;
|
|
73
73
|
|
|
74
|
-
// avoid alias loop
|
|
75
74
|
if (symbol !== original && (symbol.flags & ts.SymbolFlags.Alias)) {
|
|
76
75
|
symbol = checker.getAliasedSymbol(symbol);
|
|
77
76
|
}
|
|
@@ -95,6 +94,8 @@ export function resolveNodeValue(
|
|
|
95
94
|
}
|
|
96
95
|
}
|
|
97
96
|
}
|
|
97
|
+
|
|
98
|
+
return { values: [], dynamic: true };
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
if (ts.isPropertyAccessExpression(node)) {
|
|
@@ -107,7 +108,6 @@ export function resolveNodeValue(
|
|
|
107
108
|
s = checker.getAliasedSymbol(s);
|
|
108
109
|
}
|
|
109
110
|
|
|
110
|
-
// ENUM support
|
|
111
111
|
for (const decl of s.getDeclarations() ?? []) {
|
|
112
112
|
if (ts.isEnumMember(decl) && decl.initializer) {
|
|
113
113
|
if (ts.isStringLiteral(decl.initializer)) {
|
|
@@ -120,7 +120,6 @@ export function resolveNodeValue(
|
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
// OBJECT support
|
|
124
123
|
if (ts.isIdentifier(node.expression)) {
|
|
125
124
|
const objSymbol = checker.getSymbolAtLocation(node.expression);
|
|
126
125
|
|
|
@@ -149,6 +148,8 @@ export function resolveNodeValue(
|
|
|
149
148
|
}
|
|
150
149
|
}
|
|
151
150
|
}
|
|
151
|
+
|
|
152
|
+
return { values: [], dynamic: true };
|
|
152
153
|
}
|
|
153
154
|
|
|
154
155
|
if (ts.isObjectLiteralExpression(node)) {
|
|
@@ -161,7 +162,7 @@ export function resolveNodeValue(
|
|
|
161
162
|
|
|
162
163
|
if (name === "event") {
|
|
163
164
|
const res = resolveNodeValue(prop.initializer, checker, paramMap, seen);
|
|
164
|
-
|
|
165
|
+
values.push(...res.values);
|
|
165
166
|
}
|
|
166
167
|
}
|
|
167
168
|
|
|
@@ -176,7 +177,9 @@ export function resolveNodeValue(
|
|
|
176
177
|
if (left && right) {
|
|
177
178
|
return {
|
|
178
179
|
values: left.values.flatMap(l =>
|
|
179
|
-
right.values.
|
|
180
|
+
right.values.length
|
|
181
|
+
? right.values.map(r => l + r)
|
|
182
|
+
: [l + "*"]
|
|
180
183
|
),
|
|
181
184
|
dynamic: true,
|
|
182
185
|
};
|
|
@@ -184,5 +187,9 @@ export function resolveNodeValue(
|
|
|
184
187
|
}
|
|
185
188
|
}
|
|
186
189
|
|
|
187
|
-
|
|
190
|
+
if (ts.isCallExpression(node)) {
|
|
191
|
+
return { values: [], dynamic: true };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return { values: [], dynamic: true };
|
|
188
195
|
}
|
package/src/engine/scanner.ts
CHANGED
|
@@ -166,9 +166,11 @@ export function scanSource(
|
|
|
166
166
|
paramMap
|
|
167
167
|
);
|
|
168
168
|
|
|
169
|
-
res
|
|
170
|
-
|
|
171
|
-
|
|
169
|
+
if (res && res.values.length) {
|
|
170
|
+
res.values.forEach(v => {
|
|
171
|
+
if (isValidEvent(v)) events.add(v);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
172
174
|
|
|
173
175
|
handled = true;
|
|
174
176
|
}
|
|
@@ -179,9 +181,11 @@ export function scanSource(
|
|
|
179
181
|
for (const arg of node.arguments) {
|
|
180
182
|
const res = resolveNodeValue(arg, checker, paramMap);
|
|
181
183
|
|
|
182
|
-
res
|
|
183
|
-
|
|
184
|
-
|
|
184
|
+
if (res && res.values.length) {
|
|
185
|
+
res.values.forEach(v => {
|
|
186
|
+
if (isValidEvent(v)) events.add(v);
|
|
187
|
+
});
|
|
188
|
+
}
|
|
185
189
|
}
|
|
186
190
|
}
|
|
187
191
|
|
package/src/utils/processFile.ts
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
import
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { parseUniversal } from "./universal";
|
|
2
3
|
|
|
3
4
|
export function processFile(file: string, content: string) {
|
|
4
|
-
const
|
|
5
|
+
const { code, deps } = parseUniversal(content, file);
|
|
5
6
|
|
|
6
|
-
const
|
|
7
|
+
const ext = path.extname(file);
|
|
7
8
|
|
|
8
9
|
const virtualFile =
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
file.endsWith(".astro")
|
|
12
|
-
? file + ".tsx"
|
|
10
|
+
/\.(vue|svelte|astro|html)$/i.test(file)
|
|
11
|
+
? file.replace(ext, "") + ".tsx"
|
|
13
12
|
: file;
|
|
14
13
|
|
|
15
14
|
return {
|
|
16
|
-
content:
|
|
15
|
+
content: code || "",
|
|
17
16
|
virtualFile,
|
|
18
|
-
deps:
|
|
17
|
+
deps: [...new Set(deps.filter(Boolean))],
|
|
19
18
|
};
|
|
20
19
|
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { ParseResult } from "../types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* exact JS:
|
|
6
|
+
* - {...}
|
|
7
|
+
* - attr="..."
|
|
8
|
+
* - Vue / Svelte handlers
|
|
9
|
+
*/
|
|
10
|
+
function extractJS(input: string): string[] {
|
|
11
|
+
const result: string[] = [];
|
|
12
|
+
|
|
13
|
+
let i = 0;
|
|
14
|
+
const len = input.length;
|
|
15
|
+
|
|
16
|
+
let inString: '"' | "'" | "`" | null = null;
|
|
17
|
+
let escape = false;
|
|
18
|
+
|
|
19
|
+
while (i < len) {
|
|
20
|
+
const ch = input[i];
|
|
21
|
+
|
|
22
|
+
// STRING
|
|
23
|
+
if (inString) {
|
|
24
|
+
if (escape) escape = false;
|
|
25
|
+
else if (ch === "\\") escape = true;
|
|
26
|
+
else if (ch === inString) inString = null;
|
|
27
|
+
|
|
28
|
+
i++;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
33
|
+
inString = ch;
|
|
34
|
+
i++;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// { ... }
|
|
39
|
+
if (ch === "{") {
|
|
40
|
+
let depth = 1;
|
|
41
|
+
let j = i + 1;
|
|
42
|
+
|
|
43
|
+
let innerStr: '"' | "'" | "`" | null = null;
|
|
44
|
+
let innerEsc = false;
|
|
45
|
+
|
|
46
|
+
while (j < len && depth > 0) {
|
|
47
|
+
const c = input[j];
|
|
48
|
+
|
|
49
|
+
if (innerStr) {
|
|
50
|
+
if (innerEsc) innerEsc = false;
|
|
51
|
+
else if (c === "\\") innerEsc = true;
|
|
52
|
+
else if (c === innerStr) innerStr = null;
|
|
53
|
+
j++;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
58
|
+
innerStr = c;
|
|
59
|
+
j++;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (c === "{") depth++;
|
|
64
|
+
else if (c === "}") depth--;
|
|
65
|
+
|
|
66
|
+
j++;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (depth === 0) {
|
|
70
|
+
const expr = input.slice(i + 1, j - 1).trim();
|
|
71
|
+
if (expr) result.push(expr);
|
|
72
|
+
i = j;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// attr="..."
|
|
78
|
+
if (ch === "=" && (input[i + 1] === '"' || input[i + 1] === "'")) {
|
|
79
|
+
const quote = input[i + 1];
|
|
80
|
+
let j = i + 2;
|
|
81
|
+
let val = "";
|
|
82
|
+
|
|
83
|
+
while (j < len) {
|
|
84
|
+
const c = input[j];
|
|
85
|
+
|
|
86
|
+
if (c === "\\" && input[j + 1]) {
|
|
87
|
+
val += c + input[j + 1];
|
|
88
|
+
j += 2;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (c === quote) break;
|
|
93
|
+
|
|
94
|
+
val += c;
|
|
95
|
+
j++;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (val.trim()) result.push(val.trim());
|
|
99
|
+
|
|
100
|
+
i = j + 1;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
i++;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Vue / Svelte / JSX handlers
|
|
108
|
+
const extra = [
|
|
109
|
+
/@[\w-]+\s*=\s*["']([\s\S]*?)["']/g,
|
|
110
|
+
/v-on:[\w-]+\s*=\s*["']([\s\S]*?)["']/g,
|
|
111
|
+
/on:[\w-]+\s*=\s*{([\s\S]*?)}/g,
|
|
112
|
+
/on\w+\s*=\s*{([\s\S]*?)}/g,
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
for (const r of extra) {
|
|
116
|
+
const m = input.matchAll(r);
|
|
117
|
+
for (const x of m) {
|
|
118
|
+
const v = x[1]?.trim();
|
|
119
|
+
if (v) result.push(v);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function extractLooseJS(input: string): string[] {
|
|
127
|
+
const result: string[] = [];
|
|
128
|
+
|
|
129
|
+
const lines = input.split("\n");
|
|
130
|
+
|
|
131
|
+
for (const line of lines) {
|
|
132
|
+
const l = line.trim();
|
|
133
|
+
|
|
134
|
+
if (!l) continue;
|
|
135
|
+
if (l.startsWith("<")) continue;
|
|
136
|
+
|
|
137
|
+
if (
|
|
138
|
+
l.includes("(") ||
|
|
139
|
+
l.includes("=") ||
|
|
140
|
+
l.includes("=>") ||
|
|
141
|
+
l.includes("function") ||
|
|
142
|
+
l.includes("track")
|
|
143
|
+
) {
|
|
144
|
+
result.push(l);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Universal:
|
|
153
|
+
* - Astro
|
|
154
|
+
* - Vue
|
|
155
|
+
* - Svelte
|
|
156
|
+
* - React / JSX
|
|
157
|
+
* - Node / backend
|
|
158
|
+
*/
|
|
159
|
+
|
|
160
|
+
export function parseUniversal(
|
|
161
|
+
content: string,
|
|
162
|
+
file: string
|
|
163
|
+
): ParseResult {
|
|
164
|
+
const parts: string[] = [];
|
|
165
|
+
const deps: string[] = [];
|
|
166
|
+
|
|
167
|
+
// Astro frontmatter ---
|
|
168
|
+
const fm = content.match(/^---([\s\S]*?)---/);
|
|
169
|
+
if (fm?.[1]) parts.push(fm[1]);
|
|
170
|
+
|
|
171
|
+
// <script src="">
|
|
172
|
+
const scriptSrc = content.matchAll(
|
|
173
|
+
/<script\b[^>]*?\bsrc=["'](.+?)["'][^>]*>/g
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
for (const s of scriptSrc) {
|
|
177
|
+
const src = s[1];
|
|
178
|
+
|
|
179
|
+
const resolved = src.startsWith("/")
|
|
180
|
+
? path.resolve(process.cwd(), "." + src)
|
|
181
|
+
: path.resolve(path.dirname(file), src);
|
|
182
|
+
|
|
183
|
+
deps.push(resolved);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// inline <script>
|
|
187
|
+
const scripts = content.matchAll(
|
|
188
|
+
/<script\b[^>]*>([\s\S]*?)<\/script>/g
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
for (const m of scripts) {
|
|
192
|
+
if (m[1].trim()) parts.push(m[1]);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const noScripts = content.replace(
|
|
196
|
+
/<script[\s\S]*?<\/script>/g,
|
|
197
|
+
""
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
const loose = extractLooseJS(noScripts);
|
|
201
|
+
|
|
202
|
+
for (const l of loose) {
|
|
203
|
+
parts.push(l);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// expressions
|
|
207
|
+
const extracted = extractJS(content);
|
|
208
|
+
|
|
209
|
+
for (const e of extracted) {
|
|
210
|
+
parts.push(e + ";");
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
code: [...new Set(parts)].join("\n"),
|
|
215
|
+
deps,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.parseAstro = parseAstro;
|
|
7
|
-
const path_1 = __importDefault(require("path"));
|
|
8
|
-
const utils_1 = require("./utils");
|
|
9
|
-
function parseAstro(content, file) {
|
|
10
|
-
const parts = [];
|
|
11
|
-
const deps = [];
|
|
12
|
-
// frontmatter
|
|
13
|
-
const frontmatter = content.match(/^---([\s\S]*?)---/);
|
|
14
|
-
if (frontmatter?.[1]) {
|
|
15
|
-
parts.push(frontmatter[1]);
|
|
16
|
-
}
|
|
17
|
-
// scripts
|
|
18
|
-
const scripts = content.matchAll(/<script([^>]*)>([\s\S]*?)<\/script>/g);
|
|
19
|
-
for (const m of scripts) {
|
|
20
|
-
const attrs = m[1];
|
|
21
|
-
const body = m[2];
|
|
22
|
-
// external script
|
|
23
|
-
if (attrs.includes("src")) {
|
|
24
|
-
const src = attrs.match(/src=["'](.+?)["']/)?.[1];
|
|
25
|
-
if (!src)
|
|
26
|
-
continue;
|
|
27
|
-
let resolved;
|
|
28
|
-
if (src.startsWith("/")) {
|
|
29
|
-
resolved = path_1.default.join(process.cwd(), src); // FIX
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
resolved = path_1.default.resolve(path_1.default.dirname(file), src);
|
|
33
|
-
}
|
|
34
|
-
deps.push(resolved);
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
parts.push(body);
|
|
38
|
-
const imports = body.matchAll(/import\s+.*?from\s+["'](.+?)["']/g);
|
|
39
|
-
for (const im of imports) {
|
|
40
|
-
const resolved = (0, utils_1.resolveImport)(file, im[1]);
|
|
41
|
-
if (resolved)
|
|
42
|
-
deps.push(resolved);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return {
|
|
46
|
-
code: parts.join("\n"),
|
|
47
|
-
deps,
|
|
48
|
-
};
|
|
49
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
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
|
-
});
|
|
11
|
-
function detectParser(file) {
|
|
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;
|
|
20
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseSvelte = parseSvelte;
|
|
4
|
-
const utils_1 = require("./utils");
|
|
5
|
-
function parseSvelte(content, file) {
|
|
6
|
-
const parts = [];
|
|
7
|
-
const deps = [];
|
|
8
|
-
// script
|
|
9
|
-
const scripts = content.matchAll(/<script[^>]*>([\s\S]*?)<\/script>/g);
|
|
10
|
-
for (const m of scripts) {
|
|
11
|
-
const code = m[1];
|
|
12
|
-
parts.push(code);
|
|
13
|
-
// imports
|
|
14
|
-
const imports = code.matchAll(/import\s+.*?from\s+["'](.+?)["']/g);
|
|
15
|
-
for (const im of imports) {
|
|
16
|
-
const resolved = (0, utils_1.resolveImport)(file, im[1]);
|
|
17
|
-
if (resolved)
|
|
18
|
-
deps.push(resolved);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
// handlers
|
|
22
|
-
const handlers = content.matchAll(/on:\w+=\{([^}]+)\}/g);
|
|
23
|
-
for (const h of handlers) {
|
|
24
|
-
parts.push(h[1] + ";");
|
|
25
|
-
}
|
|
26
|
-
return {
|
|
27
|
-
code: parts.join("\n"),
|
|
28
|
-
deps,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.resolveImport = resolveImport;
|
|
7
|
-
const fs_1 = __importDefault(require("fs"));
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
function resolveImport(from, src) {
|
|
10
|
-
if (!src.startsWith("."))
|
|
11
|
-
return null;
|
|
12
|
-
const base = path_1.default.resolve(path_1.default.dirname(from), src);
|
|
13
|
-
const exts = [".ts", ".tsx", ".js", ".jsx"];
|
|
14
|
-
for (const ext of exts) {
|
|
15
|
-
if (fs_1.default.existsSync(base + ext))
|
|
16
|
-
return base + ext;
|
|
17
|
-
}
|
|
18
|
-
if (fs_1.default.existsSync(base))
|
|
19
|
-
return base;
|
|
20
|
-
return null;
|
|
21
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.parseVue = parseVue;
|
|
7
|
-
const path_1 = __importDefault(require("path"));
|
|
8
|
-
const utils_1 = require("./utils");
|
|
9
|
-
function parseVue(content, file) {
|
|
10
|
-
const parts = [];
|
|
11
|
-
const deps = [];
|
|
12
|
-
// SCRIPT
|
|
13
|
-
const scripts = content.matchAll(/<script([^>]*)>([\s\S]*?)<\/script>/g);
|
|
14
|
-
for (const m of scripts) {
|
|
15
|
-
const attrs = m[1];
|
|
16
|
-
const body = m[2];
|
|
17
|
-
if (attrs.includes("src")) {
|
|
18
|
-
const src = attrs.match(/src=["'](.+?)["']/)?.[1];
|
|
19
|
-
if (!src)
|
|
20
|
-
continue;
|
|
21
|
-
const resolved = src.startsWith("/")
|
|
22
|
-
? path_1.default.join(process.cwd(), src)
|
|
23
|
-
: path_1.default.resolve(path_1.default.dirname(file), src);
|
|
24
|
-
deps.push(resolved);
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
|
-
parts.push(body);
|
|
28
|
-
// imports
|
|
29
|
-
const imports = body.matchAll(/import\s+.*?from\s+["'](.+?)["']/g);
|
|
30
|
-
for (const im of imports) {
|
|
31
|
-
const resolved = (0, utils_1.resolveImport)(file, im[1]);
|
|
32
|
-
if (resolved)
|
|
33
|
-
deps.push(resolved);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
// TEMPLATE
|
|
37
|
-
const templateMatch = content.match(/<template[^>]*>([\s\S]*?)<\/template>/);
|
|
38
|
-
let template = templateMatch?.[1] ?? "";
|
|
39
|
-
template = template.replace(/<!--[\s\S]*?-->/g, "");
|
|
40
|
-
// @click
|
|
41
|
-
const handlers = template.matchAll(/@[\w-]+="([^"]+)"/g);
|
|
42
|
-
for (const h of handlers) {
|
|
43
|
-
parts.push(h[1] + ";");
|
|
44
|
-
}
|
|
45
|
-
// v-on
|
|
46
|
-
const vOn = template.matchAll(/v-on:[\w-]+="([^"]+)"/g);
|
|
47
|
-
for (const v of vOn) {
|
|
48
|
-
parts.push(v[1] + ";");
|
|
49
|
-
}
|
|
50
|
-
// :bind
|
|
51
|
-
const binds = template.matchAll(/:[\w-]+="([^"]+)"/g);
|
|
52
|
-
for (const b of binds) {
|
|
53
|
-
parts.push(b[1] + ";");
|
|
54
|
-
}
|
|
55
|
-
return {
|
|
56
|
-
code: parts.join("\n"),
|
|
57
|
-
deps,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import { ParseResult } from "../../types";
|
|
3
|
-
import { resolveImport } from "./utils";
|
|
4
|
-
|
|
5
|
-
export function parseAstro(content: string, file: string): ParseResult {
|
|
6
|
-
const parts: string[] = [];
|
|
7
|
-
const deps: string[] = [];
|
|
8
|
-
|
|
9
|
-
// frontmatter
|
|
10
|
-
const frontmatter = content.match(/^---([\s\S]*?)---/);
|
|
11
|
-
if (frontmatter?.[1]) {
|
|
12
|
-
parts.push(frontmatter[1]);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// scripts
|
|
16
|
-
const scripts = content.matchAll(/<script([^>]*)>([\s\S]*?)<\/script>/g);
|
|
17
|
-
|
|
18
|
-
for (const m of scripts) {
|
|
19
|
-
const attrs = m[1];
|
|
20
|
-
const body = m[2];
|
|
21
|
-
|
|
22
|
-
// external script
|
|
23
|
-
if (attrs.includes("src")) {
|
|
24
|
-
const src = attrs.match(/src=["'](.+?)["']/)?.[1];
|
|
25
|
-
if (!src) continue;
|
|
26
|
-
|
|
27
|
-
let resolved: string;
|
|
28
|
-
|
|
29
|
-
if (src.startsWith("/")) {
|
|
30
|
-
resolved = path.join(process.cwd(), src); // FIX
|
|
31
|
-
} else {
|
|
32
|
-
resolved = path.resolve(path.dirname(file), src);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
deps.push(resolved);
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
parts.push(body);
|
|
40
|
-
|
|
41
|
-
const imports = body.matchAll(/import\s+.*?from\s+["'](.+?)["']/g);
|
|
42
|
-
|
|
43
|
-
for (const im of imports) {
|
|
44
|
-
const resolved = resolveImport(file, im[1]);
|
|
45
|
-
if (resolved) deps.push(resolved);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
code: parts.join("\n"),
|
|
51
|
-
deps,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { Parser } from "../../types";
|
|
2
|
-
import { parseVue } from "./vue";
|
|
3
|
-
import { parseSvelte } from "./svelte";
|
|
4
|
-
import { parseAstro } from "./astro";
|
|
5
|
-
|
|
6
|
-
const fallback: Parser = (content) => ({
|
|
7
|
-
code: content,
|
|
8
|
-
deps: [],
|
|
9
|
-
});
|
|
10
|
-
|
|
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;
|
|
19
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { ParseResult } from "../../types";
|
|
2
|
-
import { resolveImport } from "./utils";
|
|
3
|
-
|
|
4
|
-
export function parseSvelte(content: string, file: string): ParseResult {
|
|
5
|
-
const parts: string[] = [];
|
|
6
|
-
const deps: string[] = [];
|
|
7
|
-
|
|
8
|
-
// script
|
|
9
|
-
const scripts = content.matchAll(/<script[^>]*>([\s\S]*?)<\/script>/g);
|
|
10
|
-
|
|
11
|
-
for (const m of scripts) {
|
|
12
|
-
const code = m[1];
|
|
13
|
-
|
|
14
|
-
parts.push(code);
|
|
15
|
-
|
|
16
|
-
// imports
|
|
17
|
-
const imports = code.matchAll(/import\s+.*?from\s+["'](.+?)["']/g);
|
|
18
|
-
|
|
19
|
-
for (const im of imports) {
|
|
20
|
-
const resolved = resolveImport(file, im[1]);
|
|
21
|
-
if (resolved) deps.push(resolved);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// handlers
|
|
26
|
-
const handlers = content.matchAll(/on:\w+=\{([^}]+)\}/g);
|
|
27
|
-
|
|
28
|
-
for (const h of handlers) {
|
|
29
|
-
parts.push(h[1] + ";");
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return {
|
|
33
|
-
code: parts.join("\n"),
|
|
34
|
-
deps,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
|
|
4
|
-
export function resolveImport(from: string, src: string): string | null {
|
|
5
|
-
if (!src.startsWith(".")) return null;
|
|
6
|
-
|
|
7
|
-
const base = path.resolve(path.dirname(from), src);
|
|
8
|
-
|
|
9
|
-
const exts = [".ts", ".tsx", ".js", ".jsx"];
|
|
10
|
-
|
|
11
|
-
for (const ext of exts) {
|
|
12
|
-
if (fs.existsSync(base + ext)) return base + ext;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (fs.existsSync(base)) return base;
|
|
16
|
-
|
|
17
|
-
return null;
|
|
18
|
-
}
|
package/src/utils/parsers/vue.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import { ParseResult } from "../../types";
|
|
3
|
-
import { resolveImport } from "./utils";
|
|
4
|
-
|
|
5
|
-
export function parseVue(content: string, file: string): ParseResult {
|
|
6
|
-
const parts: string[] = [];
|
|
7
|
-
const deps: string[] = [];
|
|
8
|
-
|
|
9
|
-
// SCRIPT
|
|
10
|
-
const scripts = content.matchAll(/<script([^>]*)>([\s\S]*?)<\/script>/g);
|
|
11
|
-
|
|
12
|
-
for (const m of scripts) {
|
|
13
|
-
const attrs = m[1];
|
|
14
|
-
const body = m[2];
|
|
15
|
-
|
|
16
|
-
if (attrs.includes("src")) {
|
|
17
|
-
const src = attrs.match(/src=["'](.+?)["']/)?.[1];
|
|
18
|
-
if (!src) continue;
|
|
19
|
-
|
|
20
|
-
const resolved = src.startsWith("/")
|
|
21
|
-
? path.join(process.cwd(), src)
|
|
22
|
-
: path.resolve(path.dirname(file), src);
|
|
23
|
-
|
|
24
|
-
deps.push(resolved);
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
parts.push(body);
|
|
29
|
-
|
|
30
|
-
// imports
|
|
31
|
-
const imports = body.matchAll(/import\s+.*?from\s+["'](.+?)["']/g);
|
|
32
|
-
|
|
33
|
-
for (const im of imports) {
|
|
34
|
-
const resolved = resolveImport(file, im[1]);
|
|
35
|
-
if (resolved) deps.push(resolved);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// TEMPLATE
|
|
40
|
-
const templateMatch = content.match(/<template[^>]*>([\s\S]*?)<\/template>/);
|
|
41
|
-
let template = templateMatch?.[1] ?? "";
|
|
42
|
-
|
|
43
|
-
template = template.replace(/<!--[\s\S]*?-->/g, "");
|
|
44
|
-
|
|
45
|
-
// @click
|
|
46
|
-
const handlers = template.matchAll(/@[\w-]+="([^"]+)"/g);
|
|
47
|
-
for (const h of handlers) {
|
|
48
|
-
parts.push(h[1] + ";");
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// v-on
|
|
52
|
-
const vOn = template.matchAll(/v-on:[\w-]+="([^"]+)"/g);
|
|
53
|
-
for (const v of vOn) {
|
|
54
|
-
parts.push(v[1] + ";");
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// :bind
|
|
58
|
-
const binds = template.matchAll(/:[\w-]+="([^"]+)"/g);
|
|
59
|
-
for (const b of binds) {
|
|
60
|
-
parts.push(b[1] + ";");
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return {
|
|
64
|
-
code: parts.join("\n"),
|
|
65
|
-
deps,
|
|
66
|
-
};
|
|
67
|
-
}
|