@eventra_dev/eventra-cli 0.0.17 → 0.0.19
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 +91 -94
- package/dist/commands/check.js +153 -0
- package/dist/commands/sync.js +93 -53
- package/dist/commands/watch.js +97 -0
- package/dist/index.js +14 -3
- package/dist/utils/detect-aliases.js +39 -0
- package/dist/utils/detect-wrappers.js +84 -0
- package/dist/utils/extract.js +18 -98
- package/dist/utils/scanners/component-wrappers.js +23 -20
- package/dist/utils/scanners/function-wrappers.js +16 -18
- package/dist/utils/scanners/track.js +20 -8
- package/package.json +2 -1
- package/src/commands/check.ts +197 -0
- package/src/commands/sync.ts +170 -110
- package/src/commands/watch.ts +113 -0
- package/src/index.ts +16 -3
- package/src/types.ts +4 -0
- package/src/utils/detect-aliases.ts +46 -0
- package/src/utils/detect-wrappers.ts +119 -0
- package/src/utils/extract.ts +20 -133
- package/src/utils/scanners/component-wrappers.ts +27 -25
- package/src/utils/scanners/function-wrappers.ts +47 -90
- package/src/utils/scanners/track.ts +23 -8
package/README.md
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
<p align="center">
|
|
2
3
|
<img src="./assets/eventra-icon-animated.svg" width="120">
|
|
3
4
|
</p>
|
|
@@ -7,56 +8,22 @@
|
|
|
7
8
|
[](https://www.npmjs.com/package/@eventra_dev/eventra-cli)
|
|
8
9
|
[](https://www.npmjs.com/package/@eventra_dev/eventra-cli)
|
|
9
10
|
[](https://www.typescriptlang.org/)
|
|
10
|
-
[]()
|
|
11
11
|
[]()
|
|
12
12
|
|
|
13
13
|
Eventra CLI automatically discovers feature usage events in your codebase and syncs them with Eventra.
|
|
14
14
|
|
|
15
|
-
Eventra CLI helps you:
|
|
16
|
-
|
|
17
|
-
- Discover feature usage automatically
|
|
18
|
-
- Detect wrapper components
|
|
19
|
-
- Detect wrapper functions
|
|
20
|
-
- Keep events in sync
|
|
21
|
-
- Register features in Eventra
|
|
22
|
-
- Maintain consistent event naming
|
|
23
|
-
|
|
24
|
-
It is designed to be:
|
|
25
|
-
|
|
26
|
-
- framework-agnostic
|
|
27
|
-
- static analysis based
|
|
28
|
-
- zero runtime overhead
|
|
29
|
-
- production-safe
|
|
30
|
-
- backend + frontend compatible
|
|
31
|
-
|
|
32
15
|
---
|
|
33
16
|
|
|
34
17
|
# Installation
|
|
35
18
|
|
|
36
|
-
### npm
|
|
37
|
-
|
|
38
19
|
```bash
|
|
39
20
|
npm install -D @eventra_dev/eventra-cli
|
|
40
21
|
```
|
|
41
22
|
|
|
42
|
-
### pnpm
|
|
43
|
-
|
|
44
23
|
```bash
|
|
45
24
|
pnpm add -D @eventra_dev/eventra-cli
|
|
46
25
|
```
|
|
47
26
|
|
|
48
|
-
### yarn
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
yarn add -D @eventra_dev/eventra-cli
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### npx
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
npx eventra init
|
|
58
|
-
```
|
|
59
|
-
|
|
60
27
|
---
|
|
61
28
|
|
|
62
29
|
# Quick Start
|
|
@@ -64,6 +31,7 @@ npx eventra init
|
|
|
64
31
|
```bash
|
|
65
32
|
eventra init
|
|
66
33
|
eventra sync
|
|
34
|
+
eventra check
|
|
67
35
|
eventra send
|
|
68
36
|
```
|
|
69
37
|
|
|
@@ -75,75 +43,93 @@ eventra send
|
|
|
75
43
|
|
|
76
44
|
Creates `eventra.json` configuration file.
|
|
77
45
|
|
|
78
|
-
```bash
|
|
79
|
-
eventra init
|
|
80
|
-
```
|
|
81
|
-
|
|
82
46
|
---
|
|
83
47
|
|
|
84
48
|
## eventra sync
|
|
85
49
|
|
|
86
50
|
Scans your project and discovers events automatically.
|
|
87
51
|
|
|
88
|
-
|
|
52
|
+
Supports:
|
|
89
53
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
54
|
+
- track("event")
|
|
55
|
+
- analytics.track("event")
|
|
56
|
+
- function wrappers
|
|
57
|
+
- component wrappers
|
|
58
|
+
- aliases
|
|
93
59
|
|
|
94
|
-
|
|
95
|
-
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## eventra check
|
|
63
|
+
|
|
64
|
+
Validate events without modifying config.
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
eventra check
|
|
96
68
|
```
|
|
97
69
|
|
|
98
|
-
|
|
70
|
+
### Detects:
|
|
99
71
|
|
|
100
|
-
|
|
72
|
+
- New events
|
|
73
|
+
- Unresolved dynamic events
|
|
74
|
+
|
|
75
|
+
### Output example:
|
|
101
76
|
|
|
102
|
-
```tsx
|
|
103
|
-
<TrackedButton event="feature_created" />
|
|
104
77
|
```
|
|
78
|
+
New events:
|
|
79
|
+
+ user_click (src/Button.tsx:42)
|
|
105
80
|
|
|
106
|
-
|
|
107
|
-
|
|
81
|
+
Dynamic:
|
|
82
|
+
- eventName (src/App.tsx:10)
|
|
108
83
|
```
|
|
109
84
|
|
|
110
85
|
---
|
|
111
86
|
|
|
112
|
-
|
|
87
|
+
## eventra check --fix
|
|
113
88
|
|
|
114
|
-
|
|
115
|
-
trackFeature("feature_created")
|
|
116
|
-
```
|
|
89
|
+
Interactive auto-fix mode.
|
|
117
90
|
|
|
118
|
-
```
|
|
119
|
-
|
|
91
|
+
```bash
|
|
92
|
+
eventra check --fix
|
|
120
93
|
```
|
|
121
94
|
|
|
95
|
+
### What it does:
|
|
96
|
+
|
|
97
|
+
- Adds new events to config
|
|
98
|
+
- Resolves dynamic events via alias
|
|
99
|
+
- Allows skipping dynamic values
|
|
100
|
+
|
|
122
101
|
---
|
|
123
102
|
|
|
124
|
-
## eventra
|
|
103
|
+
## eventra watch
|
|
125
104
|
|
|
126
|
-
|
|
105
|
+
Real-time event detection.
|
|
127
106
|
|
|
128
107
|
```bash
|
|
129
|
-
eventra
|
|
108
|
+
eventra watch
|
|
130
109
|
```
|
|
131
110
|
|
|
132
|
-
|
|
111
|
+
### Features:
|
|
133
112
|
|
|
134
|
-
|
|
113
|
+
- Detects new events instantly
|
|
114
|
+
- Debounced updates
|
|
115
|
+
- No duplicates
|
|
116
|
+
- Ignores temp files
|
|
135
117
|
|
|
136
|
-
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## eventra send
|
|
137
121
|
|
|
138
|
-
|
|
122
|
+
Send events to backend.
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
eventra send
|
|
126
|
+
```
|
|
139
127
|
|
|
140
128
|
---
|
|
141
129
|
|
|
142
130
|
# Configuration
|
|
143
131
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
Example:
|
|
132
|
+
Example `eventra.json`:
|
|
147
133
|
|
|
148
134
|
```json
|
|
149
135
|
{
|
|
@@ -151,28 +137,58 @@ Example:
|
|
|
151
137
|
"events": [],
|
|
152
138
|
"wrappers": [],
|
|
153
139
|
"functionWrappers": [],
|
|
140
|
+
"aliases": {},
|
|
154
141
|
"sync": {
|
|
155
|
-
"include": ["**/*.{ts,tsx,js,jsx}"],
|
|
156
|
-
"exclude": [
|
|
157
|
-
"node_modules",
|
|
158
|
-
"dist",
|
|
159
|
-
".next",
|
|
160
|
-
".git"
|
|
161
|
-
]
|
|
142
|
+
"include": ["**/*.{ts,tsx,js,jsx,vue,svelte,astro}"],
|
|
143
|
+
"exclude": ["node_modules", "dist", ".next", ".git"]
|
|
162
144
|
}
|
|
163
145
|
}
|
|
164
146
|
```
|
|
165
147
|
|
|
166
148
|
---
|
|
167
149
|
|
|
150
|
+
# Key Concepts
|
|
151
|
+
|
|
152
|
+
### Aliases
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
const EVENT = "user_click";
|
|
156
|
+
track(EVENT);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Auto-resolved → `user_click`
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
### Dynamic events
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
track(eventName);
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Must be:
|
|
170
|
+
|
|
171
|
+
- aliased
|
|
172
|
+
- or skipped (`__skip__`)
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
### File tracking
|
|
177
|
+
|
|
178
|
+
All events include:
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
event_name (file:line)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
168
186
|
# Supported Frameworks
|
|
169
187
|
|
|
170
188
|
Frontend:
|
|
171
189
|
|
|
172
190
|
- React
|
|
173
|
-
- Next.js
|
|
174
191
|
- Vue
|
|
175
|
-
- Nuxt
|
|
176
192
|
- Svelte
|
|
177
193
|
- Astro
|
|
178
194
|
|
|
@@ -182,31 +198,12 @@ Backend:
|
|
|
182
198
|
- Express
|
|
183
199
|
- NestJS
|
|
184
200
|
- Fastify
|
|
185
|
-
- Hono
|
|
186
|
-
- Bun
|
|
187
|
-
- Deno
|
|
188
|
-
|
|
189
|
-
---
|
|
190
|
-
|
|
191
|
-
# How It Works
|
|
192
|
-
|
|
193
|
-
Eventra CLI:
|
|
194
|
-
|
|
195
|
-
1. Scans your codebase
|
|
196
|
-
2. Detects tracking calls
|
|
197
|
-
3. Detects wrapper components
|
|
198
|
-
4. Detects wrapper functions
|
|
199
|
-
5. Syncs discovered events
|
|
200
|
-
6. Registers events in Eventra
|
|
201
|
-
|
|
202
|
-
No runtime SDK required.
|
|
203
201
|
|
|
204
202
|
---
|
|
205
203
|
|
|
206
204
|
# Requirements
|
|
207
205
|
|
|
208
206
|
- Node.js 18+
|
|
209
|
-
- JavaScript / TypeScript project
|
|
210
207
|
|
|
211
208
|
---
|
|
212
209
|
|
|
@@ -0,0 +1,153 @@
|
|
|
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.check = check;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
9
|
+
const ts_morph_1 = require("ts-morph");
|
|
10
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
11
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
12
|
+
const config_1 = require("../utils/config");
|
|
13
|
+
const router_1 = require("../utils/parsers/router");
|
|
14
|
+
const vue_1 = require("../utils/parsers/vue");
|
|
15
|
+
const svelte_1 = require("../utils/parsers/svelte");
|
|
16
|
+
const astro_1 = require("../utils/parsers/astro");
|
|
17
|
+
const track_1 = require("../utils/scanners/track");
|
|
18
|
+
const function_wrappers_1 = require("../utils/scanners/function-wrappers");
|
|
19
|
+
const component_wrappers_1 = require("../utils/scanners/component-wrappers");
|
|
20
|
+
async function check({ fix = false }) {
|
|
21
|
+
const config = await (0, config_1.loadConfig)();
|
|
22
|
+
if (!config) {
|
|
23
|
+
console.log(chalk_1.default.red("eventra.json not found"));
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
console.log(chalk_1.default.blue("Checking events..."));
|
|
27
|
+
const project = new ts_morph_1.Project();
|
|
28
|
+
const knownEvents = new Set(config.events ?? []);
|
|
29
|
+
const aliases = { ...(config.aliases ?? {}) };
|
|
30
|
+
const foundEvents = new Map();
|
|
31
|
+
const newEvents = new Map();
|
|
32
|
+
const unresolvedDynamic = new Map();
|
|
33
|
+
const files = await (0, fast_glob_1.default)(config.sync.include, {
|
|
34
|
+
ignore: config.sync.exclude
|
|
35
|
+
});
|
|
36
|
+
for (const file of files) {
|
|
37
|
+
try {
|
|
38
|
+
const stat = await promises_1.default.stat(file);
|
|
39
|
+
if (stat.size > 2 * 1024 * 1024) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const parser = (0, router_1.detectParser)(file);
|
|
43
|
+
let content = await promises_1.default.readFile(file, "utf-8");
|
|
44
|
+
if (parser === "vue")
|
|
45
|
+
content = (0, vue_1.parseVue)(content);
|
|
46
|
+
if (parser === "svelte")
|
|
47
|
+
content = (0, svelte_1.parseSvelte)(content);
|
|
48
|
+
if (parser === "astro")
|
|
49
|
+
content = (0, astro_1.parseAstro)(content);
|
|
50
|
+
const source = project.createSourceFile(file, content, {
|
|
51
|
+
overwrite: true
|
|
52
|
+
});
|
|
53
|
+
const found = [
|
|
54
|
+
...(0, track_1.scanTrack)(source, config, aliases),
|
|
55
|
+
...(0, function_wrappers_1.scanFunctionWrappers)(source, config.functionWrappers ?? [], aliases),
|
|
56
|
+
...(0, component_wrappers_1.scanComponentWrappers)(source, config.wrappers ?? [], aliases)
|
|
57
|
+
];
|
|
58
|
+
for (const event of found) {
|
|
59
|
+
const { value, dynamic } = event;
|
|
60
|
+
if (!value)
|
|
61
|
+
continue;
|
|
62
|
+
// skip
|
|
63
|
+
if (aliases[value] === "__skip__")
|
|
64
|
+
continue;
|
|
65
|
+
// alias resolve
|
|
66
|
+
if (value in aliases) {
|
|
67
|
+
foundEvents.set(aliases[value], {
|
|
68
|
+
...event,
|
|
69
|
+
value: aliases[value]
|
|
70
|
+
});
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (dynamic) {
|
|
74
|
+
unresolvedDynamic.set(value, event);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
foundEvents.set(value, event);
|
|
78
|
+
}
|
|
79
|
+
project.removeSourceFile(source);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
console.log(chalk_1.default.gray(`Skipped: ${file}`));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// find new
|
|
86
|
+
for (const [key, event] of foundEvents) {
|
|
87
|
+
if (!knownEvents.has(key)) {
|
|
88
|
+
newEvents.set(key, event);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// FIX MODE
|
|
92
|
+
if (fix) {
|
|
93
|
+
console.log(chalk_1.default.yellow("\nFix mode\n"));
|
|
94
|
+
// add new events
|
|
95
|
+
for (const [name] of newEvents) {
|
|
96
|
+
config.events.push(name);
|
|
97
|
+
console.log(chalk_1.default.green(`+ ${name}`));
|
|
98
|
+
}
|
|
99
|
+
// resolve dynamic
|
|
100
|
+
for (const [value] of unresolvedDynamic) {
|
|
101
|
+
const { action } = await inquirer_1.default.prompt([
|
|
102
|
+
{
|
|
103
|
+
type: "list",
|
|
104
|
+
name: "action",
|
|
105
|
+
message: `Dynamic: ${value}`,
|
|
106
|
+
choices: [
|
|
107
|
+
{ name: "Alias", value: "alias" },
|
|
108
|
+
{ name: "Skip", value: "skip" }
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
]);
|
|
112
|
+
if (action === "skip") {
|
|
113
|
+
aliases[value] = "__skip__";
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const { name } = await inquirer_1.default.prompt([
|
|
117
|
+
{
|
|
118
|
+
type: "input",
|
|
119
|
+
name: "name",
|
|
120
|
+
message: "Event name:"
|
|
121
|
+
}
|
|
122
|
+
]);
|
|
123
|
+
const normalized = name.trim().toLowerCase();
|
|
124
|
+
if (!normalized)
|
|
125
|
+
continue;
|
|
126
|
+
aliases[value] = normalized;
|
|
127
|
+
config.events.push(normalized);
|
|
128
|
+
console.log(chalk_1.default.green(`${value} → ${normalized}`));
|
|
129
|
+
}
|
|
130
|
+
config.aliases = Object.fromEntries(Object.entries(aliases).sort());
|
|
131
|
+
config.events = [...new Set(config.events)].sort();
|
|
132
|
+
await (0, config_1.saveConfig)(config);
|
|
133
|
+
console.log(chalk_1.default.green("\n✔ Fixed"));
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
// NORMAL MODE
|
|
137
|
+
let hasError = false;
|
|
138
|
+
if (unresolvedDynamic.size) {
|
|
139
|
+
hasError = true;
|
|
140
|
+
console.log(chalk_1.default.red("\nDynamic events:"));
|
|
141
|
+
unresolvedDynamic.forEach((e) => console.log(chalk_1.default.red(`- ${e.value} (${e.file}:${e.line})`)));
|
|
142
|
+
}
|
|
143
|
+
if (newEvents.size) {
|
|
144
|
+
hasError = true;
|
|
145
|
+
console.log(chalk_1.default.red("\nNew events:"));
|
|
146
|
+
newEvents.forEach((e) => console.log(chalk_1.default.red(`+ ${e.value} (${e.file}:${e.line})`)));
|
|
147
|
+
}
|
|
148
|
+
if (hasError) {
|
|
149
|
+
console.log(chalk_1.default.red("\nEvent check failed"));
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
console.log(chalk_1.default.green("\nAll good"));
|
|
153
|
+
}
|
package/dist/commands/sync.js
CHANGED
|
@@ -10,6 +10,8 @@ const ts_morph_1 = require("ts-morph");
|
|
|
10
10
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
11
11
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
12
12
|
const config_1 = require("../utils/config");
|
|
13
|
+
const detect_wrappers_1 = require("../utils/detect-wrappers");
|
|
14
|
+
const detect_aliases_1 = require("../utils/detect-aliases");
|
|
13
15
|
const router_1 = require("../utils/parsers/router");
|
|
14
16
|
const vue_1 = require("../utils/parsers/vue");
|
|
15
17
|
const svelte_1 = require("../utils/parsers/svelte");
|
|
@@ -32,65 +34,103 @@ async function sync() {
|
|
|
32
34
|
ignore: config.sync.exclude
|
|
33
35
|
});
|
|
34
36
|
for (const file of files) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
? file
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const { value, dynamic } = event;
|
|
54
|
-
if (!value)
|
|
55
|
-
continue;
|
|
56
|
-
// alias
|
|
57
|
-
if (aliases[value]) {
|
|
58
|
-
console.log(chalk_1.default.gray(`alias: ${value} → ${aliases[value]}`));
|
|
59
|
-
events.add(aliases[value]);
|
|
60
|
-
continue;
|
|
37
|
+
try {
|
|
38
|
+
const parser = (0, router_1.detectParser)(file);
|
|
39
|
+
let content = await promises_1.default.readFile(file, "utf-8");
|
|
40
|
+
if (parser === "vue")
|
|
41
|
+
content = (0, vue_1.parseVue)(content);
|
|
42
|
+
if (parser === "svelte")
|
|
43
|
+
content = (0, svelte_1.parseSvelte)(content);
|
|
44
|
+
if (parser === "astro")
|
|
45
|
+
content = (0, astro_1.parseAstro)(content);
|
|
46
|
+
const virtualFile = parser === "ts" ? file : file + ".tsx";
|
|
47
|
+
const source = project.createSourceFile(virtualFile, content, { overwrite: true });
|
|
48
|
+
// AUTO ALIASES
|
|
49
|
+
const detectedAliases = (0, detect_aliases_1.detectAliases)(source);
|
|
50
|
+
for (const key in detectedAliases) {
|
|
51
|
+
if (!(key in aliases)) {
|
|
52
|
+
aliases[key] = detectedAliases[key];
|
|
53
|
+
console.log(chalk_1.default.green(`Detected alias: ${key} → ${detectedAliases[key]}`));
|
|
54
|
+
}
|
|
61
55
|
}
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
56
|
+
// AUTO WRAPPERS
|
|
57
|
+
const detected = (0, detect_wrappers_1.detectWrappers)(source);
|
|
58
|
+
// function wrappers
|
|
59
|
+
for (const fn of detected.functions) {
|
|
60
|
+
if (!config.functionWrappers?.some((w) => w.name === fn.name)) {
|
|
61
|
+
config.functionWrappers.push(fn);
|
|
62
|
+
console.log(chalk_1.default.green(`Detected function wrapper: ${fn.name}`));
|
|
63
|
+
}
|
|
66
64
|
}
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
// component wrappers
|
|
66
|
+
for (const comp of detected.components) {
|
|
67
|
+
if (!config.wrappers?.some((w) => w.name === comp.name)) {
|
|
68
|
+
config.wrappers.push(comp);
|
|
69
|
+
console.log(chalk_1.default.green(`Detected component wrapper: ${comp.name} (prop: ${comp.prop})`));
|
|
70
|
+
}
|
|
70
71
|
}
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
72
|
+
// SCAN EVENTS
|
|
73
|
+
const found = [
|
|
74
|
+
...(0, track_1.scanTrack)(source, config, aliases),
|
|
75
|
+
...(0, function_wrappers_1.scanFunctionWrappers)(source, config.functionWrappers ?? [], aliases),
|
|
76
|
+
...(0, component_wrappers_1.scanComponentWrappers)(source, config.wrappers ?? [], aliases)
|
|
77
|
+
];
|
|
78
|
+
for (const event of found) {
|
|
79
|
+
const { value, dynamic } = event;
|
|
80
|
+
if (!value)
|
|
81
|
+
continue;
|
|
82
|
+
// skip explicit ignore
|
|
83
|
+
if (value in aliases && aliases[value] === "__skip__") {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
// resolve alias
|
|
87
|
+
if (value in aliases) {
|
|
88
|
+
events.add(aliases[value]);
|
|
89
|
+
continue;
|
|
79
90
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
91
|
+
// static
|
|
92
|
+
if (!dynamic) {
|
|
93
|
+
events.add(value);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
// already handled
|
|
97
|
+
if (asked.has(value))
|
|
98
|
+
continue;
|
|
99
|
+
// ASK ONLY IF NEEDED
|
|
100
|
+
console.log(chalk_1.default.yellow("\nDynamic event detected:"));
|
|
101
|
+
console.log(chalk_1.default.gray(value));
|
|
102
|
+
const { name } = await inquirer_1.default.prompt([
|
|
103
|
+
{
|
|
104
|
+
type: "input",
|
|
105
|
+
name: "name",
|
|
106
|
+
message: "Enter event name (or type 'skip'):"
|
|
107
|
+
}
|
|
108
|
+
]);
|
|
109
|
+
const normalized = name?.trim();
|
|
110
|
+
asked.add(value);
|
|
111
|
+
if (!normalized || normalized === "skip") {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
// save alias
|
|
115
|
+
aliases[value] = normalized;
|
|
116
|
+
console.log(chalk_1.default.green(`Saved alias: ${value} → ${normalized}`));
|
|
117
|
+
events.add(normalized);
|
|
85
118
|
}
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
119
|
+
// free memory
|
|
120
|
+
project.removeSourceFile(source);
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
console.log(chalk_1.default.gray(`Skipped file: ${file}`));
|
|
89
124
|
}
|
|
90
125
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
126
|
+
// SAVE CONFIG
|
|
127
|
+
config.aliases = Object.fromEntries(Object.entries(aliases).sort());
|
|
128
|
+
// MERGE
|
|
129
|
+
const merged = new Set([
|
|
130
|
+
...config.events,
|
|
131
|
+
...events
|
|
132
|
+
]);
|
|
133
|
+
config.events = [...merged].sort();
|
|
94
134
|
await (0, config_1.saveConfig)(config);
|
|
95
|
-
console.log(chalk_1.default.green(
|
|
135
|
+
console.log(chalk_1.default.green(`\nFound ${config.events.length} events`));
|
|
96
136
|
}
|