@eventra_dev/eventra-cli 0.0.19 → 0.1.1
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 +17 -117
- package/dist/commands/sync.js +20 -115
- package/dist/commands/watch.js +107 -69
- package/dist/engine/callResolver.js +31 -0
- package/dist/engine/engine.js +33 -0
- package/dist/engine/extract.js +53 -0
- package/dist/engine/flow.js +38 -0
- package/dist/engine/graph.js +22 -0
- package/dist/engine/project.js +74 -0
- package/dist/engine/resolver.js +38 -0
- package/dist/engine/scanner.js +78 -0
- package/dist/engine/symbol.js +31 -0
- package/dist/utils/parsers/vue.js +16 -12
- package/dist/utils/processFile.js +20 -0
- package/package.json +1 -1
- package/src/commands/check.ts +19 -151
- package/src/commands/sync.ts +23 -194
- package/src/commands/watch.ts +119 -66
- package/src/engine/callResolver.ts +37 -0
- package/src/engine/engine.ts +39 -0
- package/src/engine/extract.ts +74 -0
- package/src/engine/flow.ts +54 -0
- package/src/engine/graph.ts +23 -0
- package/src/engine/project.ts +75 -0
- package/src/engine/resolver.ts +53 -0
- package/src/engine/scanner.ts +90 -0
- package/src/engine/symbol.ts +42 -0
- package/src/types.ts +3 -9
- package/src/utils/parsers/vue.ts +19 -20
- package/src/utils/processFile.ts +18 -0
- package/tests/fixtures/backend/express/app.ts +167 -12
- package/tests/fixtures/wrappers/component/test.tsx +1 -1
- package/tests/run.ts +4 -17
- package/dist/utils/detect-aliases.js +0 -39
- package/dist/utils/detect-wrappers.js +0 -84
- package/dist/utils/extract.js +0 -56
- package/dist/utils/scanners/component-wrappers.js +0 -73
- package/dist/utils/scanners/function-wrappers.js +0 -83
- package/dist/utils/scanners/track.js +0 -64
- package/src/utils/detect-aliases.ts +0 -46
- package/src/utils/detect-wrappers.ts +0 -119
- package/src/utils/extract.ts +0 -72
- package/src/utils/scanners/component-wrappers.ts +0 -109
- package/src/utils/scanners/function-wrappers.ts +0 -137
- package/src/utils/scanners/track.ts +0 -99
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DependencyGraph = void 0;
|
|
4
|
+
class DependencyGraph {
|
|
5
|
+
reverse = new Map();
|
|
6
|
+
update(file, source) {
|
|
7
|
+
const imports = source
|
|
8
|
+
.getImportDeclarations()
|
|
9
|
+
.map(i => i.getModuleSpecifierSourceFile()?.getFilePath())
|
|
10
|
+
.filter(Boolean);
|
|
11
|
+
for (const dep of imports) {
|
|
12
|
+
if (!this.reverse.has(dep)) {
|
|
13
|
+
this.reverse.set(dep, new Set());
|
|
14
|
+
}
|
|
15
|
+
this.reverse.get(dep).add(file);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
getDependents(file) {
|
|
19
|
+
return [...(this.reverse.get(file) ?? [])];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.DependencyGraph = DependencyGraph;
|
|
@@ -0,0 +1,74 @@
|
|
|
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.ProjectGraph = void 0;
|
|
7
|
+
const ts_morph_1 = require("ts-morph");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
function normalize(file) {
|
|
11
|
+
return path_1.default.resolve(file);
|
|
12
|
+
}
|
|
13
|
+
function findTsConfig(start) {
|
|
14
|
+
let dir = path_1.default.dirname(start);
|
|
15
|
+
while (true) {
|
|
16
|
+
const file = path_1.default.join(dir, "tsconfig.json");
|
|
17
|
+
if (fs_1.default.existsSync(file))
|
|
18
|
+
return file;
|
|
19
|
+
const parent = path_1.default.dirname(dir);
|
|
20
|
+
if (parent === dir)
|
|
21
|
+
break;
|
|
22
|
+
dir = parent;
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
function getScriptKind(file) {
|
|
27
|
+
if (file.endsWith(".tsx"))
|
|
28
|
+
return ts_morph_1.ts.ScriptKind.TSX;
|
|
29
|
+
if (file.endsWith(".jsx"))
|
|
30
|
+
return ts_morph_1.ts.ScriptKind.JSX;
|
|
31
|
+
if (file.endsWith(".js"))
|
|
32
|
+
return ts_morph_1.ts.ScriptKind.JS;
|
|
33
|
+
if (file.endsWith(".vue"))
|
|
34
|
+
return ts_morph_1.ts.ScriptKind.TSX;
|
|
35
|
+
return ts_morph_1.ts.ScriptKind.TS;
|
|
36
|
+
}
|
|
37
|
+
class ProjectGraph {
|
|
38
|
+
project;
|
|
39
|
+
constructor(entry) {
|
|
40
|
+
const tsconfig = findTsConfig(entry);
|
|
41
|
+
this.project = tsconfig
|
|
42
|
+
? new ts_morph_1.Project({
|
|
43
|
+
tsConfigFilePath: tsconfig,
|
|
44
|
+
skipAddingFilesFromTsConfig: false,
|
|
45
|
+
})
|
|
46
|
+
: new ts_morph_1.Project({
|
|
47
|
+
useInMemoryFileSystem: true,
|
|
48
|
+
compilerOptions: {
|
|
49
|
+
allowJs: true,
|
|
50
|
+
jsx: ts_morph_1.ts.JsxEmit.Preserve,
|
|
51
|
+
moduleResolution: ts_morph_1.ts.ModuleResolutionKind.NodeJs,
|
|
52
|
+
target: ts_morph_1.ts.ScriptTarget.ESNext,
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
getSource(file, content) {
|
|
57
|
+
const filePath = normalize(file);
|
|
58
|
+
let source = this.project.getSourceFile(filePath);
|
|
59
|
+
if (!source) {
|
|
60
|
+
source = this.project.createSourceFile(filePath, content, {
|
|
61
|
+
overwrite: true,
|
|
62
|
+
scriptKind: getScriptKind(filePath),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
source.replaceWithText(content);
|
|
67
|
+
}
|
|
68
|
+
return source;
|
|
69
|
+
}
|
|
70
|
+
getChecker() {
|
|
71
|
+
return this.project.getTypeChecker().compilerObject;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.ProjectGraph = ProjectGraph;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveNodeValue = resolveNodeValue;
|
|
4
|
+
const ts_morph_1 = require("ts-morph");
|
|
5
|
+
function resolveNodeValue(node, checker) {
|
|
6
|
+
if (!ts_morph_1.Node.isIdentifier(node))
|
|
7
|
+
return null;
|
|
8
|
+
const symbol = checker.getSymbolAtLocation(node.compilerNode);
|
|
9
|
+
if (!symbol)
|
|
10
|
+
return null;
|
|
11
|
+
const decls = symbol.getDeclarations() ?? [];
|
|
12
|
+
for (const d of decls) {
|
|
13
|
+
if (ts_morph_1.ts.isVariableDeclaration(d) && d.initializer) {
|
|
14
|
+
const init = d.initializer;
|
|
15
|
+
if (ts_morph_1.ts.isStringLiteral(init)) {
|
|
16
|
+
return { values: [init.text], dynamic: false };
|
|
17
|
+
}
|
|
18
|
+
if (ts_morph_1.ts.isNoSubstitutionTemplateLiteral(init)) {
|
|
19
|
+
return { values: [init.text], dynamic: false };
|
|
20
|
+
}
|
|
21
|
+
if (ts_morph_1.ts.isTemplateExpression(init)) {
|
|
22
|
+
let result = init.head.text;
|
|
23
|
+
for (const span of init.templateSpans) {
|
|
24
|
+
result += "*";
|
|
25
|
+
result += span.literal.text;
|
|
26
|
+
}
|
|
27
|
+
return { values: [result], dynamic: true };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (ts_morph_1.ts.isParameter(d) && d.initializer) {
|
|
31
|
+
const init = d.initializer;
|
|
32
|
+
if (ts_morph_1.ts.isStringLiteral(init)) {
|
|
33
|
+
return { values: [init.text], dynamic: false };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.scanSource = scanSource;
|
|
4
|
+
const ts_morph_1 = require("ts-morph");
|
|
5
|
+
const extract_1 = require("./extract");
|
|
6
|
+
const callResolver_1 = require("./callResolver");
|
|
7
|
+
const flow_1 = require("./flow");
|
|
8
|
+
function getCallName(expr) {
|
|
9
|
+
if (ts_morph_1.Node.isIdentifier(expr))
|
|
10
|
+
return expr.getText();
|
|
11
|
+
if (ts_morph_1.Node.isPropertyAccessExpression(expr))
|
|
12
|
+
return expr.getName();
|
|
13
|
+
return expr.getText();
|
|
14
|
+
}
|
|
15
|
+
function isTrackLike(name) {
|
|
16
|
+
return /(track|trackFeature)/i.test(name);
|
|
17
|
+
}
|
|
18
|
+
function pickArg(args) {
|
|
19
|
+
return (args.find(ts_morph_1.Node.isStringLiteral) ??
|
|
20
|
+
args.find(ts_morph_1.Node.isTemplateExpression) ??
|
|
21
|
+
args.find(ts_morph_1.Node.isObjectLiteralExpression) ??
|
|
22
|
+
args[0]);
|
|
23
|
+
}
|
|
24
|
+
function scanSource(source, checker) {
|
|
25
|
+
const events = new Set();
|
|
26
|
+
// CALLS
|
|
27
|
+
for (const call of source.getDescendantsOfKind(ts_morph_1.SyntaxKind.CallExpression)) {
|
|
28
|
+
const expr = call.getExpression();
|
|
29
|
+
const name = getCallName(expr);
|
|
30
|
+
if (!isTrackLike(name))
|
|
31
|
+
continue;
|
|
32
|
+
const args = call.getArguments();
|
|
33
|
+
if (!args.length)
|
|
34
|
+
continue;
|
|
35
|
+
let target = pickArg(args);
|
|
36
|
+
const fn = (0, callResolver_1.resolveFunctionFromCall)(expr);
|
|
37
|
+
if (fn) {
|
|
38
|
+
const index = (0, flow_1.getForwardedParamIndex)(fn);
|
|
39
|
+
if (index !== null && args[index]) {
|
|
40
|
+
target = args[index];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
(0, extract_1.extractEventsFromArgs)([target], checker).forEach(({ value }) => {
|
|
44
|
+
if (isValid(value))
|
|
45
|
+
events.add(value);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
// JSX
|
|
49
|
+
const jsx = [
|
|
50
|
+
...source.getDescendantsOfKind(ts_morph_1.SyntaxKind.JsxOpeningElement),
|
|
51
|
+
...source.getDescendantsOfKind(ts_morph_1.SyntaxKind.JsxSelfClosingElement),
|
|
52
|
+
];
|
|
53
|
+
for (const el of jsx) {
|
|
54
|
+
for (const attr of el.getAttributes()) {
|
|
55
|
+
if (!ts_morph_1.Node.isJsxAttribute(attr))
|
|
56
|
+
continue;
|
|
57
|
+
const name = attr.getNameNode().getText();
|
|
58
|
+
if (!/(event|name|action)/i.test(name))
|
|
59
|
+
continue;
|
|
60
|
+
const init = attr.getInitializer();
|
|
61
|
+
if (!init)
|
|
62
|
+
continue;
|
|
63
|
+
const expr = ts_morph_1.Node.isJsxExpression(init)
|
|
64
|
+
? init.getExpression()
|
|
65
|
+
: init;
|
|
66
|
+
if (!expr)
|
|
67
|
+
continue;
|
|
68
|
+
(0, extract_1.extractEventsFromArgs)([expr], checker).forEach(({ value }) => {
|
|
69
|
+
if (isValid(value))
|
|
70
|
+
events.add(value);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return events;
|
|
75
|
+
}
|
|
76
|
+
function isValid(v) {
|
|
77
|
+
return !!v && v.length > 1 && !v.includes(" ");
|
|
78
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveNodeValue = resolveNodeValue;
|
|
4
|
+
const ts_morph_1 = require("ts-morph");
|
|
5
|
+
function resolveNodeValue(node, checker) {
|
|
6
|
+
if (ts_morph_1.Node.isIdentifier(node)) {
|
|
7
|
+
const symbol = checker.getSymbolAtLocation(node.compilerNode);
|
|
8
|
+
if (!symbol)
|
|
9
|
+
return null;
|
|
10
|
+
const decls = symbol.getDeclarations() ?? [];
|
|
11
|
+
for (const d of decls) {
|
|
12
|
+
if (ts_morph_1.ts.isVariableDeclaration(d) && d.initializer) {
|
|
13
|
+
if (ts_morph_1.Node.isStringLiteral(d.initializer)) {
|
|
14
|
+
return {
|
|
15
|
+
values: [d.initializer.text],
|
|
16
|
+
dynamic: false
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (ts_morph_1.ts.isParameter(d) && d.initializer) {
|
|
21
|
+
if (ts_morph_1.Node.isStringLiteral(d.initializer)) {
|
|
22
|
+
return {
|
|
23
|
+
values: [d.initializer.text],
|
|
24
|
+
dynamic: false
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
@@ -2,17 +2,21 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseVue = parseVue;
|
|
4
4
|
function parseVue(content) {
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
5
|
+
const scriptMatch = content.match(/<script[\s\S]*?>([\s\S]*?)<\/script>/);
|
|
6
|
+
const templateMatch = content.match(/<template>([\s\S]*?)<\/template>/);
|
|
7
|
+
const script = scriptMatch?.[1] ?? "";
|
|
8
|
+
let template = templateMatch?.[1] ?? "";
|
|
9
|
+
template = template.replace(/<!--[\s\S]*?-->/g, "");
|
|
10
|
+
template = template
|
|
11
|
+
.replace(/v-if="[^"]+"/g, "")
|
|
12
|
+
.replace(/v-for="[^"]+"/g, "")
|
|
13
|
+
.replace(/@click=/g, "onClick=");
|
|
14
|
+
const jsx = `
|
|
15
|
+
const __VUE_JSX__ = (
|
|
16
|
+
<>
|
|
17
|
+
${template}
|
|
18
|
+
</>
|
|
19
|
+
);
|
|
17
20
|
`;
|
|
21
|
+
return script + "\n" + jsx;
|
|
18
22
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.processFile = processFile;
|
|
4
|
+
const router_1 = require("./parsers/router");
|
|
5
|
+
const vue_1 = require("./parsers/vue");
|
|
6
|
+
const svelte_1 = require("./parsers/svelte");
|
|
7
|
+
const astro_1 = require("./parsers/astro");
|
|
8
|
+
function processFile(file, content) {
|
|
9
|
+
const parser = (0, router_1.detectParser)(file);
|
|
10
|
+
if (parser === "vue")
|
|
11
|
+
content = (0, vue_1.parseVue)(content);
|
|
12
|
+
if (parser === "svelte")
|
|
13
|
+
content = (0, svelte_1.parseSvelte)(content);
|
|
14
|
+
if (parser === "astro")
|
|
15
|
+
content = (0, astro_1.parseAstro)(content);
|
|
16
|
+
const virtualFile = file.endsWith(".vue")
|
|
17
|
+
? file + ".tsx"
|
|
18
|
+
: file;
|
|
19
|
+
return { content, virtualFile };
|
|
20
|
+
}
|
package/package.json
CHANGED
package/src/commands/check.ts
CHANGED
|
@@ -1,21 +1,10 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import fg from "fast-glob";
|
|
3
|
-
import { Project } from "ts-morph";
|
|
4
3
|
import fs from "fs/promises";
|
|
5
|
-
import inquirer from "inquirer";
|
|
6
4
|
|
|
7
5
|
import { loadConfig, saveConfig } from "../utils/config";
|
|
8
|
-
|
|
9
|
-
import {
|
|
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";
|
|
6
|
+
import { EventraEngine } from "../engine/engine";
|
|
7
|
+
import { processFile } from "../utils/processFile";
|
|
19
8
|
|
|
20
9
|
export async function check({ fix = false }: { fix?: boolean }) {
|
|
21
10
|
const config = await loadConfig();
|
|
@@ -27,169 +16,48 @@ export async function check({ fix = false }: { fix?: boolean }) {
|
|
|
27
16
|
|
|
28
17
|
console.log(chalk.blue("Checking events..."));
|
|
29
18
|
|
|
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
19
|
const files = await fg(config.sync.include, {
|
|
40
|
-
ignore: config.sync.exclude
|
|
20
|
+
ignore: config.sync.exclude,
|
|
41
21
|
});
|
|
42
22
|
|
|
23
|
+
const engine = new EventraEngine(process.cwd());
|
|
24
|
+
|
|
43
25
|
for (const file of files) {
|
|
44
26
|
try {
|
|
45
|
-
const
|
|
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
|
-
}
|
|
27
|
+
const raw = await fs.readFile(file, "utf-8");
|
|
88
28
|
|
|
89
|
-
|
|
90
|
-
}
|
|
29
|
+
const { content, virtualFile } = processFile(file, raw);
|
|
91
30
|
|
|
92
|
-
|
|
31
|
+
engine.scanFile(virtualFile, content);
|
|
93
32
|
|
|
94
33
|
} catch {
|
|
95
34
|
console.log(chalk.gray(`Skipped: ${file}`));
|
|
96
35
|
}
|
|
97
36
|
}
|
|
98
37
|
|
|
99
|
-
|
|
100
|
-
|
|
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"));
|
|
38
|
+
const found = new Set(engine.getAllEvents());
|
|
39
|
+
const known = new Set(config.events ?? []);
|
|
109
40
|
|
|
110
|
-
|
|
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
|
-
}
|
|
41
|
+
const newEvents = [...found].filter(e => !known.has(e));
|
|
151
42
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
43
|
+
if (fix) {
|
|
44
|
+
newEvents.forEach(e => {
|
|
45
|
+
config.events.push(e);
|
|
46
|
+
console.log(chalk.green(`+ ${e}`));
|
|
47
|
+
});
|
|
155
48
|
|
|
156
49
|
config.events = [...new Set(config.events)].sort();
|
|
157
50
|
|
|
158
51
|
await saveConfig(config);
|
|
159
52
|
|
|
160
|
-
console.log(chalk.green("\
|
|
53
|
+
console.log(chalk.green("\nFixed"));
|
|
161
54
|
return;
|
|
162
55
|
}
|
|
163
56
|
|
|
164
|
-
|
|
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
|
-
|
|
57
|
+
if (newEvents.length) {
|
|
182
58
|
console.log(chalk.red("\nNew events:"));
|
|
59
|
+
newEvents.forEach(e => console.log(chalk.red(`+ ${e}`)));
|
|
183
60
|
|
|
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
61
|
process.exit(1);
|
|
194
62
|
}
|
|
195
63
|
|