Every variable was mapped when the engine was set up, once per evaluation,
whether or not the script ever looked at it - WritableContext did it in its
constructor for the ctx path, and Engine.SetValue did it per variable for
the non-context path. Some of those mappings are not cheap: a user variable
walks and groups every claim, a content data variable builds a wrapper. A
typical script reads a handful of the variables available to it.
Both paths now defer the mapping to the first read of the value, through
the two APIs Jint 4.15.3 added for exactly this:
- PropertyDescriptor.CreateLazy for the ctx object. Unlike a hand-written
CustomJsValue descriptor it drops the flag once the value exists, so the
descriptor rejoins the write inline cache instead of paying the
indirection for the rest of its life.
- Engine.Advanced.AddLazyGlobal for the non-context path. The options-time
AddLazyGlobal could not serve it - the variables are only known after the
engine has been built - and the descriptor a host could install itself is
declined by the global-identifier cache. The Advanced overload is
documented as being for exactly this case, and its factory may capture
engine-affine state.
In both cases the property itself is installed eagerly, so nothing about
the shape changes: key order, enumeration, `in`, Object.getOwnPropertyNames,
delete and the write-through to ScriptVars behave exactly as before, which
is what the tests pin - including a counting principal that proves the
mapping has not run for a variable the script never mentions, and has run
for one it reads. MapVariable reproduces Engine.SetValue's special case for
a CLR type so a deferred variable cannot project differently.
One edge is worth recording: Engine.SetValue writes through [[Set]] while
AddLazyGlobal replaces the descriptor, so a variable named after a
non-writable built-in global (undefined, NaN, Infinity) would now shadow it
where it was previously ignored. ScriptVars keys are domain names, so this
is not reachable in practice.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016uV6H9cTntzsoKiaJRBn4f
Squidex is an open source headless CMS and content management hub. In contrast to a traditional CMS Squidex provides a rich API with OData filter and Swagger definitions. It is up to you to build your UI on top of it. It can be website, a native app or just another server. We build it with ASP.NET Core and CQRS and is tested for Windows and Linux on modern browsers.
Read the docs at https://docs.squidex.io/ (work in progress) or just check out the code and play around.
How to make feature requests, get help or report bugs?
Please create issues to report bugs, suggest new functionalities, ask questions or just share your thoughts about the project. We will really appreciate your contribution, thanks.