mirror of https://github.com/Squidex/squidex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Tree:
0ecfe2fc68
4_1
copilot/improve-logging-source-generation
copilot/migrate-initializeasync-jsonfunctions
fix-serialization
fix-ui-bugs
improve-inline-filter
improve-queries
master
menu-fix
release/2.x
release/3.x
release/4.5
release/4.x
release/5.7
release/6.x
snyk-fix-2bd281b6df15ba73066ccd02cac2b81a
snyk-fix-50bb73c99b99521bbac8eaa6483b39ec
work-directory
17.4.0
3.0.0
3.0.0-beta2
3.0.0-beta3
3.1.0
3.2.0
3.2.1
3.2.2
3.3.0
3.4.0
3.5.0
4.0.0
4.0.0-beta1
4.0.1
4.0.2
4.0.3
4.1.0
4.1.0-beta1
4.1.0-rc
4.1.1
4.1.2
4.1.3
4.2.0
4.2.0-beta1
4.2.0-beta2
4.3.0
4.4.0
4.4.0-rc
4.5.0
4.5.1
4.5.2
4.5.3
4.6.0
4.7.0
4.7.1
4.7.2
4.7.3
4.7.4
4.7.5
4.7.6
5.0.0
5.0.0-beta1
5.0.0-beta2
5.1.0
5.1.1
5.2.0
5.2.1
5.3.0
5.4.0
5.5.0
5.6.0
5.7.0
5.7.1
5.8.0
5.8.1
5.8.2
5.9.0
6.0.0
6.0.1
6.1.0
6.10.0
6.11.0
6.12.0
6.13.0
6.14.0
6.2.0
6.3.0
6.4.0
6.5.0
6.6.0
6.7.0
6.8.0
6.9.0
7.0.0
7.0.0-rc1
7.0.0-rc2
7.0.0-rc3
7.0.1
7.0.2
7.0.3
7.1.0
7.10.0
7.11.0
7.12.0
7.13.0
7.14.0
7.15.0
7.16.0
7.17.0
7.18.0
7.19.0
7.2.0
7.20.0
7.21.0
7.22.0
7.23.0
7.3.0
7.4.0
7.5.0
7.6.0
7.6.1
7.7.0
7.8.0
7.8.1
7.8.2
7.9.0
v1.0
v1.0-beta1
v1.0-beta2
v1.0-beta3
v1.1
v1.1.1
v1.1.2
v1.1.3
v1.1.4
v1.1.5
v1.1.6
v1.1.7
v1.10.0
v1.11.0
v1.12.0
v1.13.0
v1.14.0
v1.15.0
v1.16.0
v1.16.1
v1.16.2
v1.2.0
v1.3.0
v1.3.1
v1.4.0
v1.4.1
v1.6.0
v1.6.1
v1.6.2
v1.6.3
v1.7.0
v1.8.0
v1.9.0
v2.0
v2.0-RC1
v2.0-beta1
v2.0.1
v2.0.2
v2.0.3
v2.0.4
v2.0.5
v2.1.0
v2.2.0
v2.2.1
v2.2.2
v3.0-beta1
${ noResults }
* Pin observable scripting behaviour before the Jint upgrade The Jint upgrade that follows re-arms three engine-wide inline cache gates. Each of those changes is only worth making if it is observably identical, so pin the behaviour first, against Jint 4.8.0: - null propagation: undeclared identifier reads, nullish property chains, calls over a nullish base, calls of a non-callable member (which return the base), and that ordinary member reads/calls are unaffected; - enum values crossing into script as their member name, including a [Flags] combination and an enum member of a wrapped CLR object; - JSON objects projected into script: own key order, JSON.stringify, for..in, mutation (add/replace/delete) and the round trip back to JsonValue; - content field objects: `in`, hasOwnProperty, propertyIsEnumerable, Object.keys, spread, JSON.stringify, and that all of them follow deletes and additions; - the context object: key enumeration, `in`, typeof per value, reads, write-through to ScriptVars and delete. All 156 tests in Operations/Scripting pass unchanged on 4.8.0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016uV6H9cTntzsoKiaJRBn4f * Upgrade Jint from 4.8.0 to 4.15.3 Package provenance verified after restore: source is https://api.nuget.org/v3/index.json and the nuspec repository commit is a304aa5dacd340e2a5ff51e1ea0c465e38e50aa8, the v4.15.3 tag. Acornima moves to 1.6.2 transitively; ParseErrorException, ScriptPreparationException and JintException, which JintScriptEngine.MapException switches on, all still exist, and so do Engine.Constraints.Reset, Options.Constraints.PromiseTimeout, AllowClrWrite, EvaluateAsync(in Prepared<Script>, CancellationToken), ObjectWrapper.Create and the ObjectInstance virtuals the ContentWrapper family overrides. No source change is needed for the upgrade itself: the whole backend solution builds warning-clean and all 156 tests in Operations/Scripting, including the behaviour pins added in the previous commit, pass unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016uV6H9cTntzsoKiaJRBn4f * Verify Jint's host contracts on every test run The scripting integration defines several Jint extension points: the ContentWrapper objects override GetOwnProperty, and the engine trusts the answer without re-verifying it on the hot path. A hook that contradicts another therefore fails silently in production - a key vanishes from every enumeration, or a read resolves on the prototype for a property that exists - which is the class of bug no assertion in this repository would catch. Jint 4.15.3 exposes its host-contract verifiers to the shipped Release package through an AppContext switch, where before they were compiled out unless you built the engine from source in Debug. A module initializer sets it for this test assembly, so the verifiers run against the same NuGet package production uses and report a violation as an ordinary test failure. It must be set before the first use of any Jint type, which is exactly what a module initializer guarantees. Confirmed live rather than assumed: with a deliberately wrong ProbeOwnProperty the run fails with "ContentFieldObject.ProbeOwnProperty answered 'iv' with Missing but its GetOwnProperty reports Enumerable". Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016uV6H9cTntzsoKiaJRBn4f * Declare the reference resolver's interests to re-arm the read caches Registering an IReferenceResolver without interests gives it ReferenceResolverInterests.All, and two of those flags - ObjectPropertyBase and PrimitivePropertyBase - are the gate on the non-computed member-read inline caches, the dense-array indexed-read lane and the member-call callee lane. With All declared, every property read in every script has to be routed through a Reference so the resolver gets offered the base, and all three lanes stay off for the whole engine. NullPropagation.TryPropertyReference returns false for every base that is not null or undefined, so on those two situations the engine consulting it can never change the result. Declaring only the three situations the resolver actually answers - NullishPropertyBase, UnresolvableReference and NonCallableCallee - is therefore observably identical and re-arms all three lanes. Interests are documented as a subscription filter and not a promise: a situation that is not subscribed to behaves exactly as if no resolver were registered. Jint also ships a built-in NullPropagatingReferenceResolver, which is deliberately NOT adopted here: it declines unresolvable identifiers and non-callable callees, where this resolver answers both, so swapping it in would turn an undeclared-name read and a call on a nullish chain into errors for existing tenant scripts. The behaviour pins from the first commit cover exactly those edges and all 156 tests in Operations/Scripting still pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016uV6H9cTntzsoKiaJRBn4f * Declare the object converter's types and convert enums natively An IObjectConverter registered without declaring the CLR types it handles can be handed anything, so the engine has to assume every wrapped CLR member read might reach it and disables the compiled interop member-read lane engine-wide. JintObjectConverter handles a closed set, so declare it: matching is by assignability, which keeps IUser covering every implementation. The converter is still offered every value - the declaration only lets the engine keep the fast lane for members whose declared type could never produce a handled value, and it errs towards claiming (a member typed `object` is always claimed). The Enum branch is dropped in favour of Options.Interop.EnumConversion = EnumConversionMode.String, which Jint documents as the member name "as produced by object.ToString()", including the comma-separated combination for a [Flags] value and the numeric value rendered as a string for a value with no name - verbatim what the branch did. The write direction keeps accepting both the name and the number. Handling enums natively rather than through the converter also keeps one more declared type off the list, so more members stay on the fast lane. Pinned by Should_convert_enum_to_name, Should_convert_flags_enum_to_names and Should_convert_enum_member_of_wrapped_object_to_name, which pass before and after. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016uV6H9cTntzsoKiaJRBn4f * Project JSON objects into script as shape-mode objects JsonMapper built every JSON object it projects into script as an instance of a private ObjectInstance subclass that existed only to be instantiable. A host subclass can never carry the engine's shape-mode storage flag, so each of those objects - all of ctx.data's leaf objects, and every JsonValue var - sat permanently outside the own-property inline caches, and a script reading the same property across a batch of content items re-resolved it every time. JsObject.CreateFromEntries builds the same object through the hidden class machinery instead: repeated calls presenting the same key sequence, which every content item of one schema does, share an interned hidden class, so those reads stay monomorphic. The result is documented as indistinguishable from the equivalent object literal - same own key order, same configurable/enumerable/writable data properties - and anything the representation cannot express (a digit-leading key, a very wide object) falls back to the ordinary dictionary representation rather than to different behaviour. That fallback is silent, which is why the shaping is asserted rather than assumed: Engine.Advanced.HasSharedShape is the supported predicate for it, and JsonMapperTests pins that the projected object and its nested objects answer true. Building them as a host subclass again would fail that test. Three smaller fixes in the same file: - the reverse direction allocated a string key per array element (a.Get(i.ToString(...))); the indexed accessor reads the dense backing directly and keeps the prototype walk for a modified array; - JsNumber.Create reuses cached instances for small integers where new JsNumber always allocated; - JsString.Create, public since 4.15.3, interns the empty and single character strings where new JsString always allocated. Pinned by the projection tests added first - own key order, JSON.stringify, for..in, mutation including delete and add, and the round trip back to JsonValue - which pass before and after. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016uV6H9cTntzsoKiaJRBn4f * Answer field existence questions without mapping the field value ContentFieldProperty is a CustomJsValue descriptor whose CustomValue maps the stored JsonValue to a JsValue on first read. Existence and enumerability questions never need that value, but they used to pay for it: `in`, hasOwnProperty, propertyIsEnumerable, Object.keys/values/entries, Object.assign, object spread and JSON.stringify all reached the object through GetOwnProperty, which materializes the descriptor whose value the caller then reads or discards. Jint lets a host answer those questions directly through ProbeOwnProperty. The override deliberately mirrors GetOwnProperty line for line, minus the descriptor: same initialization, same toJSON exclusion, same lookup, and the enumerable flag read off the descriptor rather than off its value. The engine trusts the probe without re-verifying it on the hot path, so a wrong Missing would silently drop the key from every enumeration above - which is why the two are kept adjacent in the file, pinned by tests covering `in`, hasOwnProperty, propertyIsEnumerable, Object.keys, spread and JSON.stringify plus a delete and an add, and checked on every test run by the host-contract verification enabled earlier in this branch. ContentDataObject deliberately does not get the same override: its GetOwnProperty auto-creates a field for any name probed, so a probe that agreed with it at the same instant would have to do the same, and that quirk is pre-existing tenant-visible behaviour this change has no business altering. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016uV6H9cTntzsoKiaJRBn4f * Map script variables on first read instead of eagerly 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 * Rewrite the code comments in plainer language The comments explained the change in Jint's own vocabulary - inline caches, shape mode, descriptors, lanes - which is not vocabulary this repository uses. Say what each change does and why it is worth it instead, and name a Jint concept only where the reader has to look it up anyway. No behaviour change: comments and XML docs only, plus one short comment on the enum conversion option. --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
3 weeks ago | |
|---|---|---|
| .. | ||
| Squidex.Data.Tests | Security fixes. (#1327) | 3 weeks ago |
| Squidex.Data.Tests.CodeGenerator | Update packages. Fix serialization. (#1310) | 4 months ago |
| Squidex.Domain.Apps.Core.Tests | Upgrade Jint to 4.15.3 and adopt its cache-gate and lazy-value APIs (#1326) | 3 weeks ago |
| Squidex.Domain.Apps.Entities.Tests | Stabilize logger-based unit tests by enabling fake `ILogger` in affected suites (#1318) | 3 months ago |
| Squidex.Domain.Users.Tests | Update packages. Fix serialization. (#1310) | 4 months ago |
| Squidex.Infrastructure.Tests | Security fixes. (#1327) | 3 weeks ago |
| Squidex.Web.Tests | Update packages. Fix serialization. (#1310) | 4 months ago |
| mssql | Run tests on all servers (#1191) | 2 years ago |
| RunCoverage.ps1 | Batch processing for events. (#1222) | 1 year ago |
| coverlet.runsettings.xml | Batch processing for events. (#1222) | 1 year ago |
| tests.sln | Batch processing for events. (#1222) | 1 year ago |