@eventra_dev/eventra-cli 0.1.20 → 0.1.22

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.
@@ -7,10 +7,10 @@ exports.resolveNodeValue = resolveNodeValue;
7
7
  const typescript_1 = __importDefault(require("typescript"));
8
8
  const exportResolver_1 = require("./exportResolver");
9
9
  function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
10
- if (seen.has(node))
11
- return null;
10
+ if (seen.has(node)) {
11
+ return { values: [], dynamic: true };
12
+ }
12
13
  seen.add(node);
13
- // param mapping
14
14
  if (typescript_1.default.isIdentifier(node) && paramMap?.has(node.text)) {
15
15
  return resolveNodeValue(paramMap.get(node.text), checker, paramMap, seen);
16
16
  }
@@ -29,15 +29,14 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
29
29
  const a = resolveNodeValue(node.whenTrue, checker, paramMap, seen);
30
30
  const b = resolveNodeValue(node.whenFalse, checker, paramMap, seen);
31
31
  return {
32
- values: [...new Set([...(a?.values ?? []), ...(b?.values ?? [])])],
32
+ values: [...new Set([...(a.values ?? []), ...(b.values ?? [])])],
33
33
  dynamic: true,
34
34
  };
35
35
  }
36
36
  if (typescript_1.default.isIdentifier(node)) {
37
37
  let symbol = checker.getSymbolAtLocation(node);
38
38
  if (!symbol)
39
- return null;
40
- // variable inline resolve FIRST
39
+ return { values: [], dynamic: true };
41
40
  for (const decl of symbol.getDeclarations() ?? []) {
42
41
  if (typescript_1.default.isVariableDeclaration(decl) && decl.initializer) {
43
42
  return resolveNodeValue(decl.initializer, checker, paramMap, seen);
@@ -45,7 +44,6 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
45
44
  }
46
45
  const original = symbol;
47
46
  symbol = (0, exportResolver_1.resolveExportedSymbol)(symbol, checker) ?? symbol;
48
- // avoid alias loop
49
47
  if (symbol !== original && (symbol.flags & typescript_1.default.SymbolFlags.Alias)) {
50
48
  symbol = checker.getAliasedSymbol(symbol);
51
49
  }
@@ -62,6 +60,7 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
62
60
  }
63
61
  }
64
62
  }
63
+ return { values: [], dynamic: true };
65
64
  }
66
65
  if (typescript_1.default.isPropertyAccessExpression(node)) {
67
66
  const symbol = checker.getSymbolAtLocation(node);
@@ -70,7 +69,6 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
70
69
  if (s.flags & typescript_1.default.SymbolFlags.Alias) {
71
70
  s = checker.getAliasedSymbol(s);
72
71
  }
73
- // ENUM support
74
72
  for (const decl of s.getDeclarations() ?? []) {
75
73
  if (typescript_1.default.isEnumMember(decl) && decl.initializer) {
76
74
  if (typescript_1.default.isStringLiteral(decl.initializer)) {
@@ -82,7 +80,6 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
82
80
  }
83
81
  }
84
82
  }
85
- // OBJECT support
86
83
  if (typescript_1.default.isIdentifier(node.expression)) {
87
84
  const objSymbol = checker.getSymbolAtLocation(node.expression);
88
85
  if (objSymbol) {
@@ -102,6 +99,7 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
102
99
  }
103
100
  }
104
101
  }
102
+ return { values: [], dynamic: true };
105
103
  }
106
104
  if (typescript_1.default.isObjectLiteralExpression(node)) {
107
105
  const values = [];
@@ -111,8 +109,7 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
111
109
  const name = prop.name.getText();
112
110
  if (name === "event") {
113
111
  const res = resolveNodeValue(prop.initializer, checker, paramMap, seen);
114
- if (res)
115
- values.push(...res.values);
112
+ values.push(...res.values);
116
113
  }
117
114
  }
118
115
  return { values, dynamic: true };
@@ -123,11 +120,16 @@ function resolveNodeValue(node, checker, paramMap, seen = new Set()) {
123
120
  const right = resolveNodeValue(node.right, checker, paramMap, seen);
124
121
  if (left && right) {
125
122
  return {
126
- values: left.values.flatMap(l => right.values.map(r => l + r)),
123
+ values: left.values.flatMap(l => right.values.length
124
+ ? right.values.map(r => l + r)
125
+ : [l + "*"]),
127
126
  dynamic: true,
128
127
  };
129
128
  }
130
129
  }
131
130
  }
132
- return null;
131
+ if (typescript_1.default.isCallExpression(node)) {
132
+ return { values: [], dynamic: true };
133
+ }
134
+ return { values: [], dynamic: true };
133
135
  }
@@ -115,10 +115,12 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
115
115
  const idx = (0, functionAnalyzer_1.findTrackParamIndex)(resolvedFn);
116
116
  if (idx !== null && node.arguments[idx]) {
117
117
  const res = (0, resolver_1.resolveNodeValue)(node.arguments[idx], checker, paramMap);
118
- res?.values.forEach(v => {
119
- if (isValidEvent(v))
120
- events.add(v);
121
- });
118
+ if (res && res.values.length) {
119
+ res.values.forEach(v => {
120
+ if (isValidEvent(v))
121
+ events.add(v);
122
+ });
123
+ }
122
124
  handled = true;
123
125
  }
124
126
  }
@@ -126,10 +128,12 @@ function scanSource(source, checker, config, visited = new Set(), depth = 0, inh
126
128
  if (!handled) {
127
129
  for (const arg of node.arguments) {
128
130
  const res = (0, resolver_1.resolveNodeValue)(arg, checker, paramMap);
129
- res?.values.forEach(v => {
130
- if (isValidEvent(v))
131
- events.add(v);
132
- });
131
+ if (res && res.values.length) {
132
+ res.values.forEach(v => {
133
+ if (isValidEvent(v))
134
+ events.add(v);
135
+ });
136
+ }
133
137
  }
134
138
  }
135
139
  // CROSS FILE
@@ -1,18 +1,20 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.processFile = processFile;
4
- const router_1 = require("./parsers/router");
7
+ const path_1 = __importDefault(require("path"));
8
+ const universal_1 = require("./universal");
5
9
  function processFile(file, content) {
6
- const parser = (0, router_1.detectParser)(file);
7
- const res = parser(content, file);
8
- const virtualFile = file.endsWith(".vue") ||
9
- file.endsWith(".svelte") ||
10
- file.endsWith(".astro")
11
- ? file + ".tsx"
10
+ const { code, deps } = (0, universal_1.parseUniversal)(content, file);
11
+ const ext = path_1.default.extname(file);
12
+ const virtualFile = /\.(vue|svelte|astro|html)$/i.test(file)
13
+ ? file.replace(ext, "") + ".tsx"
12
14
  : file;
13
15
  return {
14
- content: res.code,
16
+ content: code || "",
15
17
  virtualFile,
16
- deps: res.deps,
18
+ deps: [...new Set(deps.filter(Boolean))],
17
19
  };
18
20
  }
@@ -0,0 +1,179 @@
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
+ * exact JS:
10
+ * - {...}
11
+ * - attr="..."
12
+ * - Vue / Svelte handlers
13
+ */
14
+ function extractJS(input) {
15
+ const result = [];
16
+ let i = 0;
17
+ const len = input.length;
18
+ let inString = null;
19
+ let escape = false;
20
+ while (i < len) {
21
+ const ch = input[i];
22
+ // STRING
23
+ if (inString) {
24
+ if (escape)
25
+ escape = false;
26
+ else if (ch === "\\")
27
+ escape = true;
28
+ else if (ch === inString)
29
+ inString = null;
30
+ i++;
31
+ continue;
32
+ }
33
+ if (ch === '"' || ch === "'" || ch === "`") {
34
+ inString = ch;
35
+ i++;
36
+ continue;
37
+ }
38
+ // { ... }
39
+ if (ch === "{") {
40
+ let depth = 1;
41
+ let j = i + 1;
42
+ let innerStr = null;
43
+ let innerEsc = false;
44
+ while (j < len && depth > 0) {
45
+ const c = input[j];
46
+ if (innerStr) {
47
+ if (innerEsc)
48
+ innerEsc = false;
49
+ else if (c === "\\")
50
+ innerEsc = true;
51
+ else if (c === innerStr)
52
+ innerStr = null;
53
+ j++;
54
+ continue;
55
+ }
56
+ if (c === '"' || c === "'" || c === "`") {
57
+ innerStr = c;
58
+ j++;
59
+ continue;
60
+ }
61
+ if (c === "{")
62
+ depth++;
63
+ else if (c === "}")
64
+ depth--;
65
+ j++;
66
+ }
67
+ if (depth === 0) {
68
+ const expr = input.slice(i + 1, j - 1).trim();
69
+ if (expr)
70
+ result.push(expr);
71
+ i = j;
72
+ continue;
73
+ }
74
+ }
75
+ // attr="..."
76
+ if (ch === "=" && (input[i + 1] === '"' || input[i + 1] === "'")) {
77
+ const quote = input[i + 1];
78
+ let j = i + 2;
79
+ let val = "";
80
+ while (j < len) {
81
+ const c = input[j];
82
+ if (c === "\\" && input[j + 1]) {
83
+ val += c + input[j + 1];
84
+ j += 2;
85
+ continue;
86
+ }
87
+ if (c === quote)
88
+ break;
89
+ val += c;
90
+ j++;
91
+ }
92
+ if (val.trim())
93
+ result.push(val.trim());
94
+ i = j + 1;
95
+ continue;
96
+ }
97
+ i++;
98
+ }
99
+ // Vue / Svelte / JSX handlers
100
+ const extra = [
101
+ /@[\w-]+\s*=\s*["']([\s\S]*?)["']/g,
102
+ /v-on:[\w-]+\s*=\s*["']([\s\S]*?)["']/g,
103
+ /on:[\w-]+\s*=\s*{([\s\S]*?)}/g,
104
+ /on\w+\s*=\s*{([\s\S]*?)}/g,
105
+ ];
106
+ for (const r of extra) {
107
+ const m = input.matchAll(r);
108
+ for (const x of m) {
109
+ const v = x[1]?.trim();
110
+ if (v)
111
+ result.push(v);
112
+ }
113
+ }
114
+ return result;
115
+ }
116
+ function extractLooseJS(input) {
117
+ const result = [];
118
+ const lines = input.split("\n");
119
+ for (const line of lines) {
120
+ const l = line.trim();
121
+ if (!l)
122
+ continue;
123
+ if (l.startsWith("<"))
124
+ continue;
125
+ if (l.includes("(") ||
126
+ l.includes("=") ||
127
+ l.includes("=>") ||
128
+ l.includes("function") ||
129
+ l.includes("track")) {
130
+ result.push(l);
131
+ }
132
+ }
133
+ return result;
134
+ }
135
+ /**
136
+ * Universal:
137
+ * - Astro
138
+ * - Vue
139
+ * - Svelte
140
+ * - React / JSX
141
+ * - Node / backend
142
+ */
143
+ function parseUniversal(content, file) {
144
+ const parts = [];
145
+ const deps = [];
146
+ // Astro frontmatter ---
147
+ const fm = content.match(/^---([\s\S]*?)---/);
148
+ if (fm?.[1])
149
+ parts.push(fm[1]);
150
+ // <script src="">
151
+ const scriptSrc = content.matchAll(/<script\b[^>]*?\bsrc=["'](.+?)["'][^>]*>/g);
152
+ for (const s of scriptSrc) {
153
+ const src = s[1];
154
+ const resolved = src.startsWith("/")
155
+ ? path_1.default.resolve(process.cwd(), "." + src)
156
+ : path_1.default.resolve(path_1.default.dirname(file), src);
157
+ deps.push(resolved);
158
+ }
159
+ // inline <script>
160
+ const scripts = content.matchAll(/<script\b[^>]*>([\s\S]*?)<\/script>/g);
161
+ for (const m of scripts) {
162
+ if (m[1].trim())
163
+ parts.push(m[1]);
164
+ }
165
+ const noScripts = content.replace(/<script[\s\S]*?<\/script>/g, "");
166
+ const loose = extractLooseJS(noScripts);
167
+ for (const l of loose) {
168
+ parts.push(l);
169
+ }
170
+ // expressions
171
+ const extracted = extractJS(content);
172
+ for (const e of extracted) {
173
+ parts.push(e + ";");
174
+ }
175
+ return {
176
+ code: [...new Set(parts)].join("\n"),
177
+ deps,
178
+ };
179
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventra_dev/eventra-cli",
3
- "version": "0.1.20",
3
+ "version": "0.1.22",
4
4
  "description": "Eventra CLI",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -11,12 +11,13 @@ export function resolveNodeValue(
11
11
  checker: ts.TypeChecker,
12
12
  paramMap?: Map<string, ts.Expression>,
13
13
  seen = new Set<ts.Node>()
14
- ): ResolveResult | null {
14
+ ): ResolveResult {
15
15
 
16
- if (seen.has(node)) return null;
16
+ if (seen.has(node)) {
17
+ return { values: [], dynamic: true };
18
+ }
17
19
  seen.add(node);
18
20
 
19
- // param mapping
20
21
  if (ts.isIdentifier(node) && paramMap?.has(node.text)) {
21
22
  return resolveNodeValue(
22
23
  paramMap.get(node.text)!,
@@ -46,16 +47,15 @@ export function resolveNodeValue(
46
47
  const b = resolveNodeValue(node.whenFalse, checker, paramMap, seen);
47
48
 
48
49
  return {
49
- values: [...new Set([...(a?.values ?? []), ...(b?.values ?? [])])],
50
+ values: [...new Set([...(a.values ?? []), ...(b.values ?? [])])],
50
51
  dynamic: true,
51
52
  };
52
53
  }
53
54
 
54
55
  if (ts.isIdentifier(node)) {
55
56
  let symbol = checker.getSymbolAtLocation(node);
56
- if (!symbol) return null;
57
+ if (!symbol) return { values: [], dynamic: true };
57
58
 
58
- // variable inline resolve FIRST
59
59
  for (const decl of symbol.getDeclarations() ?? []) {
60
60
  if (ts.isVariableDeclaration(decl) && decl.initializer) {
61
61
  return resolveNodeValue(
@@ -71,7 +71,6 @@ export function resolveNodeValue(
71
71
 
72
72
  symbol = resolveExportedSymbol(symbol, checker) ?? symbol;
73
73
 
74
- // avoid alias loop
75
74
  if (symbol !== original && (symbol.flags & ts.SymbolFlags.Alias)) {
76
75
  symbol = checker.getAliasedSymbol(symbol);
77
76
  }
@@ -95,6 +94,8 @@ export function resolveNodeValue(
95
94
  }
96
95
  }
97
96
  }
97
+
98
+ return { values: [], dynamic: true };
98
99
  }
99
100
 
100
101
  if (ts.isPropertyAccessExpression(node)) {
@@ -107,7 +108,6 @@ export function resolveNodeValue(
107
108
  s = checker.getAliasedSymbol(s);
108
109
  }
109
110
 
110
- // ENUM support
111
111
  for (const decl of s.getDeclarations() ?? []) {
112
112
  if (ts.isEnumMember(decl) && decl.initializer) {
113
113
  if (ts.isStringLiteral(decl.initializer)) {
@@ -120,7 +120,6 @@ export function resolveNodeValue(
120
120
  }
121
121
  }
122
122
 
123
- // OBJECT support
124
123
  if (ts.isIdentifier(node.expression)) {
125
124
  const objSymbol = checker.getSymbolAtLocation(node.expression);
126
125
 
@@ -149,6 +148,8 @@ export function resolveNodeValue(
149
148
  }
150
149
  }
151
150
  }
151
+
152
+ return { values: [], dynamic: true };
152
153
  }
153
154
 
154
155
  if (ts.isObjectLiteralExpression(node)) {
@@ -161,7 +162,7 @@ export function resolveNodeValue(
161
162
 
162
163
  if (name === "event") {
163
164
  const res = resolveNodeValue(prop.initializer, checker, paramMap, seen);
164
- if (res) values.push(...res.values);
165
+ values.push(...res.values);
165
166
  }
166
167
  }
167
168
 
@@ -176,7 +177,9 @@ export function resolveNodeValue(
176
177
  if (left && right) {
177
178
  return {
178
179
  values: left.values.flatMap(l =>
179
- right.values.map(r => l + r)
180
+ right.values.length
181
+ ? right.values.map(r => l + r)
182
+ : [l + "*"]
180
183
  ),
181
184
  dynamic: true,
182
185
  };
@@ -184,5 +187,9 @@ export function resolveNodeValue(
184
187
  }
185
188
  }
186
189
 
187
- return null;
190
+ if (ts.isCallExpression(node)) {
191
+ return { values: [], dynamic: true };
192
+ }
193
+
194
+ return { values: [], dynamic: true };
188
195
  }
@@ -166,9 +166,11 @@ export function scanSource(
166
166
  paramMap
167
167
  );
168
168
 
169
- res?.values.forEach(v => {
170
- if (isValidEvent(v)) events.add(v);
171
- });
169
+ if (res && res.values.length) {
170
+ res.values.forEach(v => {
171
+ if (isValidEvent(v)) events.add(v);
172
+ });
173
+ }
172
174
 
173
175
  handled = true;
174
176
  }
@@ -179,9 +181,11 @@ export function scanSource(
179
181
  for (const arg of node.arguments) {
180
182
  const res = resolveNodeValue(arg, checker, paramMap);
181
183
 
182
- res?.values.forEach(v => {
183
- if (isValidEvent(v)) events.add(v);
184
- });
184
+ if (res && res.values.length) {
185
+ res.values.forEach(v => {
186
+ if (isValidEvent(v)) events.add(v);
187
+ });
188
+ }
185
189
  }
186
190
  }
187
191
 
@@ -1,20 +1,19 @@
1
- import { detectParser } from "./parsers/router";
1
+ import path from "path";
2
+ import { parseUniversal } from "./universal";
2
3
 
3
4
  export function processFile(file: string, content: string) {
4
- const parser = detectParser(file);
5
+ const { code, deps } = parseUniversal(content, file);
5
6
 
6
- const res = parser(content, file);
7
+ const ext = path.extname(file);
7
8
 
8
9
  const virtualFile =
9
- file.endsWith(".vue") ||
10
- file.endsWith(".svelte") ||
11
- file.endsWith(".astro")
12
- ? file + ".tsx"
10
+ /\.(vue|svelte|astro|html)$/i.test(file)
11
+ ? file.replace(ext, "") + ".tsx"
13
12
  : file;
14
13
 
15
14
  return {
16
- content: res.code,
15
+ content: code || "",
17
16
  virtualFile,
18
- deps: res.deps,
17
+ deps: [...new Set(deps.filter(Boolean))],
19
18
  };
20
19
  }
@@ -0,0 +1,217 @@
1
+ import path from "path";
2
+ import { ParseResult } from "../types";
3
+
4
+ /**
5
+ * exact JS:
6
+ * - {...}
7
+ * - attr="..."
8
+ * - Vue / Svelte handlers
9
+ */
10
+ function extractJS(input: string): string[] {
11
+ const result: string[] = [];
12
+
13
+ let i = 0;
14
+ const len = input.length;
15
+
16
+ let inString: '"' | "'" | "`" | null = null;
17
+ let escape = false;
18
+
19
+ while (i < len) {
20
+ const ch = input[i];
21
+
22
+ // STRING
23
+ if (inString) {
24
+ if (escape) escape = false;
25
+ else if (ch === "\\") escape = true;
26
+ else if (ch === inString) inString = null;
27
+
28
+ i++;
29
+ continue;
30
+ }
31
+
32
+ if (ch === '"' || ch === "'" || ch === "`") {
33
+ inString = ch;
34
+ i++;
35
+ continue;
36
+ }
37
+
38
+ // { ... }
39
+ if (ch === "{") {
40
+ let depth = 1;
41
+ let j = i + 1;
42
+
43
+ let innerStr: '"' | "'" | "`" | null = null;
44
+ let innerEsc = false;
45
+
46
+ while (j < len && depth > 0) {
47
+ const c = input[j];
48
+
49
+ if (innerStr) {
50
+ if (innerEsc) innerEsc = false;
51
+ else if (c === "\\") innerEsc = true;
52
+ else if (c === innerStr) innerStr = null;
53
+ j++;
54
+ continue;
55
+ }
56
+
57
+ if (c === '"' || c === "'" || c === "`") {
58
+ innerStr = c;
59
+ j++;
60
+ continue;
61
+ }
62
+
63
+ if (c === "{") depth++;
64
+ else if (c === "}") depth--;
65
+
66
+ j++;
67
+ }
68
+
69
+ if (depth === 0) {
70
+ const expr = input.slice(i + 1, j - 1).trim();
71
+ if (expr) result.push(expr);
72
+ i = j;
73
+ continue;
74
+ }
75
+ }
76
+
77
+ // attr="..."
78
+ if (ch === "=" && (input[i + 1] === '"' || input[i + 1] === "'")) {
79
+ const quote = input[i + 1];
80
+ let j = i + 2;
81
+ let val = "";
82
+
83
+ while (j < len) {
84
+ const c = input[j];
85
+
86
+ if (c === "\\" && input[j + 1]) {
87
+ val += c + input[j + 1];
88
+ j += 2;
89
+ continue;
90
+ }
91
+
92
+ if (c === quote) break;
93
+
94
+ val += c;
95
+ j++;
96
+ }
97
+
98
+ if (val.trim()) result.push(val.trim());
99
+
100
+ i = j + 1;
101
+ continue;
102
+ }
103
+
104
+ i++;
105
+ }
106
+
107
+ // Vue / Svelte / JSX handlers
108
+ const extra = [
109
+ /@[\w-]+\s*=\s*["']([\s\S]*?)["']/g,
110
+ /v-on:[\w-]+\s*=\s*["']([\s\S]*?)["']/g,
111
+ /on:[\w-]+\s*=\s*{([\s\S]*?)}/g,
112
+ /on\w+\s*=\s*{([\s\S]*?)}/g,
113
+ ];
114
+
115
+ for (const r of extra) {
116
+ const m = input.matchAll(r);
117
+ for (const x of m) {
118
+ const v = x[1]?.trim();
119
+ if (v) result.push(v);
120
+ }
121
+ }
122
+
123
+ return result;
124
+ }
125
+
126
+ function extractLooseJS(input: string): string[] {
127
+ const result: string[] = [];
128
+
129
+ const lines = input.split("\n");
130
+
131
+ for (const line of lines) {
132
+ const l = line.trim();
133
+
134
+ if (!l) continue;
135
+ if (l.startsWith("<")) continue;
136
+
137
+ if (
138
+ l.includes("(") ||
139
+ l.includes("=") ||
140
+ l.includes("=>") ||
141
+ l.includes("function") ||
142
+ l.includes("track")
143
+ ) {
144
+ result.push(l);
145
+ }
146
+ }
147
+
148
+ return result;
149
+ }
150
+
151
+ /**
152
+ * Universal:
153
+ * - Astro
154
+ * - Vue
155
+ * - Svelte
156
+ * - React / JSX
157
+ * - Node / backend
158
+ */
159
+
160
+ export function parseUniversal(
161
+ content: string,
162
+ file: string
163
+ ): ParseResult {
164
+ const parts: string[] = [];
165
+ const deps: string[] = [];
166
+
167
+ // Astro frontmatter ---
168
+ const fm = content.match(/^---([\s\S]*?)---/);
169
+ if (fm?.[1]) parts.push(fm[1]);
170
+
171
+ // <script src="">
172
+ const scriptSrc = content.matchAll(
173
+ /<script\b[^>]*?\bsrc=["'](.+?)["'][^>]*>/g
174
+ );
175
+
176
+ for (const s of scriptSrc) {
177
+ const src = s[1];
178
+
179
+ const resolved = src.startsWith("/")
180
+ ? path.resolve(process.cwd(), "." + src)
181
+ : path.resolve(path.dirname(file), src);
182
+
183
+ deps.push(resolved);
184
+ }
185
+
186
+ // inline <script>
187
+ const scripts = content.matchAll(
188
+ /<script\b[^>]*>([\s\S]*?)<\/script>/g
189
+ );
190
+
191
+ for (const m of scripts) {
192
+ if (m[1].trim()) parts.push(m[1]);
193
+ }
194
+
195
+ const noScripts = content.replace(
196
+ /<script[\s\S]*?<\/script>/g,
197
+ ""
198
+ );
199
+
200
+ const loose = extractLooseJS(noScripts);
201
+
202
+ for (const l of loose) {
203
+ parts.push(l);
204
+ }
205
+
206
+ // expressions
207
+ const extracted = extractJS(content);
208
+
209
+ for (const e of extracted) {
210
+ parts.push(e + ";");
211
+ }
212
+
213
+ return {
214
+ code: [...new Set(parts)].join("\n"),
215
+ deps,
216
+ };
217
+ }
@@ -1,49 +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.parseAstro = parseAstro;
7
- const path_1 = __importDefault(require("path"));
8
- const utils_1 = require("./utils");
9
- function parseAstro(content, file) {
10
- const parts = [];
11
- const deps = [];
12
- // frontmatter
13
- const frontmatter = content.match(/^---([\s\S]*?)---/);
14
- if (frontmatter?.[1]) {
15
- parts.push(frontmatter[1]);
16
- }
17
- // scripts
18
- const scripts = content.matchAll(/<script([^>]*)>([\s\S]*?)<\/script>/g);
19
- for (const m of scripts) {
20
- const attrs = m[1];
21
- const body = m[2];
22
- // external script
23
- if (attrs.includes("src")) {
24
- const src = attrs.match(/src=["'](.+?)["']/)?.[1];
25
- if (!src)
26
- continue;
27
- let resolved;
28
- if (src.startsWith("/")) {
29
- resolved = path_1.default.join(process.cwd(), src); // FIX
30
- }
31
- else {
32
- resolved = path_1.default.resolve(path_1.default.dirname(file), src);
33
- }
34
- deps.push(resolved);
35
- continue;
36
- }
37
- parts.push(body);
38
- const imports = body.matchAll(/import\s+.*?from\s+["'](.+?)["']/g);
39
- for (const im of imports) {
40
- const resolved = (0, utils_1.resolveImport)(file, im[1]);
41
- if (resolved)
42
- deps.push(resolved);
43
- }
44
- }
45
- return {
46
- code: parts.join("\n"),
47
- deps,
48
- };
49
- }
@@ -1,20 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.detectParser = detectParser;
4
- const vue_1 = require("./vue");
5
- const svelte_1 = require("./svelte");
6
- const astro_1 = require("./astro");
7
- const fallback = (content) => ({
8
- code: content,
9
- deps: [],
10
- });
11
- function detectParser(file) {
12
- const f = file.toLowerCase();
13
- if (f.endsWith(".vue"))
14
- return vue_1.parseVue;
15
- if (f.endsWith(".svelte"))
16
- return svelte_1.parseSvelte;
17
- if (f.endsWith(".astro"))
18
- return astro_1.parseAstro;
19
- return fallback;
20
- }
@@ -1,30 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseSvelte = parseSvelte;
4
- const utils_1 = require("./utils");
5
- function parseSvelte(content, file) {
6
- const parts = [];
7
- const deps = [];
8
- // script
9
- const scripts = content.matchAll(/<script[^>]*>([\s\S]*?)<\/script>/g);
10
- for (const m of scripts) {
11
- const code = m[1];
12
- parts.push(code);
13
- // imports
14
- const imports = code.matchAll(/import\s+.*?from\s+["'](.+?)["']/g);
15
- for (const im of imports) {
16
- const resolved = (0, utils_1.resolveImport)(file, im[1]);
17
- if (resolved)
18
- deps.push(resolved);
19
- }
20
- }
21
- // handlers
22
- const handlers = content.matchAll(/on:\w+=\{([^}]+)\}/g);
23
- for (const h of handlers) {
24
- parts.push(h[1] + ";");
25
- }
26
- return {
27
- code: parts.join("\n"),
28
- deps,
29
- };
30
- }
@@ -1,21 +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.resolveImport = resolveImport;
7
- const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
9
- function resolveImport(from, src) {
10
- if (!src.startsWith("."))
11
- return null;
12
- const base = path_1.default.resolve(path_1.default.dirname(from), src);
13
- const exts = [".ts", ".tsx", ".js", ".jsx"];
14
- for (const ext of exts) {
15
- if (fs_1.default.existsSync(base + ext))
16
- return base + ext;
17
- }
18
- if (fs_1.default.existsSync(base))
19
- return base;
20
- return null;
21
- }
@@ -1,59 +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.parseVue = parseVue;
7
- const path_1 = __importDefault(require("path"));
8
- const utils_1 = require("./utils");
9
- function parseVue(content, file) {
10
- const parts = [];
11
- const deps = [];
12
- // SCRIPT
13
- const scripts = content.matchAll(/<script([^>]*)>([\s\S]*?)<\/script>/g);
14
- for (const m of scripts) {
15
- const attrs = m[1];
16
- const body = m[2];
17
- if (attrs.includes("src")) {
18
- const src = attrs.match(/src=["'](.+?)["']/)?.[1];
19
- if (!src)
20
- continue;
21
- const resolved = src.startsWith("/")
22
- ? path_1.default.join(process.cwd(), src)
23
- : path_1.default.resolve(path_1.default.dirname(file), src);
24
- deps.push(resolved);
25
- continue;
26
- }
27
- parts.push(body);
28
- // imports
29
- const imports = body.matchAll(/import\s+.*?from\s+["'](.+?)["']/g);
30
- for (const im of imports) {
31
- const resolved = (0, utils_1.resolveImport)(file, im[1]);
32
- if (resolved)
33
- deps.push(resolved);
34
- }
35
- }
36
- // TEMPLATE
37
- const templateMatch = content.match(/<template[^>]*>([\s\S]*?)<\/template>/);
38
- let template = templateMatch?.[1] ?? "";
39
- template = template.replace(/<!--[\s\S]*?-->/g, "");
40
- // @click
41
- const handlers = template.matchAll(/@[\w-]+="([^"]+)"/g);
42
- for (const h of handlers) {
43
- parts.push(h[1] + ";");
44
- }
45
- // v-on
46
- const vOn = template.matchAll(/v-on:[\w-]+="([^"]+)"/g);
47
- for (const v of vOn) {
48
- parts.push(v[1] + ";");
49
- }
50
- // :bind
51
- const binds = template.matchAll(/:[\w-]+="([^"]+)"/g);
52
- for (const b of binds) {
53
- parts.push(b[1] + ";");
54
- }
55
- return {
56
- code: parts.join("\n"),
57
- deps,
58
- };
59
- }
@@ -1,53 +0,0 @@
1
- import path from "path";
2
- import { ParseResult } from "../../types";
3
- import { resolveImport } from "./utils";
4
-
5
- export function parseAstro(content: string, file: string): ParseResult {
6
- const parts: string[] = [];
7
- const deps: string[] = [];
8
-
9
- // frontmatter
10
- const frontmatter = content.match(/^---([\s\S]*?)---/);
11
- if (frontmatter?.[1]) {
12
- parts.push(frontmatter[1]);
13
- }
14
-
15
- // scripts
16
- const scripts = content.matchAll(/<script([^>]*)>([\s\S]*?)<\/script>/g);
17
-
18
- for (const m of scripts) {
19
- const attrs = m[1];
20
- const body = m[2];
21
-
22
- // external script
23
- if (attrs.includes("src")) {
24
- const src = attrs.match(/src=["'](.+?)["']/)?.[1];
25
- if (!src) continue;
26
-
27
- let resolved: string;
28
-
29
- if (src.startsWith("/")) {
30
- resolved = path.join(process.cwd(), src); // FIX
31
- } else {
32
- resolved = path.resolve(path.dirname(file), src);
33
- }
34
-
35
- deps.push(resolved);
36
- continue;
37
- }
38
-
39
- parts.push(body);
40
-
41
- const imports = body.matchAll(/import\s+.*?from\s+["'](.+?)["']/g);
42
-
43
- for (const im of imports) {
44
- const resolved = resolveImport(file, im[1]);
45
- if (resolved) deps.push(resolved);
46
- }
47
- }
48
-
49
- return {
50
- code: parts.join("\n"),
51
- deps,
52
- };
53
- }
@@ -1,19 +0,0 @@
1
- import { Parser } from "../../types";
2
- import { parseVue } from "./vue";
3
- import { parseSvelte } from "./svelte";
4
- import { parseAstro } from "./astro";
5
-
6
- const fallback: Parser = (content) => ({
7
- code: content,
8
- deps: [],
9
- });
10
-
11
- export function detectParser(file: string): Parser {
12
- const f = file.toLowerCase();
13
-
14
- if (f.endsWith(".vue")) return parseVue;
15
- if (f.endsWith(".svelte")) return parseSvelte;
16
- if (f.endsWith(".astro")) return parseAstro;
17
-
18
- return fallback;
19
- }
@@ -1,36 +0,0 @@
1
- import { ParseResult } from "../../types";
2
- import { resolveImport } from "./utils";
3
-
4
- export function parseSvelte(content: string, file: string): ParseResult {
5
- const parts: string[] = [];
6
- const deps: string[] = [];
7
-
8
- // script
9
- const scripts = content.matchAll(/<script[^>]*>([\s\S]*?)<\/script>/g);
10
-
11
- for (const m of scripts) {
12
- const code = m[1];
13
-
14
- parts.push(code);
15
-
16
- // imports
17
- const imports = code.matchAll(/import\s+.*?from\s+["'](.+?)["']/g);
18
-
19
- for (const im of imports) {
20
- const resolved = resolveImport(file, im[1]);
21
- if (resolved) deps.push(resolved);
22
- }
23
- }
24
-
25
- // handlers
26
- const handlers = content.matchAll(/on:\w+=\{([^}]+)\}/g);
27
-
28
- for (const h of handlers) {
29
- parts.push(h[1] + ";");
30
- }
31
-
32
- return {
33
- code: parts.join("\n"),
34
- deps,
35
- };
36
- }
@@ -1,18 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
-
4
- export function resolveImport(from: string, src: string): string | null {
5
- if (!src.startsWith(".")) return null;
6
-
7
- const base = path.resolve(path.dirname(from), src);
8
-
9
- const exts = [".ts", ".tsx", ".js", ".jsx"];
10
-
11
- for (const ext of exts) {
12
- if (fs.existsSync(base + ext)) return base + ext;
13
- }
14
-
15
- if (fs.existsSync(base)) return base;
16
-
17
- return null;
18
- }
@@ -1,67 +0,0 @@
1
- import path from "path";
2
- import { ParseResult } from "../../types";
3
- import { resolveImport } from "./utils";
4
-
5
- export function parseVue(content: string, file: string): ParseResult {
6
- const parts: string[] = [];
7
- const deps: string[] = [];
8
-
9
- // SCRIPT
10
- const scripts = content.matchAll(/<script([^>]*)>([\s\S]*?)<\/script>/g);
11
-
12
- for (const m of scripts) {
13
- const attrs = m[1];
14
- const body = m[2];
15
-
16
- if (attrs.includes("src")) {
17
- const src = attrs.match(/src=["'](.+?)["']/)?.[1];
18
- if (!src) continue;
19
-
20
- const resolved = src.startsWith("/")
21
- ? path.join(process.cwd(), src)
22
- : path.resolve(path.dirname(file), src);
23
-
24
- deps.push(resolved);
25
- continue;
26
- }
27
-
28
- parts.push(body);
29
-
30
- // imports
31
- const imports = body.matchAll(/import\s+.*?from\s+["'](.+?)["']/g);
32
-
33
- for (const im of imports) {
34
- const resolved = resolveImport(file, im[1]);
35
- if (resolved) deps.push(resolved);
36
- }
37
- }
38
-
39
- // TEMPLATE
40
- const templateMatch = content.match(/<template[^>]*>([\s\S]*?)<\/template>/);
41
- let template = templateMatch?.[1] ?? "";
42
-
43
- template = template.replace(/<!--[\s\S]*?-->/g, "");
44
-
45
- // @click
46
- const handlers = template.matchAll(/@[\w-]+="([^"]+)"/g);
47
- for (const h of handlers) {
48
- parts.push(h[1] + ";");
49
- }
50
-
51
- // v-on
52
- const vOn = template.matchAll(/v-on:[\w-]+="([^"]+)"/g);
53
- for (const v of vOn) {
54
- parts.push(v[1] + ";");
55
- }
56
-
57
- // :bind
58
- const binds = template.matchAll(/:[\w-]+="([^"]+)"/g);
59
- for (const b of binds) {
60
- parts.push(b[1] + ";");
61
- }
62
-
63
- return {
64
- code: parts.join("\n"),
65
- deps,
66
- };
67
- }