@eventra_dev/eventra-cli 0.0.18 → 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.
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.scanFunctionWrappers = scanFunctionWrappers;
4
4
  const ts_morph_1 = require("ts-morph");
5
5
  const extract_1 = require("../extract");
6
- function scanFunctionWrappers(source, wrappers) {
7
- const events = new Set();
6
+ function scanFunctionWrappers(source, wrappers, aliases) {
7
+ const events = new Map();
8
8
  const calls = source.getDescendantsOfKind(ts_morph_1.SyntaxKind.CallExpression);
9
9
  for (const call of calls) {
10
10
  const name = getFunctionName(call);
@@ -13,13 +13,16 @@ function scanFunctionWrappers(source, wrappers) {
13
13
  for (const wrapper of wrappers) {
14
14
  if (wrapper.name !== name)
15
15
  continue;
16
- const results = extractEventFromArgs(call, wrapper.event);
16
+ const results = extractEventFromArgs(call, wrapper.event, aliases);
17
17
  if (!results)
18
18
  continue;
19
- results.forEach((r) => events.add(r));
19
+ for (const r of results) {
20
+ const key = `${r.value}:${r.dynamic}`;
21
+ events.set(key, r);
22
+ }
20
23
  }
21
24
  }
22
- return events;
25
+ return [...events.values()];
23
26
  }
24
27
  function getFunctionName(call) {
25
28
  const expression = call.getExpression();
@@ -35,21 +38,18 @@ function getDeepName(node) {
35
38
  let current = node;
36
39
  let name = "";
37
40
  while (ts_morph_1.Node.isPropertyAccessExpression(current)) {
38
- name =
39
- current.getName();
40
- current =
41
- current.getExpression();
41
+ name = current.getName();
42
+ current = current.getExpression();
42
43
  }
43
44
  return name;
44
45
  }
45
- function extractEventFromArgs(call, event) {
46
+ function extractEventFromArgs(call, event, aliases) {
46
47
  const args = call.getArguments();
47
48
  const events = [];
48
- for (let i = 0; i < args.length; i++) {
49
- const arg = args[i];
49
+ for (const arg of args) {
50
50
  // track("event")
51
51
  if (!event) {
52
- const result = (0, extract_1.extractExpression)(arg);
52
+ const result = (0, extract_1.extractExpression)(arg, aliases);
53
53
  if (!result)
54
54
  continue;
55
55
  result.values.forEach((value) => events.push({
@@ -57,7 +57,7 @@ function extractEventFromArgs(call, event) {
57
57
  dynamic: result.dynamic
58
58
  }));
59
59
  }
60
- // track({event})
60
+ // track({ event })
61
61
  if (event) {
62
62
  const obj = arg.asKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
63
63
  if (!obj)
@@ -69,7 +69,7 @@ function extractEventFromArgs(call, event) {
69
69
  const init = prop.getInitializer();
70
70
  if (!init)
71
71
  continue;
72
- const result = (0, extract_1.extractExpression)(init);
72
+ const result = (0, extract_1.extractExpression)(init, aliases);
73
73
  if (!result)
74
74
  continue;
75
75
  result.values.forEach((value) => events.push({
@@ -79,7 +79,5 @@ function extractEventFromArgs(call, event) {
79
79
  }
80
80
  }
81
81
  }
82
- return events.length
83
- ? events
84
- : null;
82
+ return events.length ? events : null;
85
83
  }
@@ -1,10 +1,14 @@
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.scanTrack = scanTrack;
4
7
  const ts_morph_1 = require("ts-morph");
8
+ const path_1 = __importDefault(require("path"));
5
9
  const extract_1 = require("../extract");
6
- function scanTrack(source, config) {
7
- const events = new Set();
10
+ function scanTrack(source, config, aliases) {
11
+ const events = new Map();
8
12
  const calls = source.getDescendantsOfKind(ts_morph_1.SyntaxKind.CallExpression);
9
13
  for (const call of calls) {
10
14
  const expr = call.getExpression();
@@ -19,6 +23,7 @@ function scanTrack(source, config) {
19
23
  }
20
24
  if (!isTrack)
21
25
  continue;
26
+ // ❗ skip wrapper functions
22
27
  const func = call.getFirstAncestorByKind(ts_morph_1.SyntaxKind.FunctionDeclaration) ||
23
28
  call.getFirstAncestorByKind(ts_morph_1.SyntaxKind.ArrowFunction) ||
24
29
  call.getFirstAncestorByKind(ts_morph_1.SyntaxKind.FunctionExpression);
@@ -40,13 +45,20 @@ function scanTrack(source, config) {
40
45
  const arg = call.getArguments()[0];
41
46
  if (!arg)
42
47
  continue;
43
- const result = (0, extract_1.extractExpression)(arg);
48
+ const result = (0, extract_1.extractExpression)(arg, aliases);
44
49
  if (!result)
45
50
  continue;
46
- result.values.forEach((value) => events.add({
47
- value,
48
- dynamic: result.dynamic,
49
- }));
51
+ const line = call.getStartLineNumber();
52
+ const file = path_1.default.relative(process.cwd(), source.getFilePath());
53
+ for (const value of result.values) {
54
+ const key = `${value}:${file}:${line}`;
55
+ events.set(key, {
56
+ value,
57
+ dynamic: result.dynamic,
58
+ file,
59
+ line
60
+ });
61
+ }
50
62
  }
51
- return events;
63
+ return [...events.values()];
52
64
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventra_dev/eventra-cli",
3
- "version": "0.0.18",
3
+ "version": "0.0.19",
4
4
  "description": "Eventra CLI",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -20,6 +20,7 @@
20
20
  },
21
21
  "dependencies": {
22
22
  "chalk": "^4.1.2",
23
+ "chokidar": "^5.0.0",
23
24
  "commander": "^11.0.0",
24
25
  "fast-glob": "^3.3.3",
25
26
  "fs-extra": "^11.2.0",
@@ -2,8 +2,9 @@ import chalk from "chalk";
2
2
  import fg from "fast-glob";
3
3
  import { Project } from "ts-morph";
4
4
  import fs from "fs/promises";
5
+ import inquirer from "inquirer";
5
6
 
6
- import { loadConfig } from "../utils/config";
7
+ import { loadConfig, saveConfig } from "../utils/config";
7
8
 
8
9
  import { detectParser } from "../utils/parsers/router";
9
10
  import { parseVue } from "../utils/parsers/vue";
@@ -16,7 +17,7 @@ import { scanComponentWrappers } from "../utils/scanners/component-wrappers";
16
17
 
17
18
  import { ExtractedEvent } from "../types";
18
19
 
19
- export async function check() {
20
+ export async function check({ fix = false }: { fix?: boolean }) {
20
21
  const config = await loadConfig();
21
22
 
22
23
  if (!config) {
@@ -29,11 +30,11 @@ export async function check() {
29
30
  const project = new Project();
30
31
 
31
32
  const knownEvents = new Set(config.events ?? []);
32
- const aliases = config.aliases ?? {};
33
+ const aliases = { ...(config.aliases ?? {}) };
33
34
 
34
- const foundEvents = new Set<string>();
35
- const newEvents = new Set<string>();
36
- const unresolvedDynamic = new Set<string>();
35
+ const foundEvents = new Map<string, ExtractedEvent>();
36
+ const newEvents = new Map<string, ExtractedEvent>();
37
+ const unresolvedDynamic = new Map<string, ExtractedEvent>();
37
38
 
38
39
  const files = await fg(config.sync.include, {
39
40
  ignore: config.sync.exclude
@@ -41,132 +42,156 @@ export async function check() {
41
42
 
42
43
  for (const file of files) {
43
44
  try {
44
- // skip huge files
45
45
  const stat = await fs.stat(file);
46
+
46
47
  if (stat.size > 2 * 1024 * 1024) {
47
- console.log(chalk.gray(`Skipped large file: ${file}`));
48
48
  continue;
49
49
  }
50
50
 
51
51
  const parser = detectParser(file);
52
-
53
52
  let content = await fs.readFile(file, "utf-8");
54
53
 
55
54
  if (parser === "vue") content = parseVue(content);
56
55
  if (parser === "svelte") content = parseSvelte(content);
57
56
  if (parser === "astro") content = parseAstro(content);
58
57
 
59
- const virtualFile =
60
- parser === "ts" ? file : file + ".tsx";
61
-
62
- const source = project.createSourceFile(
63
- virtualFile,
64
- content,
65
- { overwrite: true }
66
- );
58
+ const source = project.createSourceFile(file, content, {
59
+ overwrite: true
60
+ });
67
61
 
68
62
  const found: ExtractedEvent[] = [
69
- ...scanTrack(source, config),
70
- ...scanFunctionWrappers(
71
- source,
72
- config.functionWrappers ?? []
73
- ),
74
- ...scanComponentWrappers(
75
- source,
76
- config.wrappers ?? []
77
- )
63
+ ...scanTrack(source, config, aliases),
64
+ ...scanFunctionWrappers(source, config.functionWrappers ?? [], aliases),
65
+ ...scanComponentWrappers(source, config.wrappers ?? [], aliases)
78
66
  ];
79
67
 
80
68
  for (const event of found) {
81
69
  const { value, dynamic } = event;
82
-
83
70
  if (!value) continue;
84
71
 
85
- // alias skip
86
- if (aliases[value] === "__skip__") {
87
- continue;
88
- }
72
+ // skip
73
+ if (aliases[value] === "__skip__") continue;
89
74
 
90
75
  // alias resolve
91
- if (aliases[value]) {
92
- foundEvents.add(aliases[value]);
76
+ if (value in aliases) {
77
+ foundEvents.set(aliases[value], {
78
+ ...event,
79
+ value: aliases[value]
80
+ });
93
81
  continue;
94
82
  }
95
83
 
96
- // dynamic without alias
97
84
  if (dynamic) {
98
- unresolvedDynamic.add(value);
85
+ unresolvedDynamic.set(value, event);
99
86
  continue;
100
87
  }
101
88
 
102
- // static
103
- foundEvents.add(value);
89
+ foundEvents.set(value, event);
104
90
  }
105
91
 
106
- // clear memory
107
92
  project.removeSourceFile(source);
108
93
 
109
94
  } catch {
110
- console.log(
111
- chalk.gray(`Skipped file (error): ${file}`)
112
- );
95
+ console.log(chalk.gray(`Skipped: ${file}`));
113
96
  }
114
97
  }
115
98
 
116
- // find new events
117
- for (const event of foundEvents) {
118
- if (!knownEvents.has(event)) {
119
- newEvents.add(event);
99
+ // find new
100
+ for (const [key, event] of foundEvents) {
101
+ if (!knownEvents.has(key)) {
102
+ newEvents.set(key, event);
120
103
  }
121
104
  }
122
105
 
123
- let hasError = false;
106
+ // FIX MODE
107
+ if (fix) {
108
+ console.log(chalk.yellow("\nFix mode\n"));
124
109
 
125
- // dynamic
126
- if (unresolvedDynamic.size > 0) {
127
- hasError = true;
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
+ ]);
128
142
 
129
- console.log(
130
- chalk.red("\nUnresolved dynamic events:")
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()
131
154
  );
132
155
 
133
- [...unresolvedDynamic]
134
- .sort()
135
- .forEach((e) =>
136
- console.log(chalk.red(`- ${e}`))
137
- );
156
+ config.events = [...new Set(config.events)].sort();
157
+
158
+ await saveConfig(config);
159
+
160
+ console.log(chalk.green("\n✔ Fixed"));
161
+ return;
138
162
  }
139
163
 
140
- // new events
141
- if (newEvents.size > 0) {
164
+ // NORMAL MODE
165
+ let hasError = false;
166
+
167
+ if (unresolvedDynamic.size) {
142
168
  hasError = true;
143
169
 
144
- console.log(
145
- chalk.red("\nNew events detected:")
146
- );
170
+ console.log(chalk.red("\nDynamic events:"));
147
171
 
148
- [...newEvents]
149
- .sort()
150
- .forEach((e) =>
151
- console.log(chalk.red(`+ ${e}`))
152
- );
172
+ unresolvedDynamic.forEach((e) =>
173
+ console.log(
174
+ chalk.red(`- ${e.value} (${e.file}:${e.line})`)
175
+ )
176
+ );
153
177
  }
154
178
 
155
- if (hasError) {
156
- console.log("");
179
+ if (newEvents.size) {
180
+ hasError = true;
157
181
 
158
- console.log(chalk.red("Event check failed"));
182
+ console.log(chalk.red("\nNew events:"));
159
183
 
160
- console.log(
161
- chalk.red(
162
- `dynamic: ${unresolvedDynamic.size}, new: ${newEvents.size}`
184
+ newEvents.forEach((e) =>
185
+ console.log(
186
+ chalk.red(`+ ${e.value} (${e.file}:${e.line})`)
163
187
  )
164
188
  );
189
+ }
165
190
 
191
+ if (hasError) {
192
+ console.log(chalk.red("\nEvent check failed"));
166
193
  process.exit(1);
167
194
  }
168
195
 
169
- console.log(
170
- chalk.green("\nAll events are valid")
171
- );
196
+ console.log(chalk.green("\nAll good"));
172
197
  }