@eventra_dev/eventra-cli 0.2.3 → 0.3.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.
Files changed (89) hide show
  1. package/README.md +154 -32
  2. package/dist/analysis/cache/evaluationCache.js +21 -0
  3. package/dist/analysis/cache/resolvedCallCache.js +21 -0
  4. package/dist/analysis/cache/resolvedExportCache.js +21 -0
  5. package/dist/analysis/cache/semanticDependencyGraph.js +25 -0
  6. package/dist/analysis/cache/symbolInvalidation.js +20 -0
  7. package/dist/analysis/extractor/extractor.js +47 -0
  8. package/dist/analysis/extractor/propagationExtractor.js +52 -0
  9. package/dist/analysis/pipeline/semanticPass.js +2 -0
  10. package/dist/analysis/resolver/callResolver.js +125 -0
  11. package/dist/analysis/resolver/exportResolver.js +75 -0
  12. package/dist/analysis/resolver/resolver.js +133 -0
  13. package/dist/analysis/scanner/analyzer/propagationAnalyzer.js +193 -0
  14. package/dist/analysis/scanner/analyzer/returnPropagationAnalyzer.js +105 -0
  15. package/dist/analysis/scanner/scanner.js +117 -0
  16. package/dist/analysis/scanner/sinkDetector.js +91 -0
  17. package/dist/analysis/shared/evaluationContext.js +9 -0
  18. package/dist/analysis/shared/propagation.js +3 -0
  19. package/dist/analysis/shared/returnPropagation.js +2 -0
  20. package/dist/analysis/shared/types.js +2 -0
  21. package/dist/analysis/shared/utils.js +62 -0
  22. package/dist/analysis/symbols/symbolUtils.js +68 -0
  23. package/dist/analysis/symbols/wrapperRegistry.js +55 -0
  24. package/dist/cli/check.js +73 -0
  25. package/dist/{commands → cli}/init.js +1 -1
  26. package/dist/{commands → cli}/send.js +1 -1
  27. package/dist/cli/sync.js +56 -0
  28. package/dist/{commands → cli}/watch.js +41 -25
  29. package/dist/compiler/compilerContext.js +204 -0
  30. package/dist/compiler/documentRegistry.js +78 -0
  31. package/dist/compiler/importGraph.js +83 -0
  32. package/dist/compiler/scheduler.js +29 -0
  33. package/dist/core/EventraEngine.js +234 -0
  34. package/dist/core/projectScanner.js +73 -0
  35. package/dist/{utils → filesystem}/getVirtualFile.js +1 -3
  36. package/dist/filesystem/processFile.js +38 -0
  37. package/dist/index.js +5 -5
  38. package/dist/shared/buildSyntheticTsx.js +20 -0
  39. package/dist/shared/templateExpressionExtractor.js +22 -0
  40. package/package.json +32 -9
  41. package/.github/workflows/release.yml +0 -43
  42. package/ARCHITECTURE.md +0 -88
  43. package/assets/eventra-icon-animated.svg +0 -19
  44. package/dist/commands/check.js +0 -78
  45. package/dist/commands/sync.js +0 -79
  46. package/dist/engine/boundary.js +0 -14
  47. package/dist/engine/callResolver.js +0 -58
  48. package/dist/engine/engine.js +0 -154
  49. package/dist/engine/exportResolver.js +0 -46
  50. package/dist/engine/functionAnalyzer.js +0 -71
  51. package/dist/engine/graph.js +0 -168
  52. package/dist/engine/languageService.js +0 -162
  53. package/dist/engine/resolver.js +0 -149
  54. package/dist/engine/scanner.js +0 -230
  55. package/dist/utils/processFile.js +0 -28
  56. package/dist/utils/universal.js +0 -190
  57. package/src/commands/check.ts +0 -91
  58. package/src/commands/init.ts +0 -174
  59. package/src/commands/send.ts +0 -213
  60. package/src/commands/sync.ts +0 -106
  61. package/src/commands/watch.ts +0 -144
  62. package/src/engine/boundary.ts +0 -12
  63. package/src/engine/callResolver.ts +0 -65
  64. package/src/engine/engine.ts +0 -227
  65. package/src/engine/exportResolver.ts +0 -56
  66. package/src/engine/functionAnalyzer.ts +0 -81
  67. package/src/engine/graph.ts +0 -193
  68. package/src/engine/hash.ts +0 -5
  69. package/src/engine/languageService.ts +0 -209
  70. package/src/engine/resolver.ts +0 -177
  71. package/src/engine/scanner.ts +0 -298
  72. package/src/index.ts +0 -49
  73. package/src/types.ts +0 -35
  74. package/src/utils/config.ts +0 -53
  75. package/src/utils/getVirtualFile.ts +0 -5
  76. package/src/utils/processFile.ts +0 -29
  77. package/src/utils/universal.ts +0 -249
  78. package/tests/fixtures/backend/express/app.ts +0 -233
  79. package/tests/fixtures/backend/nest/service.ts +0 -70
  80. package/tests/fixtures/backend/node/index.ts +0 -63
  81. package/tests/fixtures/frontend/next/page.tsx +0 -101
  82. package/tests/fixtures/frontend/react/App.tsx +0 -104
  83. package/tests/fixtures/frontend/vue/App.vue +0 -83
  84. package/tests/fixtures/wrappers/component/test.tsx +0 -62
  85. package/tests/fixtures/wrappers/function/test.ts +0 -60
  86. package/tests/run.ts +0 -106
  87. package/tsconfig.json +0 -14
  88. /package/dist/{utils → config}/config.js +0 -0
  89. /package/dist/{engine → shared}/hash.js +0 -0
@@ -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
- }
@@ -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
- }
@@ -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
- }
@@ -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
- }