Skip to content

fix(effect): allow nested tagged pattern objects in Match calls - #46

Open
FNDEVVE wants to merge 1 commit into
dmmulroy:mainfrom
FNDEVVE:fix/match-pattern-nested-tagged-objects
Open

FNDEVVE wants to merge 1 commit into
dmmulroy:mainfrom
FNDEVVE:fix/match-pattern-nested-tagged-objects

Conversation

@FNDEVVE

@FNDEVVE FNDEVVE commented Sep 14, 2026

Copy link
Copy Markdown

Problem

no-manual-tagged-construction incorrectly flags literal _tag objects in Match patterns as value construction when nested inside objects/arrays or used with multi-predicate helpers like Match.whenAnd:

Match.whenAnd(
  HttpClientError.isHttpClientError,
  { reason: { _tag: "StatusCodeError", response: { status: 429 } } },
  () => true,
)

Previously, isMatchPatternObject only checked node.parent directly for Match.when or Match.not, which failed for nested containers and missed whenAnd / whenOr.


Solution

Walk outward from the _tag ObjectExpression through nested pattern containers (properties within ObjectExpression, ArrayExpression, and parentheses) to the enclosing Match call, ensuring the containing argument is a pattern/predicate and not a handler:

flowchart TD
    Node["ObjectExpression with _tag"] --> Loop{"Walk Up Containers"}
    Loop -->|"Property.value in Object"| Obj["Parent ObjectExpression"]
    Loop -->|"Element in Array"| Arr["Parent ArrayExpression"]
    Loop -->|"Expression in Parentheses"| Paren["Parent ParenthesizedExpression"]
    Obj --> Loop
    Arr --> Loop
    Paren --> Loop
    Loop -->|"Boundary / Enclosing Call"| Call{"Enclosing Call"}
    Call -->|"Match.when / not / whenAnd / whenOr"| CheckArg{"Argument Position"}
    Call -->|"Other function or boundary"| Flag["❌ Flag as manualConstruction"]
    CheckArg -->|"Pattern argument (index < last)"| Pass["✅ Allowed pattern"]
    CheckArg -->|"Handler argument (last argument)"| Flag
Loading
- node.parent === Match.when | Match.not (direct only)
+ while (parent in [Property.value, ArrayExpression, ParenthesizedExpression])
+   current = parent
+ if (current.parent in [Match.when, Match.not, Match.whenAnd, Match.whenOr])
+   allow only if current is a pattern argument (not the handler)

Changes

  • Updated isMatchPatternObject in src/effect/shared/tagged-values.ts to support outward container traversal.
  • Covered Match.when, Match.not, Match.whenAnd, and Match.whenOr (supporting both Match.* and Effect.Match.*).
  • Verified handlers (arrow returns, block returns, arrays, handler objects) and helper calls inside patterns remain strictly rejected.
  • Added exhaustive RuleTester test coverage in src/effect/rules/no-manual-tagged-construction.test.ts.
  • Synced skill assets with pnpm sync:skill-assets.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant