@eventra_dev/eventra-cli 0.0.19 → 0.1.2
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 -117
- package/dist/commands/sync.js +20 -115
- package/dist/commands/watch.js +107 -69
- package/dist/engine/callResolver.js +34 -0
- package/dist/engine/engine.js +47 -0
- package/dist/engine/graph.js +25 -0
- package/dist/engine/hash.js +10 -0
- package/dist/engine/languageService.js +67 -0
- package/dist/engine/resolver.js +69 -0
- package/dist/engine/scanner.js +50 -0
- package/dist/utils/parsers/vue.js +16 -12
- package/dist/utils/processFile.js +20 -0
- package/package.json +1 -1
- package/src/commands/check.ts +19 -151
- package/src/commands/sync.ts +23 -194
- package/src/commands/watch.ts +119 -66
- package/src/engine/callResolver.ts +43 -0
- package/src/engine/engine.ts +60 -0
- package/src/engine/graph.ts +23 -0
- package/src/engine/hash.ts +5 -0
- package/src/engine/languageService.ts +73 -0
- package/src/engine/resolver.ts +86 -0
- package/src/engine/scanner.ts +61 -0
- package/src/types.ts +5 -6
- package/src/utils/parsers/vue.ts +19 -20
- package/src/utils/processFile.ts +18 -0
- package/tests/fixtures/backend/express/app.ts +167 -12
- package/tests/fixtures/wrappers/component/test.tsx +1 -1
- package/tests/run.ts +4 -17
- package/dist/utils/detect-aliases.js +0 -39
- package/dist/utils/detect-wrappers.js +0 -84
- package/dist/utils/extract.js +0 -56
- package/dist/utils/scanners/component-wrappers.js +0 -73
- package/dist/utils/scanners/function-wrappers.js +0 -83
- package/dist/utils/scanners/track.js +0 -64
- package/src/utils/detect-aliases.ts +0 -46
- package/src/utils/detect-wrappers.ts +0 -119
- package/src/utils/extract.ts +0 -72
- package/src/utils/scanners/component-wrappers.ts +0 -109
- package/src/utils/scanners/function-wrappers.ts +0 -137
- package/src/utils/scanners/track.ts +0 -99
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
|
|
3
|
+
export type ResolveResult = {
|
|
4
|
+
values: string[];
|
|
5
|
+
dynamic: boolean;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export function resolveNodeValue(
|
|
9
|
+
node: ts.Node,
|
|
10
|
+
checker: ts.TypeChecker
|
|
11
|
+
): ResolveResult | null {
|
|
12
|
+
|
|
13
|
+
if (ts.isStringLiteral(node)) {
|
|
14
|
+
return { values: [node.text], dynamic: false };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (ts.isTemplateExpression(node)) {
|
|
18
|
+
let result = node.head.text;
|
|
19
|
+
|
|
20
|
+
for (const span of node.templateSpans) {
|
|
21
|
+
result += "*";
|
|
22
|
+
result += span.literal.text;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return { values: [result], dynamic: true };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (ts.isConditionalExpression(node)) {
|
|
29
|
+
const a = resolveNodeValue(node.whenTrue, checker);
|
|
30
|
+
const b = resolveNodeValue(node.whenFalse, checker);
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
values: [...new Set([...(a?.values ?? []), ...(b?.values ?? [])])],
|
|
34
|
+
dynamic: true,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (ts.isIdentifier(node)) {
|
|
39
|
+
let symbol = checker.getSymbolAtLocation(node);
|
|
40
|
+
if (!symbol) return null;
|
|
41
|
+
|
|
42
|
+
if (symbol.flags & ts.SymbolFlags.Alias) {
|
|
43
|
+
symbol = checker.getAliasedSymbol(symbol);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
for (const decl of symbol.getDeclarations() ?? []) {
|
|
47
|
+
if (ts.isVariableDeclaration(decl) && decl.initializer) {
|
|
48
|
+
return resolveNodeValue(decl.initializer, checker);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (ts.isEnumMember(decl) && decl.initializer) {
|
|
52
|
+
if (ts.isStringLiteral(decl.initializer)) {
|
|
53
|
+
return {
|
|
54
|
+
values: [decl.initializer.text],
|
|
55
|
+
dynamic: false,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
63
|
+
const symbol = checker.getSymbolAtLocation(node);
|
|
64
|
+
|
|
65
|
+
if (symbol) {
|
|
66
|
+
let s = symbol;
|
|
67
|
+
|
|
68
|
+
if (s.flags & ts.SymbolFlags.Alias) {
|
|
69
|
+
s = checker.getAliasedSymbol(s);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
for (const decl of s.getDeclarations() ?? []) {
|
|
73
|
+
if (ts.isEnumMember(decl) && decl.initializer) {
|
|
74
|
+
if (ts.isStringLiteral(decl.initializer)) {
|
|
75
|
+
return {
|
|
76
|
+
values: [decl.initializer.text],
|
|
77
|
+
dynamic: false,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import { resolveNodeValue } from "./resolver";
|
|
3
|
+
import { resolveFunctionFromCall } from "./callResolver";
|
|
4
|
+
|
|
5
|
+
export function scanSource(
|
|
6
|
+
source: ts.SourceFile,
|
|
7
|
+
checker: ts.TypeChecker,
|
|
8
|
+
visited = new Set<string>()
|
|
9
|
+
) {
|
|
10
|
+
const events = new Set<string>();
|
|
11
|
+
|
|
12
|
+
if (visited.has(source.fileName)) return events;
|
|
13
|
+
visited.add(source.fileName);
|
|
14
|
+
|
|
15
|
+
function visit(node: ts.Node) {
|
|
16
|
+
if (ts.isCallExpression(node)) {
|
|
17
|
+
const name = getCallName(node.expression);
|
|
18
|
+
|
|
19
|
+
if (/(track|event|capture|send)/i.test(name)) {
|
|
20
|
+
let target = node.arguments[0];
|
|
21
|
+
|
|
22
|
+
const fn = resolveFunctionFromCall(node.expression, checker);
|
|
23
|
+
|
|
24
|
+
// 🔥 cross-file
|
|
25
|
+
if (fn) {
|
|
26
|
+
const sf = fn.getSourceFile();
|
|
27
|
+
|
|
28
|
+
if (!visited.has(sf.fileName)) {
|
|
29
|
+
scanSource(sf, checker, visited).forEach(e => events.add(e));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (target) {
|
|
34
|
+
const res = resolveNodeValue(target, checker);
|
|
35
|
+
|
|
36
|
+
res?.values.forEach(v => {
|
|
37
|
+
if (v && v.length > 1 && !v.includes(" ")) {
|
|
38
|
+
events.add(v);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
ts.forEachChild(node, visit);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
visit(source);
|
|
49
|
+
|
|
50
|
+
return events;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function getCallName(expr: ts.Expression): string {
|
|
54
|
+
if (ts.isIdentifier(expr)) return expr.text;
|
|
55
|
+
|
|
56
|
+
if (ts.isPropertyAccessExpression(expr)) {
|
|
57
|
+
return expr.name.text;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return "";
|
|
61
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export type ScanMode = "strict" | "hybrid" | "discovery";
|
|
2
|
+
|
|
1
3
|
export type ComponentWrapper = {
|
|
2
4
|
name: string;
|
|
3
5
|
prop: string;
|
|
@@ -6,14 +8,13 @@ export type ComponentWrapper = {
|
|
|
6
8
|
export type FunctionWrapper = {
|
|
7
9
|
name: string;
|
|
8
10
|
event?: string;
|
|
9
|
-
file?: string;
|
|
10
|
-
line?: number;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
export type EventraConfig = {
|
|
14
14
|
apiKey?: string;
|
|
15
15
|
endpoint?: string;
|
|
16
16
|
events: string[];
|
|
17
|
+
mode?: ScanMode;
|
|
17
18
|
wrappers: ComponentWrapper[];
|
|
18
19
|
functionWrappers: FunctionWrapper[];
|
|
19
20
|
aliases?: Record<string, string>;
|
|
@@ -23,9 +24,7 @@ export type EventraConfig = {
|
|
|
23
24
|
};
|
|
24
25
|
};
|
|
25
26
|
|
|
26
|
-
export type
|
|
27
|
-
|
|
27
|
+
export type ResolveResult = {
|
|
28
|
+
values: string[];
|
|
28
29
|
dynamic: boolean;
|
|
29
|
-
file?: string;
|
|
30
|
-
line?: number;
|
|
31
30
|
};
|
package/src/utils/parsers/vue.ts
CHANGED
|
@@ -1,25 +1,24 @@
|
|
|
1
|
-
export function parseVue(
|
|
2
|
-
content
|
|
3
|
-
)
|
|
4
|
-
const template =
|
|
5
|
-
content.match(
|
|
6
|
-
/<template[\s\S]*?>([\s\S]*?)<\/template>/
|
|
7
|
-
);
|
|
1
|
+
export function parseVue(content: string) {
|
|
2
|
+
const scriptMatch = content.match(/<script[\s\S]*?>([\s\S]*?)<\/script>/);
|
|
3
|
+
const templateMatch = content.match(/<template>([\s\S]*?)<\/template>/);
|
|
8
4
|
|
|
9
|
-
const script =
|
|
10
|
-
|
|
11
|
-
/<script[\s\S]*?>([\s\S]*?)<\/script>/
|
|
12
|
-
);
|
|
5
|
+
const script = scriptMatch?.[1] ?? "";
|
|
6
|
+
let template = templateMatch?.[1] ?? "";
|
|
13
7
|
|
|
14
|
-
|
|
15
|
-
${script?.[1] ?? ""}
|
|
8
|
+
template = template.replace(/<!--[\s\S]*?-->/g, "");
|
|
16
9
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
10
|
+
template = template
|
|
11
|
+
.replace(/v-if="[^"]+"/g, "")
|
|
12
|
+
.replace(/v-for="[^"]+"/g, "")
|
|
13
|
+
.replace(/@click=/g, "onClick=");
|
|
14
|
+
|
|
15
|
+
const jsx = `
|
|
16
|
+
const __VUE_JSX__ = (
|
|
17
|
+
<>
|
|
18
|
+
${template}
|
|
19
|
+
</>
|
|
20
|
+
);
|
|
24
21
|
`;
|
|
22
|
+
|
|
23
|
+
return script + "\n" + jsx;
|
|
25
24
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
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
|
+
|
|
6
|
+
export function processFile(file: string, content: string) {
|
|
7
|
+
const parser = detectParser(file);
|
|
8
|
+
|
|
9
|
+
if (parser === "vue") content = parseVue(content);
|
|
10
|
+
if (parser === "svelte") content = parseSvelte(content);
|
|
11
|
+
if (parser === "astro") content = parseAstro(content);
|
|
12
|
+
|
|
13
|
+
const virtualFile = file.endsWith(".vue")
|
|
14
|
+
? file + ".tsx"
|
|
15
|
+
: file;
|
|
16
|
+
|
|
17
|
+
return { content, virtualFile };
|
|
18
|
+
}
|
|
@@ -13,66 +13,221 @@ const express = (...args: any[]) => ({
|
|
|
13
13
|
|
|
14
14
|
const app = express();
|
|
15
15
|
|
|
16
|
-
//
|
|
16
|
+
// =========================
|
|
17
|
+
// BASIC
|
|
18
|
+
// =========================
|
|
19
|
+
|
|
17
20
|
track("express_event");
|
|
18
21
|
|
|
19
|
-
//
|
|
22
|
+
// =========================
|
|
23
|
+
// VARIABLES
|
|
24
|
+
// =========================
|
|
25
|
+
|
|
26
|
+
const eventName = "variable_event";
|
|
27
|
+
track(eventName);
|
|
28
|
+
|
|
29
|
+
let anotherEvent;
|
|
30
|
+
anotherEvent = "assigned_event";
|
|
31
|
+
track(anotherEvent);
|
|
32
|
+
|
|
33
|
+
// =========================
|
|
34
|
+
// TEMPLATE
|
|
35
|
+
// =========================
|
|
36
|
+
|
|
37
|
+
track(`template_event`);
|
|
38
|
+
|
|
39
|
+
const id = "123";
|
|
40
|
+
track(`template_${id}`); // dynamic
|
|
41
|
+
|
|
42
|
+
// =========================
|
|
43
|
+
// MIDDLEWARE
|
|
44
|
+
// =========================
|
|
45
|
+
|
|
20
46
|
app.use(() => {
|
|
21
47
|
track("middleware_event");
|
|
22
48
|
});
|
|
23
49
|
|
|
24
|
-
//
|
|
50
|
+
// =========================
|
|
51
|
+
// ROUTES
|
|
52
|
+
// =========================
|
|
53
|
+
|
|
25
54
|
app.get("/", () => {
|
|
26
55
|
track("get_event");
|
|
27
56
|
});
|
|
28
57
|
|
|
29
|
-
// ===== post =====
|
|
30
58
|
app.post("/users", () => {
|
|
31
59
|
track("post_event");
|
|
32
60
|
});
|
|
33
61
|
|
|
34
|
-
// ===== put =====
|
|
35
62
|
app.put("/users", () => {
|
|
36
63
|
track("put_event");
|
|
37
64
|
});
|
|
38
65
|
|
|
39
|
-
// ===== delete =====
|
|
40
66
|
app.delete("/users", () => {
|
|
41
67
|
track("delete_event");
|
|
42
68
|
});
|
|
43
69
|
|
|
44
|
-
//
|
|
70
|
+
// =========================
|
|
71
|
+
// NESTED
|
|
72
|
+
// =========================
|
|
73
|
+
|
|
45
74
|
app.get("/nested", () => {
|
|
46
75
|
if (true) {
|
|
47
76
|
track("nested_event");
|
|
48
77
|
}
|
|
49
78
|
});
|
|
50
79
|
|
|
51
|
-
//
|
|
80
|
+
// =========================
|
|
81
|
+
// ASYNC
|
|
82
|
+
// =========================
|
|
83
|
+
|
|
52
84
|
app.get("/async", async () => {
|
|
53
85
|
track("async_event");
|
|
54
86
|
});
|
|
55
87
|
|
|
56
|
-
//
|
|
88
|
+
// =========================
|
|
89
|
+
// ARROW HANDLER
|
|
90
|
+
// =========================
|
|
91
|
+
|
|
57
92
|
const handler = () => {
|
|
58
93
|
track("arrow_event");
|
|
59
94
|
};
|
|
60
95
|
|
|
61
96
|
app.get("/arrow", handler);
|
|
62
97
|
|
|
63
|
-
//
|
|
98
|
+
// =========================
|
|
99
|
+
// FUNCTION DECLARATION
|
|
100
|
+
// =========================
|
|
101
|
+
|
|
64
102
|
function service() {
|
|
65
103
|
track("function_event");
|
|
66
104
|
}
|
|
67
105
|
|
|
68
|
-
//
|
|
106
|
+
// =========================
|
|
107
|
+
// CLASS
|
|
108
|
+
// =========================
|
|
109
|
+
|
|
69
110
|
class Service {
|
|
70
111
|
run() {
|
|
71
112
|
track("class_event");
|
|
72
113
|
}
|
|
73
114
|
}
|
|
74
115
|
|
|
75
|
-
//
|
|
116
|
+
// =========================
|
|
117
|
+
// LISTEN
|
|
118
|
+
// =========================
|
|
119
|
+
|
|
76
120
|
app.listen(3000, () => {
|
|
77
121
|
track("listen_event");
|
|
78
122
|
});
|
|
123
|
+
|
|
124
|
+
// =========================
|
|
125
|
+
// OBJECT WRAPPER
|
|
126
|
+
// =========================
|
|
127
|
+
|
|
128
|
+
const analytics = {
|
|
129
|
+
track
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
analytics.track("object_event");
|
|
133
|
+
|
|
134
|
+
// nested object
|
|
135
|
+
const analyticsDeep = {
|
|
136
|
+
events: {
|
|
137
|
+
track
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
analyticsDeep.events.track("nested_object_event");
|
|
142
|
+
|
|
143
|
+
// =========================
|
|
144
|
+
// CONDITIONALS
|
|
145
|
+
// =========================
|
|
146
|
+
|
|
147
|
+
if (true) {
|
|
148
|
+
track("if_event");
|
|
149
|
+
} else {
|
|
150
|
+
track("else_event");
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ternary
|
|
154
|
+
true
|
|
155
|
+
? track("ternary_true")
|
|
156
|
+
: track("ternary_false");
|
|
157
|
+
|
|
158
|
+
// =========================
|
|
159
|
+
// ARRAYS
|
|
160
|
+
// =========================
|
|
161
|
+
|
|
162
|
+
[
|
|
163
|
+
() => track("array_1"),
|
|
164
|
+
() => track("array_2")
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
// =========================
|
|
168
|
+
// LOOP
|
|
169
|
+
// =========================
|
|
170
|
+
|
|
171
|
+
for (let i = 0; i < 1; i++) {
|
|
172
|
+
track("loop_event");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// =========================
|
|
176
|
+
// TRY / CATCH
|
|
177
|
+
// =========================
|
|
178
|
+
|
|
179
|
+
try {
|
|
180
|
+
track("try_event");
|
|
181
|
+
} catch {
|
|
182
|
+
track("catch_event");
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// =========================
|
|
186
|
+
// RETURN
|
|
187
|
+
// =========================
|
|
188
|
+
|
|
189
|
+
function returnTest() {
|
|
190
|
+
return track("return_event");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// =========================
|
|
194
|
+
// PARAM DEFAULT
|
|
195
|
+
// =========================
|
|
196
|
+
|
|
197
|
+
function withDefault(e = "default_event") {
|
|
198
|
+
track(e);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// =========================
|
|
202
|
+
// INLINE OBJECT
|
|
203
|
+
// =========================
|
|
204
|
+
|
|
205
|
+
track({
|
|
206
|
+
name: "object_payload_event"
|
|
207
|
+
} as any);
|
|
208
|
+
|
|
209
|
+
// =========================
|
|
210
|
+
// OPTIONAL CHAINING
|
|
211
|
+
// =========================
|
|
212
|
+
|
|
213
|
+
analytics?.track?.("optional_chain_event");
|
|
214
|
+
|
|
215
|
+
// =========================
|
|
216
|
+
// EDGE CASES
|
|
217
|
+
// =========================
|
|
218
|
+
|
|
219
|
+
// not first argument (should be ignored usually)
|
|
220
|
+
// @ts-ignore
|
|
221
|
+
track("real_event", "extra");
|
|
222
|
+
|
|
223
|
+
// no args
|
|
224
|
+
// @ts-ignore
|
|
225
|
+
track();
|
|
226
|
+
|
|
227
|
+
// dynamic identifier (should be dynamic)
|
|
228
|
+
const dynamicEvent = Math.random() > 0.5 ? "a" : "b";
|
|
229
|
+
track(dynamicEvent);
|
|
230
|
+
|
|
231
|
+
// =========================
|
|
232
|
+
// END
|
|
233
|
+
// =========================
|
package/tests/run.ts
CHANGED
|
@@ -18,7 +18,7 @@ const fixtures = [
|
|
|
18
18
|
"wrappers/function"
|
|
19
19
|
];
|
|
20
20
|
|
|
21
|
-
function runCLI(args: string[], cwd: string) {
|
|
21
|
+
function runCLI(args: string[], cwd: string): string {
|
|
22
22
|
const result = spawnSync(
|
|
23
23
|
process.execPath,
|
|
24
24
|
[CLI, ...args],
|
|
@@ -35,23 +35,12 @@ function runCLI(args: string[], cwd: string) {
|
|
|
35
35
|
function ensureTestConfig(dir: string) {
|
|
36
36
|
const configPath = path.join(dir, "eventra.json");
|
|
37
37
|
|
|
38
|
-
if (fs.existsSync(configPath)) return;
|
|
39
|
-
|
|
40
38
|
const config = {
|
|
41
39
|
apiKey: "",
|
|
42
40
|
events: [],
|
|
43
|
-
wrappers: [
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
prop: "event"
|
|
47
|
-
}
|
|
48
|
-
],
|
|
49
|
-
functionWrappers: [
|
|
50
|
-
{
|
|
51
|
-
name: "trackFeature",
|
|
52
|
-
path: "0"
|
|
53
|
-
}
|
|
54
|
-
],
|
|
41
|
+
wrappers: [],
|
|
42
|
+
functionWrappers: [],
|
|
43
|
+
aliases: {},
|
|
55
44
|
sync: {
|
|
56
45
|
include: [
|
|
57
46
|
"**/*.{ts,tsx,js,jsx,vue,svelte,astro}"
|
|
@@ -90,8 +79,6 @@ function runFixture(name: string) {
|
|
|
90
79
|
|
|
91
80
|
ensureTestConfig(dir);
|
|
92
81
|
|
|
93
|
-
runCLI(["init"], dir);
|
|
94
|
-
|
|
95
82
|
const output = runCLI(["sync"], dir);
|
|
96
83
|
|
|
97
84
|
const match =
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.detectAliases = detectAliases;
|
|
4
|
-
const ts_morph_1 = require("ts-morph");
|
|
5
|
-
function detectAliases(source) {
|
|
6
|
-
const aliases = {};
|
|
7
|
-
const vars = source.getDescendantsOfKind(ts_morph_1.SyntaxKind.VariableDeclaration);
|
|
8
|
-
for (const v of vars) {
|
|
9
|
-
const name = v.getName();
|
|
10
|
-
const init = v.getInitializer();
|
|
11
|
-
if (!init)
|
|
12
|
-
continue;
|
|
13
|
-
// const A = "event"
|
|
14
|
-
if (ts_morph_1.Node.isStringLiteral(init)) {
|
|
15
|
-
aliases[name] = init.getLiteralText();
|
|
16
|
-
continue;
|
|
17
|
-
}
|
|
18
|
-
// const A = `event`
|
|
19
|
-
if (init.getKind() === ts_morph_1.SyntaxKind.NoSubstitutionTemplateLiteral) {
|
|
20
|
-
aliases[name] = init.getText().replace(/`/g, "");
|
|
21
|
-
continue;
|
|
22
|
-
}
|
|
23
|
-
// const EVENTS = { CLICK: "click" }
|
|
24
|
-
if (ts_morph_1.Node.isObjectLiteralExpression(init)) {
|
|
25
|
-
for (const p of init.getProperties()) {
|
|
26
|
-
if (!ts_morph_1.Node.isPropertyAssignment(p))
|
|
27
|
-
continue;
|
|
28
|
-
const key = p.getName();
|
|
29
|
-
const val = p.getInitializer();
|
|
30
|
-
if (!val)
|
|
31
|
-
continue;
|
|
32
|
-
if (ts_morph_1.Node.isStringLiteral(val)) {
|
|
33
|
-
aliases[`${name}.${key}`] = val.getLiteralText();
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return aliases;
|
|
39
|
-
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.detectWrappers = detectWrappers;
|
|
4
|
-
const ts_morph_1 = require("ts-morph");
|
|
5
|
-
function detectWrappers(source) {
|
|
6
|
-
return {
|
|
7
|
-
functions: detectFunctionWrappers(source),
|
|
8
|
-
components: detectComponentWrappers(source)
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
// FUNCTIONS
|
|
12
|
-
function detectFunctionWrappers(source) {
|
|
13
|
-
const result = new Map();
|
|
14
|
-
const functions = [
|
|
15
|
-
...source.getDescendantsOfKind(ts_morph_1.SyntaxKind.FunctionDeclaration),
|
|
16
|
-
...source.getDescendantsOfKind(ts_morph_1.SyntaxKind.ArrowFunction),
|
|
17
|
-
...source.getDescendantsOfKind(ts_morph_1.SyntaxKind.FunctionExpression)
|
|
18
|
-
];
|
|
19
|
-
for (const fn of functions) {
|
|
20
|
-
const body = fn.getBody();
|
|
21
|
-
if (!body)
|
|
22
|
-
continue;
|
|
23
|
-
const calls = body.getDescendantsOfKind(ts_morph_1.SyntaxKind.CallExpression);
|
|
24
|
-
for (const call of calls) {
|
|
25
|
-
if (!isTrackCall(call))
|
|
26
|
-
continue;
|
|
27
|
-
const name = getFunctionName(fn);
|
|
28
|
-
if (!name)
|
|
29
|
-
continue;
|
|
30
|
-
const arg = call.getArguments()[0];
|
|
31
|
-
let eventField;
|
|
32
|
-
if (arg && ts_morph_1.Node.isObjectLiteralExpression(arg)) {
|
|
33
|
-
const prop = arg.getProperties()[0];
|
|
34
|
-
if (prop && ts_morph_1.Node.isPropertyAssignment(prop)) {
|
|
35
|
-
eventField = prop.getName();
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
result.set(name, { name, event: eventField });
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return [...result.values()];
|
|
42
|
-
}
|
|
43
|
-
function isTrackCall(call) {
|
|
44
|
-
const expr = call.getExpression();
|
|
45
|
-
if (ts_morph_1.Node.isIdentifier(expr)) {
|
|
46
|
-
return expr.getText() === "track";
|
|
47
|
-
}
|
|
48
|
-
if (ts_morph_1.Node.isPropertyAccessExpression(expr)) {
|
|
49
|
-
return expr.getName() === "track";
|
|
50
|
-
}
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
function getFunctionName(fn) {
|
|
54
|
-
if (ts_morph_1.Node.isFunctionDeclaration(fn)) {
|
|
55
|
-
return fn.getName() ?? null;
|
|
56
|
-
}
|
|
57
|
-
const varDecl = fn.getFirstAncestorByKind(ts_morph_1.SyntaxKind.VariableDeclaration);
|
|
58
|
-
return varDecl?.getName() ?? null;
|
|
59
|
-
}
|
|
60
|
-
// COMPONENTS
|
|
61
|
-
function detectComponentWrappers(source) {
|
|
62
|
-
const result = new Map();
|
|
63
|
-
const elements = [
|
|
64
|
-
...source.getDescendantsOfKind(ts_morph_1.SyntaxKind.JsxOpeningElement),
|
|
65
|
-
...source.getDescendantsOfKind(ts_morph_1.SyntaxKind.JsxSelfClosingElement)
|
|
66
|
-
];
|
|
67
|
-
for (const el of elements) {
|
|
68
|
-
const name = el.getTagNameNode().getText();
|
|
69
|
-
for (const attr of el.getAttributes()) {
|
|
70
|
-
const a = attr.asKind(ts_morph_1.SyntaxKind.JsxAttribute);
|
|
71
|
-
if (!a)
|
|
72
|
-
continue;
|
|
73
|
-
const prop = a.getNameNode().getText();
|
|
74
|
-
const val = a.getInitializer();
|
|
75
|
-
if (!val)
|
|
76
|
-
continue;
|
|
77
|
-
if (ts_morph_1.Node.isStringLiteral(val) ||
|
|
78
|
-
ts_morph_1.Node.isJsxExpression(val)) {
|
|
79
|
-
result.set(name, { name, prop });
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return [...result.values()];
|
|
84
|
-
}
|