@eventra_dev/eventra-cli 0.0.19 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/check.js +17 -117
- package/dist/commands/sync.js +20 -115
- package/dist/commands/watch.js +107 -69
- package/dist/engine/callResolver.js +31 -0
- package/dist/engine/engine.js +33 -0
- package/dist/engine/extract.js +53 -0
- package/dist/engine/flow.js +38 -0
- package/dist/engine/graph.js +22 -0
- package/dist/engine/project.js +74 -0
- package/dist/engine/resolver.js +38 -0
- package/dist/engine/scanner.js +78 -0
- package/dist/engine/symbol.js +31 -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 +37 -0
- package/src/engine/engine.ts +39 -0
- package/src/engine/extract.ts +74 -0
- package/src/engine/flow.ts +54 -0
- package/src/engine/graph.ts +23 -0
- package/src/engine/project.ts +75 -0
- package/src/engine/resolver.ts +53 -0
- package/src/engine/scanner.ts +90 -0
- package/src/engine/symbol.ts +42 -0
- package/src/types.ts +3 -9
- 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
|
@@ -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
|
-
}
|
package/dist/utils/extract.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.extractExpression = extractExpression;
|
|
4
|
-
const ts_morph_1 = require("ts-morph");
|
|
5
|
-
function extractExpression(expr, aliases) {
|
|
6
|
-
// "event"
|
|
7
|
-
if (ts_morph_1.Node.isStringLiteral(expr)) {
|
|
8
|
-
return {
|
|
9
|
-
values: [expr.getLiteralText()],
|
|
10
|
-
dynamic: false
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
// `event`
|
|
14
|
-
if (expr.getKind() === ts_morph_1.SyntaxKind.NoSubstitutionTemplateLiteral) {
|
|
15
|
-
return {
|
|
16
|
-
values: [expr.getText().replace(/`/g, "")],
|
|
17
|
-
dynamic: false
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
// IDENTIFIER
|
|
21
|
-
if (ts_morph_1.Node.isIdentifier(expr)) {
|
|
22
|
-
const name = expr.getText();
|
|
23
|
-
if (name in aliases) {
|
|
24
|
-
return {
|
|
25
|
-
values: [aliases[name]],
|
|
26
|
-
dynamic: false
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
return {
|
|
30
|
-
values: [name],
|
|
31
|
-
dynamic: true
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
// PROPERTY ACCESS
|
|
35
|
-
if (ts_morph_1.Node.isPropertyAccessExpression(expr)) {
|
|
36
|
-
const name = expr.getText();
|
|
37
|
-
if (name in aliases) {
|
|
38
|
-
return {
|
|
39
|
-
values: [aliases[name]],
|
|
40
|
-
dynamic: false
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
return {
|
|
44
|
-
values: [name],
|
|
45
|
-
dynamic: true
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
// template `${}`
|
|
49
|
-
if (ts_morph_1.Node.isTemplateExpression(expr)) {
|
|
50
|
-
return {
|
|
51
|
-
values: [expr.getText()],
|
|
52
|
-
dynamic: true
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.scanComponentWrappers = scanComponentWrappers;
|
|
4
|
-
const ts_morph_1 = require("ts-morph");
|
|
5
|
-
const extract_1 = require("../extract");
|
|
6
|
-
function scanComponentWrappers(source, wrappers, aliases) {
|
|
7
|
-
const events = new Map();
|
|
8
|
-
const elements = [
|
|
9
|
-
...source.getDescendantsOfKind(ts_morph_1.SyntaxKind.JsxOpeningElement),
|
|
10
|
-
...source.getDescendantsOfKind(ts_morph_1.SyntaxKind.JsxSelfClosingElement)
|
|
11
|
-
];
|
|
12
|
-
for (const el of elements) {
|
|
13
|
-
const name = el
|
|
14
|
-
.getTagNameNode()
|
|
15
|
-
.getText()
|
|
16
|
-
.toLowerCase();
|
|
17
|
-
for (const wrapper of wrappers) {
|
|
18
|
-
if (name !== wrapper.name.toLowerCase())
|
|
19
|
-
continue;
|
|
20
|
-
for (const attr of el.getAttributes()) {
|
|
21
|
-
if (ts_morph_1.Node.isJsxSpreadAttribute(attr))
|
|
22
|
-
continue;
|
|
23
|
-
const attrNode = attr.asKind(ts_morph_1.SyntaxKind.JsxAttribute);
|
|
24
|
-
if (!attrNode)
|
|
25
|
-
continue;
|
|
26
|
-
const key = attrNode
|
|
27
|
-
.getNameNode()
|
|
28
|
-
.getText()
|
|
29
|
-
.toLowerCase();
|
|
30
|
-
if (key !== wrapper.prop.toLowerCase())
|
|
31
|
-
continue;
|
|
32
|
-
const init = attrNode.getInitializer();
|
|
33
|
-
// <Button event />
|
|
34
|
-
if (!init) {
|
|
35
|
-
const value = key;
|
|
36
|
-
const k = `${value}:true`;
|
|
37
|
-
events.set(k, {
|
|
38
|
-
value,
|
|
39
|
-
dynamic: true
|
|
40
|
-
});
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
// <Button event="click" />
|
|
44
|
-
if (ts_morph_1.Node.isStringLiteral(init)) {
|
|
45
|
-
const value = init.getLiteralText();
|
|
46
|
-
const k = `${value}:false`;
|
|
47
|
-
events.set(k, {
|
|
48
|
-
value,
|
|
49
|
-
dynamic: false
|
|
50
|
-
});
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
// <Button event={...} />
|
|
54
|
-
if (ts_morph_1.Node.isJsxExpression(init)) {
|
|
55
|
-
const expr = init.getExpression();
|
|
56
|
-
if (!expr)
|
|
57
|
-
continue;
|
|
58
|
-
const result = (0, extract_1.extractExpression)(expr, aliases);
|
|
59
|
-
if (!result)
|
|
60
|
-
continue;
|
|
61
|
-
for (const value of result.values) {
|
|
62
|
-
const k = `${value}:${result.dynamic}`;
|
|
63
|
-
events.set(k, {
|
|
64
|
-
value,
|
|
65
|
-
dynamic: result.dynamic
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return [...events.values()];
|
|
73
|
-
}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.scanFunctionWrappers = scanFunctionWrappers;
|
|
4
|
-
const ts_morph_1 = require("ts-morph");
|
|
5
|
-
const extract_1 = require("../extract");
|
|
6
|
-
function scanFunctionWrappers(source, wrappers, aliases) {
|
|
7
|
-
const events = new Map();
|
|
8
|
-
const calls = source.getDescendantsOfKind(ts_morph_1.SyntaxKind.CallExpression);
|
|
9
|
-
for (const call of calls) {
|
|
10
|
-
const name = getFunctionName(call);
|
|
11
|
-
if (!name)
|
|
12
|
-
continue;
|
|
13
|
-
for (const wrapper of wrappers) {
|
|
14
|
-
if (wrapper.name !== name)
|
|
15
|
-
continue;
|
|
16
|
-
const results = extractEventFromArgs(call, wrapper.event, aliases);
|
|
17
|
-
if (!results)
|
|
18
|
-
continue;
|
|
19
|
-
for (const r of results) {
|
|
20
|
-
const key = `${r.value}:${r.dynamic}`;
|
|
21
|
-
events.set(key, r);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return [...events.values()];
|
|
26
|
-
}
|
|
27
|
-
function getFunctionName(call) {
|
|
28
|
-
const expression = call.getExpression();
|
|
29
|
-
if (ts_morph_1.Node.isIdentifier(expression)) {
|
|
30
|
-
return expression.getText();
|
|
31
|
-
}
|
|
32
|
-
if (ts_morph_1.Node.isPropertyAccessExpression(expression)) {
|
|
33
|
-
return getDeepName(expression);
|
|
34
|
-
}
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
function getDeepName(node) {
|
|
38
|
-
let current = node;
|
|
39
|
-
let name = "";
|
|
40
|
-
while (ts_morph_1.Node.isPropertyAccessExpression(current)) {
|
|
41
|
-
name = current.getName();
|
|
42
|
-
current = current.getExpression();
|
|
43
|
-
}
|
|
44
|
-
return name;
|
|
45
|
-
}
|
|
46
|
-
function extractEventFromArgs(call, event, aliases) {
|
|
47
|
-
const args = call.getArguments();
|
|
48
|
-
const events = [];
|
|
49
|
-
for (const arg of args) {
|
|
50
|
-
// track("event")
|
|
51
|
-
if (!event) {
|
|
52
|
-
const result = (0, extract_1.extractExpression)(arg, aliases);
|
|
53
|
-
if (!result)
|
|
54
|
-
continue;
|
|
55
|
-
result.values.forEach((value) => events.push({
|
|
56
|
-
value,
|
|
57
|
-
dynamic: result.dynamic
|
|
58
|
-
}));
|
|
59
|
-
}
|
|
60
|
-
// track({ event })
|
|
61
|
-
if (event) {
|
|
62
|
-
const obj = arg.asKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
|
|
63
|
-
if (!obj)
|
|
64
|
-
continue;
|
|
65
|
-
const prop = obj.getProperty(event);
|
|
66
|
-
if (!prop)
|
|
67
|
-
continue;
|
|
68
|
-
if (ts_morph_1.Node.isPropertyAssignment(prop)) {
|
|
69
|
-
const init = prop.getInitializer();
|
|
70
|
-
if (!init)
|
|
71
|
-
continue;
|
|
72
|
-
const result = (0, extract_1.extractExpression)(init, aliases);
|
|
73
|
-
if (!result)
|
|
74
|
-
continue;
|
|
75
|
-
result.values.forEach((value) => events.push({
|
|
76
|
-
value,
|
|
77
|
-
dynamic: result.dynamic
|
|
78
|
-
}));
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return events.length ? events : null;
|
|
83
|
-
}
|
|
@@ -1,64 +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.scanTrack = scanTrack;
|
|
7
|
-
const ts_morph_1 = require("ts-morph");
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const extract_1 = require("../extract");
|
|
10
|
-
function scanTrack(source, config, aliases) {
|
|
11
|
-
const events = new Map();
|
|
12
|
-
const calls = source.getDescendantsOfKind(ts_morph_1.SyntaxKind.CallExpression);
|
|
13
|
-
for (const call of calls) {
|
|
14
|
-
const expr = call.getExpression();
|
|
15
|
-
let isTrack = false;
|
|
16
|
-
// track()
|
|
17
|
-
if (ts_morph_1.Node.isIdentifier(expr)) {
|
|
18
|
-
isTrack = expr.getText() === "track";
|
|
19
|
-
}
|
|
20
|
-
// analytics.track()
|
|
21
|
-
if (ts_morph_1.Node.isPropertyAccessExpression(expr)) {
|
|
22
|
-
isTrack = expr.getName() === "track";
|
|
23
|
-
}
|
|
24
|
-
if (!isTrack)
|
|
25
|
-
continue;
|
|
26
|
-
// ❗ skip wrapper functions
|
|
27
|
-
const func = call.getFirstAncestorByKind(ts_morph_1.SyntaxKind.FunctionDeclaration) ||
|
|
28
|
-
call.getFirstAncestorByKind(ts_morph_1.SyntaxKind.ArrowFunction) ||
|
|
29
|
-
call.getFirstAncestorByKind(ts_morph_1.SyntaxKind.FunctionExpression);
|
|
30
|
-
let fnName;
|
|
31
|
-
if (func) {
|
|
32
|
-
if (ts_morph_1.Node.isFunctionDeclaration(func)) {
|
|
33
|
-
fnName = func.getName();
|
|
34
|
-
}
|
|
35
|
-
if (ts_morph_1.Node.isArrowFunction(func) ||
|
|
36
|
-
ts_morph_1.Node.isFunctionExpression(func)) {
|
|
37
|
-
const varDecl = func.getFirstAncestorByKind(ts_morph_1.SyntaxKind.VariableDeclaration);
|
|
38
|
-
fnName = varDecl?.getName();
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
if (fnName &&
|
|
42
|
-
config.functionWrappers?.some((w) => w.name === fnName)) {
|
|
43
|
-
continue;
|
|
44
|
-
}
|
|
45
|
-
const arg = call.getArguments()[0];
|
|
46
|
-
if (!arg)
|
|
47
|
-
continue;
|
|
48
|
-
const result = (0, extract_1.extractExpression)(arg, aliases);
|
|
49
|
-
if (!result)
|
|
50
|
-
continue;
|
|
51
|
-
const line = call.getStartLineNumber();
|
|
52
|
-
const file = path_1.default.relative(process.cwd(), source.getFilePath());
|
|
53
|
-
for (const value of result.values) {
|
|
54
|
-
const key = `${value}:${file}:${line}`;
|
|
55
|
-
events.set(key, {
|
|
56
|
-
value,
|
|
57
|
-
dynamic: result.dynamic,
|
|
58
|
-
file,
|
|
59
|
-
line
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
return [...events.values()];
|
|
64
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
SourceFile,
|
|
3
|
-
SyntaxKind,
|
|
4
|
-
Node
|
|
5
|
-
} from "ts-morph";
|
|
6
|
-
|
|
7
|
-
export function detectAliases(source: SourceFile) {
|
|
8
|
-
const aliases: Record<string, string> = {};
|
|
9
|
-
|
|
10
|
-
const vars = source.getDescendantsOfKind(SyntaxKind.VariableDeclaration);
|
|
11
|
-
|
|
12
|
-
for (const v of vars) {
|
|
13
|
-
const name = v.getName();
|
|
14
|
-
const init = v.getInitializer();
|
|
15
|
-
if (!init) continue;
|
|
16
|
-
|
|
17
|
-
// const A = "event"
|
|
18
|
-
if (Node.isStringLiteral(init)) {
|
|
19
|
-
aliases[name] = init.getLiteralText();
|
|
20
|
-
continue;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// const A = `event`
|
|
24
|
-
if (init.getKind() === SyntaxKind.NoSubstitutionTemplateLiteral) {
|
|
25
|
-
aliases[name] = init.getText().replace(/`/g, "");
|
|
26
|
-
continue;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// const EVENTS = { CLICK: "click" }
|
|
30
|
-
if (Node.isObjectLiteralExpression(init)) {
|
|
31
|
-
for (const p of init.getProperties()) {
|
|
32
|
-
if (!Node.isPropertyAssignment(p)) continue;
|
|
33
|
-
|
|
34
|
-
const key = p.getName();
|
|
35
|
-
const val = p.getInitializer();
|
|
36
|
-
if (!val) continue;
|
|
37
|
-
|
|
38
|
-
if (Node.isStringLiteral(val)) {
|
|
39
|
-
aliases[`${name}.${key}`] = val.getLiteralText();
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return aliases;
|
|
46
|
-
}
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
SourceFile,
|
|
3
|
-
SyntaxKind,
|
|
4
|
-
Node,
|
|
5
|
-
CallExpression
|
|
6
|
-
} from "ts-morph";
|
|
7
|
-
|
|
8
|
-
export type FunctionWrapper = {
|
|
9
|
-
name: string;
|
|
10
|
-
event?: string;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export type ComponentWrapper = {
|
|
14
|
-
name: string;
|
|
15
|
-
prop: string;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export function detectWrappers(source: SourceFile) {
|
|
19
|
-
return {
|
|
20
|
-
functions: detectFunctionWrappers(source),
|
|
21
|
-
components: detectComponentWrappers(source)
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// FUNCTIONS
|
|
26
|
-
function detectFunctionWrappers(source: SourceFile): FunctionWrapper[] {
|
|
27
|
-
const result = new Map<string, FunctionWrapper>();
|
|
28
|
-
|
|
29
|
-
const functions = [
|
|
30
|
-
...source.getDescendantsOfKind(SyntaxKind.FunctionDeclaration),
|
|
31
|
-
...source.getDescendantsOfKind(SyntaxKind.ArrowFunction),
|
|
32
|
-
...source.getDescendantsOfKind(SyntaxKind.FunctionExpression)
|
|
33
|
-
];
|
|
34
|
-
|
|
35
|
-
for (const fn of functions) {
|
|
36
|
-
const body = fn.getBody();
|
|
37
|
-
if (!body) continue;
|
|
38
|
-
|
|
39
|
-
const calls = body.getDescendantsOfKind(SyntaxKind.CallExpression);
|
|
40
|
-
|
|
41
|
-
for (const call of calls) {
|
|
42
|
-
if (!isTrackCall(call)) continue;
|
|
43
|
-
|
|
44
|
-
const name = getFunctionName(fn);
|
|
45
|
-
if (!name) continue;
|
|
46
|
-
|
|
47
|
-
const arg = call.getArguments()[0];
|
|
48
|
-
|
|
49
|
-
let eventField: string | undefined;
|
|
50
|
-
|
|
51
|
-
if (arg && Node.isObjectLiteralExpression(arg)) {
|
|
52
|
-
const prop = arg.getProperties()[0];
|
|
53
|
-
if (prop && Node.isPropertyAssignment(prop)) {
|
|
54
|
-
eventField = prop.getName();
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
result.set(name, { name, event: eventField });
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return [...result.values()];
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function isTrackCall(call: CallExpression) {
|
|
66
|
-
const expr = call.getExpression();
|
|
67
|
-
|
|
68
|
-
if (Node.isIdentifier(expr)) {
|
|
69
|
-
return expr.getText() === "track";
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (Node.isPropertyAccessExpression(expr)) {
|
|
73
|
-
return expr.getName() === "track";
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function getFunctionName(fn: Node): string | null {
|
|
80
|
-
if (Node.isFunctionDeclaration(fn)) {
|
|
81
|
-
return fn.getName() ?? null;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const varDecl = fn.getFirstAncestorByKind(SyntaxKind.VariableDeclaration);
|
|
85
|
-
return varDecl?.getName() ?? null;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// COMPONENTS
|
|
89
|
-
function detectComponentWrappers(source: SourceFile): ComponentWrapper[] {
|
|
90
|
-
const result = new Map<string, ComponentWrapper>();
|
|
91
|
-
|
|
92
|
-
const elements = [
|
|
93
|
-
...source.getDescendantsOfKind(SyntaxKind.JsxOpeningElement),
|
|
94
|
-
...source.getDescendantsOfKind(SyntaxKind.JsxSelfClosingElement)
|
|
95
|
-
];
|
|
96
|
-
|
|
97
|
-
for (const el of elements) {
|
|
98
|
-
const name = el.getTagNameNode().getText();
|
|
99
|
-
|
|
100
|
-
for (const attr of el.getAttributes()) {
|
|
101
|
-
const a = attr.asKind(SyntaxKind.JsxAttribute);
|
|
102
|
-
if (!a) continue;
|
|
103
|
-
|
|
104
|
-
const prop = a.getNameNode().getText();
|
|
105
|
-
const val = a.getInitializer();
|
|
106
|
-
|
|
107
|
-
if (!val) continue;
|
|
108
|
-
|
|
109
|
-
if (
|
|
110
|
-
Node.isStringLiteral(val) ||
|
|
111
|
-
Node.isJsxExpression(val)
|
|
112
|
-
) {
|
|
113
|
-
result.set(name, { name, prop });
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return [...result.values()];
|
|
119
|
-
}
|
package/src/utils/extract.ts
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { Node, SyntaxKind } from "ts-morph";
|
|
2
|
-
|
|
3
|
-
export type ExtractResult = {
|
|
4
|
-
values: string[];
|
|
5
|
-
dynamic: boolean;
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
export function extractExpression(
|
|
9
|
-
expr: Node,
|
|
10
|
-
aliases: Record<string, string>
|
|
11
|
-
): ExtractResult | null {
|
|
12
|
-
|
|
13
|
-
// "event"
|
|
14
|
-
if (Node.isStringLiteral(expr)) {
|
|
15
|
-
return {
|
|
16
|
-
values: [expr.getLiteralText()],
|
|
17
|
-
dynamic: false
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// `event`
|
|
22
|
-
if (expr.getKind() === SyntaxKind.NoSubstitutionTemplateLiteral) {
|
|
23
|
-
return {
|
|
24
|
-
values: [expr.getText().replace(/`/g, "")],
|
|
25
|
-
dynamic: false
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// IDENTIFIER
|
|
30
|
-
if (Node.isIdentifier(expr)) {
|
|
31
|
-
const name = expr.getText();
|
|
32
|
-
|
|
33
|
-
if (name in aliases) {
|
|
34
|
-
return {
|
|
35
|
-
values: [aliases[name]],
|
|
36
|
-
dynamic: false
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
values: [name],
|
|
42
|
-
dynamic: true
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// PROPERTY ACCESS
|
|
47
|
-
if (Node.isPropertyAccessExpression(expr)) {
|
|
48
|
-
const name = expr.getText();
|
|
49
|
-
|
|
50
|
-
if (name in aliases) {
|
|
51
|
-
return {
|
|
52
|
-
values: [aliases[name]],
|
|
53
|
-
dynamic: false
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return {
|
|
58
|
-
values: [name],
|
|
59
|
-
dynamic: true
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// template `${}`
|
|
64
|
-
if (Node.isTemplateExpression(expr)) {
|
|
65
|
-
return {
|
|
66
|
-
values: [expr.getText()],
|
|
67
|
-
dynamic: true
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return null;
|
|
72
|
-
}
|