@fjall/eslint-plugin 2.23.0 → 2.24.0

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.
@@ -9,6 +9,13 @@
9
9
  * - `<expr>.error.reason` / `<expr>.error?.reason`
10
10
  * - `<bareErrorBinding>.message` / `.reason` where the binding name is
11
11
  * `err`, `error`, `cause`, or `rejection` (common error-handler param)
12
+ * - `<anyBinding>.message` inside a ConditionalExpression branch whose test
13
+ * proves error-ness name-independently: the consequent of
14
+ * `X instanceof Error ? X.message : …` (RHS: any Identifier matching
15
+ * /Error$/ — `Error` itself or a custom ctor), or
16
+ * the alternate of `!(X instanceof Error) ? … : X.message`. The
17
+ * same-identifier requirement between test and leaf is strict, and the
18
+ * check is AST-local (no interprocedural inference).
12
19
  * - `<expr>.reason` (Promise rejection / settled-result shape)
13
20
  * - `<expr>.error` / `<expr>.errorMessage` — server-error envelope reads.
14
21
  * The webapp's JSON failure shape is `{ error: string }` or
@@ -325,6 +332,14 @@ function classifyErrorLeaf(node, context) {
325
332
  return { label: `${object.name}.${propName}`, shape: "strict" };
326
333
  }
327
334
 
335
+ if (
336
+ propName === "message" &&
337
+ object.type === "Identifier" &&
338
+ isInInstanceofProvenErrorBranch(node, object.name)
339
+ ) {
340
+ return { label: `${object.name}.message`, shape: "strict" };
341
+ }
342
+
328
343
  if (propName === "reason" && object.type === "Identifier") {
329
344
  return { label: `${object.name}.reason`, shape: "strict" };
330
345
  }
@@ -386,6 +401,62 @@ function classifyErrorLeaf(node, context) {
386
401
  return null;
387
402
  }
388
403
 
404
+ /**
405
+ * True when `node` (an `X.message` MemberExpression, `X` an Identifier named
406
+ * `bindingName`) sits in a ConditionalExpression branch whose test proves
407
+ * `X instanceof Error`: the consequent of `X instanceof Error ? … : …`, or
408
+ * the alternate of `!(X instanceof Error) ? … : …`. The instanceof test
409
+ * proves error-ness name-independently, so bindings outside
410
+ * ERROR_BINDING_NAMES qualify. The identifier match between test and leaf is
411
+ * strict; the walk is AST-local and stops at function boundaries. A leaf in
412
+ * a ternary TEST position never qualifies (boolean check, not value flow).
413
+ */
414
+ function isInInstanceofProvenErrorBranch(node, bindingName) {
415
+ let child = node;
416
+ let parent = node.parent;
417
+ while (parent) {
418
+ if (
419
+ parent.type === "FunctionDeclaration" ||
420
+ parent.type === "FunctionExpression" ||
421
+ parent.type === "ArrowFunctionExpression" ||
422
+ parent.type === "Program"
423
+ ) {
424
+ return false;
425
+ }
426
+ if (parent.type === "ConditionalExpression") {
427
+ if (parent.test === child) return false;
428
+ if (
429
+ parent.consequent === child &&
430
+ isInstanceofErrorTest(parent.test, bindingName)
431
+ ) {
432
+ return true;
433
+ }
434
+ if (
435
+ parent.alternate === child &&
436
+ parent.test.type === "UnaryExpression" &&
437
+ parent.test.operator === "!" &&
438
+ isInstanceofErrorTest(parent.test.argument, bindingName)
439
+ ) {
440
+ return true;
441
+ }
442
+ }
443
+ child = parent;
444
+ parent = parent.parent;
445
+ }
446
+ return false;
447
+ }
448
+
449
+ function isInstanceofErrorTest(test, bindingName) {
450
+ return (
451
+ test.type === "BinaryExpression" &&
452
+ test.operator === "instanceof" &&
453
+ test.left.type === "Identifier" &&
454
+ test.left.name === bindingName &&
455
+ test.right.type === "Identifier" &&
456
+ CUSTOM_ERROR_CTOR_RE.test(test.right.name)
457
+ );
458
+ }
459
+
389
460
  /**
390
461
  * Returns true when `objectNode` is an Identifier bound from a
391
462
  * `<schema>.safeParse(...)` call. `parsed.error` in that shape is a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fjall/eslint-plugin",
3
- "version": "2.23.0",
3
+ "version": "2.24.0",
4
4
  "description": "ESLint plugin with Fjall-specific coding standard rules",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -32,5 +32,5 @@
32
32
  "vitest": "^4.1.5"
33
33
  },
34
34
  "license": "SEE LICENSE IN LICENSE",
35
- "gitHead": "dadd84e6118f03252877974eec755e812cb5b42f"
35
+ "gitHead": "616d7af846f0eebfa3409f5f47c98fbee836bad9"
36
36
  }