@eventra_dev/eventra-cli 2.3.1 → 2.3.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.
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.resolveFunctionFromCall = resolveFunctionFromCall;
7
7
  const typescript_1 = __importDefault(require("typescript"));
8
8
  const exportResolver_1 = require("./exportResolver");
9
+ const utils_1 = require("../shared/utils");
9
10
  function isFunctionLike(node) {
10
11
  return (typescript_1.default.isFunctionDeclaration(node) || typescript_1.default.isMethodDeclaration(node) || typescript_1.default.isArrowFunction(node) || typescript_1.default.isFunctionExpression(node));
11
12
  }
@@ -44,10 +45,7 @@ function resolveReturnedFunction(call, checker, callCache, exportCache, hops) {
44
45
  return null;
45
46
  }
46
47
  for (const returned of returnedExpressions(factory)) {
47
- let value = returned;
48
- while (typescript_1.default.isParenthesizedExpression(value) || typescript_1.default.isAsExpression(value) || typescript_1.default.isNonNullExpression(value)) {
49
- value = value.expression;
50
- }
48
+ const value = (0, utils_1.unwrapExpression)(returned);
51
49
  if (isFunctionLike(value)) {
52
50
  return value;
53
51
  }
@@ -4,21 +4,26 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
5
  };
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.isExpressionWrapper = isExpressionWrapper;
7
8
  exports.unwrapExpression = unwrapExpression;
8
9
  exports.getPropertyName = getPropertyName;
9
10
  exports.getCallName = getCallName;
10
11
  exports.getFunctionName = getFunctionName;
11
12
  const typescript_1 = __importDefault(require("typescript"));
13
+ /** A node that only wraps an expression without changing what it is: `(x)`, `x as T`, `<T>x`, `x!`, `x satisfies T`. */
14
+ function isExpressionWrapper(node) {
15
+ return (typescript_1.default.isAsExpression(node) ||
16
+ typescript_1.default.isTypeAssertionExpression(node) ||
17
+ typescript_1.default.isNonNullExpression(node) ||
18
+ typescript_1.default.isParenthesizedExpression(node) ||
19
+ typescript_1.default.isSatisfiesExpression(node));
20
+ }
12
21
  // track(payload?.event as string)
13
22
  // track((payload.event))
14
23
  // track(payload!.event)
15
24
  function unwrapExpression(expression) {
16
25
  let current = expression;
17
- while (typescript_1.default.isAsExpression(current) ||
18
- typescript_1.default.isTypeAssertionExpression(current) ||
19
- typescript_1.default.isNonNullExpression(current) ||
20
- typescript_1.default.isParenthesizedExpression(current) ||
21
- typescript_1.default.isSatisfiesExpression(current)) {
26
+ while (isExpressionWrapper(current)) {
22
27
  current = current.expression;
23
28
  }
24
29
  return current;
@@ -8,6 +8,7 @@ exports.getFunctionSymbol = getFunctionSymbol;
8
8
  exports.isReturnedFunction = isReturnedFunction;
9
9
  exports.wrapperName = wrapperName;
10
10
  const typescript_1 = __importDefault(require("typescript"));
11
+ const utils_1 = require("../shared/utils");
11
12
  /**
12
13
  * Symbol an identifier *refers to*. For the name in a shorthand property (`{ event }`) a plain
13
14
  * `getSymbolAtLocation` yields the property's own symbol, not the variable/parameter it reads.
@@ -63,22 +64,19 @@ function getFunctionSymbol(node, checker) {
63
64
  }
64
65
  return undefined;
65
66
  }
66
- /** An arrow/function expression that is the value of a `return`, or the concise body of an arrow. */
67
+ /** An arrow/function expression that is the value of a `return`, or the concise body of an arrow, possibly in parentheses, `as` or `!`. */
67
68
  function isReturnedFunction(node) {
68
69
  if (!typescript_1.default.isArrowFunction(node) && !typescript_1.default.isFunctionExpression(node)) {
69
70
  return false;
70
71
  }
72
+ // `inner` is the outermost wrapper around the function, or the function itself
73
+ let inner = node;
71
74
  let outer = node.parent;
72
- while (typescript_1.default.isParenthesizedExpression(outer)) {
75
+ while ((0, utils_1.isExpressionWrapper)(outer)) {
76
+ inner = outer;
73
77
  outer = outer.parent;
74
78
  }
75
- return typescript_1.default.isReturnStatement(outer) || (typescript_1.default.isArrowFunction(outer) && unparen(outer.body) === node);
76
- }
77
- function unparen(node) {
78
- while (typescript_1.default.isParenthesizedExpression(node)) {
79
- node = node.expression;
80
- }
81
- return node;
79
+ return typescript_1.default.isReturnStatement(outer) || (typescript_1.default.isArrowFunction(outer) && outer.body === inner);
82
80
  }
83
81
  /**
84
82
  * The name a wrapper is reported under: its own, or for an anonymous returned function the hook that
package/dist/cli/sync.js CHANGED
@@ -18,7 +18,10 @@ async function sync({ strict = false } = {}) {
18
18
  // report what was saved: with skipped files that is the union of the known and
19
19
  // the found events, not just what this scan found
20
20
  const saved = await (0, scanResults_1.persistScanResults)(config, engine, { preserveKnown: skipped.length > 0 });
21
- console.log(chalk_1.default.green(`Found ${(0, skipped_1.plural)(saved.events?.length ?? 0, "event")}, ${(0, skipped_1.plural)(saved.functionWrappers?.length ?? 0, "function wrapper")}`));
21
+ // normalizeConfig always fills functionWrappers; the type only marks it optional
22
+ /* v8 ignore next */
23
+ const wrapperCount = saved.functionWrappers?.length ?? 0;
24
+ console.log(chalk_1.default.green(`Found ${(0, skipped_1.plural)(saved.events.length, "event")}, ${(0, skipped_1.plural)(wrapperCount, "function wrapper")}`));
22
25
  await plugins.runDynamicEventReporters(engine.getAllDynamicOccurrences());
23
26
  (0, skipped_1.reportSkipped)(skipped);
24
27
  (0, skipped_1.reportIgnored)(ignored);
package/dist/cli/watch.js CHANGED
@@ -221,6 +221,8 @@ async function watch() {
221
221
  .on("add", schedule)
222
222
  .on("unlink", (file) => {
223
223
  const abs = normalize(file);
224
+ // chokidar's `ignored` already drops excluded paths, so this only guards against a stray event
225
+ /* v8 ignore next */
224
226
  if (filter.isExcluded(abs))
225
227
  return;
226
228
  // a file that failed to analyse is in no set but is still remembered as skipped
@@ -9,7 +9,8 @@ const path_1 = __importDefault(require("path"));
9
9
  // paths are printed relative to where the command runs, with forward slashes
10
10
  function displayPath(fileName) {
11
11
  const relative = path_1.default.relative(process.cwd(), fileName);
12
- const outside = relative === ".." || relative.startsWith(`..${path_1.default.sep}`) || relative.startsWith("../");
12
+ // path.relative always joins with path.sep, so that is the only separator to look for
13
+ const outside = relative === ".." || relative.startsWith(`..${path_1.default.sep}`);
13
14
  const shown = relative && !outside && !path_1.default.isAbsolute(relative) ? relative : fileName;
14
15
  return shown.replace(/\\/g, "/");
15
16
  }
@@ -23,9 +23,9 @@ function templateRegionOf(content) {
23
23
  }
24
24
  // `__eventra_x_template_event__(expr)` (callText may be cut with an ellipsis)
25
25
  function templateExpression(occurrence) {
26
- const open = occurrence.callText.indexOf("(");
27
- let expression = open === -1 ? occurrence.callText : occurrence.callText.slice(open + 1);
28
- expression = expression.endsWith(")") ? expression.slice(0, -1) : expression;
26
+ // no "(" gives indexOf -1, so slice(0) keeps the whole text
27
+ const afterOpen = occurrence.callText.slice(occurrence.callText.indexOf("(") + 1);
28
+ const expression = afterOpen.endsWith(")") ? afterOpen.slice(0, -1) : afterOpen;
29
29
  // Angular qualifies a bare name with `this.`; the template never writes it
30
30
  return occurrence.calleeText.includes("_angular_") ? expression.replace(/^this\./, "") : expression;
31
31
  }
@@ -86,11 +86,8 @@ class PluginRegistry {
86
86
  }
87
87
  /** Disk paths produced by the last preprocess run for a source file (for watch unlink). */
88
88
  getVirtualPathsForSource(fileName) {
89
- const mapped = this.sourceToVirtuals.get(this.normalizePath(fileName));
90
- if (mapped && mapped.length > 0) {
91
- return mapped;
92
- }
93
- return [this.normalizePath(fileName)];
89
+ // a source is only recorded with at least one virtual file, so a hit is never empty
90
+ return this.sourceToVirtuals.get(this.normalizePath(fileName)) ?? [this.normalizePath(fileName)];
94
91
  }
95
92
  async preprocessFile(input) {
96
93
  const sourceKey = this.normalizePath(input.fileName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventra_dev/eventra-cli",
3
- "version": "2.3.1",
3
+ "version": "2.3.2",
4
4
  "description": "Static analytics event extraction CLI powered by the TypeScript compiler API",
5
5
  "license": "MIT",
6
6
  "author": {