Skip to content

Keep array-index keys out of the named getter, and declare the Jint the package needs - #131

Merged
FlorianRappl merged 1 commit into
AngleSharp:develfrom
lahma:fix/jint-4.15-adoption-followups
Jul 28, 2026
Merged

Keep array-index keys out of the named getter, and declare the Jint the package needs#131
FlorianRappl merged 1 commit into
AngleSharp:develfrom
lahma:fix/jint-4.15-adoption-followups

Conversation

@lahma

@lahma lahma commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Two follow-ups from a post-merge review of #130, one behavioural, one packaging. Both are small; the behavioural one comes with the regression tests that prove it both ways.

1. An array-index key must never reach the named getter

DomCollectionInstance.GetOwnProperty fell through to the string indexer for any key the array-like base did not answer — including an array-index key past the end. But the base's answer for such a key is not "I don't know", it is an authoritative no: the value and existence hooks (TryGetOwnPropertyValue, ProbeOwnProperty) commit to the miss, and Jint 4.15 trusts them without re-asking. So an element whose id happens to be numeric produced this, with one form <form id='5'> on the page:

Object.getOwnPropertyDescriptor(document.forms, '5')   // a descriptor…
'5' in document.forms                                   // …for a key that answers false,
document.forms['5']                                     // reads as undefined,
document.forms.hasOwnProperty('5')                      // and is not an own property

Every answer except the descriptor was already correct — and browser-correct: WebIDL's [[GetOwnProperty]] for a platform object that supports indexed properties sets ignoreNamedProps when the index is unsupported, so a named element is never served under an array-index name. The fix makes the named lookup step aside for canonical array-index keys, classified exactly the way the engine classifies them (canonical form of a UInt32 below the maximum), which restores the agreement the 4.15 hook contracts require — a Debug build of Jint asserts that agreement on every read, and this was the one reachable key class where it would have fired.

Reachable through any collection that has both indexers: document.forms / form.elements / other HTMLCollections with an element whose id/name is numeric, and el.attributes with an attribute literally named like a number (HTML parsing permits those).

Two tests pin it: the numeric-id case now answers the same thing five ways, and a non-index named entry (document.forms.login) keeps resolving, descriptor included. Without the one-line guard the first test fails exactly on the descriptor field ("false,false,true,false,true"); with it, both pass.

2. The package manifest still promised Jint 4.0

AngleSharp.Js.nuspec declared Jint [4.0.0,5.0.0) in every group, but since #130 the assembly derives from ArrayLikeObject and overrides hooks that exist only in Jint 4.15.0 — and NuGet resolves the lowest version a range admits, so a consumer adding the package with defaults restored Jint 4.0.0 and got a TypeLoadException the moment a DOM object was projected. The nuspec is what CreatePackage packs, so the manifest is the shipped contract; the floor now names the version the code is written against. Worth cherry-picking into whatever ships after 1.0.0-beta.118.

Verification

dotnet test on net8.0, net462, net472, in both Release and Debug, against the released Jint 4.15.0 package: 230/230, 228/228, 228/228, all green, warning-clean. The A/B above (guard reverted, new tests only) was run to confirm the regression test bites before trusting it green.

🤖 Generated with Claude Code

https://claude.ai/code/session_016uV6H9cTntzsoKiaJRBn4f

… the package needs

Two follow-ups to AngleSharp#130.

The collection proxy's GetOwnProperty asked the string indexer about a name the
array-like base had already answered: an index past the end is an authoritative
miss - the value and existence hooks commit to it, the engine trusts them and
does not ask again - so an element whose id happens to be numeric surfaced as a
descriptor for a key that reads as undefined, answers false to "in" and
hasOwnProperty, and never enumerates. WebIDL resolves the same collision the
same way: an object supporting indexed properties never serves an array-index
name from its named getter. The named lookup now steps aside for canonical
array-index keys, classified exactly as the engine classifies them.

The package manifest still declared Jint [4.0.0,5.0.0), but the assembly now
derives from a base class and overrides hooks that exist only in 4.15.0, and
NuGet resolves the lowest version a range admits - a consumer taking the
package defaults got an engine the types in it cannot load against. The floor
is now the version the code is actually written to.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016uV6H9cTntzsoKiaJRBn4f
@lahma

lahma commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

@FlorianRappl is there a reason to still have the nuspec file separately? dotnet pack can handle pretty much all the scenarios driven by csproj information.

@FlorianRappl FlorianRappl added this to the v1.0 milestone Jul 28, 2026
@FlorianRappl

Copy link
Copy Markdown
Contributor

It still has the same deficiencies that have been discussed in AngleSharp.Core - even though I wish to have everything in csproj that just does not work.

Most importantly, it does not allow specifying version ranges which we use for AngleSharp.

@FlorianRappl FlorianRappl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@FlorianRappl
FlorianRappl merged commit 8f79d5f into AngleSharp:devel Jul 28, 2026
5 checks passed
@lahma
lahma deleted the fix/jint-4.15-adoption-followups branch July 28, 2026 09:02
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