@eventra_dev/eventra-cli 0.1.29 → 0.1.31

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.
@@ -1,100 +1,132 @@
1
1
  import path from "path";
2
2
  import { ParseResult } from "../types";
3
3
 
4
- // Strip comments (HTML + JS)
4
+ // SAFE COMMENT STRIP
5
5
  function stripComments(input: string): string {
6
6
  return input
7
7
  .replace(/<!--[\s\S]*?-->/g, "")
8
- .replace(/\/\*[\s\S]*?\*\//g, "")
9
- .replace(/\/\/.*$/gm, "");
8
+ .replace(/\/\*[\s\S]*?\*\//g, "");
10
9
  }
11
10
 
12
- // Extract JS expressions inside {}
13
- function extractJS(input: string): string[] {
14
- const result: string[] = [];
11
+ // TRACK FILTER
12
+ function looksLikeTracking(code: string) {
13
+ return /\btrack\w*\s*\(/.test(code);
14
+ }
15
15
 
16
- let i = 0;
17
- const len = input.length;
16
+ // SAFE {} PARSER
17
+ function extractBracedExpressions(input: string): string[] {
18
+ const result: string[] = [];
18
19
 
19
- let inString: '"' | "'" | "`" | null = null;
20
- let escape = false;
20
+ let depth = 0;
21
+ let start = -1;
21
22
 
22
- while (i < len) {
23
- const ch = input[i];
23
+ for (let i = 0; i < input.length; i++) {
24
+ const char = input[i];
24
25
 
25
- if (inString) {
26
- if (escape) escape = false;
27
- else if (ch === "\\") escape = true;
28
- else if (ch === inString) inString = null;
29
- i++;
30
- continue;
26
+ if (char === "{") {
27
+ if (depth === 0) start = i + 1;
28
+ depth++;
29
+ } else if (char === "}") {
30
+ depth--;
31
+ if (depth === 0 && start !== -1) {
32
+ const expr = input.slice(start, i);
33
+ if (looksLikeTracking(expr)) {
34
+ result.push(expr);
35
+ }
36
+ start = -1;
37
+ }
31
38
  }
39
+ }
32
40
 
33
- if (ch === '"' || ch === "'" || ch === "`") {
34
- inString = ch;
35
- i++;
36
- continue;
37
- }
41
+ return result;
42
+ }
38
43
 
39
- if (ch === "{") {
40
- let depth = 1;
41
- let j = i + 1;
44
+ // HTML handlers
45
+ function extractHTMLHandlers(input: string): string[] {
46
+ const result: string[] = [];
42
47
 
43
- while (j < len && depth > 0) {
44
- if (input[j] === "{") depth++;
45
- else if (input[j] === "}") depth--;
46
- j++;
47
- }
48
+ const regex = /\bon\w+\s*=\s*["']([^"']+)["']/g;
48
49
 
49
- if (depth === 0) {
50
- const expr = input.slice(i + 1, j - 1).trim();
50
+ for (const m of input.matchAll(regex)) {
51
+ if (looksLikeTracking(m[1])) {
52
+ result.push(m[1]);
53
+ }
54
+ }
51
55
 
52
- if (expr && /[a-zA-Z0-9_$]\s*\(/.test(expr)) {
53
- result.push(expr);
54
- }
56
+ return result;
57
+ }
55
58
 
56
- i = j;
57
- continue;
58
- }
59
- }
59
+ // VUE handlers
60
+ function extractVueHandlers(input: string): string[] {
61
+ const result: string[] = [];
62
+
63
+ const regex = /(?:@|v-on:)[\w:-]+\s*=\s*["']([^"']+)["']/g;
60
64
 
61
- i++;
65
+ for (const m of input.matchAll(regex)) {
66
+ if (looksLikeTracking(m[1])) {
67
+ result.push(m[1]);
68
+ }
62
69
  }
63
70
 
64
71
  return result;
65
72
  }
66
73
 
67
- // Extract inline HTML handlers
68
- function extractInlineHandlers(input: string): string[] {
74
+ // SVELTE handlers
75
+ function extractSvelteHandlers(input: string): string[] {
69
76
  const result: string[] = [];
70
77
 
71
- const matches = input.matchAll(
72
- /\bon\w+\s*=\s*["']([^"']+)["']/g
73
- );
78
+ const regex = /\bon:[\w]+\s*=\s*{([^}]+)}/g;
74
79
 
75
- for (const m of matches) {
76
- const code = m[1];
77
- if (/[a-zA-Z0-9_$]\s*\(/.test(code)) {
78
- result.push(code);
80
+ for (const m of input.matchAll(regex)) {
81
+ if (looksLikeTracking(m[1])) {
82
+ result.push(m[1]);
79
83
  }
80
84
  }
81
85
 
82
86
  return result;
83
87
  }
84
88
 
85
- // Extract dynamic imports
86
- function extractDynamicImports(
87
- input: string,
88
- file: string
89
- ): { deps: string[]; calls: string[] } {
89
+ // SCRIPT EXTRACTION
90
+ function extractScripts(input: string, file: string) {
91
+ const scripts: string[] = [];
90
92
  const deps: string[] = [];
91
- const calls: string[] = [];
92
93
 
93
- const matches = input.matchAll(
94
- /import\(\s*["'](.+?)["']\s*\)/g
95
- );
94
+ // src scripts
95
+ const srcRegex =
96
+ /<script\b[^>]*?\bsrc=["'](.+?)["'][^>]*>/g;
96
97
 
97
- for (const m of matches) {
98
+ for (const m of input.matchAll(srcRegex)) {
99
+ const src = m[1];
100
+
101
+ const resolved = src.startsWith("/")
102
+ ? path.resolve(process.cwd(), "." + src)
103
+ : path.resolve(path.dirname(file), src);
104
+
105
+ deps.push(resolved);
106
+ }
107
+
108
+ // inline scripts
109
+ const scriptRegex =
110
+ /<script\b[^>]*>([\s\S]*?)<\/script>/g;
111
+
112
+ for (const m of input.matchAll(scriptRegex)) {
113
+ if (m[1]?.trim()) {
114
+ scripts.push(m[1]);
115
+ }
116
+ }
117
+
118
+ const noScripts = input.replace(scriptRegex, "");
119
+
120
+ return { scripts, deps, noScripts };
121
+ }
122
+
123
+ // DYNAMIC IMPORTS
124
+ function extractDynamicImports(input: string, file: string) {
125
+ const deps: string[] = [];
126
+
127
+ const regex = /import\(\s*["'](.+?)["']\s*\)/g;
128
+
129
+ for (const m of input.matchAll(regex)) {
98
130
  const mod = m[1];
99
131
 
100
132
  const resolved = mod.startsWith("/")
@@ -102,18 +134,12 @@ function extractDynamicImports(
102
134
  : path.resolve(path.dirname(file), mod);
103
135
 
104
136
  deps.push(resolved);
105
- calls.push(`import("${mod}")`);
106
137
  }
107
138
 
108
- return { deps, calls };
139
+ return deps;
109
140
  }
110
141
 
111
- // Filter only probable tracking-related code
112
- function isProbablyTracking(code: string): boolean {
113
- return /track|event|analytics/i.test(code);
114
- }
115
-
116
- // UNIVERSAL PARSER
142
+ // MAIN
117
143
  export function parseUniversal(
118
144
  content: string,
119
145
  file: string
@@ -123,66 +149,29 @@ export function parseUniversal(
123
149
 
124
150
  const clean = stripComments(content);
125
151
 
126
- // ASTRO FRONTMATTER
152
+ /* ---------- ASTRO FRONTMATTER ---------- */
127
153
  const fm = clean.match(/^---([\s\S]*?)---/);
128
154
  if (fm?.[1]) {
129
155
  parts.push(fm[1]);
130
156
  }
131
157
 
132
- // <script src="">
133
- const scriptSrc = clean.matchAll(
134
- /<script\b[^>]*?\bsrc=["'](.+?)["'][^>]*>/g
135
- );
136
-
137
- for (const s of scriptSrc) {
138
- const src = s[1];
139
-
140
- const resolved = src.startsWith("/")
141
- ? path.resolve(process.cwd(), "." + src)
142
- : path.resolve(path.dirname(file), src);
143
-
144
- deps.push(resolved);
145
- }
146
-
147
- // INLINE <script>
148
- const scripts = clean.matchAll(
149
- /<script\b([^>]*)>([\s\S]*?)<\/script>/g
150
- );
158
+ /* ---------- SCRIPTS ---------- */
159
+ const { scripts, deps: scriptDeps, noScripts } =
160
+ extractScripts(clean, file);
151
161
 
152
- for (const m of scripts) {
153
- const attrs = m[1];
162
+ parts.push(...scripts);
163
+ deps.push(...scriptDeps);
154
164
 
155
- if (/type=["']application\/json/.test(attrs)) continue;
165
+ /* ---------- HANDLERS ---------- */
166
+ parts.push(...extractHTMLHandlers(noScripts));
167
+ parts.push(...extractVueHandlers(noScripts));
168
+ parts.push(...extractSvelteHandlers(noScripts));
156
169
 
157
- if (m[2].trim()) {
158
- parts.push(m[2]);
159
- }
160
- }
161
-
162
- // REMOVE SCRIPTS → TEMPLATE PART
163
- const noScripts = clean.replace(
164
- /<script[\s\S]*?<\/script>/g,
165
- ""
166
- );
167
-
168
- // INLINE HANDLERS
169
- parts.push(
170
- ...extractInlineHandlers(noScripts).filter(isProbablyTracking)
171
- );
172
-
173
- // DYNAMIC IMPORTS
174
- const dyn = extractDynamicImports(clean, file);
175
- deps.push(...dyn.deps);
176
- parts.push(...dyn.calls.filter(isProbablyTracking));
170
+ /* ---------- JSX / TEMPLATE ---------- */
171
+ parts.push(...extractBracedExpressions(clean));
177
172
 
178
- // EXPRESSIONS
179
- const extracted = extractJS(clean);
180
-
181
- for (const e of extracted) {
182
- if (isProbablyTracking(e)) {
183
- parts.push(e + ";");
184
- }
185
- }
173
+ /* ---------- IMPORTS ---------- */
174
+ deps.push(...extractDynamicImports(clean, file));
186
175
 
187
176
  return {
188
177
  code: [...new Set(parts)].join("\n"),
package/tests/run.ts CHANGED
@@ -40,7 +40,6 @@ function ensureTestConfig(dir: string) {
40
40
  events: [],
41
41
  wrappers: [],
42
42
  functionWrappers: [],
43
- aliases: {},
44
43
  sync: {
45
44
  include: [
46
45
  "**/*.{ts,tsx,js,jsx,vue,svelte,astro}"
@@ -1,68 +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.isTrackingCall = isTrackingCall;
7
- const typescript_1 = __importDefault(require("typescript"));
8
- function isStringLike(type) {
9
- return ((type.flags & typescript_1.default.TypeFlags.StringLike) !== 0 ||
10
- (type.flags & typescript_1.default.TypeFlags.StringLiteral) !== 0);
11
- }
12
- function hasTrackLikeSignature(type, checker) {
13
- const sigs = type.getCallSignatures();
14
- for (const sig of sigs) {
15
- const params = sig.getParameters();
16
- if (!params.length)
17
- continue;
18
- const t = checker.getTypeOfSymbolAtLocation(params[0], params[0].valueDeclaration);
19
- if (isStringLike(t)) {
20
- return true;
21
- }
22
- }
23
- return false;
24
- }
25
- function isEventraLikeType(type, checker) {
26
- const props = type.getProperties();
27
- for (const prop of props) {
28
- const decl = prop.valueDeclaration ?? prop.declarations?.[0];
29
- if (!decl)
30
- continue;
31
- const t = checker.getTypeOfSymbolAtLocation(prop, decl);
32
- if (hasTrackLikeSignature(t, checker)) {
33
- return true;
34
- }
35
- }
36
- return false;
37
- }
38
- function isTrackingCall(node, checker) {
39
- const expr = node.expression;
40
- // fn(...)
41
- if (typescript_1.default.isIdentifier(expr)) {
42
- const type = checker.getTypeAtLocation(expr);
43
- if (hasTrackLikeSignature(type, checker)) {
44
- return true;
45
- }
46
- }
47
- // obj.method(...)
48
- if (typescript_1.default.isPropertyAccessExpression(expr)) {
49
- const objType = checker.getTypeAtLocation(expr.expression);
50
- // объект похож на tracker
51
- if (isEventraLikeType(objType, checker)) {
52
- return true;
53
- }
54
- // fallback
55
- const methodType = checker.getTypeAtLocation(expr.name);
56
- if (hasTrackLikeSignature(methodType, checker)) {
57
- return true;
58
- }
59
- }
60
- // obj["track"](...)
61
- if (typescript_1.default.isElementAccessExpression(expr)) {
62
- const objType = checker.getTypeAtLocation(expr.expression);
63
- if (isEventraLikeType(objType, checker)) {
64
- return true;
65
- }
66
- }
67
- return false;
68
- }
@@ -1,94 +0,0 @@
1
- import ts from "typescript";
2
-
3
- function isStringLike(type: ts.Type) {
4
- return (
5
- (type.flags & ts.TypeFlags.StringLike) !== 0 ||
6
- (type.flags & ts.TypeFlags.StringLiteral) !== 0
7
- );
8
- }
9
-
10
- function hasTrackLikeSignature(
11
- type: ts.Type,
12
- checker: ts.TypeChecker
13
- ): boolean {
14
- const sigs = type.getCallSignatures();
15
-
16
- for (const sig of sigs) {
17
- const params = sig.getParameters();
18
- if (!params.length) continue;
19
-
20
- const t = checker.getTypeOfSymbolAtLocation(
21
- params[0],
22
- params[0].valueDeclaration!
23
- );
24
-
25
- if (isStringLike(t)) {
26
- return true;
27
- }
28
- }
29
-
30
- return false;
31
- }
32
-
33
- function isEventraLikeType(
34
- type: ts.Type,
35
- checker: ts.TypeChecker
36
- ): boolean {
37
- const props = type.getProperties();
38
-
39
- for (const prop of props) {
40
- const decl = prop.valueDeclaration ?? prop.declarations?.[0];
41
- if (!decl) continue;
42
-
43
- const t = checker.getTypeOfSymbolAtLocation(prop, decl);
44
-
45
- if (hasTrackLikeSignature(t, checker)) {
46
- return true;
47
- }
48
- }
49
-
50
- return false;
51
- }
52
-
53
- export function isTrackingCall(
54
- node: ts.CallExpression,
55
- checker: ts.TypeChecker
56
- ): boolean {
57
- const expr = node.expression;
58
-
59
- // fn(...)
60
- if (ts.isIdentifier(expr)) {
61
- const type = checker.getTypeAtLocation(expr);
62
- if (hasTrackLikeSignature(type, checker)) {
63
- return true;
64
- }
65
- }
66
-
67
- // obj.method(...)
68
- if (ts.isPropertyAccessExpression(expr)) {
69
- const objType = checker.getTypeAtLocation(expr.expression);
70
-
71
- // объект похож на tracker
72
- if (isEventraLikeType(objType, checker)) {
73
- return true;
74
- }
75
-
76
- // fallback
77
- const methodType = checker.getTypeAtLocation(expr.name);
78
-
79
- if (hasTrackLikeSignature(methodType, checker)) {
80
- return true;
81
- }
82
- }
83
-
84
- // obj["track"](...)
85
- if (ts.isElementAccessExpression(expr)) {
86
- const objType = checker.getTypeAtLocation(expr.expression);
87
-
88
- if (isEventraLikeType(objType, checker)) {
89
- return true;
90
- }
91
- }
92
-
93
- return false;
94
- }