@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
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import fg from "fast-glob";
|
|
3
|
+
import { Project } from "ts-morph";
|
|
4
|
+
import fs from "fs/promises";
|
|
5
|
+
import inquirer from "inquirer";
|
|
6
|
+
|
|
7
|
+
import { loadConfig, saveConfig } from "../utils/config";
|
|
8
|
+
|
|
9
|
+
import { detectParser } from "../utils/parsers/router";
|
|
10
|
+
import { parseVue } from "../utils/parsers/vue";
|
|
11
|
+
import { parseSvelte } from "../utils/parsers/svelte";
|
|
12
|
+
import { parseAstro } from "../utils/parsers/astro";
|
|
13
|
+
|
|
14
|
+
import { scanTrack } from "../utils/scanners/track";
|
|
15
|
+
import { scanFunctionWrappers } from "../utils/scanners/function-wrappers";
|
|
16
|
+
import { scanComponentWrappers } from "../utils/scanners/component-wrappers";
|
|
17
|
+
|
|
18
|
+
import { ExtractedEvent } from "../types";
|
|
19
|
+
|
|
20
|
+
export async function check({ fix = false }: { fix?: boolean }) {
|
|
21
|
+
const config = await loadConfig();
|
|
22
|
+
|
|
23
|
+
if (!config) {
|
|
24
|
+
console.log(chalk.red("eventra.json not found"));
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
console.log(chalk.blue("Checking events..."));
|
|
29
|
+
|
|
30
|
+
const project = new Project();
|
|
31
|
+
|
|
32
|
+
const knownEvents = new Set(config.events ?? []);
|
|
33
|
+
const aliases = { ...(config.aliases ?? {}) };
|
|
34
|
+
|
|
35
|
+
const foundEvents = new Map<string, ExtractedEvent>();
|
|
36
|
+
const newEvents = new Map<string, ExtractedEvent>();
|
|
37
|
+
const unresolvedDynamic = new Map<string, ExtractedEvent>();
|
|
38
|
+
|
|
39
|
+
const files = await fg(config.sync.include, {
|
|
40
|
+
ignore: config.sync.exclude
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
for (const file of files) {
|
|
44
|
+
try {
|
|
45
|
+
const stat = await fs.stat(file);
|
|
46
|
+
|
|
47
|
+
if (stat.size > 2 * 1024 * 1024) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const parser = detectParser(file);
|
|
52
|
+
let content = await fs.readFile(file, "utf-8");
|
|
53
|
+
|
|
54
|
+
if (parser === "vue") content = parseVue(content);
|
|
55
|
+
if (parser === "svelte") content = parseSvelte(content);
|
|
56
|
+
if (parser === "astro") content = parseAstro(content);
|
|
57
|
+
|
|
58
|
+
const source = project.createSourceFile(file, content, {
|
|
59
|
+
overwrite: true
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const found: ExtractedEvent[] = [
|
|
63
|
+
...scanTrack(source, config, aliases),
|
|
64
|
+
...scanFunctionWrappers(source, config.functionWrappers ?? [], aliases),
|
|
65
|
+
...scanComponentWrappers(source, config.wrappers ?? [], aliases)
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
for (const event of found) {
|
|
69
|
+
const { value, dynamic } = event;
|
|
70
|
+
if (!value) continue;
|
|
71
|
+
|
|
72
|
+
// skip
|
|
73
|
+
if (aliases[value] === "__skip__") continue;
|
|
74
|
+
|
|
75
|
+
// alias resolve
|
|
76
|
+
if (value in aliases) {
|
|
77
|
+
foundEvents.set(aliases[value], {
|
|
78
|
+
...event,
|
|
79
|
+
value: aliases[value]
|
|
80
|
+
});
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (dynamic) {
|
|
85
|
+
unresolvedDynamic.set(value, event);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
foundEvents.set(value, event);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
project.removeSourceFile(source);
|
|
93
|
+
|
|
94
|
+
} catch {
|
|
95
|
+
console.log(chalk.gray(`Skipped: ${file}`));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// find new
|
|
100
|
+
for (const [key, event] of foundEvents) {
|
|
101
|
+
if (!knownEvents.has(key)) {
|
|
102
|
+
newEvents.set(key, event);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// FIX MODE
|
|
107
|
+
if (fix) {
|
|
108
|
+
console.log(chalk.yellow("\nFix mode\n"));
|
|
109
|
+
|
|
110
|
+
// add new events
|
|
111
|
+
for (const [name] of newEvents) {
|
|
112
|
+
config.events.push(name);
|
|
113
|
+
console.log(chalk.green(`+ ${name}`));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// resolve dynamic
|
|
117
|
+
for (const [value] of unresolvedDynamic) {
|
|
118
|
+
const { action } = await inquirer.prompt([
|
|
119
|
+
{
|
|
120
|
+
type: "list",
|
|
121
|
+
name: "action",
|
|
122
|
+
message: `Dynamic: ${value}`,
|
|
123
|
+
choices: [
|
|
124
|
+
{ name: "Alias", value: "alias" },
|
|
125
|
+
{ name: "Skip", value: "skip" }
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
]);
|
|
129
|
+
|
|
130
|
+
if (action === "skip") {
|
|
131
|
+
aliases[value] = "__skip__";
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const { name } = await inquirer.prompt([
|
|
136
|
+
{
|
|
137
|
+
type: "input",
|
|
138
|
+
name: "name",
|
|
139
|
+
message: "Event name:"
|
|
140
|
+
}
|
|
141
|
+
]);
|
|
142
|
+
|
|
143
|
+
const normalized = name.trim().toLowerCase();
|
|
144
|
+
if (!normalized) continue;
|
|
145
|
+
|
|
146
|
+
aliases[value] = normalized;
|
|
147
|
+
config.events.push(normalized);
|
|
148
|
+
|
|
149
|
+
console.log(chalk.green(`${value} → ${normalized}`));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
config.aliases = Object.fromEntries(
|
|
153
|
+
Object.entries(aliases).sort()
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
config.events = [...new Set(config.events)].sort();
|
|
157
|
+
|
|
158
|
+
await saveConfig(config);
|
|
159
|
+
|
|
160
|
+
console.log(chalk.green("\n✔ Fixed"));
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// NORMAL MODE
|
|
165
|
+
let hasError = false;
|
|
166
|
+
|
|
167
|
+
if (unresolvedDynamic.size) {
|
|
168
|
+
hasError = true;
|
|
169
|
+
|
|
170
|
+
console.log(chalk.red("\nDynamic events:"));
|
|
171
|
+
|
|
172
|
+
unresolvedDynamic.forEach((e) =>
|
|
173
|
+
console.log(
|
|
174
|
+
chalk.red(`- ${e.value} (${e.file}:${e.line})`)
|
|
175
|
+
)
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (newEvents.size) {
|
|
180
|
+
hasError = true;
|
|
181
|
+
|
|
182
|
+
console.log(chalk.red("\nNew events:"));
|
|
183
|
+
|
|
184
|
+
newEvents.forEach((e) =>
|
|
185
|
+
console.log(
|
|
186
|
+
chalk.red(`+ ${e.value} (${e.file}:${e.line})`)
|
|
187
|
+
)
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (hasError) {
|
|
192
|
+
console.log(chalk.red("\nEvent check failed"));
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
console.log(chalk.green("\nAll good"));
|
|
197
|
+
}
|
package/src/commands/sync.ts
CHANGED
|
@@ -1,157 +1,217 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import fg from "fast-glob";
|
|
3
|
-
import {
|
|
3
|
+
import {Project} from "ts-morph";
|
|
4
4
|
import fs from "fs/promises";
|
|
5
5
|
import inquirer from "inquirer";
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
loadConfig,
|
|
9
|
-
saveConfig
|
|
10
|
-
} from "../utils/config";
|
|
7
|
+
import {loadConfig, saveConfig} from "../utils/config";
|
|
11
8
|
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { parseSvelte } from "../utils/parsers/svelte";
|
|
15
|
-
import { parseAstro } from "../utils/parsers/astro";
|
|
9
|
+
import {detectWrappers} from "../utils/detect-wrappers";
|
|
10
|
+
import {detectAliases} from "../utils/detect-aliases";
|
|
16
11
|
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
12
|
+
import {detectParser} from "../utils/parsers/router";
|
|
13
|
+
import {parseVue} from "../utils/parsers/vue";
|
|
14
|
+
import {parseSvelte} from "../utils/parsers/svelte";
|
|
15
|
+
import {parseAstro} from "../utils/parsers/astro";
|
|
20
16
|
|
|
21
|
-
import {
|
|
17
|
+
import {scanTrack} from "../utils/scanners/track";
|
|
18
|
+
import {scanFunctionWrappers} from "../utils/scanners/function-wrappers";
|
|
19
|
+
import {scanComponentWrappers} from "../utils/scanners/component-wrappers";
|
|
20
|
+
|
|
21
|
+
import {ExtractedEvent} from "../types";
|
|
22
22
|
|
|
23
23
|
export async function sync() {
|
|
24
24
|
const config = await loadConfig();
|
|
25
25
|
|
|
26
26
|
if (!config) {
|
|
27
|
-
console.log(
|
|
28
|
-
chalk.red("Run 'eventra init'")
|
|
29
|
-
);
|
|
27
|
+
console.log(chalk.red("Run 'eventra init'"));
|
|
30
28
|
return;
|
|
31
29
|
}
|
|
32
30
|
|
|
33
|
-
console.log(
|
|
34
|
-
chalk.blue("Scanning project...")
|
|
35
|
-
);
|
|
31
|
+
console.log(chalk.blue("Scanning project..."));
|
|
36
32
|
|
|
37
33
|
const project = new Project();
|
|
38
|
-
const events = new Set<string>();
|
|
39
34
|
|
|
35
|
+
const events = new Set<string>();
|
|
40
36
|
const aliases = config.aliases ?? {};
|
|
41
37
|
const asked = new Set<string>();
|
|
42
38
|
|
|
43
|
-
const files = await fg(
|
|
44
|
-
config.sync.
|
|
45
|
-
|
|
46
|
-
ignore: config.sync.exclude
|
|
47
|
-
}
|
|
48
|
-
);
|
|
39
|
+
const files = await fg(config.sync.include, {
|
|
40
|
+
ignore: config.sync.exclude
|
|
41
|
+
});
|
|
49
42
|
|
|
50
43
|
for (const file of files) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
file,
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
),
|
|
84
|
-
...scanComponentWrappers(
|
|
85
|
-
source,
|
|
86
|
-
config.wrappers ?? []
|
|
87
|
-
)
|
|
88
|
-
];
|
|
89
|
-
|
|
90
|
-
for (const event of found) {
|
|
91
|
-
const { value, dynamic } = event;
|
|
92
|
-
|
|
93
|
-
if (!value) continue;
|
|
94
|
-
|
|
95
|
-
// alias
|
|
96
|
-
if (aliases[value]) {
|
|
97
|
-
console.log(
|
|
98
|
-
chalk.gray(`alias: ${value} → ${aliases[value]}`)
|
|
99
|
-
);
|
|
100
|
-
events.add(aliases[value]);
|
|
101
|
-
continue;
|
|
44
|
+
try {
|
|
45
|
+
const parser = detectParser(file);
|
|
46
|
+
|
|
47
|
+
let content = await fs.readFile(file, "utf-8");
|
|
48
|
+
|
|
49
|
+
if (parser === "vue") content = parseVue(content);
|
|
50
|
+
if (parser === "svelte") content = parseSvelte(content);
|
|
51
|
+
if (parser === "astro") content = parseAstro(content);
|
|
52
|
+
|
|
53
|
+
const virtualFile =
|
|
54
|
+
parser === "ts" ? file : file + ".tsx";
|
|
55
|
+
|
|
56
|
+
const source = project.createSourceFile(
|
|
57
|
+
virtualFile,
|
|
58
|
+
content,
|
|
59
|
+
{overwrite: true}
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
// AUTO ALIASES
|
|
64
|
+
const detectedAliases = detectAliases(source);
|
|
65
|
+
|
|
66
|
+
for (const key in detectedAliases) {
|
|
67
|
+
if (!(key in aliases)) {
|
|
68
|
+
aliases[key] = detectedAliases[key];
|
|
69
|
+
|
|
70
|
+
console.log(
|
|
71
|
+
chalk.green(
|
|
72
|
+
`Detected alias: ${key} → ${detectedAliases[key]}`
|
|
73
|
+
)
|
|
74
|
+
);
|
|
75
|
+
}
|
|
102
76
|
}
|
|
103
77
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
78
|
+
|
|
79
|
+
// AUTO WRAPPERS
|
|
80
|
+
const detected = detectWrappers(source);
|
|
81
|
+
|
|
82
|
+
// function wrappers
|
|
83
|
+
for (const fn of detected.functions) {
|
|
84
|
+
if (
|
|
85
|
+
!config.functionWrappers?.some(
|
|
86
|
+
(w) => w.name === fn.name
|
|
87
|
+
)
|
|
88
|
+
) {
|
|
89
|
+
config.functionWrappers.push(fn);
|
|
90
|
+
|
|
91
|
+
console.log(
|
|
92
|
+
chalk.green(
|
|
93
|
+
`Detected function wrapper: ${fn.name}`
|
|
94
|
+
)
|
|
95
|
+
);
|
|
96
|
+
}
|
|
108
97
|
}
|
|
109
98
|
|
|
110
|
-
//
|
|
111
|
-
|
|
112
|
-
|
|
99
|
+
// component wrappers
|
|
100
|
+
for (const comp of detected.components) {
|
|
101
|
+
if (
|
|
102
|
+
!config.wrappers?.some(
|
|
103
|
+
(w) => w.name === comp.name
|
|
104
|
+
)
|
|
105
|
+
) {
|
|
106
|
+
config.wrappers.push(comp);
|
|
107
|
+
|
|
108
|
+
console.log(
|
|
109
|
+
chalk.green(
|
|
110
|
+
`Detected component wrapper: ${comp.name} (prop: ${comp.prop})`
|
|
111
|
+
)
|
|
112
|
+
);
|
|
113
|
+
}
|
|
113
114
|
}
|
|
114
115
|
|
|
115
|
-
//
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
116
|
+
// SCAN EVENTS
|
|
117
|
+
const found: ExtractedEvent[] = [
|
|
118
|
+
...scanTrack(source, config, aliases),
|
|
119
|
+
...scanFunctionWrappers(
|
|
120
|
+
source,
|
|
121
|
+
config.functionWrappers ?? [],
|
|
122
|
+
aliases
|
|
123
|
+
),
|
|
124
|
+
...scanComponentWrappers(
|
|
125
|
+
source,
|
|
126
|
+
config.wrappers ?? [],
|
|
127
|
+
aliases
|
|
128
|
+
)
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
for (const event of found) {
|
|
132
|
+
const {value, dynamic} = event;
|
|
133
|
+
|
|
134
|
+
if (!value) continue;
|
|
135
|
+
|
|
136
|
+
// skip explicit ignore
|
|
137
|
+
if (value in aliases && aliases[value] === "__skip__") {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// resolve alias
|
|
142
|
+
if (value in aliases) {
|
|
143
|
+
events.add(aliases[value]);
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// static
|
|
148
|
+
if (!dynamic) {
|
|
149
|
+
events.add(value);
|
|
150
|
+
continue;
|
|
127
151
|
}
|
|
128
|
-
]);
|
|
129
152
|
|
|
130
|
-
|
|
153
|
+
// already handled
|
|
154
|
+
if (asked.has(value)) continue;
|
|
131
155
|
|
|
132
|
-
|
|
156
|
+
// ASK ONLY IF NEEDED
|
|
157
|
+
console.log(
|
|
158
|
+
chalk.yellow("\nDynamic event detected:")
|
|
159
|
+
);
|
|
160
|
+
console.log(chalk.gray(value));
|
|
161
|
+
|
|
162
|
+
const {name} = await inquirer.prompt([
|
|
163
|
+
{
|
|
164
|
+
type: "input",
|
|
165
|
+
name: "name",
|
|
166
|
+
message:
|
|
167
|
+
"Enter event name (or type 'skip'):"
|
|
168
|
+
}
|
|
169
|
+
]);
|
|
170
|
+
|
|
171
|
+
const normalized = name?.trim();
|
|
172
|
+
asked.add(value);
|
|
173
|
+
|
|
174
|
+
if (!normalized || normalized === "skip") {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// save alias
|
|
179
|
+
aliases[value] = normalized;
|
|
180
|
+
|
|
181
|
+
console.log(
|
|
182
|
+
chalk.green(
|
|
183
|
+
`Saved alias: ${value} → ${normalized}`
|
|
184
|
+
)
|
|
185
|
+
);
|
|
133
186
|
|
|
134
|
-
|
|
135
|
-
continue;
|
|
187
|
+
events.add(normalized);
|
|
136
188
|
}
|
|
137
189
|
|
|
138
|
-
//
|
|
139
|
-
|
|
190
|
+
// free memory
|
|
191
|
+
project.removeSourceFile(source);
|
|
140
192
|
|
|
141
|
-
|
|
193
|
+
} catch {
|
|
194
|
+
console.log(
|
|
195
|
+
chalk.gray(`Skipped file: ${file}`)
|
|
196
|
+
);
|
|
142
197
|
}
|
|
143
198
|
}
|
|
199
|
+
// SAVE CONFIG
|
|
200
|
+
config.aliases = Object.fromEntries(
|
|
201
|
+
Object.entries(aliases).sort()
|
|
202
|
+
);
|
|
144
203
|
|
|
145
|
-
|
|
204
|
+
// MERGE
|
|
205
|
+
const merged = new Set([
|
|
206
|
+
...config.events,
|
|
207
|
+
...events
|
|
208
|
+
]);
|
|
146
209
|
|
|
147
|
-
|
|
148
|
-
config.events = list;
|
|
210
|
+
config.events = [...merged].sort();
|
|
149
211
|
|
|
150
212
|
await saveConfig(config);
|
|
151
213
|
|
|
152
214
|
console.log(
|
|
153
|
-
chalk.green(
|
|
154
|
-
`Found ${list.length} events`
|
|
155
|
-
)
|
|
215
|
+
chalk.green(`\nFound ${config.events.length} events`)
|
|
156
216
|
);
|
|
157
217
|
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import chokidar from "chokidar";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { Project } from "ts-morph";
|
|
4
|
+
import fs from "fs/promises";
|
|
5
|
+
|
|
6
|
+
import { loadConfig, saveConfig } from "../utils/config";
|
|
7
|
+
|
|
8
|
+
import { detectParser } from "../utils/parsers/router";
|
|
9
|
+
import { parseVue } from "../utils/parsers/vue";
|
|
10
|
+
import { parseSvelte } from "../utils/parsers/svelte";
|
|
11
|
+
import { parseAstro } from "../utils/parsers/astro";
|
|
12
|
+
|
|
13
|
+
import { scanTrack } from "../utils/scanners/track";
|
|
14
|
+
import { scanFunctionWrappers } from "../utils/scanners/function-wrappers";
|
|
15
|
+
import { scanComponentWrappers } from "../utils/scanners/component-wrappers";
|
|
16
|
+
|
|
17
|
+
export async function watch() {
|
|
18
|
+
const config = await loadConfig();
|
|
19
|
+
|
|
20
|
+
if (!config) {
|
|
21
|
+
console.log(chalk.red("Run init first"));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
console.log(chalk.blue("Watching...\n"));
|
|
26
|
+
|
|
27
|
+
const project = new Project();
|
|
28
|
+
|
|
29
|
+
const aliases = config.aliases ?? {};
|
|
30
|
+
|
|
31
|
+
// уже известные события
|
|
32
|
+
const seen = new Set(config.events);
|
|
33
|
+
|
|
34
|
+
const queue = new Set<string>();
|
|
35
|
+
let timer: NodeJS.Timeout;
|
|
36
|
+
|
|
37
|
+
const processQueue = async () => {
|
|
38
|
+
const files = [...queue];
|
|
39
|
+
queue.clear();
|
|
40
|
+
|
|
41
|
+
for (const file of files) {
|
|
42
|
+
await handle(file);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
config.events = [...new Set(config.events)].sort();
|
|
46
|
+
|
|
47
|
+
await saveConfig(config);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const handle = async (file: string) => {
|
|
51
|
+
try {
|
|
52
|
+
let content = await fs.readFile(file, "utf-8");
|
|
53
|
+
|
|
54
|
+
const parser = detectParser(file);
|
|
55
|
+
|
|
56
|
+
if (parser === "vue") content = parseVue(content);
|
|
57
|
+
if (parser === "svelte") content = parseSvelte(content);
|
|
58
|
+
if (parser === "astro") content = parseAstro(content);
|
|
59
|
+
|
|
60
|
+
const source = project.createSourceFile(file, content, {
|
|
61
|
+
overwrite: true
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const found = [
|
|
65
|
+
...scanTrack(source, config, aliases),
|
|
66
|
+
...scanFunctionWrappers(source, config.functionWrappers ?? [], aliases),
|
|
67
|
+
...scanComponentWrappers(source, config.wrappers ?? [], aliases)
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
for (const e of found) {
|
|
71
|
+
if (!e.value) continue;
|
|
72
|
+
|
|
73
|
+
if (aliases[e.value] === "__skip__") continue;
|
|
74
|
+
|
|
75
|
+
if (e.value in aliases) continue;
|
|
76
|
+
|
|
77
|
+
if (seen.has(e.value)) continue;
|
|
78
|
+
|
|
79
|
+
seen.add(e.value);
|
|
80
|
+
|
|
81
|
+
if (!e.dynamic) {
|
|
82
|
+
config.events.push(e.value);
|
|
83
|
+
console.log(chalk.green(`+ ${e.value}`));
|
|
84
|
+
} else {
|
|
85
|
+
console.log(chalk.yellow(`Dynamic: ${e.value}`));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
project.removeSourceFile(source);
|
|
90
|
+
|
|
91
|
+
} catch {
|
|
92
|
+
console.log(chalk.gray(`skip: ${file}`));
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const watcher = chokidar.watch(config.sync.include, {
|
|
97
|
+
ignored: [
|
|
98
|
+
...config.sync.exclude,
|
|
99
|
+
"**/*.log",
|
|
100
|
+
"**/*.tmp",
|
|
101
|
+
"**/*.swp"
|
|
102
|
+
],
|
|
103
|
+
ignoreInitial: true
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
watcher.on("change", (file) => {
|
|
107
|
+
queue.add(file);
|
|
108
|
+
|
|
109
|
+
clearTimeout(timer);
|
|
110
|
+
|
|
111
|
+
timer = setTimeout(processQueue, 200);
|
|
112
|
+
});
|
|
113
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -11,7 +11,6 @@ program
|
|
|
11
11
|
|
|
12
12
|
program
|
|
13
13
|
.command("init")
|
|
14
|
-
.description("Initialize Eventra")
|
|
15
14
|
.action(async () => {
|
|
16
15
|
const { init } = await import("./commands/init");
|
|
17
16
|
await init();
|
|
@@ -19,15 +18,29 @@ program
|
|
|
19
18
|
|
|
20
19
|
program
|
|
21
20
|
.command("sync")
|
|
22
|
-
.description("Sync events")
|
|
23
21
|
.action(async () => {
|
|
24
22
|
const { sync } = await import("./commands/sync");
|
|
25
23
|
await sync();
|
|
26
24
|
});
|
|
27
25
|
|
|
26
|
+
program
|
|
27
|
+
.command("check")
|
|
28
|
+
.option("--fix", "auto fix issues")
|
|
29
|
+
.action(async (opts) => {
|
|
30
|
+
const { check } = await import("./commands/check");
|
|
31
|
+
await check({ fix: opts.fix });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
program
|
|
35
|
+
.command("watch")
|
|
36
|
+
.description("Watch files and detect events in real-time")
|
|
37
|
+
.action(async () => {
|
|
38
|
+
const { watch } = await import("./commands/watch");
|
|
39
|
+
await watch();
|
|
40
|
+
});
|
|
41
|
+
|
|
28
42
|
program
|
|
29
43
|
.command("send")
|
|
30
|
-
.description("Send events")
|
|
31
44
|
.action(async () => {
|
|
32
45
|
const { send } = await import("./commands/send");
|
|
33
46
|
await send();
|
package/src/types.ts
CHANGED
|
@@ -6,6 +6,8 @@ export type ComponentWrapper = {
|
|
|
6
6
|
export type FunctionWrapper = {
|
|
7
7
|
name: string;
|
|
8
8
|
event?: string;
|
|
9
|
+
file?: string;
|
|
10
|
+
line?: number;
|
|
9
11
|
};
|
|
10
12
|
|
|
11
13
|
export type EventraConfig = {
|
|
@@ -24,4 +26,6 @@ export type EventraConfig = {
|
|
|
24
26
|
export type ExtractedEvent = {
|
|
25
27
|
value: string;
|
|
26
28
|
dynamic: boolean;
|
|
29
|
+
file?: string;
|
|
30
|
+
line?: number;
|
|
27
31
|
};
|