< Summary

Information
Class: Elsa.Expressions.JavaScript.Handlers.ConfigureEngineWithCommonFunctions
Assembly: Elsa.Expressions.JavaScript
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Expressions.JavaScript/Handlers/ConfigureEngineWithCommonFunctions.cs
Line coverage
92%
Covered lines: 46
Uncovered lines: 4
Coverable lines: 50
Total lines: 105
Line coverage: 92%
Branch coverage
100%
Covered branches: 32
Total branches: 32
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
HandleAsync(...)100%3232100%
Serialize(...)100%11100%
CreateJsonSerializerOptions()100%11100%
StreamToBytes(...)100%210%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Expressions.JavaScript/Handlers/ConfigureEngineWithCommonFunctions.cs

#LineLine coverage
 1using System.Text;
 2using System.Text.Encodings.Web;
 3using System.Text.Json;
 4using System.Text.Json.Serialization;
 5using System.Text.RegularExpressions;
 6using System.Text.Unicode;
 7using Elsa.Extensions;
 8using Elsa.Expressions.JavaScript.Helpers;
 9using Elsa.Expressions.JavaScript.Notifications;
 10using Elsa.Expressions.JavaScript.Options;
 11using Elsa.Mediator.Contracts;
 12using JetBrains.Annotations;
 13using Jint;
 14using Jint.Native;
 15using Jint.Runtime.Descriptors;
 16using Microsoft.Extensions.Options;
 17
 18namespace Elsa.Expressions.JavaScript.Handlers;
 19
 20/// <summary>
 21/// A handler that configures the Jint engine with common functions.
 22/// </summary>
 23[UsedImplicitly]
 90924public class ConfigureEngineWithCommonFunctions(IOptions<JintOptions> options) : INotificationHandler<EvaluatingJavaScri
 25{
 90926    private readonly JsonSerializerOptions _jsonSerializerOptions = CreateJsonSerializerOptions();
 27
 28    /// <inheritdoc />
 29    public Task HandleAsync(EvaluatingJavaScript notification, CancellationToken cancellationToken)
 30    {
 28531        var engine = notification.Engine;
 28532        var context = notification.Context;
 33
 34        // Add common functions. Each one is installed as a global whose value is produced the first time a script
 35        // reads the name, so a fresh engine no longer builds twenty-seven interop function wrappers for an
 36        // expression that calls none of them. The CLR delegate is created inside the factory for the same reason.
 28837        AddFunction("getWorkflowDefinitionId", e => JsValue.FromObject(e, (Func<string>)(() => context.GetWorkflowExecut
 28838        AddFunction("getWorkflowDefinitionVersionId", e => JsValue.FromObject(e, (Func<string>)(() => context.GetWorkflo
 28839        AddFunction("getWorkflowDefinitionVersion", e => JsValue.FromObject(e, (Func<int>)(() => context.GetWorkflowExec
 28840        AddFunction("getWorkflowInstanceId", e => JsValue.FromObject(e, (Func<string>)(() => context.GetActivityExecutio
 28841        AddFunction("setCorrelationId", e => JsValue.FromObject(e, (Action<string?>)(value => context.GetActivityExecuti
 29042        AddFunction("getCorrelationId", e => JsValue.FromObject(e, (Func<string?>)(() => context.GetActivityExecutionCon
 28843        AddFunction("setWorkflowInstanceName", e => JsValue.FromObject(e, (Action<string?>)(value => context.GetWorkflow
 29044        AddFunction("getWorkflowInstanceName", e => JsValue.FromObject(e, (Func<string?>)(() => context.GetWorkflowExecu
 28945        AddFunction("setVariable", e => JsValue.FromObject(e, (Action<string, object>)((name, value) =>
 28946        {
 247            engine.SyncVariablesContainer(options, name, value);
 248            context.SetVariableInScope(name, value);
 29149        })));
 43150        AddFunction("getVariable", e => JsValue.FromObject(e, (Func<string, object?>)(name => context.GetVariableInScope
 28751        AddFunction("getInput", e => JsValue.FromObject(e, (Func<string, object?>)(name => context.GetInput(name))));
 28752        AddFunction("getOutputFrom", e => JsValue.FromObject(e, (Func<string, string?, object?>)((activityIdName, output
 28753        AddFunction("getLastResult", e => JsValue.FromObject(e, (Func<object?>)(() => context.GetLastResult())));
 29354        AddFunction("isNullOrWhiteSpace", e => JsValue.FromObject(e, (Func<string, bool>)(value => string.IsNullOrWhiteS
 29455        AddFunction("isNullOrEmpty", e => JsValue.FromObject(e, (Func<string, bool>)(value => string.IsNullOrEmpty(value
 29656        AddFunction("toJson", e => JsValue.FromObject(e, (Func<object, string>)(value => Serialize(value))));
 28957        AddFunction("parseGuid", e => JsValue.FromObject(e, (Func<string, Guid>)(value => Guid.Parse(value))));
 29358        AddFunction("newGuid", e => JsValue.FromObject(e, (Func<Guid>)(() => Guid.NewGuid())));
 29059        AddFunction("newGuidString", e => JsValue.FromObject(e, (Func<string>)(() => Guid.NewGuid().ToString())));
 29060        AddFunction("newShortGuid", e => JsValue.FromObject(e, (Func<string>)(() => Regex.Replace(Convert.ToBase64String
 29261        AddFunction("bytesToString", e => JsValue.FromObject(e, (Func<byte[], string>)(value => Encoding.UTF8.GetString(
 29062        AddFunction("bytesFromString", e => JsValue.FromObject(e, (Func<string, byte[]>)(value => Encoding.UTF8.GetBytes
 29263        AddFunction("bytesToBase64", e => JsValue.FromObject(e, (Func<byte[], string>)(value => Convert.ToBase64String(v
 29064        AddFunction("bytesFromBase64", e => JsValue.FromObject(e, (Func<string, byte[]>)(value => Convert.FromBase64Stri
 29265        AddFunction("stringToBase64", e => JsValue.FromObject(e, (Func<string, string>)(value => Convert.ToBase64String(
 29066        AddFunction("stringFromBase64", e => JsValue.FromObject(e, (Func<string, string>)(value => Encoding.UTF8.GetStri
 28767        AddFunction("streamToBytes", e => JsValue.FromObject(e, (Func<Stream, byte[]>)(value => StreamToBytes(value))));
 28668        AddFunction("streamToBase64", e => JsValue.FromObject(e, (Func<Stream, string>)(value => Convert.ToBase64String(
 69
 70        // Deprecated, use newGuidString instead.
 28871        AddFunction("getGuidString", e => JsValue.FromObject(e, (Func<string>)(() => Guid.NewGuid().ToString())));
 72
 73        // Deprecated, use newShortGuid instead.
 28974        AddFunction("getShortGuid", e => JsValue.FromObject(e, (Func<string>)(() => Regex.Replace(Convert.ToBase64String
 28575        return Task.CompletedTask;
 76
 77        // AddLazyGlobal installs the property itself eagerly and defers only its value, so `in`, `hasOwnProperty`
 78        // and Object.getOwnPropertyNames see every function immediately and the factory runs at most once, on the
 79        // first read. NonEnumerable is the flag engine.SetValue(string, Delegate) applies, so the attributes — and
 80        // therefore what Object.keys(globalThis) reports — are exactly what they were.
 81        void AddFunction(string name, Func<Engine, JsValue> valueFactory) => engine.Advanced.AddLazyGlobal(name, valueFa
 82    }
 83
 84    private string Serialize(object value)
 85    {
 586        return JsonSerializer.Serialize(value, _jsonSerializerOptions);
 87    }
 88
 89    private static JsonSerializerOptions CreateJsonSerializerOptions()
 90    {
 90991        var options = new JsonSerializerOptions
 90992        {
 90993            Encoder = JavaScriptEncoder.Create(UnicodeRanges.All)
 90994        };
 90995        options.Converters.Add(new JsonStringEnumConverter());
 90996        return options;
 97    }
 98
 99    private byte[] StreamToBytes(Stream stream)
 100    {
 0101        using var memoryStream = new MemoryStream();
 0102        stream.CopyTo(memoryStream);
 0103        return memoryStream.ToArray();
 0104    }
 105}