Skip to content

fix: case-sensitive key lookup for IDictionary/Hashtable (issue #521)#638

Merged
rexm merged 2 commits into
masterfrom
fix/issue-521
Jun 20, 2026
Merged

fix: case-sensitive key lookup for IDictionary/Hashtable (issue #521)#638
rexm merged 2 commits into
masterfrom
fix/issue-521

Conversation

@rexm

@rexm rexm commented Jun 20, 2026

Copy link
Copy Markdown
Member

Summary

  • Fixes Can't Reference Capitalized Hashtable Elements #521
  • Hashtable (and any other non-generic IDictionary) with an uppercase key (e.g. "NAME") was silently returning empty when accessed via {{NAME}} in a template, while Dictionary<string, string> with the same key worked correctly.
  • Hashtable with a lowercase key also incorrectly resolved for any casing in the template expression, violating case-sensitive JS object key semantics.

Root cause

In DictionaryMemberAccessor.TryGetValue, the lookup was performed using memberName.LowerInvariant instead of memberName.TrimmedValue. This bug was introduced in commit 9d52004 when the string memberName parameter was replaced with ChainSegment memberNameLowerInvariant was chosen instead of TrimmedValue.

The original code (pre-refactor) used the raw string with no case folding, which is the correct behaviour.

Fix

One-line change in source/Handlebars/MemberAccessors/DictionaryMemberAccessor.cs:

-value = dictionary[memberName.LowerInvariant];
+value = dictionary[memberName.TrimmedValue];

JS parity

Handlebars.js resolves object keys case-sensitively ({{NAME}} on { NAME: "bob" } works; {{NAME}} on { name: "bob" } does not). This fix restores that behaviour for IDictionary/Hashtable.

Test plan

Four new regression tests added to IssueTests.cs:

  • Hashtable with uppercase key resolves correctly via matching expression
  • Hashtable with lowercase key still resolves via matching expression
  • Dictionary<string, string> with uppercase key still works (no regression)
  • {{name}} does NOT resolve a Hashtable key "NAME" (case-sensitive, JS-parity)

All 1750 existing tests pass.

🤖 Generated with Claude Code

rexm and others added 2 commits June 20, 2026 13:53
The DictionaryMemberAccessor was using ChainSegment.LowerInvariant to
index into a non-generic IDictionary (e.g. Hashtable), silently
downcasing the lookup key. This meant uppercase keys like "NAME" could
never be found via {{NAME}}, while lowercase keys resolved incorrectly
for any casing in the template.

The bug was introduced in commit 9d52004 when the string memberName
parameter was replaced with ChainSegment: LowerInvariant was chosen
instead of TrimmedValue. The fix restores the original exact-match
behaviour, which matches Handlebars.js (JS object keys are always
case-sensitive).

Fixes #521

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@rexm rexm enabled auto-merge June 20, 2026 19:37
@sonarqubecloud

Copy link
Copy Markdown

@rexm rexm merged commit 630bcc3 into master Jun 20, 2026
7 checks passed
@rexm rexm deleted the fix/issue-521 branch June 20, 2026 19:47
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.

Can't Reference Capitalized Hashtable Elements

1 participant