Skip to content

fix: resolve case-insensitive lookups of keys holding false - #368

Merged
santiagocardo merged 2 commits into
developfrom
fix/case-insensitive-false-lookup
Jul 31, 2026
Merged

fix: resolve case-insensitive lookups of keys holding false#368
santiagocardo merged 2 commits into
developfrom
fix/case-insensitive-false-lookup

Conversation

@santiagocardo

@santiagocardo santiagocardo commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Problem

Looking up a context key whose value is false returned nil:

Expression.evaluate("@parsed.errorswhilecomputingflags", %{
  "parsed" => %{"errorsWhileComputingFlags" => false}
})
# => {:ok, nil}   (expected {:ok, false})

case_insensitive_scan/2 was built on Enum.find_value/3, which treats a falsy
callback return as "no match". When the matching key held false, the scan kept
going, found nothing else, and returned the {:not_found, _} sentinel — which
handle_not_found/1 then converted to nil.

This is not limited to case-mismatched lookups. The parser lowercases variable
names in the AST, so every attribute lookup reaches this scan rather than the
Map.fetch/2 fast path — @parsed.isActive was equally broken.

Fix

Wrap matches in an {:ok, value} tuple so the callback's return is truthy
regardless of the value, then unwrap.

Scope

false is the only value affected in practice. 0, [], and "" are truthy in
Elixir and always worked. nil hits the same path internally, but is
indistinguishable from a missing key through the public API since both yield nil.

Tests

Four tests added to test/expression_test.exs. Reverting the fix fails them.

  • camelCase key holding false, asserted across three casings
  • top-level key holding false
  • a resolved false used downstream (==, evaluate_as_boolean!, IF, string output)
  • a missing key is still reported as not found, guarding against over-correction

🤖 Generated with Claude Code

santiagocardo and others added 2 commits July 30, 2026 17:25
`case_insensitive_scan/2` was built on `Enum.find_value/3`, which treats a
falsy callback return as "no match". A key that matched case-insensitively
but held `false` therefore fell through to the `{:not_found, _}` sentinel
and evaluated to `nil`.

Wrapping matches in an `{:ok, value}` tuple keeps the callback's return
truthy regardless of the value, so `false` now resolves correctly.

Note that this affects exact-case lookups too, not just mismatched ones:
the parser lowercases variable names in the AST, so every attribute lookup
reaches this scan rather than the `Map.fetch/2` fast path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Santiago <santiagocardo80@gmail.com>
@santiagocardo
santiagocardo requested a review from smn July 30, 2026 22:39
@santiagocardo santiagocardo self-assigned this Jul 30, 2026
@santiagocardo
santiagocardo merged commit be70854 into develop Jul 31, 2026
2 checks passed
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.

2 participants