@eventra_dev/eventra-cli 0.3.1 → 0.3.3

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.
Files changed (35) hide show
  1. package/README.md +2 -13
  2. package/dist/analysis/cache/evaluationCache.js +1 -3
  3. package/dist/analysis/cache/resolvedCallCache.js +1 -3
  4. package/dist/analysis/cache/resolvedExportCache.js +1 -3
  5. package/dist/analysis/cache/returnPropagationCache.js +19 -0
  6. package/dist/analysis/cache/symbolInvalidation.js +8 -2
  7. package/dist/analysis/extractor/extractor.js +5 -13
  8. package/dist/analysis/extractor/propagationExtractor.js +55 -14
  9. package/dist/analysis/resolver/callResolver.js +10 -52
  10. package/dist/analysis/resolver/exportResolver.js +4 -19
  11. package/dist/analysis/resolver/resolver.js +148 -29
  12. package/dist/analysis/scanner/analyzer/propagationAnalyzer.js +19 -48
  13. package/dist/analysis/scanner/analyzer/returnPropagationAnalyzer.js +2 -13
  14. package/dist/analysis/scanner/scanner.js +16 -44
  15. package/dist/analysis/scanner/sinkDetector.js +10 -44
  16. package/dist/analysis/shared/evaluationContext.js +0 -1
  17. package/dist/analysis/symbols/symbolUtils.js +6 -29
  18. package/dist/analysis/symbols/wrapperRegistry.js +25 -25
  19. package/dist/cli/check.js +8 -10
  20. package/dist/cli/init.js +18 -82
  21. package/dist/cli/send.js +7 -5
  22. package/dist/cli/sync.js +4 -39
  23. package/dist/cli/watch.js +42 -40
  24. package/dist/compiler/compilerContext.js +18 -41
  25. package/dist/compiler/documentRegistry.js +5 -15
  26. package/dist/compiler/importGraph.js +4 -8
  27. package/dist/compiler/scheduler.js +1 -3
  28. package/dist/config/config.js +9 -19
  29. package/dist/core/EventraEngine.js +37 -101
  30. package/dist/core/projectScanner.js +7 -6
  31. package/dist/filesystem/processFile.js +1 -4
  32. package/dist/shared/buildSyntheticTsx.js +1 -2
  33. package/package.json +1 -1
  34. package/dist/analysis/cache/semanticDependencyGraph.js +0 -25
  35. package/dist/analysis/pipeline/semanticPass.js +0 -2
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- // src/analysis/scanner/sinkDetector.ts
3
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
4
  };
@@ -7,69 +6,39 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
6
  exports.detectTrackSink = detectTrackSink;
8
7
  const typescript_1 = __importDefault(require("typescript"));
9
8
  function isElementTrackProperty(expr) {
10
- return (typescript_1.default.isElementAccessExpression(expr)
11
- && expr.argumentExpression
12
- && typescript_1.default.isStringLiteral(expr.argumentExpression)
13
- && expr.argumentExpression.text
14
- === "track");
9
+ return (typescript_1.default.isElementAccessExpression(expr) && expr.argumentExpression && typescript_1.default.isStringLiteral(expr.argumentExpression) && expr.argumentExpression.text === "track");
15
10
  }
16
11
  function isTrackIdentifier(expr) {
17
- return (typescript_1.default.isIdentifier(expr)
18
- && expr.text === "track");
12
+ return (typescript_1.default.isIdentifier(expr) && expr.text === "track");
19
13
  }
20
14
  function isTrackProperty(expr) {
21
- return (typescript_1.default.isPropertyAccessExpression(expr)
22
- && expr.name.text
23
- === "track");
15
+ return (typescript_1.default.isPropertyAccessExpression(expr) && expr.name.text === "track");
24
16
  }
25
17
  function isOptionalTrackProperty(expr) {
26
- return (typescript_1.default.isPropertyAccessChain(expr)
27
- && expr.name.text
28
- === "track");
18
+ return (typescript_1.default.isPropertyAccessChain(expr) && expr.name.text === "track");
29
19
  }
30
20
  function extractTrackedArguments(call) {
31
21
  const result = [];
32
- if (call.arguments.length
33
- === 0) {
22
+ if (call.arguments.length === 0) {
34
23
  return result;
35
24
  }
36
- //
37
- // ONLY FIRST ARGUMENT
38
- // IS EVENT SINK
39
- //
40
- // track(name, payload)
41
- // ^^^^
42
- //
43
25
  const first = call.arguments[0];
44
- //
45
- // track({
46
- // event: "signup"
47
- // })
48
- //
49
26
  if (typescript_1.default.isObjectLiteralExpression(first)) {
50
27
  for (const property of first.properties) {
51
- if (!typescript_1.default.isPropertyAssignment(property)) {
28
+ if (!typescript_1.default.isPropertyAssignment(property) && !typescript_1.default.isShorthandPropertyAssignment(property)) {
52
29
  continue;
53
30
  }
54
- const name = property.name
55
- .getText();
56
- if (name !== "event"
57
- && name !== "name"
58
- && name !== "type") {
31
+ const name = property.name.getText();
32
+ if (name !== "event" && name !== "name" && name !== "type") {
59
33
  continue;
60
34
  }
61
35
  result.push({
62
36
  index: 0,
63
- propertyPath: [
64
- name,
65
- ],
37
+ propertyPath: [name],
66
38
  });
67
39
  }
68
40
  return result;
69
41
  }
70
- //
71
- // track(name)
72
- //
73
42
  result.push({
74
43
  index: 0,
75
44
  propertyPath: [],
@@ -78,10 +47,7 @@ function extractTrackedArguments(call) {
78
47
  }
79
48
  function detectTrackSink(call) {
80
49
  const expression = call.expression;
81
- if (!isTrackIdentifier(expression)
82
- && !isTrackProperty(expression)
83
- && !isOptionalTrackProperty(expression)
84
- && !isElementTrackProperty(expression)) {
50
+ if (!isTrackIdentifier(expression) && !isTrackProperty(expression) && !isOptionalTrackProperty(expression) && !isElementTrackProperty(expression)) {
85
51
  return null;
86
52
  }
87
53
  return {
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- // src/analysis/shared/evaluationContext.ts
3
2
  Object.defineProperty(exports, "__esModule", { value: true });
4
3
  exports.createEvaluationContext = createEvaluationContext;
5
4
  function createEvaluationContext() {
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- // src/analysis/symbols/symbolUtils.ts
3
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
4
  };
@@ -7,60 +6,38 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
6
  exports.getFunctionSymbol = getFunctionSymbol;
8
7
  const typescript_1 = __importDefault(require("typescript"));
9
8
  function getFunctionSymbol(node, checker) {
10
- //
11
9
  // function foo() {}
12
- //
13
- if (typescript_1.default.isFunctionDeclaration(node)
14
- && node.name) {
10
+ if (typescript_1.default.isFunctionDeclaration(node) && node.name) {
15
11
  return checker.getSymbolAtLocation(node.name);
16
12
  }
17
- //
18
13
  // class method() {}
19
- //
20
- if (typescript_1.default.isMethodDeclaration(node)
21
- && typescript_1.default.isIdentifier(node.name)) {
14
+ if (typescript_1.default.isMethodDeclaration(node) && typescript_1.default.isIdentifier(node.name)) {
22
15
  return checker.getSymbolAtLocation(node.name);
23
16
  }
24
- //
25
17
  // object literal method
26
- //
27
18
  // const obj = {
28
19
  // foo() {}
29
20
  // }
30
- //
31
- if (typescript_1.default.isMethodDeclaration(node)
32
- && typescript_1.default.isComputedPropertyName(node.name)) {
21
+ if (typescript_1.default.isMethodDeclaration(node) && typescript_1.default.isComputedPropertyName(node.name)) {
33
22
  return checker.getSymbolAtLocation(node.name.expression);
34
23
  }
35
- //
36
24
  // const foo = () => {}
37
- //
38
25
  const parent = node.parent;
39
- if (typescript_1.default.isVariableDeclaration(parent)
40
- && typescript_1.default.isIdentifier(parent.name)) {
26
+ if (typescript_1.default.isVariableDeclaration(parent) && typescript_1.default.isIdentifier(parent.name)) {
41
27
  return checker.getSymbolAtLocation(parent.name);
42
28
  }
43
- //
44
29
  // class field = () => {}
45
- //
46
- if (typescript_1.default.isPropertyDeclaration(parent)
47
- && typescript_1.default.isIdentifier(parent.name)) {
30
+ if (typescript_1.default.isPropertyDeclaration(parent) && typescript_1.default.isIdentifier(parent.name)) {
48
31
  return checker.getSymbolAtLocation(parent.name);
49
32
  }
50
- //
51
33
  // object property
52
- //
53
34
  // const x = {
54
35
  // foo: () => {}
55
36
  // }
56
- //
57
- if (typescript_1.default.isPropertyAssignment(parent)
58
- && typescript_1.default.isIdentifier(parent.name)) {
37
+ if (typescript_1.default.isPropertyAssignment(parent) && typescript_1.default.isIdentifier(parent.name)) {
59
38
  return checker.getSymbolAtLocation(parent.name);
60
39
  }
61
- //
62
40
  // export default function() {}
63
- //
64
41
  if (typescript_1.default.isExportAssignment(parent)) {
65
42
  return checker.getSymbolAtLocation(node);
66
43
  }
@@ -10,46 +10,46 @@ function isSymbol(value) {
10
10
  return "flags" in value;
11
11
  }
12
12
  class WrapperRegistry {
13
+ checker;
14
+ exportCache;
13
15
  wrappers = new WeakMap();
14
- normalize(symbol, checker, exportCache) {
15
- return ((0, exportResolver_1.resolveExportedSymbol)(symbol, checker, exportCache)
16
- ?? symbol);
16
+ constructor(checker, exportCache) {
17
+ this.checker = checker;
18
+ this.exportCache = exportCache;
17
19
  }
18
- set(semantic, checker, exportCache) {
19
- this.wrappers.set(this.normalize(semantic.symbol, checker, exportCache), semantic);
20
+ normalize(symbol) {
21
+ return ((0, exportResolver_1.resolveExportedSymbol)(symbol, this.checker, this.exportCache) ?? symbol);
20
22
  }
21
- get(target, checker, exportCache) {
23
+ set(semantic) {
24
+ this.wrappers.set(this.normalize(semantic.symbol), semantic);
25
+ }
26
+ get(target) {
22
27
  if (isSymbol(target)) {
23
- return this.wrappers.get(this.normalize(target, checker, exportCache));
28
+ return this.wrappers.get(this.normalize(target));
24
29
  }
25
30
  let symbol;
26
- if (typescript_1.default.isFunctionDeclaration(target)
27
- && target.name) {
28
- symbol =
29
- checker.getSymbolAtLocation(target.name);
31
+ if (typescript_1.default.isFunctionDeclaration(target) && target.name) {
32
+ symbol = this.checker.getSymbolAtLocation(target.name);
30
33
  }
31
- else if (typescript_1.default.isMethodDeclaration(target)
32
- && typescript_1.default.isIdentifier(target.name)) {
33
- symbol =
34
- checker.getSymbolAtLocation(target.name);
34
+ else if (typescript_1.default.isMethodDeclaration(target) && typescript_1.default.isIdentifier(target.name)) {
35
+ symbol = this.checker.getSymbolAtLocation(target.name);
35
36
  }
36
- else if (target.parent
37
- && typescript_1.default.isVariableDeclaration(target.parent)
38
- && typescript_1.default.isIdentifier(target.parent.name)) {
39
- symbol =
40
- checker.getSymbolAtLocation(target.parent.name);
37
+ else if (target.parent && typescript_1.default.isVariableDeclaration(target.parent) && typescript_1.default.isIdentifier(target.parent.name)) {
38
+ symbol = this.checker.getSymbolAtLocation(target.parent.name);
41
39
  }
42
40
  if (!symbol) {
43
41
  return undefined;
44
42
  }
45
- return this.wrappers.get(this.normalize(symbol, checker, exportCache));
43
+ return this.wrappers.get(this.normalize(symbol));
44
+ }
45
+ has(symbol) {
46
+ return this.wrappers.has(this.normalize(symbol));
46
47
  }
47
- has(symbol, checker, exportCache) {
48
- return this.wrappers.has(this.normalize(symbol, checker, exportCache));
48
+ delete(symbol) {
49
+ this.wrappers.delete(this.normalize(symbol));
49
50
  }
50
51
  clear() {
51
- this.wrappers =
52
- new WeakMap();
52
+ this.wrappers = new WeakMap();
53
53
  }
54
54
  }
55
55
  exports.WrapperRegistry = WrapperRegistry;
package/dist/cli/check.js CHANGED
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- // src/commands/check.ts
3
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
3
  if (k2 === undefined) k2 = k;
5
4
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -51,20 +50,19 @@ async function check({ fix = false }) {
51
50
  const { engine } = await (0, projectScanner_1.scanProject)(config);
52
51
  const found = new Set(engine.getAllEvents());
53
52
  const known = new Set(config.events ?? []);
54
- const added = [...found]
55
- .filter(e => !known.has(e));
56
- const removed = [...known]
57
- .filter(e => !found.has(e));
53
+ const added = [...found].filter(e => !known.has(e));
54
+ const removed = [...known].filter(e => !found.has(e));
58
55
  if (fix) {
59
- config.events =
60
- [...found].sort();
56
+ const nextConfig = {
57
+ ...config,
58
+ events: [...found].sort(),
59
+ };
61
60
  const { saveConfig } = await Promise.resolve().then(() => __importStar(require("../config/config")));
62
- await saveConfig(config);
61
+ await saveConfig(nextConfig);
63
62
  console.log(chalk_1.default.green("Synced"));
64
63
  return;
65
64
  }
66
- if (added.length
67
- || removed.length) {
65
+ if (added.length || removed.length) {
68
66
  added.forEach(e => console.log(chalk_1.default.red(`+ ${e}`)));
69
67
  removed.forEach(e => console.log(chalk_1.default.yellow(`- ${e}`)));
70
68
  process.exit(1);
package/dist/cli/init.js CHANGED
@@ -9,109 +9,45 @@ const inquirer_1 = __importDefault(require("inquirer"));
9
9
  const config_1 = require("../config/config");
10
10
  async function init() {
11
11
  console.log(chalk_1.default.blue("Initializing Eventra..."));
12
- // API KEY ENDPOINT
13
- const { apiKey, endpoint } = await inquirer_1.default.prompt([
12
+ const { apiKey, endpoint, } = await inquirer_1.default.prompt([
14
13
  {
15
14
  type: "input",
16
15
  name: "apiKey",
17
- message: "API Key (optional):"
16
+ message: "API Key (optional):",
18
17
  },
19
18
  {
20
19
  type: "input",
21
20
  name: "endpoint",
22
21
  message: "Custom endpoint (optional):",
23
- default: "https://api.eventra.dev/api/v1/cli/events"
24
- }
22
+ default: "https://api.eventra.dev/api/v1/cli/events",
23
+ },
25
24
  ]);
26
- console.log(chalk_1.default.gray("\nEventra automatically detects:"));
25
+ console.log("");
26
+ console.log(chalk_1.default.gray("Eventra automatically detects:"));
27
27
  console.log(chalk_1.default.gray("• track('event')"));
28
- console.log(chalk_1.default.gray("• tracker.track('event')"));
29
- const wrappers = [];
30
- const functionWrappers = [];
31
- // COMPONENT WRAPPERS
32
- console.log(chalk_1.default.blue("\nComponent wrappers"));
33
- let addComponent = true;
34
- while (addComponent) {
35
- const { useWrapper } = await inquirer_1.default.prompt([
36
- {
37
- type: "confirm",
38
- name: "useWrapper",
39
- message: "Add component wrapper?",
40
- default: false
41
- }
42
- ]);
43
- if (!useWrapper)
44
- break;
45
- const { name, prop } = await inquirer_1.default.prompt([
46
- {
47
- type: "input",
48
- name: "name",
49
- message: "Component name:",
50
- validate: (v) => v ? true : "Required"
51
- },
52
- {
53
- type: "input",
54
- name: "prop",
55
- message: "Event prop:",
56
- default: "event"
57
- }
58
- ]);
59
- wrappers.push({
60
- name,
61
- prop
62
- });
63
- }
64
- // FUNCTION WRAPPERS
65
- console.log(chalk_1.default.blue("\nFunction wrappers"));
66
- let addFunction = true;
67
- while (addFunction) {
68
- const { useWrapper } = await inquirer_1.default.prompt([
69
- {
70
- type: "confirm",
71
- name: "useWrapper",
72
- message: "Add function wrapper?",
73
- default: false
74
- }
75
- ]);
76
- if (!useWrapper)
77
- break;
78
- const { name, event } = await inquirer_1.default.prompt([
79
- {
80
- type: "input",
81
- name: "name",
82
- message: "Function name:"
83
- },
84
- {
85
- type: "input",
86
- name: "event",
87
- message: "Event field (leave empty if string argument):",
88
- default: ""
89
- }
90
- ]);
91
- functionWrappers.push({
92
- name,
93
- event: event || undefined
94
- });
95
- }
28
+ console.log(chalk_1.default.gray("• analytics.track('event')"));
29
+ console.log(chalk_1.default.gray("• semantic parameter propagation"));
30
+ console.log(chalk_1.default.gray("• cross-file wrappers"));
31
+ console.log(chalk_1.default.gray("• parameter propagation"));
32
+ console.log("");
96
33
  const config = {
97
34
  apiKey,
98
35
  endpoint,
99
36
  events: [],
100
- wrappers,
101
- functionWrappers,
102
37
  sync: {
103
38
  include: [
104
- "**/*.{ts,tsx,js,jsx,vue,svelte,astro}"
39
+ "**/*.{ts,tsx,js,jsx}",
105
40
  ],
106
41
  exclude: [
107
42
  "node_modules",
108
43
  "dist",
109
44
  ".next",
110
- ".git"
111
- ]
112
- }
45
+ ".git",
46
+ ],
47
+ },
113
48
  };
114
49
  await (0, config_1.saveConfig)(config);
115
- console.log(chalk_1.default.green("\neventra.json created"));
116
- console.log(chalk_1.default.gray("\nRun `eventra sync`"));
50
+ console.log(chalk_1.default.green("eventra.json created"));
51
+ console.log("");
52
+ console.log(chalk_1.default.gray("Run `eventra sync`"));
117
53
  }
package/dist/cli/send.js CHANGED
@@ -11,8 +11,7 @@ const package_json_1 = __importDefault(require("../../package.json"));
11
11
  const CLI_VERSION = package_json_1.default.version;
12
12
  async function send() {
13
13
  const config = await (0, config_1.loadConfig)();
14
- const endpoint = config?.endpoint ||
15
- process.env.EVENTRA_ENDPOINT;
14
+ const endpoint = config?.endpoint || process.env.EVENTRA_ENDPOINT;
16
15
  if (!config) {
17
16
  console.log(chalk_1.default.red("eventra.json not found. Run 'eventra init'"));
18
17
  return;
@@ -28,8 +27,10 @@ async function send() {
28
27
  }
29
28
  ]);
30
29
  apiKey = answers.apiKey;
31
- config.apiKey = apiKey;
32
- await (0, config_1.saveConfig)(config);
30
+ await (0, config_1.saveConfig)({
31
+ ...config,
32
+ apiKey,
33
+ });
33
34
  console.log(chalk_1.default.green("API key saved"));
34
35
  }
35
36
  // no events
@@ -72,7 +73,8 @@ async function send() {
72
73
  const text = await res.text();
73
74
  console.log(chalk_1.default.gray(text));
74
75
  }
75
- catch { }
76
+ catch {
77
+ }
76
78
  return;
77
79
  }
78
80
  const data = await res.json();
package/dist/cli/sync.js CHANGED
@@ -1,5 +1,4 @@
1
1
  "use strict";
2
- // src/commands/sync.ts
3
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
4
  };
@@ -11,46 +10,12 @@ const projectScanner_1 = require("../core/projectScanner");
11
10
  async function sync() {
12
11
  const config = await (0, config_1.loadConfig)();
13
12
  if (!config) {
13
+ console.log(chalk_1.default.red("eventra.json not found"));
14
14
  return;
15
15
  }
16
16
  console.log(chalk_1.default.blue("Scanning..."));
17
- const { engine, results, } = await (0, projectScanner_1.scanProject)(config);
18
- const detectedFn = new Set();
19
- const detectedCmp = new Map();
20
- for (const result of results.values()) {
21
- result
22
- .detectedFunctionWrappers
23
- .forEach(w => detectedFn.add(w));
24
- result
25
- .detectedComponentWrappers
26
- .forEach((v, k) => detectedCmp.set(k, v));
27
- }
28
- const events = engine
29
- .getAllEvents()
30
- .sort();
31
- config.events =
32
- events;
33
- config.functionWrappers =
34
- mergeUnique(config.functionWrappers
35
- ?? [], [...detectedFn]
36
- .map(name => ({
37
- name
38
- })), w => w.name);
39
- config.wrappers =
40
- mergeUnique(config.wrappers
41
- ?? [], [...detectedCmp.entries()]
42
- .map(([name, prop]) => ({
43
- name,
44
- prop,
45
- })), w => `${w.name}:${w.prop}`);
46
- await (0, config_1.saveConfig)(config);
17
+ const { engine } = await (0, projectScanner_1.scanProject)(config);
18
+ const events = engine.getAllEvents().sort();
19
+ await (0, config_1.saveConfig)({ ...config, events });
47
20
  console.log(chalk_1.default.green(`Found ${events.length} events`));
48
21
  }
49
- function mergeUnique(a, b, key) {
50
- const map = new Map();
51
- [...b, ...a]
52
- .forEach(item => map.set(key(item), item));
53
- return [
54
- ...map.values()
55
- ];
56
- }
package/dist/cli/watch.js CHANGED
@@ -16,6 +16,7 @@ const getVirtualFile_1 = require("../filesystem/getVirtualFile");
16
16
  async function watch() {
17
17
  const config = await (0, config_1.loadConfig)();
18
18
  if (!config) {
19
+ console.log(chalk_1.default.red("eventra.json not found"));
19
20
  return;
20
21
  }
21
22
  console.log(chalk_1.default.blue("Watching...\n"));
@@ -23,13 +24,15 @@ async function watch() {
23
24
  const fileDeps = new Map();
24
25
  const cache = new Map();
25
26
  const watchedDeps = new Set();
26
- const normalize = (f) => path_1.default.resolve(f)
27
- .replace(/\\/g, "/");
27
+ const normalize = (file) => {
28
+ return path_1.default.resolve(file).replace(/\\/g, "/");
29
+ };
28
30
  // INITIAL LOAD
29
31
  const files = await (0, fast_glob_1.default)(config.sync.include, {
30
32
  ignore: config.sync.exclude,
31
33
  absolute: true,
32
34
  });
35
+ engine.beginPreload();
33
36
  for (const file of files) {
34
37
  try {
35
38
  const abs = normalize(file);
@@ -38,22 +41,21 @@ async function watch() {
38
41
  cache.set(abs, parsed);
39
42
  await engine.preloadFile((0, getVirtualFile_1.getVirtualFile)(abs), parsed.content);
40
43
  await engine.updateFile((0, getVirtualFile_1.getVirtualFile)(abs), parsed.content, config);
41
- fileDeps.set(abs, new Set(parsed.dependencies.map(d => normalize(d))));
44
+ fileDeps.set(abs, new Set(parsed.dependencies.map(dep => normalize(dep))));
45
+ }
46
+ catch {
47
+ // ignore invalid files
42
48
  }
43
- catch { }
44
49
  }
45
- config.events =
46
- engine.getAllEvents()
47
- .sort();
48
- await (0, config_1.saveConfig)(config);
49
- console.log(chalk_1.default.gray(`Initial: ${config.events.length}\n`));
50
- // WATCHER
51
- const watcher = chokidar_1.default.watch([
52
- ...files.map(normalize),
53
- ...watchedDeps,
54
- ], {
55
- ignoreInitial: true
50
+ engine.endPreload();
51
+ const initialEvents = engine.getAllEvents().sort();
52
+ await (0, config_1.saveConfig)({
53
+ ...config,
54
+ events: initialEvents,
56
55
  });
56
+ console.log(chalk_1.default.gray(`Initial: ${initialEvents.length}\n`));
57
+ // WATCHER
58
+ const watcher = chokidar_1.default.watch([...files.map(normalize), ...watchedDeps], { ignoreInitial: true });
57
59
  const queue = new Map();
58
60
  let timer = null;
59
61
  const run = async () => {
@@ -67,22 +69,23 @@ async function watch() {
67
69
  await engine.updateFile((0, getVirtualFile_1.getVirtualFile)(file), parsed.content, config);
68
70
  // dependency diff
69
71
  const abs = normalize(file);
70
- const prevDeps = fileDeps.get(abs)
71
- ?? new Set();
72
- const nextDeps = new Set(parsed.dependencies.map(d => normalize(d)));
73
- // add new deps
72
+ const prevDeps = fileDeps.get(abs) ?? new Set();
73
+ const nextDeps = new Set(parsed.dependencies.map(dep => normalize(dep)));
74
+ // add deps
74
75
  for (const dep of nextDeps) {
75
- if (!prevDeps.has(dep)) {
76
- watcher.add(dep);
77
- watchedDeps.add(dep);
76
+ if (prevDeps.has(dep)) {
77
+ continue;
78
78
  }
79
+ watcher.add(dep);
80
+ watchedDeps.add(dep);
79
81
  }
80
- // remove old deps
82
+ // remove deps
81
83
  for (const dep of prevDeps) {
82
- if (!nextDeps.has(dep)) {
83
- watcher.unwatch(dep);
84
- watchedDeps.delete(dep);
84
+ if (nextDeps.has(dep)) {
85
+ continue;
85
86
  }
87
+ watcher.unwatch(dep);
88
+ watchedDeps.delete(dep);
86
89
  }
87
90
  fileDeps.set(abs, nextDeps);
88
91
  }
@@ -90,12 +93,12 @@ async function watch() {
90
93
  console.log(chalk_1.default.gray(`skip: ${file}`));
91
94
  }
92
95
  }
93
- const next = engine.getAllEvents()
94
- .sort();
95
- config.events =
96
- next;
97
- await (0, config_1.saveConfig)(config);
98
- console.log(chalk_1.default.green(`Updated: ${next.length}`));
96
+ const nextEvents = engine.getAllEvents().sort();
97
+ await (0, config_1.saveConfig)({
98
+ ...config,
99
+ events: nextEvents,
100
+ });
101
+ console.log(chalk_1.default.green(`Updated: ${nextEvents.length}`));
99
102
  };
100
103
  const schedule = (file) => {
101
104
  const abs = normalize(file);
@@ -103,8 +106,7 @@ async function watch() {
103
106
  if (timer) {
104
107
  clearTimeout(timer);
105
108
  }
106
- timer =
107
- setTimeout(run, 200);
109
+ timer = setTimeout(run, 200);
108
110
  };
109
111
  watcher
110
112
  .on("change", schedule)
@@ -112,12 +114,12 @@ async function watch() {
112
114
  .on("unlink", async (file) => {
113
115
  const abs = normalize(file);
114
116
  await engine.removeFile((0, getVirtualFile_1.getVirtualFile)(abs), config);
115
- const next = engine.getAllEvents()
116
- .sort();
117
- config.events =
118
- next;
119
- await (0, config_1.saveConfig)(config);
120
- console.log(chalk_1.default.red(`Removed → ${next.length}`));
117
+ const nextEvents = engine.getAllEvents().sort();
118
+ await (0, config_1.saveConfig)({
119
+ ...config,
120
+ events: nextEvents,
121
+ });
122
+ console.log(chalk_1.default.red(`Removed → ${nextEvents.length}`));
121
123
  });
122
124
  process.on("SIGINT", async () => {
123
125
  await watcher.close();