@eventra_dev/eventra-cli 0.0.18 → 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/README.md +74 -166
- package/dist/commands/check.js +25 -88
- package/dist/commands/sync.js +22 -77
- package/dist/commands/watch.js +135 -0
- 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/index.js +10 -6
- package/dist/utils/parsers/vue.js +16 -12
- package/dist/utils/processFile.js +20 -0
- package/package.json +2 -1
- package/src/commands/check.ts +29 -136
- package/src/commands/sync.ts +24 -135
- package/src/commands/watch.ts +166 -0
- 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/index.ts +11 -6
- package/src/types.ts +3 -5
- 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/extract.js +0 -136
- package/dist/utils/scanners/component-wrappers.js +0 -70
- package/dist/utils/scanners/function-wrappers.js +0 -85
- package/dist/utils/scanners/track.js +0 -52
- package/src/utils/extract.ts +0 -185
- package/src/utils/scanners/component-wrappers.ts +0 -107
- package/src/utils/scanners/function-wrappers.ts +0 -180
- package/src/utils/scanners/track.ts +0 -84
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 =
|
package/dist/utils/extract.js
DELETED
|
@@ -1,136 +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) {
|
|
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() ===
|
|
15
|
-
ts_morph_1.SyntaxKind.NoSubstitutionTemplateLiteral) {
|
|
16
|
-
return {
|
|
17
|
-
values: [
|
|
18
|
-
expr.getText().replace(/`/g, "")
|
|
19
|
-
],
|
|
20
|
-
dynamic: false
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
// identifier (TEST)
|
|
24
|
-
if (ts_morph_1.Node.isIdentifier(expr)) {
|
|
25
|
-
const name = expr.getText();
|
|
26
|
-
const defs = "getDefinitions" in expr
|
|
27
|
-
? expr.getDefinitions()
|
|
28
|
-
: [];
|
|
29
|
-
if (defs && defs.length > 0) {
|
|
30
|
-
const decl = defs[0]?.getDeclarationNode();
|
|
31
|
-
if (decl && ts_morph_1.Node.isVariableDeclaration(decl)) {
|
|
32
|
-
const initializer = decl.getInitializer();
|
|
33
|
-
// const TEST = "event"
|
|
34
|
-
if (initializer &&
|
|
35
|
-
ts_morph_1.Node.isStringLiteral(initializer)) {
|
|
36
|
-
return {
|
|
37
|
-
values: [initializer.getLiteralText()],
|
|
38
|
-
dynamic: false
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
// const TEST = `event`
|
|
42
|
-
if (initializer &&
|
|
43
|
-
initializer.getKind() ===
|
|
44
|
-
ts_morph_1.SyntaxKind.NoSubstitutionTemplateLiteral) {
|
|
45
|
-
return {
|
|
46
|
-
values: [
|
|
47
|
-
initializer.getText().replace(/`/g, "")
|
|
48
|
-
],
|
|
49
|
-
dynamic: false
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return {
|
|
55
|
-
values: [name],
|
|
56
|
-
dynamic: true
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
// property access (EVENTS.CLICK)
|
|
60
|
-
if (ts_morph_1.Node.isPropertyAccessExpression(expr)) {
|
|
61
|
-
const fullName = expr.getText(); // EVENTS.CLICK
|
|
62
|
-
const propName = expr.getName(); // CLICK
|
|
63
|
-
const defs = "getDefinitions" in expr
|
|
64
|
-
? expr.getDefinitions()
|
|
65
|
-
: [];
|
|
66
|
-
if (defs && defs.length > 0) {
|
|
67
|
-
const decl = defs[0]?.getDeclarationNode();
|
|
68
|
-
// const EVENTS = { CLICK: "event" }
|
|
69
|
-
if (decl && ts_morph_1.Node.isVariableDeclaration(decl)) {
|
|
70
|
-
const init = decl.getInitializer();
|
|
71
|
-
if (init && ts_morph_1.Node.isObjectLiteralExpression(init)) {
|
|
72
|
-
const prop = init.getProperty(propName);
|
|
73
|
-
if (prop &&
|
|
74
|
-
ts_morph_1.Node.isPropertyAssignment(prop)) {
|
|
75
|
-
const value = prop.getInitializer();
|
|
76
|
-
if (value &&
|
|
77
|
-
ts_morph_1.Node.isStringLiteral(value)) {
|
|
78
|
-
return {
|
|
79
|
-
values: [value.getLiteralText()],
|
|
80
|
-
dynamic: false
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
// fallback
|
|
87
|
-
if (decl && ts_morph_1.Node.isPropertyAssignment(decl)) {
|
|
88
|
-
const initializer = decl.getInitializer();
|
|
89
|
-
if (initializer &&
|
|
90
|
-
ts_morph_1.Node.isStringLiteral(initializer)) {
|
|
91
|
-
return {
|
|
92
|
-
values: [initializer.getLiteralText()],
|
|
93
|
-
dynamic: false
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
return {
|
|
99
|
-
values: [fullName],
|
|
100
|
-
dynamic: true
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
// ternary (a ? b : c)
|
|
104
|
-
if (ts_morph_1.Node.isConditionalExpression(expr)) {
|
|
105
|
-
const values = [];
|
|
106
|
-
const whenTrue = extractExpression(expr.getWhenTrue());
|
|
107
|
-
const whenFalse = extractExpression(expr.getWhenFalse());
|
|
108
|
-
if (whenTrue)
|
|
109
|
-
values.push(...whenTrue.values);
|
|
110
|
-
if (whenFalse)
|
|
111
|
-
values.push(...whenFalse.values);
|
|
112
|
-
return {
|
|
113
|
-
values,
|
|
114
|
-
dynamic: true
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
// template `${}`
|
|
118
|
-
if (ts_morph_1.Node.isTemplateExpression(expr)) {
|
|
119
|
-
return {
|
|
120
|
-
values: [
|
|
121
|
-
expr.getText().replace(/`/g, "")
|
|
122
|
-
],
|
|
123
|
-
dynamic: true
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
// call (fn())
|
|
127
|
-
if (ts_morph_1.Node.isCallExpression(expr)) {
|
|
128
|
-
return {
|
|
129
|
-
values: [
|
|
130
|
-
expr.getExpression().getText()
|
|
131
|
-
],
|
|
132
|
-
dynamic: true
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
return null;
|
|
136
|
-
}
|
|
@@ -1,70 +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) {
|
|
7
|
-
const events = new Set();
|
|
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
|
-
const attrs = el.getAttributes();
|
|
21
|
-
for (const attr of attrs) {
|
|
22
|
-
// ❗ NO spread props
|
|
23
|
-
if (ts_morph_1.Node.isJsxSpreadAttribute(attr)) {
|
|
24
|
-
continue;
|
|
25
|
-
}
|
|
26
|
-
const attrNode = attr.asKind(ts_morph_1.SyntaxKind.JsxAttribute);
|
|
27
|
-
if (!attrNode)
|
|
28
|
-
continue;
|
|
29
|
-
const key = attrNode
|
|
30
|
-
.getNameNode()
|
|
31
|
-
.getText()
|
|
32
|
-
.toLowerCase();
|
|
33
|
-
if (key !== wrapper.prop.toLowerCase())
|
|
34
|
-
continue;
|
|
35
|
-
const init = attrNode.getInitializer();
|
|
36
|
-
// <Button event />
|
|
37
|
-
if (!init) {
|
|
38
|
-
events.add({
|
|
39
|
-
value: key,
|
|
40
|
-
dynamic: true
|
|
41
|
-
});
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
// string: <Button event="click" />
|
|
45
|
-
if (ts_morph_1.Node.isStringLiteral(init)) {
|
|
46
|
-
events.add({
|
|
47
|
-
value: init.getLiteralText(),
|
|
48
|
-
dynamic: false
|
|
49
|
-
});
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
// jsx expression: <Button event={"click"} />
|
|
53
|
-
if (ts_morph_1.Node.isJsxExpression(init)) {
|
|
54
|
-
const expr = init.getExpression();
|
|
55
|
-
if (!expr)
|
|
56
|
-
continue;
|
|
57
|
-
const result = (0, extract_1.extractExpression)(expr);
|
|
58
|
-
if (!result)
|
|
59
|
-
continue;
|
|
60
|
-
result.values.forEach((value) => events.add({
|
|
61
|
-
value,
|
|
62
|
-
dynamic: result.dynamic
|
|
63
|
-
}));
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
return events;
|
|
70
|
-
}
|
|
@@ -1,85 +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) {
|
|
7
|
-
const events = new Set();
|
|
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);
|
|
17
|
-
if (!results)
|
|
18
|
-
continue;
|
|
19
|
-
results.forEach((r) => events.add(r));
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
return events;
|
|
23
|
-
}
|
|
24
|
-
function getFunctionName(call) {
|
|
25
|
-
const expression = call.getExpression();
|
|
26
|
-
if (ts_morph_1.Node.isIdentifier(expression)) {
|
|
27
|
-
return expression.getText();
|
|
28
|
-
}
|
|
29
|
-
if (ts_morph_1.Node.isPropertyAccessExpression(expression)) {
|
|
30
|
-
return getDeepName(expression);
|
|
31
|
-
}
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
function getDeepName(node) {
|
|
35
|
-
let current = node;
|
|
36
|
-
let name = "";
|
|
37
|
-
while (ts_morph_1.Node.isPropertyAccessExpression(current)) {
|
|
38
|
-
name =
|
|
39
|
-
current.getName();
|
|
40
|
-
current =
|
|
41
|
-
current.getExpression();
|
|
42
|
-
}
|
|
43
|
-
return name;
|
|
44
|
-
}
|
|
45
|
-
function extractEventFromArgs(call, event) {
|
|
46
|
-
const args = call.getArguments();
|
|
47
|
-
const events = [];
|
|
48
|
-
for (let i = 0; i < args.length; i++) {
|
|
49
|
-
const arg = args[i];
|
|
50
|
-
// track("event")
|
|
51
|
-
if (!event) {
|
|
52
|
-
const result = (0, extract_1.extractExpression)(arg);
|
|
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);
|
|
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
|
|
83
|
-
? events
|
|
84
|
-
: null;
|
|
85
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.scanTrack = scanTrack;
|
|
4
|
-
const ts_morph_1 = require("ts-morph");
|
|
5
|
-
const extract_1 = require("../extract");
|
|
6
|
-
function scanTrack(source, config) {
|
|
7
|
-
const events = new Set();
|
|
8
|
-
const calls = source.getDescendantsOfKind(ts_morph_1.SyntaxKind.CallExpression);
|
|
9
|
-
for (const call of calls) {
|
|
10
|
-
const expr = call.getExpression();
|
|
11
|
-
let isTrack = false;
|
|
12
|
-
// track()
|
|
13
|
-
if (ts_morph_1.Node.isIdentifier(expr)) {
|
|
14
|
-
isTrack = expr.getText() === "track";
|
|
15
|
-
}
|
|
16
|
-
// analytics.track()
|
|
17
|
-
if (ts_morph_1.Node.isPropertyAccessExpression(expr)) {
|
|
18
|
-
isTrack = expr.getName() === "track";
|
|
19
|
-
}
|
|
20
|
-
if (!isTrack)
|
|
21
|
-
continue;
|
|
22
|
-
const func = call.getFirstAncestorByKind(ts_morph_1.SyntaxKind.FunctionDeclaration) ||
|
|
23
|
-
call.getFirstAncestorByKind(ts_morph_1.SyntaxKind.ArrowFunction) ||
|
|
24
|
-
call.getFirstAncestorByKind(ts_morph_1.SyntaxKind.FunctionExpression);
|
|
25
|
-
let fnName;
|
|
26
|
-
if (func) {
|
|
27
|
-
if (ts_morph_1.Node.isFunctionDeclaration(func)) {
|
|
28
|
-
fnName = func.getName();
|
|
29
|
-
}
|
|
30
|
-
if (ts_morph_1.Node.isArrowFunction(func) ||
|
|
31
|
-
ts_morph_1.Node.isFunctionExpression(func)) {
|
|
32
|
-
const varDecl = func.getFirstAncestorByKind(ts_morph_1.SyntaxKind.VariableDeclaration);
|
|
33
|
-
fnName = varDecl?.getName();
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
if (fnName &&
|
|
37
|
-
config.functionWrappers?.some((w) => w.name === fnName)) {
|
|
38
|
-
continue;
|
|
39
|
-
}
|
|
40
|
-
const arg = call.getArguments()[0];
|
|
41
|
-
if (!arg)
|
|
42
|
-
continue;
|
|
43
|
-
const result = (0, extract_1.extractExpression)(arg);
|
|
44
|
-
if (!result)
|
|
45
|
-
continue;
|
|
46
|
-
result.values.forEach((value) => events.add({
|
|
47
|
-
value,
|
|
48
|
-
dynamic: result.dynamic,
|
|
49
|
-
}));
|
|
50
|
-
}
|
|
51
|
-
return events;
|
|
52
|
-
}
|
package/src/utils/extract.ts
DELETED
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Node,
|
|
3
|
-
SyntaxKind
|
|
4
|
-
} from "ts-morph";
|
|
5
|
-
|
|
6
|
-
export type ExtractResult = {
|
|
7
|
-
values: string[];
|
|
8
|
-
dynamic: boolean;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export function extractExpression(
|
|
12
|
-
expr: Node
|
|
13
|
-
): ExtractResult | null {
|
|
14
|
-
|
|
15
|
-
// "event"
|
|
16
|
-
if (Node.isStringLiteral(expr)) {
|
|
17
|
-
return {
|
|
18
|
-
values: [expr.getLiteralText()],
|
|
19
|
-
dynamic: false
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// `event`
|
|
24
|
-
if (
|
|
25
|
-
expr.getKind() ===
|
|
26
|
-
SyntaxKind.NoSubstitutionTemplateLiteral
|
|
27
|
-
) {
|
|
28
|
-
return {
|
|
29
|
-
values: [
|
|
30
|
-
expr.getText().replace(/`/g, "")
|
|
31
|
-
],
|
|
32
|
-
dynamic: false
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// identifier (TEST)
|
|
37
|
-
if (Node.isIdentifier(expr)) {
|
|
38
|
-
const name = expr.getText();
|
|
39
|
-
|
|
40
|
-
const defs =
|
|
41
|
-
"getDefinitions" in expr
|
|
42
|
-
? (expr as any).getDefinitions()
|
|
43
|
-
: [];
|
|
44
|
-
|
|
45
|
-
if (defs && defs.length > 0) {
|
|
46
|
-
const decl = defs[0]?.getDeclarationNode();
|
|
47
|
-
|
|
48
|
-
if (decl && Node.isVariableDeclaration(decl)) {
|
|
49
|
-
const initializer = decl.getInitializer();
|
|
50
|
-
|
|
51
|
-
// const TEST = "event"
|
|
52
|
-
if (
|
|
53
|
-
initializer &&
|
|
54
|
-
Node.isStringLiteral(initializer)
|
|
55
|
-
) {
|
|
56
|
-
return {
|
|
57
|
-
values: [initializer.getLiteralText()],
|
|
58
|
-
dynamic: false
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// const TEST = `event`
|
|
63
|
-
if (
|
|
64
|
-
initializer &&
|
|
65
|
-
initializer.getKind() ===
|
|
66
|
-
SyntaxKind.NoSubstitutionTemplateLiteral
|
|
67
|
-
) {
|
|
68
|
-
return {
|
|
69
|
-
values: [
|
|
70
|
-
initializer.getText().replace(/`/g, "")
|
|
71
|
-
],
|
|
72
|
-
dynamic: false
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
values: [name],
|
|
80
|
-
dynamic: true
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// property access (EVENTS.CLICK)
|
|
85
|
-
if (Node.isPropertyAccessExpression(expr)) {
|
|
86
|
-
const fullName = expr.getText(); // EVENTS.CLICK
|
|
87
|
-
const propName = expr.getName(); // CLICK
|
|
88
|
-
|
|
89
|
-
const defs =
|
|
90
|
-
"getDefinitions" in expr
|
|
91
|
-
? (expr as any).getDefinitions()
|
|
92
|
-
: [];
|
|
93
|
-
|
|
94
|
-
if (defs && defs.length > 0) {
|
|
95
|
-
const decl = defs[0]?.getDeclarationNode();
|
|
96
|
-
|
|
97
|
-
// const EVENTS = { CLICK: "event" }
|
|
98
|
-
if (decl && Node.isVariableDeclaration(decl)) {
|
|
99
|
-
const init = decl.getInitializer();
|
|
100
|
-
|
|
101
|
-
if (init && Node.isObjectLiteralExpression(init)) {
|
|
102
|
-
const prop = init.getProperty(propName);
|
|
103
|
-
|
|
104
|
-
if (
|
|
105
|
-
prop &&
|
|
106
|
-
Node.isPropertyAssignment(prop)
|
|
107
|
-
) {
|
|
108
|
-
const value = prop.getInitializer();
|
|
109
|
-
|
|
110
|
-
if (
|
|
111
|
-
value &&
|
|
112
|
-
Node.isStringLiteral(value)
|
|
113
|
-
) {
|
|
114
|
-
return {
|
|
115
|
-
values: [value.getLiteralText()],
|
|
116
|
-
dynamic: false
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// fallback
|
|
124
|
-
if (decl && Node.isPropertyAssignment(decl)) {
|
|
125
|
-
const initializer = decl.getInitializer();
|
|
126
|
-
|
|
127
|
-
if (
|
|
128
|
-
initializer &&
|
|
129
|
-
Node.isStringLiteral(initializer)
|
|
130
|
-
) {
|
|
131
|
-
return {
|
|
132
|
-
values: [initializer.getLiteralText()],
|
|
133
|
-
dynamic: false
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return {
|
|
140
|
-
values: [fullName],
|
|
141
|
-
dynamic: true
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// ternary (a ? b : c)
|
|
146
|
-
if (Node.isConditionalExpression(expr)) {
|
|
147
|
-
const values: string[] = [];
|
|
148
|
-
|
|
149
|
-
const whenTrue =
|
|
150
|
-
extractExpression(expr.getWhenTrue());
|
|
151
|
-
|
|
152
|
-
const whenFalse =
|
|
153
|
-
extractExpression(expr.getWhenFalse());
|
|
154
|
-
|
|
155
|
-
if (whenTrue) values.push(...whenTrue.values);
|
|
156
|
-
if (whenFalse) values.push(...whenFalse.values);
|
|
157
|
-
|
|
158
|
-
return {
|
|
159
|
-
values,
|
|
160
|
-
dynamic: true
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// template `${}`
|
|
165
|
-
if (Node.isTemplateExpression(expr)) {
|
|
166
|
-
return {
|
|
167
|
-
values: [
|
|
168
|
-
expr.getText().replace(/`/g, "")
|
|
169
|
-
],
|
|
170
|
-
dynamic: true
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// call (fn())
|
|
175
|
-
if (Node.isCallExpression(expr)) {
|
|
176
|
-
return {
|
|
177
|
-
values: [
|
|
178
|
-
expr.getExpression().getText()
|
|
179
|
-
],
|
|
180
|
-
dynamic: true
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
return null;
|
|
185
|
-
}
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
SourceFile,
|
|
3
|
-
SyntaxKind,
|
|
4
|
-
Node
|
|
5
|
-
} from "ts-morph";
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
ComponentWrapper,
|
|
9
|
-
ExtractedEvent
|
|
10
|
-
} from "../../types";
|
|
11
|
-
|
|
12
|
-
import { extractExpression } from "../extract";
|
|
13
|
-
|
|
14
|
-
export function scanComponentWrappers(
|
|
15
|
-
source: SourceFile,
|
|
16
|
-
wrappers: ComponentWrapper[]
|
|
17
|
-
) {
|
|
18
|
-
const events = new Set<ExtractedEvent>();
|
|
19
|
-
|
|
20
|
-
const elements = [
|
|
21
|
-
...source.getDescendantsOfKind(
|
|
22
|
-
SyntaxKind.JsxOpeningElement
|
|
23
|
-
),
|
|
24
|
-
...source.getDescendantsOfKind(
|
|
25
|
-
SyntaxKind.JsxSelfClosingElement
|
|
26
|
-
)
|
|
27
|
-
];
|
|
28
|
-
|
|
29
|
-
for (const el of elements) {
|
|
30
|
-
const name = el
|
|
31
|
-
.getTagNameNode()
|
|
32
|
-
.getText()
|
|
33
|
-
.toLowerCase();
|
|
34
|
-
|
|
35
|
-
for (const wrapper of wrappers) {
|
|
36
|
-
if (name !== wrapper.name.toLowerCase())
|
|
37
|
-
continue;
|
|
38
|
-
|
|
39
|
-
const attrs = el.getAttributes();
|
|
40
|
-
|
|
41
|
-
for (const attr of attrs) {
|
|
42
|
-
|
|
43
|
-
// ❗ NO spread props
|
|
44
|
-
if (Node.isJsxSpreadAttribute(attr)) {
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const attrNode =
|
|
49
|
-
attr.asKind(SyntaxKind.JsxAttribute);
|
|
50
|
-
|
|
51
|
-
if (!attrNode) continue;
|
|
52
|
-
|
|
53
|
-
const key =
|
|
54
|
-
attrNode
|
|
55
|
-
.getNameNode()
|
|
56
|
-
.getText()
|
|
57
|
-
.toLowerCase();
|
|
58
|
-
|
|
59
|
-
if (key !== wrapper.prop.toLowerCase())
|
|
60
|
-
continue;
|
|
61
|
-
|
|
62
|
-
const init = attrNode.getInitializer();
|
|
63
|
-
|
|
64
|
-
// <Button event />
|
|
65
|
-
if (!init) {
|
|
66
|
-
events.add({
|
|
67
|
-
value: key,
|
|
68
|
-
dynamic: true
|
|
69
|
-
});
|
|
70
|
-
continue;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// string: <Button event="click" />
|
|
74
|
-
if (Node.isStringLiteral(init)) {
|
|
75
|
-
events.add({
|
|
76
|
-
value: init.getLiteralText(),
|
|
77
|
-
dynamic: false
|
|
78
|
-
});
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// jsx expression: <Button event={"click"} />
|
|
83
|
-
if (Node.isJsxExpression(init)) {
|
|
84
|
-
const expr = init.getExpression();
|
|
85
|
-
|
|
86
|
-
if (!expr) continue;
|
|
87
|
-
|
|
88
|
-
const result =
|
|
89
|
-
extractExpression(expr);
|
|
90
|
-
|
|
91
|
-
if (!result) continue;
|
|
92
|
-
|
|
93
|
-
result.values.forEach((value) =>
|
|
94
|
-
events.add({
|
|
95
|
-
value,
|
|
96
|
-
dynamic: result.dynamic
|
|
97
|
-
})
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return events;
|
|
107
|
-
}
|