@eventra_dev/eventra-cli 0.2.4 → 0.3.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/README.md +143 -32
- package/dist/analysis/cache/evaluationCache.js +21 -0
- package/dist/analysis/cache/resolvedCallCache.js +21 -0
- package/dist/analysis/cache/resolvedExportCache.js +21 -0
- package/dist/analysis/cache/semanticDependencyGraph.js +25 -0
- package/dist/analysis/cache/symbolInvalidation.js +20 -0
- package/dist/analysis/extractor/extractor.js +47 -0
- package/dist/analysis/extractor/propagationExtractor.js +52 -0
- package/dist/analysis/pipeline/semanticPass.js +2 -0
- package/dist/analysis/resolver/callResolver.js +125 -0
- package/dist/analysis/resolver/exportResolver.js +75 -0
- package/dist/analysis/resolver/resolver.js +133 -0
- package/dist/analysis/scanner/analyzer/propagationAnalyzer.js +193 -0
- package/dist/analysis/scanner/analyzer/returnPropagationAnalyzer.js +105 -0
- package/dist/analysis/scanner/scanner.js +117 -0
- package/dist/analysis/scanner/sinkDetector.js +91 -0
- package/dist/analysis/shared/evaluationContext.js +9 -0
- package/dist/analysis/shared/propagation.js +3 -0
- package/dist/analysis/shared/returnPropagation.js +2 -0
- package/dist/analysis/shared/types.js +2 -0
- package/dist/analysis/shared/utils.js +62 -0
- package/dist/analysis/symbols/symbolUtils.js +68 -0
- package/dist/analysis/symbols/wrapperRegistry.js +55 -0
- package/dist/cli/check.js +73 -0
- package/dist/{commands → cli}/init.js +1 -1
- package/dist/{commands → cli}/send.js +1 -1
- package/dist/cli/sync.js +56 -0
- package/dist/{commands → cli}/watch.js +41 -25
- package/dist/compiler/compilerContext.js +204 -0
- package/dist/compiler/documentRegistry.js +78 -0
- package/dist/compiler/importGraph.js +83 -0
- package/dist/compiler/scheduler.js +29 -0
- package/dist/core/EventraEngine.js +234 -0
- package/dist/core/projectScanner.js +73 -0
- package/dist/{utils → filesystem}/getVirtualFile.js +1 -3
- package/dist/filesystem/processFile.js +38 -0
- package/dist/index.js +5 -5
- package/dist/shared/buildSyntheticTsx.js +20 -0
- package/dist/shared/templateExpressionExtractor.js +22 -0
- package/package.json +32 -9
- package/.github/workflows/release.yml +0 -43
- package/ARCHITECTURE.md +0 -88
- package/assets/eventra-icon-animated.svg +0 -19
- package/dist/commands/check.js +0 -78
- package/dist/commands/sync.js +0 -79
- package/dist/engine/boundary.js +0 -14
- package/dist/engine/callResolver.js +0 -58
- package/dist/engine/engine.js +0 -154
- package/dist/engine/exportResolver.js +0 -46
- package/dist/engine/functionAnalyzer.js +0 -71
- package/dist/engine/graph.js +0 -168
- package/dist/engine/languageService.js +0 -152
- package/dist/engine/resolver.js +0 -149
- package/dist/engine/scanner.js +0 -230
- package/dist/utils/processFile.js +0 -28
- package/dist/utils/universal.js +0 -190
- package/src/commands/check.ts +0 -91
- package/src/commands/init.ts +0 -174
- package/src/commands/send.ts +0 -213
- package/src/commands/sync.ts +0 -106
- package/src/commands/watch.ts +0 -144
- package/src/engine/boundary.ts +0 -12
- package/src/engine/callResolver.ts +0 -65
- package/src/engine/engine.ts +0 -227
- package/src/engine/exportResolver.ts +0 -56
- package/src/engine/functionAnalyzer.ts +0 -81
- package/src/engine/graph.ts +0 -193
- package/src/engine/hash.ts +0 -5
- package/src/engine/languageService.ts +0 -197
- package/src/engine/resolver.ts +0 -177
- package/src/engine/scanner.ts +0 -298
- package/src/index.ts +0 -49
- package/src/types.ts +0 -35
- package/src/utils/config.ts +0 -53
- package/src/utils/getVirtualFile.ts +0 -5
- package/src/utils/processFile.ts +0 -29
- package/src/utils/universal.ts +0 -249
- package/tests/fixtures/backend/express/app.ts +0 -233
- package/tests/fixtures/backend/nest/service.ts +0 -70
- package/tests/fixtures/backend/node/index.ts +0 -63
- package/tests/fixtures/frontend/next/page.tsx +0 -101
- package/tests/fixtures/frontend/react/App.tsx +0 -104
- package/tests/fixtures/frontend/vue/App.vue +0 -83
- package/tests/fixtures/wrappers/component/test.tsx +0 -62
- package/tests/fixtures/wrappers/function/test.ts +0 -60
- package/tests/run.ts +0 -106
- package/tsconfig.json +0 -14
- /package/dist/{utils → config}/config.js +0 -0
- /package/dist/{engine → shared}/hash.js +0 -0
package/dist/engine/resolver.js
DELETED
|
@@ -1,149 +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.resolveNodeValue = resolveNodeValue;
|
|
7
|
-
const typescript_1 = __importDefault(require("typescript"));
|
|
8
|
-
const exportResolver_1 = require("./exportResolver");
|
|
9
|
-
const callResolver_1 = require("./callResolver");
|
|
10
|
-
function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
|
|
11
|
-
if (seen.has(node))
|
|
12
|
-
return { values: [], dynamic: true };
|
|
13
|
-
seen.add(node);
|
|
14
|
-
// param passthrough
|
|
15
|
-
if (typescript_1.default.isIdentifier(node) && paramMap?.has(node.text)) {
|
|
16
|
-
return resolveNodeValue(paramMap.get(node.text), checker, paramMap, seen);
|
|
17
|
-
}
|
|
18
|
-
// string
|
|
19
|
-
if (typescript_1.default.isStringLiteral(node)) {
|
|
20
|
-
return { values: [node.text], dynamic: false };
|
|
21
|
-
}
|
|
22
|
-
// template
|
|
23
|
-
if (typescript_1.default.isTemplateExpression(node)) {
|
|
24
|
-
let results = node.head.text ? [node.head.text] : [""];
|
|
25
|
-
for (const span of node.templateSpans) {
|
|
26
|
-
const r = resolveNodeValue(span.expression, checker, paramMap, seen);
|
|
27
|
-
results = results.flatMap(s => r.values.length ? r.values.map(v => s + v) : [s + "*"]);
|
|
28
|
-
results = results.map(s => s + span.literal.text);
|
|
29
|
-
}
|
|
30
|
-
return { values: results, dynamic: true };
|
|
31
|
-
}
|
|
32
|
-
// ternary
|
|
33
|
-
if (typescript_1.default.isConditionalExpression(node)) {
|
|
34
|
-
const a = resolveNodeValue(node.whenTrue, checker, paramMap, seen);
|
|
35
|
-
const b = resolveNodeValue(node.whenFalse, checker, paramMap, seen);
|
|
36
|
-
return {
|
|
37
|
-
values: [...new Set([...a.values, ...b.values])],
|
|
38
|
-
dynamic: true,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
// object (event/name priority)
|
|
42
|
-
if (typescript_1.default.isObjectLiteralExpression(node)) {
|
|
43
|
-
for (const p of node.properties) {
|
|
44
|
-
if (typescript_1.default.isPropertyAssignment(p)) {
|
|
45
|
-
const key = p.name.getText();
|
|
46
|
-
if (key === "event" || key === "name") {
|
|
47
|
-
return resolveNodeValue(p.initializer, checker, paramMap, seen);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
const vals = [];
|
|
52
|
-
for (const p of node.properties) {
|
|
53
|
-
if (!typescript_1.default.isPropertyAssignment(p))
|
|
54
|
-
continue;
|
|
55
|
-
const r = resolveNodeValue(p.initializer, checker, paramMap, seen);
|
|
56
|
-
vals.push(...r.values);
|
|
57
|
-
}
|
|
58
|
-
return { values: [...new Set(vals)], dynamic: true };
|
|
59
|
-
}
|
|
60
|
-
// array
|
|
61
|
-
if (typescript_1.default.isArrayLiteralExpression(node)) {
|
|
62
|
-
const vals = [];
|
|
63
|
-
for (const el of node.elements) {
|
|
64
|
-
const r = resolveNodeValue(el, checker, paramMap, seen);
|
|
65
|
-
vals.push(...r.values);
|
|
66
|
-
}
|
|
67
|
-
return { values: [...new Set(vals)], dynamic: true };
|
|
68
|
-
}
|
|
69
|
-
// concat
|
|
70
|
-
if (typescript_1.default.isBinaryExpression(node) &&
|
|
71
|
-
node.operatorToken.kind === typescript_1.default.SyntaxKind.PlusToken) {
|
|
72
|
-
const l = resolveNodeValue(node.left, checker, paramMap, seen);
|
|
73
|
-
const r = resolveNodeValue(node.right, checker, paramMap, seen);
|
|
74
|
-
return {
|
|
75
|
-
values: l.values.flatMap(a => r.values.length ? r.values.map(b => a + b) : [a + "*"]),
|
|
76
|
-
dynamic: true,
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
// identifier (const / enum)
|
|
80
|
-
if (typescript_1.default.isIdentifier(node)) {
|
|
81
|
-
let s = checker.getSymbolAtLocation(node);
|
|
82
|
-
if (!s)
|
|
83
|
-
return { values: [], dynamic: true };
|
|
84
|
-
s = (0, exportResolver_1.resolveExportedSymbol)(s, checker) ?? s;
|
|
85
|
-
for (const d of s.getDeclarations() ?? []) {
|
|
86
|
-
if (typescript_1.default.isVariableDeclaration(d) && d.initializer) {
|
|
87
|
-
return resolveNodeValue(d.initializer, checker, paramMap, seen);
|
|
88
|
-
}
|
|
89
|
-
if (typescript_1.default.isEnumMember(d) && d.initializer && typescript_1.default.isStringLiteral(d.initializer)) {
|
|
90
|
-
return { values: [d.initializer.text], dynamic: false };
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return { values: [], dynamic: true };
|
|
94
|
-
}
|
|
95
|
-
// PROPERTY ACCESS (OBJECT + ENUM)
|
|
96
|
-
if (typescript_1.default.isPropertyAccessExpression(node)) {
|
|
97
|
-
const obj = node.expression;
|
|
98
|
-
const prop = node.name.text;
|
|
99
|
-
// object literal lookup
|
|
100
|
-
if (typescript_1.default.isIdentifier(obj)) {
|
|
101
|
-
const sym = checker.getSymbolAtLocation(obj);
|
|
102
|
-
if (sym) {
|
|
103
|
-
const s = (0, exportResolver_1.resolveExportedSymbol)(sym, checker) ?? sym;
|
|
104
|
-
for (const d of s.getDeclarations() ?? []) {
|
|
105
|
-
if (typescript_1.default.isVariableDeclaration(d) &&
|
|
106
|
-
d.initializer &&
|
|
107
|
-
typescript_1.default.isObjectLiteralExpression(d.initializer)) {
|
|
108
|
-
for (const p of d.initializer.properties) {
|
|
109
|
-
if (typescript_1.default.isPropertyAssignment(p) &&
|
|
110
|
-
p.name.getText() === prop) {
|
|
111
|
-
return resolveNodeValue(p.initializer, checker, paramMap, seen);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
// enum fallback
|
|
119
|
-
const sym = checker.getSymbolAtLocation(node);
|
|
120
|
-
if (sym) {
|
|
121
|
-
let s = (0, exportResolver_1.resolveExportedSymbol)(sym, checker) ?? sym;
|
|
122
|
-
if (s.flags & typescript_1.default.SymbolFlags.Alias)
|
|
123
|
-
s = checker.getAliasedSymbol(s);
|
|
124
|
-
for (const d of s.getDeclarations() ?? []) {
|
|
125
|
-
if (typescript_1.default.isEnumMember(d) && d.initializer && typescript_1.default.isStringLiteral(d.initializer)) {
|
|
126
|
-
return { values: [d.initializer.text], dynamic: false };
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
return { values: [], dynamic: true };
|
|
131
|
-
}
|
|
132
|
-
// CALL (unwrap + dive into wrapper body)
|
|
133
|
-
if (typescript_1.default.isCallExpression(node)) {
|
|
134
|
-
const vals = [];
|
|
135
|
-
// args
|
|
136
|
-
for (const a of node.arguments) {
|
|
137
|
-
const r = resolveNodeValue(a, checker, paramMap, seen);
|
|
138
|
-
vals.push(...r.values);
|
|
139
|
-
}
|
|
140
|
-
// dive into called function (wrapper support)
|
|
141
|
-
const fn = (0, callResolver_1.resolveFunctionFromCall)(node.expression, checker);
|
|
142
|
-
if (fn?.body) {
|
|
143
|
-
const r = resolveNodeValue(fn.body, checker, paramMap, seen);
|
|
144
|
-
vals.push(...r.values);
|
|
145
|
-
}
|
|
146
|
-
return { values: [...new Set(vals)], dynamic: true };
|
|
147
|
-
}
|
|
148
|
-
return { values: [], dynamic: true };
|
|
149
|
-
}
|
package/dist/engine/scanner.js
DELETED
|
@@ -1,230 +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.scanSource = scanSource;
|
|
7
|
-
const typescript_1 = __importDefault(require("typescript"));
|
|
8
|
-
const resolver_1 = require("./resolver");
|
|
9
|
-
const callResolver_1 = require("./callResolver");
|
|
10
|
-
const exportResolver_1 = require("./exportResolver");
|
|
11
|
-
// HELPERS
|
|
12
|
-
function isValidEvent(v) {
|
|
13
|
-
return (v &&
|
|
14
|
-
v.length > 1 &&
|
|
15
|
-
v.length < 120 &&
|
|
16
|
-
!v.includes(" ") &&
|
|
17
|
-
/^[a-zA-Z0-9._:-]+$/.test(v));
|
|
18
|
-
}
|
|
19
|
-
function getCallName(expr) {
|
|
20
|
-
if (typescript_1.default.isIdentifier(expr))
|
|
21
|
-
return expr.text;
|
|
22
|
-
if (typescript_1.default.isPropertyAccessExpression(expr))
|
|
23
|
-
return expr.name.text;
|
|
24
|
-
return "";
|
|
25
|
-
}
|
|
26
|
-
function getJsxTagName(tag) {
|
|
27
|
-
if (typescript_1.default.isIdentifier(tag))
|
|
28
|
-
return tag.text;
|
|
29
|
-
if (typescript_1.default.isPropertyAccessExpression(tag))
|
|
30
|
-
return tag.name.text;
|
|
31
|
-
return tag.getText();
|
|
32
|
-
}
|
|
33
|
-
function getJsxAttrName(name) {
|
|
34
|
-
if (typescript_1.default.isIdentifier(name))
|
|
35
|
-
return name.text;
|
|
36
|
-
if (typescript_1.default.isJsxNamespacedName(name))
|
|
37
|
-
return name.name.text;
|
|
38
|
-
return "";
|
|
39
|
-
}
|
|
40
|
-
// MAIN
|
|
41
|
-
function scanSource(source, checker, config, visited = new Set(), inheritedParamMap, wrapperCache = new Map()) {
|
|
42
|
-
const events = new Set();
|
|
43
|
-
const detectedFunctionWrappers = new Set();
|
|
44
|
-
const detectedComponentWrappers = new Map();
|
|
45
|
-
if (visited.has(source.fileName)) {
|
|
46
|
-
return { events, detectedFunctionWrappers, detectedComponentWrappers };
|
|
47
|
-
}
|
|
48
|
-
visited.add(source.fileName);
|
|
49
|
-
// TRACK DETECTION
|
|
50
|
-
function isTrackCall(expr) {
|
|
51
|
-
const name = getCallName(expr);
|
|
52
|
-
// direct track()
|
|
53
|
-
if (name === "track") {
|
|
54
|
-
return true;
|
|
55
|
-
}
|
|
56
|
-
// configured wrappers
|
|
57
|
-
if (config.functionWrappers?.some(w => w.name === name)) {
|
|
58
|
-
return true;
|
|
59
|
-
}
|
|
60
|
-
// *.track()
|
|
61
|
-
return typescript_1.default.isPropertyAccessExpression(expr) &&
|
|
62
|
-
expr.name.text === "track";
|
|
63
|
-
}
|
|
64
|
-
function extractTrackCall(node, paramMap) {
|
|
65
|
-
if (!isTrackCall(node.expression))
|
|
66
|
-
return;
|
|
67
|
-
const arg = node.arguments[0];
|
|
68
|
-
if (!arg)
|
|
69
|
-
return;
|
|
70
|
-
const res = (0, resolver_1.resolveNodeValue)(arg, checker, paramMap);
|
|
71
|
-
for (const v of res.values) {
|
|
72
|
-
if (isValidEvent(v)) {
|
|
73
|
-
events.add(v);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
// WRAPPER DETECTION
|
|
78
|
-
function isWrapperFunction(fn) {
|
|
79
|
-
let found = false;
|
|
80
|
-
function walk(n) {
|
|
81
|
-
if (found)
|
|
82
|
-
return;
|
|
83
|
-
if (typescript_1.default.isCallExpression(n) && isTrackCall(n.expression)) {
|
|
84
|
-
found = true;
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
typescript_1.default.forEachChild(n, walk);
|
|
88
|
-
}
|
|
89
|
-
if (fn.body)
|
|
90
|
-
walk(fn.body);
|
|
91
|
-
return found;
|
|
92
|
-
}
|
|
93
|
-
// COMPONENT WRAPPER
|
|
94
|
-
function detectComponentWrapper(tag) {
|
|
95
|
-
const tagName = getJsxTagName(tag);
|
|
96
|
-
if (wrapperCache.has(tagName)) {
|
|
97
|
-
return wrapperCache.get(tagName);
|
|
98
|
-
}
|
|
99
|
-
let symbol = checker.getSymbolAtLocation(tag);
|
|
100
|
-
if (symbol && (symbol.flags & typescript_1.default.SymbolFlags.Alias)) {
|
|
101
|
-
symbol = checker.getAliasedSymbol(symbol);
|
|
102
|
-
}
|
|
103
|
-
if (!symbol) {
|
|
104
|
-
wrapperCache.set(tagName, null);
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
symbol = (0, exportResolver_1.resolveExportedSymbol)(symbol, checker) ?? symbol;
|
|
108
|
-
for (const decl of symbol.getDeclarations() ?? []) {
|
|
109
|
-
let fn = null;
|
|
110
|
-
if (typescript_1.default.isFunctionDeclaration(decl))
|
|
111
|
-
fn = decl;
|
|
112
|
-
if (typescript_1.default.isVariableDeclaration(decl) &&
|
|
113
|
-
decl.initializer &&
|
|
114
|
-
(typescript_1.default.isArrowFunction(decl.initializer) ||
|
|
115
|
-
typescript_1.default.isFunctionExpression(decl.initializer))) {
|
|
116
|
-
fn = decl.initializer;
|
|
117
|
-
}
|
|
118
|
-
if (!fn || !fn.body)
|
|
119
|
-
continue;
|
|
120
|
-
let prop = null;
|
|
121
|
-
function walk(n) {
|
|
122
|
-
if (prop)
|
|
123
|
-
return;
|
|
124
|
-
if (typescript_1.default.isCallExpression(n) && isTrackCall(n.expression)) {
|
|
125
|
-
const arg = n.arguments[0];
|
|
126
|
-
if (typescript_1.default.isPropertyAccessExpression(arg)) {
|
|
127
|
-
prop = arg.name.text;
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
typescript_1.default.forEachChild(n, walk);
|
|
132
|
-
}
|
|
133
|
-
walk(fn.body);
|
|
134
|
-
wrapperCache.set(tagName, prop);
|
|
135
|
-
if (prop) {
|
|
136
|
-
detectedComponentWrappers.set(tagName, prop);
|
|
137
|
-
return prop;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
wrapperCache.set(tagName, null);
|
|
141
|
-
return null;
|
|
142
|
-
}
|
|
143
|
-
// VISITOR
|
|
144
|
-
function visit(node) {
|
|
145
|
-
// JSX
|
|
146
|
-
if (typescript_1.default.isJsxSelfClosingElement(node) || typescript_1.default.isJsxOpeningElement(node)) {
|
|
147
|
-
const tagName = getJsxTagName(node.tagName);
|
|
148
|
-
if (tagName[0] === tagName[0].toLowerCase()) {
|
|
149
|
-
typescript_1.default.forEachChild(node, visit);
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
let wrapper = config.wrappers.find(w => w.name === tagName);
|
|
153
|
-
if (!wrapper) {
|
|
154
|
-
const prop = detectComponentWrapper(node.tagName);
|
|
155
|
-
if (prop)
|
|
156
|
-
wrapper = { name: tagName, prop };
|
|
157
|
-
}
|
|
158
|
-
if (wrapper) {
|
|
159
|
-
for (const attr of node.attributes.properties) {
|
|
160
|
-
if (!typescript_1.default.isJsxAttribute(attr))
|
|
161
|
-
continue;
|
|
162
|
-
const name = getJsxAttrName(attr.name);
|
|
163
|
-
if (name !== wrapper.prop)
|
|
164
|
-
continue;
|
|
165
|
-
if (!attr.initializer)
|
|
166
|
-
continue;
|
|
167
|
-
if (typescript_1.default.isStringLiteral(attr.initializer)) {
|
|
168
|
-
if (isValidEvent(attr.initializer.text)) {
|
|
169
|
-
events.add(attr.initializer.text);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
if (typescript_1.default.isJsxExpression(attr.initializer)) {
|
|
173
|
-
const expr = attr.initializer.expression;
|
|
174
|
-
if (!expr)
|
|
175
|
-
continue;
|
|
176
|
-
const res = (0, resolver_1.resolveNodeValue)(expr, checker);
|
|
177
|
-
res.values.forEach(v => {
|
|
178
|
-
if (isValidEvent(v))
|
|
179
|
-
events.add(v);
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
typescript_1.default.forEachChild(node, visit);
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
// CALL
|
|
188
|
-
if (typescript_1.default.isCallExpression(node)) {
|
|
189
|
-
const resolvedFn = (0, callResolver_1.resolveFunctionFromCall)(node.expression, checker);
|
|
190
|
-
const paramMap = new Map(inheritedParamMap ?? []);
|
|
191
|
-
if (resolvedFn) {
|
|
192
|
-
resolvedFn.parameters.forEach((p, i) => {
|
|
193
|
-
const arg = node.arguments[i];
|
|
194
|
-
if (!arg)
|
|
195
|
-
return;
|
|
196
|
-
if (typescript_1.default.isIdentifier(p.name)) {
|
|
197
|
-
paramMap.set(p.name.text, arg);
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
extractTrackCall(node, paramMap);
|
|
202
|
-
if (resolvedFn && isWrapperFunction(resolvedFn)) {
|
|
203
|
-
const name = getCallName(node.expression);
|
|
204
|
-
if (name && name !== "track") {
|
|
205
|
-
detectedFunctionWrappers.add(name);
|
|
206
|
-
}
|
|
207
|
-
if (resolvedFn.body) {
|
|
208
|
-
visit(resolvedFn.body);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
if (resolvedFn && resolvedFn.body) {
|
|
212
|
-
const sf = resolvedFn.getSourceFile();
|
|
213
|
-
if (!visited.has(sf.fileName)) {
|
|
214
|
-
const res = scanSource(sf, checker, config, visited, paramMap, wrapperCache);
|
|
215
|
-
res.events.forEach(e => events.add(e));
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
node.arguments.forEach(visit);
|
|
219
|
-
visit(node.expression);
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
typescript_1.default.forEachChild(node, visit);
|
|
223
|
-
}
|
|
224
|
-
visit(source);
|
|
225
|
-
return {
|
|
226
|
-
events,
|
|
227
|
-
detectedFunctionWrappers,
|
|
228
|
-
detectedComponentWrappers,
|
|
229
|
-
};
|
|
230
|
-
}
|
|
@@ -1,28 +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.processFile = processFile;
|
|
7
|
-
const path_1 = __importDefault(require("path"));
|
|
8
|
-
const universal_1 = require("./universal");
|
|
9
|
-
function extractImports(content, file) {
|
|
10
|
-
return (0, universal_1.parseUniversal)(content, file).deps;
|
|
11
|
-
}
|
|
12
|
-
function processFile(file, content) {
|
|
13
|
-
const ext = path_1.default.extname(file);
|
|
14
|
-
if (ext === ".ts" ||
|
|
15
|
-
ext === ".tsx" ||
|
|
16
|
-
ext === ".js" ||
|
|
17
|
-
ext === ".jsx") {
|
|
18
|
-
return {
|
|
19
|
-
content,
|
|
20
|
-
deps: extractImports(content, file),
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
const parsed = (0, universal_1.parseUniversal)(content, file);
|
|
24
|
-
return {
|
|
25
|
-
content: parsed.code || "",
|
|
26
|
-
deps: [...new Set(parsed.deps.filter(Boolean))],
|
|
27
|
-
};
|
|
28
|
-
}
|
package/dist/utils/universal.js
DELETED
|
@@ -1,190 +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.parseUniversal = parseUniversal;
|
|
7
|
-
const path_1 = __importDefault(require("path"));
|
|
8
|
-
/* ---------------------------------- */
|
|
9
|
-
/* COMMENT STRIP (SAFE) */
|
|
10
|
-
/* ---------------------------------- */
|
|
11
|
-
function stripComments(input) {
|
|
12
|
-
return input
|
|
13
|
-
.replace(/<!--[\s\S]*?-->/g, "")
|
|
14
|
-
.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
15
|
-
}
|
|
16
|
-
/* ---------------------------------- */
|
|
17
|
-
/* TRACK DETECTOR */
|
|
18
|
-
/* ---------------------------------- */
|
|
19
|
-
function looksLikeTracking(code) {
|
|
20
|
-
return /\btrack\s*\(|\.track\s*\(/.test(code);
|
|
21
|
-
}
|
|
22
|
-
/* ---------------------------------- */
|
|
23
|
-
/* SAFE {} PARSER (JSX / TEMPLATES) */
|
|
24
|
-
/* ---------------------------------- */
|
|
25
|
-
function extractBracedExpressions(input) {
|
|
26
|
-
const result = [];
|
|
27
|
-
let depth = 0;
|
|
28
|
-
let start = -1;
|
|
29
|
-
let inString = null;
|
|
30
|
-
for (let i = 0; i < input.length; i++) {
|
|
31
|
-
const char = input[i];
|
|
32
|
-
// handle strings
|
|
33
|
-
if (inString) {
|
|
34
|
-
if (char === inString && input[i - 1] !== "\\") {
|
|
35
|
-
inString = null;
|
|
36
|
-
}
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
if (char === '"' || char === "'" || char === "`") {
|
|
40
|
-
inString = char;
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
if (char === "{") {
|
|
44
|
-
if (depth === 0)
|
|
45
|
-
start = i + 1;
|
|
46
|
-
depth++;
|
|
47
|
-
}
|
|
48
|
-
else if (char === "}") {
|
|
49
|
-
depth--;
|
|
50
|
-
if (depth === 0 && start !== -1) {
|
|
51
|
-
const expr = input.slice(start, i);
|
|
52
|
-
if (looksLikeTracking(expr)) {
|
|
53
|
-
result.push(expr);
|
|
54
|
-
}
|
|
55
|
-
start = -1;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return result;
|
|
60
|
-
}
|
|
61
|
-
/* ---------------------------------- */
|
|
62
|
-
/* HTML HANDLERS */
|
|
63
|
-
/* ---------------------------------- */
|
|
64
|
-
function extractHTMLHandlers(input) {
|
|
65
|
-
const result = [];
|
|
66
|
-
const regex = /\bon\w+\s*=\s*["']([^"']+)["']/g;
|
|
67
|
-
for (const m of input.matchAll(regex)) {
|
|
68
|
-
if (looksLikeTracking(m[1])) {
|
|
69
|
-
result.push(m[1]);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return result;
|
|
73
|
-
}
|
|
74
|
-
/* ---------------------------------- */
|
|
75
|
-
/* VUE HANDLERS */
|
|
76
|
-
/* ---------------------------------- */
|
|
77
|
-
function extractVueHandlers(input) {
|
|
78
|
-
const result = [];
|
|
79
|
-
const regex = /(?:@|v-on:)[\w:-]+\s*=\s*["']([^"']+)["']/g;
|
|
80
|
-
for (const m of input.matchAll(regex)) {
|
|
81
|
-
if (looksLikeTracking(m[1])) {
|
|
82
|
-
result.push(m[1]);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return result;
|
|
86
|
-
}
|
|
87
|
-
/* ---------------------------------- */
|
|
88
|
-
/* SVELTE HANDLERS */
|
|
89
|
-
/* ---------------------------------- */
|
|
90
|
-
function extractSvelteHandlers(input) {
|
|
91
|
-
const result = [];
|
|
92
|
-
const regex = /\bon:[\w]+\s*=\s*{([\s\S]*?)}/g;
|
|
93
|
-
for (const m of input.matchAll(regex)) {
|
|
94
|
-
const expr = m[1];
|
|
95
|
-
const nested = extractBracedExpressions(`{${expr}}`);
|
|
96
|
-
result.push(...nested);
|
|
97
|
-
}
|
|
98
|
-
return result;
|
|
99
|
-
}
|
|
100
|
-
/* ---------------------------------- */
|
|
101
|
-
/* SCRIPT EXTRACTION */
|
|
102
|
-
/* ---------------------------------- */
|
|
103
|
-
function extractScripts(input, file) {
|
|
104
|
-
const scripts = [];
|
|
105
|
-
const deps = [];
|
|
106
|
-
// <script src="">
|
|
107
|
-
const srcRegex = /<script\b[^>]*?\bsrc=["'](.+?)["'][^>]*>/gi;
|
|
108
|
-
for (const m of input.matchAll(srcRegex)) {
|
|
109
|
-
const src = m[1];
|
|
110
|
-
const resolved = src.startsWith("/")
|
|
111
|
-
? path_1.default.resolve(process.cwd(), "." + src)
|
|
112
|
-
: path_1.default.resolve(path_1.default.dirname(file), src);
|
|
113
|
-
deps.push(resolved);
|
|
114
|
-
}
|
|
115
|
-
// inline <script>
|
|
116
|
-
const scriptRegex = /<script\b[^>]*>([\s\S]*?)<\/script>/gi;
|
|
117
|
-
for (const m of input.matchAll(scriptRegex)) {
|
|
118
|
-
if (m[1]?.trim()) {
|
|
119
|
-
scripts.push(m[1]);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
const noScripts = input.replace(scriptRegex, "");
|
|
123
|
-
return { scripts, deps, noScripts };
|
|
124
|
-
}
|
|
125
|
-
/* ---------------------------------- */
|
|
126
|
-
/* STATIC IMPORTS */
|
|
127
|
-
/* ---------------------------------- */
|
|
128
|
-
function extractStaticImports(input, file) {
|
|
129
|
-
const deps = [];
|
|
130
|
-
const regex = /import\s+(?:.+?\s+from\s+)?["'](.+?)["']/g;
|
|
131
|
-
for (const m of input.matchAll(regex)) {
|
|
132
|
-
const mod = m[1];
|
|
133
|
-
if (!mod.startsWith(".") && !mod.startsWith("/"))
|
|
134
|
-
continue;
|
|
135
|
-
const resolved = path_1.default.resolve(path_1.default.dirname(file), mod);
|
|
136
|
-
deps.push(resolved);
|
|
137
|
-
}
|
|
138
|
-
return deps;
|
|
139
|
-
}
|
|
140
|
-
/* ---------------------------------- */
|
|
141
|
-
/* DYNAMIC IMPORTS */
|
|
142
|
-
/* ---------------------------------- */
|
|
143
|
-
function extractDynamicImports(input, file) {
|
|
144
|
-
const deps = [];
|
|
145
|
-
const calls = [];
|
|
146
|
-
const regex = /import\(\s*["'](.+?)["']\s*\)/g;
|
|
147
|
-
for (const m of input.matchAll(regex)) {
|
|
148
|
-
const mod = m[1];
|
|
149
|
-
const resolved = mod.startsWith("/")
|
|
150
|
-
? path_1.default.resolve(process.cwd(), "." + mod)
|
|
151
|
-
: path_1.default.resolve(path_1.default.dirname(file), mod);
|
|
152
|
-
deps.push(resolved);
|
|
153
|
-
if (looksLikeTracking(mod)) {
|
|
154
|
-
calls.push(`import("${mod}")`);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
return { deps, calls };
|
|
158
|
-
}
|
|
159
|
-
/* ---------------------------------- */
|
|
160
|
-
/* MAIN */
|
|
161
|
-
/* ---------------------------------- */
|
|
162
|
-
function parseUniversal(content, file) {
|
|
163
|
-
const parts = [];
|
|
164
|
-
const deps = [];
|
|
165
|
-
const clean = stripComments(content);
|
|
166
|
-
/* ---------- ASTRO FRONTMATTER ---------- */
|
|
167
|
-
const fm = clean.match(/^\s*---([\s\S]*?)---/);
|
|
168
|
-
if (fm?.[1]) {
|
|
169
|
-
parts.push(fm[1]);
|
|
170
|
-
}
|
|
171
|
-
/* ---------- SCRIPTS ---------- */
|
|
172
|
-
const { scripts, deps: scriptDeps, noScripts } = extractScripts(clean, file);
|
|
173
|
-
parts.push(...scripts);
|
|
174
|
-
deps.push(...scriptDeps);
|
|
175
|
-
/* ---------- HANDLERS ---------- */
|
|
176
|
-
parts.push(...extractHTMLHandlers(noScripts));
|
|
177
|
-
parts.push(...extractVueHandlers(noScripts));
|
|
178
|
-
parts.push(...extractSvelteHandlers(noScripts));
|
|
179
|
-
/* ---------- JSX / TEMPLATE ---------- */
|
|
180
|
-
parts.push(...extractBracedExpressions(clean));
|
|
181
|
-
/* ---------- IMPORTS ---------- */
|
|
182
|
-
deps.push(...extractStaticImports(clean, file));
|
|
183
|
-
const dyn = extractDynamicImports(clean, file);
|
|
184
|
-
deps.push(...dyn.deps);
|
|
185
|
-
parts.push(...dyn.calls);
|
|
186
|
-
return {
|
|
187
|
-
code: parts.length ? parts.join("\n") : content,
|
|
188
|
-
deps: [...new Set(deps.filter(Boolean))],
|
|
189
|
-
};
|
|
190
|
-
}
|
package/src/commands/check.ts
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
import fg from "fast-glob";
|
|
3
|
-
import fs from "fs/promises";
|
|
4
|
-
import path from "path";
|
|
5
|
-
|
|
6
|
-
import { loadConfig, saveConfig } from "../utils/config";
|
|
7
|
-
import { EventraEngine } from "../engine/engine";
|
|
8
|
-
import { processFile } from "../utils/processFile";
|
|
9
|
-
import { getVirtualFile } from "../utils/getVirtualFile";
|
|
10
|
-
|
|
11
|
-
export async function check({ fix = false }: { fix?: boolean }) {
|
|
12
|
-
const config = await loadConfig();
|
|
13
|
-
|
|
14
|
-
if (!config) {
|
|
15
|
-
console.log(chalk.red("eventra.json not found"));
|
|
16
|
-
process.exit(1);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
console.log(chalk.blue("Checking events..."));
|
|
20
|
-
|
|
21
|
-
const files = await fg(config.sync.include, {
|
|
22
|
-
ignore: config.sync.exclude,
|
|
23
|
-
absolute: true,
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
const engine = new EventraEngine(process.cwd());
|
|
27
|
-
|
|
28
|
-
const cache = new Map<string, { content: string; deps: string[] }>();
|
|
29
|
-
const toScan = new Set<string>();
|
|
30
|
-
|
|
31
|
-
// COLLECT
|
|
32
|
-
for (const file of files) {
|
|
33
|
-
try {
|
|
34
|
-
const raw = await fs.readFile(file, "utf-8");
|
|
35
|
-
if (raw.length > 2_000_000) continue;
|
|
36
|
-
|
|
37
|
-
const parsed = processFile(file, raw);
|
|
38
|
-
|
|
39
|
-
cache.set(file, parsed);
|
|
40
|
-
toScan.add(file);
|
|
41
|
-
parsed.deps.forEach(dep => toScan.add(path.resolve(dep)));
|
|
42
|
-
|
|
43
|
-
} catch {}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// PRELOAD
|
|
47
|
-
for (const file of toScan) {
|
|
48
|
-
try {
|
|
49
|
-
const parsed = cache.get(file);
|
|
50
|
-
if (!parsed) continue;
|
|
51
|
-
engine.preloadFile(getVirtualFile(file), parsed.content);
|
|
52
|
-
} catch {}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// SCAN
|
|
56
|
-
for (const file of toScan) {
|
|
57
|
-
try {
|
|
58
|
-
const parsed = cache.get(file);
|
|
59
|
-
if (!parsed) continue;
|
|
60
|
-
|
|
61
|
-
engine.scanFile(
|
|
62
|
-
getVirtualFile(file),
|
|
63
|
-
parsed.content,
|
|
64
|
-
config
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
} catch {}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const found = new Set(engine.getAllEvents());
|
|
71
|
-
const known = new Set(config.events ?? []);
|
|
72
|
-
|
|
73
|
-
const added = [...found].filter(e => !known.has(e));
|
|
74
|
-
const removed = [...known].filter(e => !found.has(e));
|
|
75
|
-
|
|
76
|
-
if (fix) {
|
|
77
|
-
config.events = [...found].sort();
|
|
78
|
-
await saveConfig(config);
|
|
79
|
-
console.log(chalk.green("Synced"));
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (added.length || removed.length) {
|
|
84
|
-
added.forEach(e => console.log(chalk.red(`+ ${e}`)));
|
|
85
|
-
removed.forEach(e => console.log(chalk.yellow(`- ${e}`)));
|
|
86
|
-
|
|
87
|
-
process.exit(1);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
console.log(chalk.green("All good"));
|
|
91
|
-
}
|