@eventra_dev/eventra-cli 0.1.34 → 0.2.2
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/dist/commands/check.js +14 -30
- package/dist/commands/sync.js +9 -27
- package/dist/commands/watch.js +38 -121
- package/dist/engine/engine.js +14 -9
- package/dist/engine/languageService.js +29 -24
- package/dist/engine/scanner.js +41 -28
- package/dist/utils/processFile.js +17 -0
- package/dist/utils/universal.js +1 -1
- package/package.json +1 -1
- package/src/commands/check.ts +17 -48
- package/src/commands/sync.ts +14 -44
- package/src/commands/watch.ts +48 -158
- package/src/engine/engine.ts +20 -12
- package/src/engine/languageService.ts +35 -32
- package/src/engine/scanner.ts +67 -27
- package/src/utils/processFile.ts +19 -0
- package/src/utils/universal.ts +1 -1
package/dist/engine/scanner.js
CHANGED
|
@@ -8,6 +8,7 @@ const typescript_1 = __importDefault(require("typescript"));
|
|
|
8
8
|
const resolver_1 = require("./resolver");
|
|
9
9
|
const callResolver_1 = require("./callResolver");
|
|
10
10
|
const exportResolver_1 = require("./exportResolver");
|
|
11
|
+
// HELPERS
|
|
11
12
|
function isValidEvent(v) {
|
|
12
13
|
return (v &&
|
|
13
14
|
v.length > 1 &&
|
|
@@ -36,6 +37,7 @@ function getJsxAttrName(name) {
|
|
|
36
37
|
return name.name.text;
|
|
37
38
|
return "";
|
|
38
39
|
}
|
|
40
|
+
// MAIN
|
|
39
41
|
function scanSource(source, checker, config, visited = new Set(), inheritedParamMap, wrapperCache = new Map()) {
|
|
40
42
|
const events = new Set();
|
|
41
43
|
const detectedFunctionWrappers = new Set();
|
|
@@ -44,30 +46,38 @@ function scanSource(source, checker, config, visited = new Set(), inheritedParam
|
|
|
44
46
|
return { events, detectedFunctionWrappers, detectedComponentWrappers };
|
|
45
47
|
}
|
|
46
48
|
visited.add(source.fileName);
|
|
49
|
+
// TRACK DETECTION
|
|
50
|
+
function isTrackCall(expr) {
|
|
51
|
+
if (typescript_1.default.isIdentifier(expr)) {
|
|
52
|
+
return expr.text === "track";
|
|
53
|
+
}
|
|
54
|
+
if (typescript_1.default.isPropertyAccessExpression(expr)) {
|
|
55
|
+
return expr.name.text === "track";
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
47
59
|
function extractTrackCall(node, paramMap) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
60
|
+
if (!isTrackCall(node.expression))
|
|
61
|
+
return;
|
|
62
|
+
const arg = node.arguments[0];
|
|
63
|
+
if (!arg)
|
|
64
|
+
return;
|
|
65
|
+
const res = (0, resolver_1.resolveNodeValue)(arg, checker, paramMap);
|
|
66
|
+
for (const v of res.values) {
|
|
67
|
+
if (isValidEvent(v)) {
|
|
68
|
+
events.add(v);
|
|
57
69
|
}
|
|
58
70
|
}
|
|
59
71
|
}
|
|
72
|
+
// WRAPPER DETECTION
|
|
60
73
|
function isWrapperFunction(fn) {
|
|
61
74
|
let found = false;
|
|
62
75
|
function walk(n) {
|
|
63
76
|
if (found)
|
|
64
77
|
return;
|
|
65
|
-
if (typescript_1.default.isCallExpression(n)) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
found = true;
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
78
|
+
if (typescript_1.default.isCallExpression(n) && isTrackCall(n.expression)) {
|
|
79
|
+
found = true;
|
|
80
|
+
return;
|
|
71
81
|
}
|
|
72
82
|
typescript_1.default.forEachChild(n, walk);
|
|
73
83
|
}
|
|
@@ -75,10 +85,12 @@ function scanSource(source, checker, config, visited = new Set(), inheritedParam
|
|
|
75
85
|
walk(fn.body);
|
|
76
86
|
return found;
|
|
77
87
|
}
|
|
88
|
+
// COMPONENT WRAPPER
|
|
78
89
|
function detectComponentWrapper(tag) {
|
|
79
90
|
const tagName = getJsxTagName(tag);
|
|
80
|
-
if (wrapperCache.has(tagName))
|
|
91
|
+
if (wrapperCache.has(tagName)) {
|
|
81
92
|
return wrapperCache.get(tagName);
|
|
93
|
+
}
|
|
82
94
|
let symbol = checker.getSymbolAtLocation(tag);
|
|
83
95
|
if (symbol && (symbol.flags & typescript_1.default.SymbolFlags.Alias)) {
|
|
84
96
|
symbol = checker.getAliasedSymbol(symbol);
|
|
@@ -104,14 +116,11 @@ function scanSource(source, checker, config, visited = new Set(), inheritedParam
|
|
|
104
116
|
function walk(n) {
|
|
105
117
|
if (prop)
|
|
106
118
|
return;
|
|
107
|
-
if (typescript_1.default.isCallExpression(n)) {
|
|
108
|
-
const
|
|
109
|
-
if (typescript_1.default.isPropertyAccessExpression(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
prop = arg.name.text;
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
119
|
+
if (typescript_1.default.isCallExpression(n) && isTrackCall(n.expression)) {
|
|
120
|
+
const arg = n.arguments[0];
|
|
121
|
+
if (typescript_1.default.isPropertyAccessExpression(arg)) {
|
|
122
|
+
prop = arg.name.text;
|
|
123
|
+
return;
|
|
115
124
|
}
|
|
116
125
|
}
|
|
117
126
|
typescript_1.default.forEachChild(n, walk);
|
|
@@ -126,6 +135,7 @@ function scanSource(source, checker, config, visited = new Set(), inheritedParam
|
|
|
126
135
|
wrapperCache.set(tagName, null);
|
|
127
136
|
return null;
|
|
128
137
|
}
|
|
138
|
+
// VISITOR
|
|
129
139
|
function visit(node) {
|
|
130
140
|
// JSX
|
|
131
141
|
if (typescript_1.default.isJsxSelfClosingElement(node) || typescript_1.default.isJsxOpeningElement(node)) {
|
|
@@ -183,9 +193,7 @@ function scanSource(source, checker, config, visited = new Set(), inheritedParam
|
|
|
183
193
|
}
|
|
184
194
|
});
|
|
185
195
|
}
|
|
186
|
-
// direct track
|
|
187
196
|
extractTrackCall(node, paramMap);
|
|
188
|
-
// wrapper
|
|
189
197
|
if (resolvedFn && isWrapperFunction(resolvedFn)) {
|
|
190
198
|
const name = getCallName(node.expression);
|
|
191
199
|
if (name && name !== "track") {
|
|
@@ -195,9 +203,14 @@ function scanSource(source, checker, config, visited = new Set(), inheritedParam
|
|
|
195
203
|
visit(resolvedFn.body);
|
|
196
204
|
}
|
|
197
205
|
}
|
|
198
|
-
|
|
199
|
-
|
|
206
|
+
if (resolvedFn && resolvedFn.body) {
|
|
207
|
+
const sf = resolvedFn.getSourceFile();
|
|
208
|
+
if (!visited.has(sf.fileName)) {
|
|
209
|
+
const res = scanSource(sf, checker, config, visited, paramMap, wrapperCache);
|
|
210
|
+
res.events.forEach(e => events.add(e));
|
|
211
|
+
}
|
|
200
212
|
}
|
|
213
|
+
node.arguments.forEach(visit);
|
|
201
214
|
visit(node.expression);
|
|
202
215
|
return;
|
|
203
216
|
}
|
|
@@ -1,8 +1,25 @@
|
|
|
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;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
4
8
|
const universal_1 = require("./universal");
|
|
9
|
+
function extractImports(content, file) {
|
|
10
|
+
return (0, universal_1.parseUniversal)(content, file).deps;
|
|
11
|
+
}
|
|
5
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
|
+
}
|
|
6
23
|
const parsed = (0, universal_1.parseUniversal)(content, file);
|
|
7
24
|
return {
|
|
8
25
|
content: parsed.code || "",
|
package/dist/utils/universal.js
CHANGED
|
@@ -184,7 +184,7 @@ function parseUniversal(content, file) {
|
|
|
184
184
|
deps.push(...dyn.deps);
|
|
185
185
|
parts.push(...dyn.calls);
|
|
186
186
|
return {
|
|
187
|
-
code:
|
|
187
|
+
code: parts.length ? parts.join("\n") : content,
|
|
188
188
|
deps: [...new Set(deps.filter(Boolean))],
|
|
189
189
|
};
|
|
190
190
|
}
|
package/package.json
CHANGED
package/src/commands/check.ts
CHANGED
|
@@ -25,28 +25,20 @@ export async function check({ fix = false }: { fix?: boolean }) {
|
|
|
25
25
|
|
|
26
26
|
const engine = new EventraEngine(process.cwd());
|
|
27
27
|
|
|
28
|
+
const cache = new Map<string, { content: string; deps: string[] }>();
|
|
28
29
|
const toScan = new Set<string>();
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
string,
|
|
32
|
-
{ content: string; deps: string[] }
|
|
33
|
-
>();
|
|
34
|
-
|
|
35
|
-
// COLLECT + CACHE
|
|
31
|
+
// COLLECT
|
|
36
32
|
for (const file of files) {
|
|
37
33
|
try {
|
|
38
34
|
const raw = await fs.readFile(file, "utf-8");
|
|
39
|
-
|
|
40
35
|
if (raw.length > 2_000_000) continue;
|
|
41
36
|
|
|
42
37
|
const parsed = processFile(file, raw);
|
|
43
38
|
|
|
44
39
|
cache.set(file, parsed);
|
|
45
40
|
toScan.add(file);
|
|
46
|
-
|
|
47
|
-
for (const dep of parsed.deps) {
|
|
48
|
-
toScan.add(path.resolve(dep));
|
|
49
|
-
}
|
|
41
|
+
parsed.deps.forEach(dep => toScan.add(path.resolve(dep)));
|
|
50
42
|
|
|
51
43
|
} catch {}
|
|
52
44
|
}
|
|
@@ -54,17 +46,9 @@ export async function check({ fix = false }: { fix?: boolean }) {
|
|
|
54
46
|
// PRELOAD
|
|
55
47
|
for (const file of toScan) {
|
|
56
48
|
try {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const raw = await fs.readFile(file, "utf-8");
|
|
61
|
-
parsed = processFile(file, raw);
|
|
62
|
-
cache.set(file, parsed);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const virtual = getVirtualFile(file);
|
|
66
|
-
engine.preloadFile(virtual, parsed.content);
|
|
67
|
-
|
|
49
|
+
const parsed = cache.get(file);
|
|
50
|
+
if (!parsed) continue;
|
|
51
|
+
engine.preloadFile(getVirtualFile(file), parsed.content);
|
|
68
52
|
} catch {}
|
|
69
53
|
}
|
|
70
54
|
|
|
@@ -74,49 +58,34 @@ export async function check({ fix = false }: { fix?: boolean }) {
|
|
|
74
58
|
const parsed = cache.get(file);
|
|
75
59
|
if (!parsed) continue;
|
|
76
60
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
61
|
+
engine.scanFile(
|
|
62
|
+
getVirtualFile(file),
|
|
63
|
+
parsed.content,
|
|
64
|
+
config
|
|
65
|
+
);
|
|
80
66
|
|
|
81
67
|
} catch {}
|
|
82
68
|
}
|
|
83
69
|
|
|
84
|
-
// DIFF
|
|
85
70
|
const found = new Set(engine.getAllEvents());
|
|
86
71
|
const known = new Set(config.events ?? []);
|
|
87
72
|
|
|
88
|
-
const
|
|
73
|
+
const added = [...found].filter(e => !known.has(e));
|
|
89
74
|
const removed = [...known].filter(e => !found.has(e));
|
|
90
75
|
|
|
91
|
-
// FIX MODE
|
|
92
76
|
if (fix) {
|
|
93
77
|
config.events = [...found].sort();
|
|
94
78
|
await saveConfig(config);
|
|
95
|
-
|
|
96
|
-
console.log(
|
|
97
|
-
chalk.green(`\nSynced (${config.events.length} events)`)
|
|
98
|
-
);
|
|
79
|
+
console.log(chalk.green("Synced"));
|
|
99
80
|
return;
|
|
100
81
|
}
|
|
101
82
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
console.log(chalk.red("\nNew events:"));
|
|
106
|
-
newEvents.forEach(e =>
|
|
107
|
-
console.log(chalk.red(`+ ${e}`))
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (removed.length) {
|
|
112
|
-
console.log(chalk.yellow("\nRemoved events:"));
|
|
113
|
-
removed.forEach(e =>
|
|
114
|
-
console.log(chalk.yellow(`- ${e}`))
|
|
115
|
-
);
|
|
116
|
-
}
|
|
83
|
+
if (added.length || removed.length) {
|
|
84
|
+
added.forEach(e => console.log(chalk.red(`+ ${e}`)));
|
|
85
|
+
removed.forEach(e => console.log(chalk.yellow(`- ${e}`)));
|
|
117
86
|
|
|
118
87
|
process.exit(1);
|
|
119
88
|
}
|
|
120
89
|
|
|
121
|
-
console.log(chalk.green("
|
|
90
|
+
console.log(chalk.green("All good"));
|
|
122
91
|
}
|
package/src/commands/sync.ts
CHANGED
|
@@ -19,25 +19,15 @@ export async function sync() {
|
|
|
19
19
|
absolute: true,
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
-
if (!files.length) {
|
|
23
|
-
console.log(chalk.yellow("No files found"));
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
22
|
const engine = new EventraEngine(process.cwd());
|
|
28
23
|
|
|
24
|
+
const cache = new Map<string, { content: string; deps: string[] }>();
|
|
29
25
|
const toScan = new Set<string>();
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
string,
|
|
33
|
-
{ content: string; deps: string[] }
|
|
34
|
-
>();
|
|
35
|
-
|
|
36
|
-
// COLLECT + CACHE
|
|
27
|
+
// COLLECT
|
|
37
28
|
for (const file of files) {
|
|
38
29
|
try {
|
|
39
30
|
const raw = await fs.readFile(file, "utf-8");
|
|
40
|
-
|
|
41
31
|
if (raw.length > 2_000_000) continue;
|
|
42
32
|
|
|
43
33
|
const parsed = processFile(file, raw);
|
|
@@ -45,9 +35,7 @@ export async function sync() {
|
|
|
45
35
|
cache.set(file, parsed);
|
|
46
36
|
toScan.add(file);
|
|
47
37
|
|
|
48
|
-
|
|
49
|
-
toScan.add(path.resolve(dep));
|
|
50
|
-
}
|
|
38
|
+
parsed.deps.forEach(dep => toScan.add(path.resolve(dep)));
|
|
51
39
|
|
|
52
40
|
} catch {}
|
|
53
41
|
}
|
|
@@ -63,8 +51,7 @@ export async function sync() {
|
|
|
63
51
|
cache.set(file, parsed);
|
|
64
52
|
}
|
|
65
53
|
|
|
66
|
-
|
|
67
|
-
engine.preloadFile(virtual, parsed.content);
|
|
54
|
+
engine.preloadFile(getVirtualFile(file), parsed.content);
|
|
68
55
|
|
|
69
56
|
} catch {}
|
|
70
57
|
}
|
|
@@ -78,21 +65,16 @@ export async function sync() {
|
|
|
78
65
|
const parsed = cache.get(file);
|
|
79
66
|
if (!parsed) continue;
|
|
80
67
|
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
res.detectedFunctionWrappers.forEach(w =>
|
|
86
|
-
detectedFn.add(w)
|
|
68
|
+
const res = engine.updateFile(
|
|
69
|
+
getVirtualFile(file),
|
|
70
|
+
parsed.content,
|
|
71
|
+
config
|
|
87
72
|
);
|
|
88
73
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
74
|
+
res.detectedFunctionWrappers.forEach(w => detectedFn.add(w));
|
|
75
|
+
res.detectedComponentWrappers.forEach((v, k) => detectedCmp.set(k, v));
|
|
92
76
|
|
|
93
|
-
} catch {
|
|
94
|
-
console.log(chalk.gray(`skip: ${file}`));
|
|
95
|
-
}
|
|
77
|
+
} catch {}
|
|
96
78
|
}
|
|
97
79
|
|
|
98
80
|
// RESULT
|
|
@@ -108,10 +90,7 @@ export async function sync() {
|
|
|
108
90
|
|
|
109
91
|
config.wrappers = mergeUnique(
|
|
110
92
|
config.wrappers ?? [],
|
|
111
|
-
[...detectedCmp.entries()].map(([name, prop]) => ({
|
|
112
|
-
name,
|
|
113
|
-
prop,
|
|
114
|
-
})),
|
|
93
|
+
[...detectedCmp.entries()].map(([name, prop]) => ({ name, prop })),
|
|
115
94
|
w => `${w.name}:${w.prop}`
|
|
116
95
|
);
|
|
117
96
|
|
|
@@ -120,17 +99,8 @@ export async function sync() {
|
|
|
120
99
|
console.log(chalk.green(`Found ${events.length} events`));
|
|
121
100
|
}
|
|
122
101
|
|
|
123
|
-
|
|
124
|
-
function mergeUnique<T>(
|
|
125
|
-
a: T[],
|
|
126
|
-
b: T[],
|
|
127
|
-
key: (v: T) => string
|
|
128
|
-
): T[] {
|
|
102
|
+
function mergeUnique<T>(a: T[], b: T[], key: (v: T) => string): T[] {
|
|
129
103
|
const map = new Map<string, T>();
|
|
130
|
-
|
|
131
|
-
[...b, ...a].forEach(item => {
|
|
132
|
-
map.set(key(item), item);
|
|
133
|
-
});
|
|
134
|
-
|
|
104
|
+
[...b, ...a].forEach(item => map.set(key(item), item));
|
|
135
105
|
return [...map.values()];
|
|
136
106
|
}
|