Browse Source

Update jint (#967)

* Update jint and move some files.

* Another update to the vars.
pull/968/head
Sebastian Stehle 4 years ago
committed by GitHub
parent
commit
3d3fa864c9
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/ContentDataProperty.cs
  2. 18
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/JsonMapper.cs
  3. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Internal/JintExtensions.cs
  4. 8
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Internal/JintObjectConverter.cs
  5. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Internal/JintUser.cs
  6. 8
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Internal/Parser.cs
  7. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/JintScriptEngine.cs
  8. 67
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptContext.cs
  9. 19
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptExecutionContext.cs
  10. 13
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptVars.cs
  11. 12
      backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/WritableContext.cs
  12. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj
  13. 2
      backend/src/Squidex.Domain.Apps.Entities/Apps/DomainObject/Guards/GuardApp.cs
  14. 7
      backend/src/Squidex.Domain.Apps.Entities/Assets/AssetsJintExtension.cs
  15. 8
      backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/Steps/ScriptAsset.cs
  16. 8
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ScriptContent.cs
  17. 1
      backend/src/Squidex.Domain.Apps.Entities/Contents/ReferencesJintExtension.cs
  18. 4
      backend/src/Squidex/Areas/Api/Controllers/Contents/Models/AllContentsByPostDto.cs
  19. 54
      backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineTests.cs
  20. 2
      backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintUserTests.cs
  21. 2
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ScriptContentTests.cs

2
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/ContentDataProperty.cs

@ -18,7 +18,7 @@ public sealed class ContentDataProperty : CustomProperty
private ContentFieldObject? contentField;
private JsValue value;
protected override JsValue CustomValue
protected override JsValue? CustomValue
{
get
{

18
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentWrapper/JsonMapper.cs

@ -16,14 +16,24 @@ namespace Squidex.Domain.Apps.Core.Scripting.ContentWrapper;
public static class JsonMapper
{
private class JsonObjectInstance : ObjectInstance
{
public JsonObjectInstance(Engine engine)
: base(engine)
{
}
}
public static JsValue Map(JsonValue value, Engine engine)
{
switch (value.Value)
{
case null:
return JsValue.Null;
case bool b:
return new JsBoolean(b);
case true:
return JsBoolean.True;
case false:
return JsBoolean.False;
case double n:
return new JsNumber(n);
case string s:
@ -52,11 +62,11 @@ public static class JsonMapper
private static JsValue FromObject(JsonObject obj, Engine engine)
{
var target = new ObjectInstance(engine);
var target = new JsonObjectInstance(engine);
foreach (var (key, value) in obj)
{
target.FastAddProperty(key, Map(value, engine), true, true, true);
target.Set(key, Map(value, engine));
}
return target;

2
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/JintExtensions.cs → backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Internal/JintExtensions.cs

@ -9,7 +9,7 @@ using Jint;
using Jint.Native;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Core.Scripting;
namespace Squidex.Domain.Apps.Core.Scripting.Internal;
public static class JintExtensions
{

8
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/DefaultConverter.cs → backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Internal/JintObjectConverter.cs

@ -16,13 +16,13 @@ using Squidex.Domain.Apps.Core.Scripting.ContentWrapper;
using Squidex.Infrastructure;
using Squidex.Shared.Users;
namespace Squidex.Domain.Apps.Core.Scripting;
namespace Squidex.Domain.Apps.Core.Scripting.Internal;
public sealed class DefaultConverter : IObjectConverter
public sealed class JintObjectConverter : IObjectConverter
{
public static readonly DefaultConverter Instance = new DefaultConverter();
public static readonly JintObjectConverter Instance = new JintObjectConverter();
private DefaultConverter()
private JintObjectConverter()
{
}

2
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/JintUser.cs → backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Internal/JintUser.cs

@ -13,7 +13,7 @@ using Squidex.Infrastructure.Security;
using Squidex.Shared.Identity;
using Squidex.Shared.Users;
namespace Squidex.Domain.Apps.Core.Scripting;
namespace Squidex.Domain.Apps.Core.Scripting.Internal;
public static class JintUser
{

8
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/Internal/Parser.cs

@ -14,10 +14,6 @@ namespace Squidex.Domain.Apps.Core.Scripting.Internal;
internal sealed class Parser
{
private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes(10);
private static readonly ParserOptions DefaultParserOptions = new ParserOptions
{
AdaptRegexp = true, Tolerant = true
};
private readonly IMemoryCache cache;
@ -34,9 +30,7 @@ internal sealed class Parser
{
entry.AbsoluteExpirationRelativeToNow = CacheDuration;
var parser = new JavaScriptParser(script, DefaultParserOptions);
return parser.ParseScript();
return new JavaScriptParser().ParseScript(script);
})!;
}
}

2
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/JintScriptEngine.cs

@ -133,7 +133,7 @@ public sealed class JintScriptEngine : IScriptEngine, IScriptDescriptor
var engine = new Engine(engineOptions =>
{
engineOptions.AddObjectConverter(DefaultConverter.Instance);
engineOptions.AddObjectConverter(JintObjectConverter.Instance);
engineOptions.SetReferencesResolver(NullPropagation.Instance);
engineOptions.Strict();

67
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptContext.cs

@ -5,16 +5,65 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Collections;
using System.Diagnostics.CodeAnalysis;
using Squidex.Infrastructure;
using Squidex.Text;
namespace Squidex.Domain.Apps.Core.Scripting;
public class ScriptContext : Dictionary<string, object?>
public class ScriptContext : IEnumerable<KeyValuePair<string, (object? Value, bool IsReadonly)>>
{
public ScriptContext()
: base(StringComparer.OrdinalIgnoreCase)
private readonly Dictionary<string, (object? Value, bool IsReadonly)> values = new Dictionary<string, (object? Value, bool IsReadonly)>(StringComparer.OrdinalIgnoreCase);
public void CopyFrom(ScriptVars vars)
{
Guard.NotNull(vars);
foreach (var (key, item) in vars)
{
if (!values.ContainsKey(key))
{
SetItem(key, item);
}
}
}
public void SetItem(string? key, (object? Value, bool IsReadonly) item)
{
Set(key, item.Value, item.IsReadonly);
}
public void Set(string? key, object? value, bool isReadonly = false)
{
if (string.IsNullOrWhiteSpace(key))
{
return;
}
var finalKey = key.ToCamelCase();
if (values.TryGetValue(finalKey, out var existing) && existing.IsReadonly)
{
return;
}
values[finalKey] = (value, isReadonly);
}
public bool TryGetValue(string key, [MaybeNullWhen(false)] out object? value)
{
Guard.NotNull(key);
value = default!;
if (values.TryGetValue(key, out var item))
{
value = item.Value;
return true;
}
return false;
}
public bool TryGetValue<T>(string key, [MaybeNullWhen(false)] out T value)
@ -23,7 +72,7 @@ public class ScriptContext : Dictionary<string, object?>
value = default!;
if (TryGetValue(key, out var temp) && temp is T typed)
if (values.TryGetValue(key, out var item) && item.Value is T typed)
{
value = typed;
return true;
@ -31,4 +80,14 @@ public class ScriptContext : Dictionary<string, object?>
return false;
}
public IEnumerator<KeyValuePair<string, (object? Value, bool IsReadonly)>> GetEnumerator()
{
return values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return values.GetEnumerator();
}
}

19
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptExecutionContext.cs

@ -7,7 +7,6 @@
using Jint;
using Squidex.Infrastructure.Tasks;
using Squidex.Text;
namespace Squidex.Domain.Apps.Core.Scripting;
@ -117,30 +116,20 @@ public sealed class ScriptExecutionContext<T> : ScriptExecutionContext, ISchedul
{
var engine = Engine;
CopyFrom(vars);
if (options.AsContext)
{
var contextInstance = new WritableContext(engine, vars);
foreach (var (key, value) in vars.Where(x => x.Value != null))
{
this[key.ToCamelCase()] = value;
}
engine.SetValue("ctx", contextInstance);
engine.SetValue("context", contextInstance);
}
else
{
foreach (var (key, value) in vars)
foreach (var (key, item) in vars)
{
var property = key.ToCamelCase();
if (value != null)
{
engine.SetValue(property, value);
this[property] = value;
}
engine.SetValue(key, item.Value!);
}
}

13
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptVars.cs

@ -11,12 +11,19 @@ namespace Squidex.Domain.Apps.Core.Scripting;
public class ScriptVars : ScriptContext
{
public void SetValue(object? value, [CallerMemberName] string? key = null)
public object? this[string key]
{
if (key != null)
get
{
this[key] = value;
TryGetValue(key, out var result);
return result;
}
set => Set(key, value, true);
}
public void SetValue(object? value, [CallerMemberName] string? key = null)
{
Set(key, value, true);
}
public T GetValue<T>([CallerMemberName] string? key = null)

12
backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/WritableContext.cs

@ -8,7 +8,6 @@
using Jint;
using Jint.Native;
using Jint.Native.Object;
using Squidex.Text;
namespace Squidex.Domain.Apps.Core.Scripting;
@ -21,14 +20,9 @@ internal sealed class WritableContext : ObjectInstance
{
this.vars = vars;
foreach (var (key, value) in vars)
foreach (var (key, item) in vars)
{
var property = key.ToCamelCase();
if (value != null)
{
FastAddProperty(property, FromObject(engine, value), true, true, true);
}
base.Set(key, FromObject(engine, item.Value), this);
}
}
@ -36,7 +30,7 @@ internal sealed class WritableContext : ObjectInstance
{
var propertyName = property.AsString();
vars[propertyName] = value.ToObject();
vars.Set(propertyName, value.ToObject());
return base.Set(property, value, receiver);
}

2
backend/src/Squidex.Domain.Apps.Core.Operations/Squidex.Domain.Apps.Core.Operations.csproj

@ -20,7 +20,7 @@
<ItemGroup>
<PackageReference Include="Fluid.Core" Version="2.3.0" />
<PackageReference Include="GeoJSON.Net" Version="1.2.19" />
<PackageReference Include="Jint" Version="3.0.0-beta-2036" />
<PackageReference Include="Jint" Version="3.0.0-beta-2046" />
<PackageReference Include="Meziantou.Analyzer" Version="1.0.756">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

2
backend/src/Squidex.Domain.Apps.Entities/Apps/DomainObject/Guards/GuardApp.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Security.Claims;
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Domain.Apps.Entities.Billing;
using Squidex.Domain.Apps.Entities.Teams;
@ -14,7 +15,6 @@ using Squidex.Infrastructure.Validation;
using Squidex.Shared;
using Squidex.Shared.Identity;
using Squidex.Text;
using System.Security.Claims;
namespace Squidex.Domain.Apps.Entities.Apps.DomainObject.Guards;

7
backend/src/Squidex.Domain.Apps.Entities/Assets/AssetsJintExtension.cs

@ -15,6 +15,7 @@ using Squidex.Assets;
using Squidex.Domain.Apps.Core.Assets;
using Squidex.Domain.Apps.Core.Rules.EnrichedEvents;
using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Domain.Apps.Core.Scripting.Internal;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Properties;
using Squidex.Infrastructure;
@ -180,14 +181,14 @@ public sealed class AssetsJintExtension : IJintExtension, IScriptDescriptor
if (componentY?.IsNumber() == true)
{
options.ComponentX = (int)componentX.AsNumber();
options.ComponentX = (int)componentY.AsNumber();
}
var assetThumbnailGenerator = serviceProvider.GetRequiredService<IAssetThumbnailGenerator>();
var assetGenerator = serviceProvider.GetRequiredService<IAssetThumbnailGenerator>();
var assetFileStore = serviceProvider.GetRequiredService<IAssetFileStore>();
try
{
var hash = await asset.GetBlurHashAsync(options, assetFileStore, assetThumbnailGenerator, ct);
var hash = await asset.GetBlurHashAsync(options, assetFileStore, assetGenerator, ct);
scheduler.Run(callback, JsValue.FromObject(context.Engine, hash));
}

8
backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/Steps/ScriptAsset.cs

@ -82,13 +82,7 @@ public sealed class ScriptAsset : IAssetEnricherStep
}
};
foreach (var (key, value) in sharedVars)
{
if (!vars.ContainsKey(key))
{
vars[key] = value;
}
}
vars.CopyFrom(sharedVars);
var options = new ScriptOptions
{

8
backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ScriptContent.cs

@ -79,13 +79,7 @@ public sealed class ScriptContent : IContentEnricherStep
StatusOld = default
};
foreach (var (key, value) in sharedVars)
{
if (!vars.ContainsKey(key))
{
vars[key] = value;
}
}
vars.CopyFrom(sharedVars);
var options = new ScriptOptions
{

1
backend/src/Squidex.Domain.Apps.Entities/Contents/ReferencesJintExtension.cs

@ -10,6 +10,7 @@ using Jint.Native;
using Jint.Runtime;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Domain.Apps.Core.Scripting.Internal;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Properties;
using Squidex.Infrastructure;

4
backend/src/Squidex/Areas/Api/Controllers/Contents/Models/AllContentsByPostDto.cs

@ -5,14 +5,14 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Text.Json;
using System.Text.Json.Serialization;
using NodaTime;
using Squidex.Domain.Apps.Entities;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Queries;
using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Squidex.Areas.Api.Controllers.Contents.Models;

54
backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintScriptEngineTests.cs

@ -488,6 +488,40 @@ public class JintScriptEngineTests : IClassFixture<TranslationsFixture>
Assert.Equal(id.ToString(), actual.ToString());
}
[Fact]
public void Should_allow_null_vars()
{
var vars = new ScriptVars
{
["value"] = null
};
const string script = @"
return value;
";
var actual = sut.Execute(vars, script);
Assert.Equal(JsonValue.Null, actual);
}
[Fact]
public void Should_not_allow_to_overwrite_initial_var()
{
var vars = new ScriptVars
{
["value"] = 13
};
const string script = @"
ctx.value = ctx.value * 2;
";
sut.Execute(vars, script, new ScriptOptions { AsContext = true });
Assert.Equal(13, vars["value"]);
}
[Fact]
public void Should_share_vars_between_executions()
{
@ -497,11 +531,11 @@ public class JintScriptEngineTests : IClassFixture<TranslationsFixture>
};
const string script1 = @"
ctx.value = ctx.value * 2;
ctx.shared = ctx.value * 2;
";
const string script2 = @"
return ctx.value + 2;
return ctx.shared + 2;
";
sut.Execute(vars, script1, new ScriptOptions { AsContext = true });
@ -543,30 +577,22 @@ public class JintScriptEngineTests : IClassFixture<TranslationsFixture>
};
const string script1 = @"
ctx.obj = { number: ctx.value * 2 };
ctx.shared = { number: ctx.value * 2 };
";
const string script2 = @"
ctx.data.test = { iv: ctx.obj.number + 2 };
ctx.data.test = { iv: ctx.shared.number + 2 };
replace();
";
#pragma warning disable MA0042 // Do not use blocking calls in an async method
sut.Execute(vars, script1, new ScriptOptions { AsContext = true });
#pragma warning restore MA0042 // Do not use blocking calls in an async method
await sut.ExecuteAsync(vars, script1, new ScriptOptions { AsContext = true });
var vars2 = new DataScriptVars
{
["data"] = new ContentData()
};
foreach (var (key, value) in vars)
{
if (!vars2.ContainsKey(key))
{
vars2[key] = value;
}
}
vars2.CopyFrom(vars);
var actual = await sut.TransformAsync(vars2, script2, new ScriptOptions { AsContext = true });

2
backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/Scripting/JintUserTests.cs

@ -7,7 +7,7 @@
using System.Security.Claims;
using Jint;
using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Domain.Apps.Core.Scripting.Internal;
using Squidex.Infrastructure.Security;
using Squidex.Shared.Identity;

2
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ScriptContentTests.cs

@ -76,7 +76,7 @@ public class ScriptContentTests : GivenContext
A<DataScriptVars>.That.Matches(x =>
Equals(x["contentId"], content.Id) &&
Equals(x["data"], oldData) &&
Equals(x["AppId"], AppId.Id) &&
Equals(x["appId"], AppId.Id) &&
Equals(x["appName"], AppId.Name) &&
Equals(x["user"], ApiContext.UserPrincipal)),
"my-query",

Loading…
Cancel
Save