@eventra_dev/eventra-cli 0.0.19 → 0.1.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 +17 -117
- package/dist/commands/sync.js +20 -115
- package/dist/commands/watch.js +107 -69
- package/dist/engine/callResolver.js +34 -0
- package/dist/engine/engine.js +47 -0
- package/dist/engine/graph.js +25 -0
- package/dist/engine/hash.js +10 -0
- package/dist/engine/languageService.js +67 -0
- package/dist/engine/resolver.js +69 -0
- package/dist/engine/scanner.js +50 -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 +43 -0
- package/src/engine/engine.ts +60 -0
- package/src/engine/graph.ts +23 -0
- package/src/engine/hash.ts +5 -0
- package/src/engine/languageService.ts +73 -0
- package/src/engine/resolver.ts +86 -0
- package/src/engine/scanner.ts +61 -0
- package/src/types.ts +5 -6
- 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,67 @@
|
|
|
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.TSService = void 0;
|
|
7
|
+
const typescript_1 = __importDefault(require("typescript"));
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
class TSService {
|
|
10
|
+
root;
|
|
11
|
+
files = new Map();
|
|
12
|
+
service;
|
|
13
|
+
constructor(root) {
|
|
14
|
+
this.root = root;
|
|
15
|
+
const host = {
|
|
16
|
+
getScriptFileNames: () => [...this.files.keys()],
|
|
17
|
+
getScriptVersion: (file) => this.files.get(file)?.version.toString() ?? "0",
|
|
18
|
+
getScriptSnapshot: (file) => {
|
|
19
|
+
const f = this.files.get(file);
|
|
20
|
+
if (f) {
|
|
21
|
+
return typescript_1.default.ScriptSnapshot.fromString(f.content);
|
|
22
|
+
}
|
|
23
|
+
if (fs_1.default.existsSync(file)) {
|
|
24
|
+
return typescript_1.default.ScriptSnapshot.fromString(fs_1.default.readFileSync(file, "utf-8"));
|
|
25
|
+
}
|
|
26
|
+
return undefined;
|
|
27
|
+
},
|
|
28
|
+
getCurrentDirectory: () => this.root,
|
|
29
|
+
getCompilationSettings: () => ({
|
|
30
|
+
allowJs: true,
|
|
31
|
+
jsx: typescript_1.default.JsxEmit.Preserve,
|
|
32
|
+
moduleResolution: typescript_1.default.ModuleResolutionKind.Node16,
|
|
33
|
+
target: typescript_1.default.ScriptTarget.ESNext,
|
|
34
|
+
esModuleInterop: true,
|
|
35
|
+
allowSyntheticDefaultImports: true,
|
|
36
|
+
}),
|
|
37
|
+
getDefaultLibFileName: (opts) => typescript_1.default.getDefaultLibFilePath(opts),
|
|
38
|
+
readFile: (fileName, encoding) => {
|
|
39
|
+
try {
|
|
40
|
+
return fs_1.default.readFileSync(fileName, encoding);
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
fileExists: fs_1.default.existsSync,
|
|
47
|
+
};
|
|
48
|
+
this.service = typescript_1.default.createLanguageService(host);
|
|
49
|
+
}
|
|
50
|
+
updateFile(file, content) {
|
|
51
|
+
const prev = this.files.get(file);
|
|
52
|
+
this.files.set(file, {
|
|
53
|
+
content,
|
|
54
|
+
version: prev ? prev.version + 1 : 1,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
getProgram() {
|
|
58
|
+
return this.service.getProgram();
|
|
59
|
+
}
|
|
60
|
+
getChecker() {
|
|
61
|
+
return this.getProgram()?.getTypeChecker();
|
|
62
|
+
}
|
|
63
|
+
getSourceFile(file) {
|
|
64
|
+
return this.getProgram()?.getSourceFile(file);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.TSService = TSService;
|
|
@@ -0,0 +1,69 @@
|
|
|
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.resolveNodeValue = resolveNodeValue;
|
|
7
|
+
const typescript_1 = __importDefault(require("typescript"));
|
|
8
|
+
function resolveNodeValue(node, checker) {
|
|
9
|
+
if (typescript_1.default.isStringLiteral(node)) {
|
|
10
|
+
return { values: [node.text], dynamic: false };
|
|
11
|
+
}
|
|
12
|
+
if (typescript_1.default.isTemplateExpression(node)) {
|
|
13
|
+
let result = node.head.text;
|
|
14
|
+
for (const span of node.templateSpans) {
|
|
15
|
+
result += "*";
|
|
16
|
+
result += span.literal.text;
|
|
17
|
+
}
|
|
18
|
+
return { values: [result], dynamic: true };
|
|
19
|
+
}
|
|
20
|
+
if (typescript_1.default.isConditionalExpression(node)) {
|
|
21
|
+
const a = resolveNodeValue(node.whenTrue, checker);
|
|
22
|
+
const b = resolveNodeValue(node.whenFalse, checker);
|
|
23
|
+
return {
|
|
24
|
+
values: [...new Set([...(a?.values ?? []), ...(b?.values ?? [])])],
|
|
25
|
+
dynamic: true,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (typescript_1.default.isIdentifier(node)) {
|
|
29
|
+
let symbol = checker.getSymbolAtLocation(node);
|
|
30
|
+
if (!symbol)
|
|
31
|
+
return null;
|
|
32
|
+
if (symbol.flags & typescript_1.default.SymbolFlags.Alias) {
|
|
33
|
+
symbol = checker.getAliasedSymbol(symbol);
|
|
34
|
+
}
|
|
35
|
+
for (const decl of symbol.getDeclarations() ?? []) {
|
|
36
|
+
if (typescript_1.default.isVariableDeclaration(decl) && decl.initializer) {
|
|
37
|
+
return resolveNodeValue(decl.initializer, checker);
|
|
38
|
+
}
|
|
39
|
+
if (typescript_1.default.isEnumMember(decl) && decl.initializer) {
|
|
40
|
+
if (typescript_1.default.isStringLiteral(decl.initializer)) {
|
|
41
|
+
return {
|
|
42
|
+
values: [decl.initializer.text],
|
|
43
|
+
dynamic: false,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (typescript_1.default.isPropertyAccessExpression(node)) {
|
|
50
|
+
const symbol = checker.getSymbolAtLocation(node);
|
|
51
|
+
if (symbol) {
|
|
52
|
+
let s = symbol;
|
|
53
|
+
if (s.flags & typescript_1.default.SymbolFlags.Alias) {
|
|
54
|
+
s = checker.getAliasedSymbol(s);
|
|
55
|
+
}
|
|
56
|
+
for (const decl of s.getDeclarations() ?? []) {
|
|
57
|
+
if (typescript_1.default.isEnumMember(decl) && decl.initializer) {
|
|
58
|
+
if (typescript_1.default.isStringLiteral(decl.initializer)) {
|
|
59
|
+
return {
|
|
60
|
+
values: [decl.initializer.text],
|
|
61
|
+
dynamic: false,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
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.scanSource = scanSource;
|
|
7
|
+
const typescript_1 = __importDefault(require("typescript"));
|
|
8
|
+
const resolver_1 = require("./resolver");
|
|
9
|
+
const callResolver_1 = require("./callResolver");
|
|
10
|
+
function scanSource(source, checker, visited = new Set()) {
|
|
11
|
+
const events = new Set();
|
|
12
|
+
if (visited.has(source.fileName))
|
|
13
|
+
return events;
|
|
14
|
+
visited.add(source.fileName);
|
|
15
|
+
function visit(node) {
|
|
16
|
+
if (typescript_1.default.isCallExpression(node)) {
|
|
17
|
+
const name = getCallName(node.expression);
|
|
18
|
+
if (/(track|event|capture|send)/i.test(name)) {
|
|
19
|
+
let target = node.arguments[0];
|
|
20
|
+
const fn = (0, callResolver_1.resolveFunctionFromCall)(node.expression, checker);
|
|
21
|
+
// 🔥 cross-file
|
|
22
|
+
if (fn) {
|
|
23
|
+
const sf = fn.getSourceFile();
|
|
24
|
+
if (!visited.has(sf.fileName)) {
|
|
25
|
+
scanSource(sf, checker, visited).forEach(e => events.add(e));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (target) {
|
|
29
|
+
const res = (0, resolver_1.resolveNodeValue)(target, checker);
|
|
30
|
+
res?.values.forEach(v => {
|
|
31
|
+
if (v && v.length > 1 && !v.includes(" ")) {
|
|
32
|
+
events.add(v);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
typescript_1.default.forEachChild(node, visit);
|
|
39
|
+
}
|
|
40
|
+
visit(source);
|
|
41
|
+
return events;
|
|
42
|
+
}
|
|
43
|
+
function getCallName(expr) {
|
|
44
|
+
if (typescript_1.default.isIdentifier(expr))
|
|
45
|
+
return expr.text;
|
|
46
|
+
if (typescript_1.default.isPropertyAccessExpression(expr)) {
|
|
47
|
+
return expr.name.text;
|
|
48
|
+
}
|
|
49
|
+
return "";
|
|
50
|
+
}
|
|
@@ -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
|
|