@eventra_dev/eventra-cli 0.1.9 → 0.1.11
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/sync.js +11 -1
- package/dist/engine/languageService.js +0 -3
- package/dist/engine/resolver.js +21 -0
- package/dist/engine/scanner.js +37 -16
- package/package.json +1 -1
- package/src/commands/sync.ts +13 -2
- package/src/engine/languageService.ts +0 -4
- package/src/engine/resolver.ts +31 -0
- package/src/engine/scanner.ts +47 -16
package/dist/commands/sync.js
CHANGED
|
@@ -25,11 +25,21 @@ async function sync() {
|
|
|
25
25
|
const engine = new engine_1.EventraEngine(process.cwd());
|
|
26
26
|
const detectedFn = new Set();
|
|
27
27
|
const detectedCmp = new Map();
|
|
28
|
+
const fileCache = [];
|
|
28
29
|
for (const file of files) {
|
|
29
30
|
try {
|
|
30
31
|
const raw = await promises_1.default.readFile(file, "utf-8");
|
|
31
32
|
const { content, virtualFile } = (0, processFile_1.processFile)(file, raw);
|
|
32
|
-
|
|
33
|
+
fileCache.push({ file: virtualFile, content });
|
|
34
|
+
engine["ts"].updateFile(virtualFile, content);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// ignore
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
for (const { file, content } of fileCache) {
|
|
41
|
+
try {
|
|
42
|
+
const res = engine.scanFile(file, content, config);
|
|
33
43
|
for (const w of res.detectedFunctionWrappers) {
|
|
34
44
|
detectedFn.add(w);
|
|
35
45
|
}
|
|
@@ -48,9 +48,6 @@ class TSService {
|
|
|
48
48
|
},
|
|
49
49
|
getScriptVersion: (file) => this.files.get(file)?.version.toString() ?? "0",
|
|
50
50
|
getScriptSnapshot: (file) => {
|
|
51
|
-
if (!this.fileNames.has(file)) {
|
|
52
|
-
return undefined;
|
|
53
|
-
}
|
|
54
51
|
const f = this.files.get(file);
|
|
55
52
|
if (f) {
|
|
56
53
|
return typescript_1.default.ScriptSnapshot.fromString(f.content);
|
package/dist/engine/resolver.js
CHANGED
|
@@ -70,6 +70,7 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
70
70
|
if (s.flags & typescript_1.default.SymbolFlags.Alias) {
|
|
71
71
|
s = checker.getAliasedSymbol(s);
|
|
72
72
|
}
|
|
73
|
+
// ENUM support
|
|
73
74
|
for (const decl of s.getDeclarations() ?? []) {
|
|
74
75
|
if (typescript_1.default.isEnumMember(decl) && decl.initializer) {
|
|
75
76
|
if (typescript_1.default.isStringLiteral(decl.initializer)) {
|
|
@@ -81,6 +82,26 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
84
|
}
|
|
85
|
+
// OBJECT support
|
|
86
|
+
if (typescript_1.default.isIdentifier(node.expression)) {
|
|
87
|
+
const objSymbol = checker.getSymbolAtLocation(node.expression);
|
|
88
|
+
if (objSymbol) {
|
|
89
|
+
for (const decl of objSymbol.getDeclarations() ?? []) {
|
|
90
|
+
if (typescript_1.default.isVariableDeclaration(decl) &&
|
|
91
|
+
decl.initializer &&
|
|
92
|
+
typescript_1.default.isObjectLiteralExpression(decl.initializer)) {
|
|
93
|
+
for (const prop of decl.initializer.properties) {
|
|
94
|
+
if (!typescript_1.default.isPropertyAssignment(prop))
|
|
95
|
+
continue;
|
|
96
|
+
const name = prop.name.getText();
|
|
97
|
+
if (name === node.name.text) {
|
|
98
|
+
return resolveNodeValue(prop.initializer, checker, paramMap, seen);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
84
105
|
}
|
|
85
106
|
if (typescript_1.default.isObjectLiteralExpression(node)) {
|
|
86
107
|
const values = [];
|
package/dist/engine/scanner.js
CHANGED
|
@@ -37,8 +37,10 @@ function isPropUsedInTracking(fn, prop) {
|
|
|
37
37
|
function visit(node) {
|
|
38
38
|
if (typescript_1.default.isCallExpression(node)) {
|
|
39
39
|
const name = getCallName(node.expression);
|
|
40
|
-
if (!TRACKING_NAMES.has(name))
|
|
40
|
+
if (!TRACKING_NAMES.has(name)) {
|
|
41
|
+
typescript_1.default.forEachChild(node, visit);
|
|
41
42
|
return;
|
|
43
|
+
}
|
|
42
44
|
for (const arg of node.arguments) {
|
|
43
45
|
if ((typescript_1.default.isIdentifier(arg) && arg.text === prop) ||
|
|
44
46
|
(typescript_1.default.isPropertyAccessExpression(arg) &&
|
|
@@ -65,22 +67,40 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
|
|
|
65
67
|
if (typescript_1.default.isCallExpression(node)) {
|
|
66
68
|
const name = getCallName(node.expression);
|
|
67
69
|
const isKnownWrapper = config.functionWrappers.some(w => w.name === name);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
let resolvedFn = (0, callResolver_1.resolveFunctionFromCall)(node.expression, checker);
|
|
71
|
+
// fallback: tracker.track(...)
|
|
72
|
+
if (!resolvedFn && typescript_1.default.isPropertyAccessExpression(node.expression)) {
|
|
73
|
+
const symbol = checker.getSymbolAtLocation(node.expression.name);
|
|
74
|
+
if (symbol) {
|
|
75
|
+
const decls = symbol.getDeclarations();
|
|
76
|
+
if (decls?.length) {
|
|
77
|
+
const d = decls[0];
|
|
78
|
+
if (typescript_1.default.isMethodDeclaration(d) ||
|
|
79
|
+
typescript_1.default.isFunctionDeclaration(d) ||
|
|
80
|
+
typescript_1.default.isFunctionExpression(d) ||
|
|
81
|
+
typescript_1.default.isArrowFunction(d)) {
|
|
82
|
+
resolvedFn = d;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const isAutoWrapper = resolvedFn && (0, functionAnalyzer_1.findTrackParamIndex)(resolvedFn) !== null;
|
|
70
88
|
const isTracking = isKnownWrapper ||
|
|
71
89
|
TRACKING_NAMES.has(name) ||
|
|
72
90
|
(isAutoWrapper &&
|
|
73
|
-
|
|
74
|
-
!(0, boundary_1.isExternalFile)(
|
|
75
|
-
if (!isTracking)
|
|
91
|
+
resolvedFn &&
|
|
92
|
+
!(0, boundary_1.isExternalFile)(resolvedFn.getSourceFile().fileName));
|
|
93
|
+
if (!isTracking) {
|
|
94
|
+
typescript_1.default.forEachChild(node, visit);
|
|
76
95
|
return;
|
|
96
|
+
}
|
|
77
97
|
if (!isKnownWrapper && isAutoWrapper && !TRACKING_NAMES.has(name)) {
|
|
78
98
|
detectedFunctionWrappers.add(name);
|
|
79
99
|
}
|
|
80
|
-
// paramMap
|
|
100
|
+
// paramMap (chain support)
|
|
81
101
|
const paramMap = new Map(inheritedParamMap ?? []);
|
|
82
|
-
if (
|
|
83
|
-
|
|
102
|
+
if (resolvedFn && typescript_1.default.isFunctionLike(resolvedFn)) {
|
|
103
|
+
resolvedFn.parameters.forEach((param, i) => {
|
|
84
104
|
const arg = node.arguments[i];
|
|
85
105
|
if (!arg)
|
|
86
106
|
return;
|
|
@@ -90,8 +110,8 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
|
|
|
90
110
|
});
|
|
91
111
|
}
|
|
92
112
|
let handled = false;
|
|
93
|
-
if (
|
|
94
|
-
const idx = (0, functionAnalyzer_1.findTrackParamIndex)(
|
|
113
|
+
if (resolvedFn) {
|
|
114
|
+
const idx = (0, functionAnalyzer_1.findTrackParamIndex)(resolvedFn);
|
|
95
115
|
if (idx !== null && node.arguments[idx]) {
|
|
96
116
|
const res = (0, resolver_1.resolveNodeValue)(node.arguments[idx], checker, paramMap);
|
|
97
117
|
res?.values.forEach(v => {
|
|
@@ -101,7 +121,6 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
|
|
|
101
121
|
handled = true;
|
|
102
122
|
}
|
|
103
123
|
}
|
|
104
|
-
// fallback
|
|
105
124
|
if (!handled) {
|
|
106
125
|
for (const arg of node.arguments) {
|
|
107
126
|
const res = (0, resolver_1.resolveNodeValue)(arg, checker, paramMap);
|
|
@@ -111,9 +130,9 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
|
|
|
111
130
|
});
|
|
112
131
|
}
|
|
113
132
|
}
|
|
114
|
-
// cross-file
|
|
115
|
-
if (
|
|
116
|
-
const sf =
|
|
133
|
+
// cross-file with paramMap
|
|
134
|
+
if (resolvedFn) {
|
|
135
|
+
const sf = resolvedFn.getSourceFile();
|
|
117
136
|
if (!visited.has(sf.fileName)) {
|
|
118
137
|
const res = scanSource(sf, checker, config, visited, depth + 1, paramMap);
|
|
119
138
|
res.events.forEach(e => events.add(e));
|
|
@@ -133,8 +152,10 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
|
|
|
133
152
|
if (symbol && (symbol.flags & typescript_1.default.SymbolFlags.Alias)) {
|
|
134
153
|
symbol = checker.getAliasedSymbol(symbol);
|
|
135
154
|
}
|
|
136
|
-
if (!symbol)
|
|
155
|
+
if (!symbol) {
|
|
156
|
+
typescript_1.default.forEachChild(node, visit);
|
|
137
157
|
return;
|
|
158
|
+
}
|
|
138
159
|
const tagName = typescript_1.default.isPropertyAccessExpression(node.tagName)
|
|
139
160
|
? node.tagName.name.getText()
|
|
140
161
|
: node.tagName.getText();
|
package/package.json
CHANGED
package/src/commands/sync.ts
CHANGED
|
@@ -26,13 +26,24 @@ export async function sync() {
|
|
|
26
26
|
const detectedFn = new Set<string>();
|
|
27
27
|
const detectedCmp = new Map<string, string>();
|
|
28
28
|
|
|
29
|
+
const fileCache: { file: string; content: string }[] = [];
|
|
30
|
+
|
|
29
31
|
for (const file of files) {
|
|
30
32
|
try {
|
|
31
33
|
const raw = await fs.readFile(file, "utf-8");
|
|
32
|
-
|
|
33
34
|
const { content, virtualFile } = processFile(file, raw);
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
fileCache.push({ file: virtualFile, content });
|
|
37
|
+
|
|
38
|
+
engine["ts"].updateFile(virtualFile, content);
|
|
39
|
+
} catch {
|
|
40
|
+
// ignore
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
for (const { file, content } of fileCache) {
|
|
45
|
+
try {
|
|
46
|
+
const res = engine.scanFile(file, content, config);
|
|
36
47
|
|
|
37
48
|
for (const w of res.detectedFunctionWrappers) {
|
|
38
49
|
detectedFn.add(w);
|
package/src/engine/resolver.ts
CHANGED
|
@@ -107,6 +107,7 @@ export function resolveNodeValue(
|
|
|
107
107
|
s = checker.getAliasedSymbol(s);
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
// ENUM support
|
|
110
111
|
for (const decl of s.getDeclarations() ?? []) {
|
|
111
112
|
if (ts.isEnumMember(decl) && decl.initializer) {
|
|
112
113
|
if (ts.isStringLiteral(decl.initializer)) {
|
|
@@ -118,6 +119,36 @@ export function resolveNodeValue(
|
|
|
118
119
|
}
|
|
119
120
|
}
|
|
120
121
|
}
|
|
122
|
+
|
|
123
|
+
// OBJECT support
|
|
124
|
+
if (ts.isIdentifier(node.expression)) {
|
|
125
|
+
const objSymbol = checker.getSymbolAtLocation(node.expression);
|
|
126
|
+
|
|
127
|
+
if (objSymbol) {
|
|
128
|
+
for (const decl of objSymbol.getDeclarations() ?? []) {
|
|
129
|
+
if (
|
|
130
|
+
ts.isVariableDeclaration(decl) &&
|
|
131
|
+
decl.initializer &&
|
|
132
|
+
ts.isObjectLiteralExpression(decl.initializer)
|
|
133
|
+
) {
|
|
134
|
+
for (const prop of decl.initializer.properties) {
|
|
135
|
+
if (!ts.isPropertyAssignment(prop)) continue;
|
|
136
|
+
|
|
137
|
+
const name = prop.name.getText();
|
|
138
|
+
|
|
139
|
+
if (name === node.name.text) {
|
|
140
|
+
return resolveNodeValue(
|
|
141
|
+
prop.initializer,
|
|
142
|
+
checker,
|
|
143
|
+
paramMap,
|
|
144
|
+
seen
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
121
152
|
}
|
|
122
153
|
|
|
123
154
|
if (ts.isObjectLiteralExpression(node)) {
|
package/src/engine/scanner.ts
CHANGED
|
@@ -40,7 +40,10 @@ function isPropUsedInTracking(
|
|
|
40
40
|
if (ts.isCallExpression(node)) {
|
|
41
41
|
const name = getCallName(node.expression);
|
|
42
42
|
|
|
43
|
-
if (!TRACKING_NAMES.has(name))
|
|
43
|
+
if (!TRACKING_NAMES.has(name)) {
|
|
44
|
+
ts.forEachChild(node, visit);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
44
47
|
|
|
45
48
|
for (const arg of node.arguments) {
|
|
46
49
|
if (
|
|
@@ -93,29 +96,54 @@ export function scanSource(
|
|
|
93
96
|
w => w.name === name
|
|
94
97
|
);
|
|
95
98
|
|
|
96
|
-
|
|
99
|
+
let resolvedFn = resolveFunctionFromCall(node.expression, checker);
|
|
100
|
+
|
|
101
|
+
// fallback: tracker.track(...)
|
|
102
|
+
if (!resolvedFn && ts.isPropertyAccessExpression(node.expression)) {
|
|
103
|
+
const symbol = checker.getSymbolAtLocation(node.expression.name);
|
|
104
|
+
|
|
105
|
+
if (symbol) {
|
|
106
|
+
const decls = symbol.getDeclarations();
|
|
107
|
+
|
|
108
|
+
if (decls?.length) {
|
|
109
|
+
const d = decls[0];
|
|
110
|
+
|
|
111
|
+
if (
|
|
112
|
+
ts.isMethodDeclaration(d) ||
|
|
113
|
+
ts.isFunctionDeclaration(d) ||
|
|
114
|
+
ts.isFunctionExpression(d) ||
|
|
115
|
+
ts.isArrowFunction(d)
|
|
116
|
+
) {
|
|
117
|
+
resolvedFn = d;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
97
122
|
|
|
98
123
|
const isAutoWrapper =
|
|
99
|
-
|
|
124
|
+
resolvedFn && findTrackParamIndex(resolvedFn) !== null;
|
|
100
125
|
|
|
101
126
|
const isTracking =
|
|
102
127
|
isKnownWrapper ||
|
|
103
128
|
TRACKING_NAMES.has(name) ||
|
|
104
129
|
(isAutoWrapper &&
|
|
105
|
-
|
|
106
|
-
!isExternalFile(
|
|
130
|
+
resolvedFn &&
|
|
131
|
+
!isExternalFile(resolvedFn.getSourceFile().fileName));
|
|
107
132
|
|
|
108
|
-
if (!isTracking)
|
|
133
|
+
if (!isTracking) {
|
|
134
|
+
ts.forEachChild(node, visit);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
109
137
|
|
|
110
138
|
if (!isKnownWrapper && isAutoWrapper && !TRACKING_NAMES.has(name)) {
|
|
111
139
|
detectedFunctionWrappers.add(name);
|
|
112
140
|
}
|
|
113
141
|
|
|
114
|
-
// paramMap
|
|
142
|
+
// paramMap (chain support)
|
|
115
143
|
const paramMap = new Map(inheritedParamMap ?? []);
|
|
116
144
|
|
|
117
|
-
if (
|
|
118
|
-
|
|
145
|
+
if (resolvedFn && ts.isFunctionLike(resolvedFn)) {
|
|
146
|
+
resolvedFn.parameters.forEach((param, i) => {
|
|
119
147
|
const arg = node.arguments[i];
|
|
120
148
|
if (!arg) return;
|
|
121
149
|
|
|
@@ -127,8 +155,8 @@ export function scanSource(
|
|
|
127
155
|
|
|
128
156
|
let handled = false;
|
|
129
157
|
|
|
130
|
-
if (
|
|
131
|
-
const idx = findTrackParamIndex(
|
|
158
|
+
if (resolvedFn) {
|
|
159
|
+
const idx = findTrackParamIndex(resolvedFn);
|
|
132
160
|
|
|
133
161
|
if (idx !== null && node.arguments[idx]) {
|
|
134
162
|
const res = resolveNodeValue(
|
|
@@ -145,7 +173,6 @@ export function scanSource(
|
|
|
145
173
|
}
|
|
146
174
|
}
|
|
147
175
|
|
|
148
|
-
// fallback
|
|
149
176
|
if (!handled) {
|
|
150
177
|
for (const arg of node.arguments) {
|
|
151
178
|
const res = resolveNodeValue(arg, checker, paramMap);
|
|
@@ -156,9 +183,9 @@ export function scanSource(
|
|
|
156
183
|
}
|
|
157
184
|
}
|
|
158
185
|
|
|
159
|
-
// cross-file
|
|
160
|
-
if (
|
|
161
|
-
const sf =
|
|
186
|
+
// cross-file with paramMap
|
|
187
|
+
if (resolvedFn) {
|
|
188
|
+
const sf = resolvedFn.getSourceFile();
|
|
162
189
|
|
|
163
190
|
if (!visited.has(sf.fileName)) {
|
|
164
191
|
const res = scanSource(
|
|
@@ -195,7 +222,10 @@ export function scanSource(
|
|
|
195
222
|
symbol = checker.getAliasedSymbol(symbol);
|
|
196
223
|
}
|
|
197
224
|
|
|
198
|
-
if (!symbol)
|
|
225
|
+
if (!symbol) {
|
|
226
|
+
ts.forEachChild(node, visit);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
199
229
|
|
|
200
230
|
const tagName =
|
|
201
231
|
ts.isPropertyAccessExpression(node.tagName)
|
|
@@ -209,6 +239,7 @@ export function scanSource(
|
|
|
209
239
|
|
|
210
240
|
if (ts.isVariableDeclaration(decl) && decl.initializer) {
|
|
211
241
|
const init = decl.initializer;
|
|
242
|
+
|
|
212
243
|
if (
|
|
213
244
|
ts.isArrowFunction(init) ||
|
|
214
245
|
ts.isFunctionExpression(init)
|