< Summary

Information
Class: Elsa.Extensions.EngineExtensions
Assembly: Elsa.Expressions.JavaScript
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Expressions.JavaScript/Extensions/EngineExtensions.cs
Line coverage
80%
Covered lines: 16
Uncovered lines: 4
Coverable lines: 20
Total lines: 76
Line coverage: 80%
Branch coverage
58%
Covered branches: 14
Total branches: 24
Branch coverage: 58.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
RegisterType(...)100%11100%
RegisterType(...)75%4485.71%
IsUsableAsIdentifier(...)56.25%251666.66%
SyncVariablesContainer(...)50%4483.33%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Expressions.JavaScript/Extensions/EngineExtensions.cs

#LineLine coverage
 1using Elsa.Expressions.JavaScript.Helpers;
 2using Elsa.Expressions.JavaScript.Options;
 3using Jint;
 4using Jint.Runtime.Interop;
 5using Microsoft.Extensions.Options;
 6
 7// ReSharper disable once CheckNamespace
 8namespace Elsa.Extensions;
 9
 10/// <summary>
 11/// Extends <see cref="Engine"/>.
 12/// </summary>
 13public static class EngineExtensions
 14{
 15    /// <summary>
 16    /// Register the specified type <c>T</c> with the engine.
 17    /// </summary>
 6618    public static void RegisterType<T>(this Engine engine) => engine.RegisterType(typeof(T));
 19
 20    /// <summary>
 21    /// Register the specified type with the engine, under its type name.
 22    /// </summary>
 23    /// <remarks>
 24    /// <para>
 25    /// Types whose name cannot be written as a JavaScript identifier are skipped. A constructed generic type such
 26    /// as <c>IDictionary&lt;string, object&gt;</c> is named <c>IDictionary`2</c> and an array type such as
 27    /// <c>byte[]</c> is named <c>Byte[]</c>. Registered, those would only be reachable through bracket notation —
 28    /// <c>globalThis['Byte[]']</c> — and every constructed generic type of the same arity would claim the same
 29    /// global, so the last one registered would silently win.
 30    /// </para>
 31    /// <para>
 32    /// A name that is already taken is left alone. Registering the same type twice is therefore a no-op, and a
 33    /// global installed before this method is called is never replaced. Built-in type globals are registered
 34    /// lazily through <see cref="EngineOptionsExtensions.RegisterType(Jint.Options, Type)"/> while the engine is
 35    /// being constructed, so host callbacks that run afterwards can replace them deliberately.
 36    /// </para>
 37    /// </remarks>
 38    public static void RegisterType(this Engine engine, Type type)
 39    {
 6640        var name = type.Name;
 41
 6642        if (!IsUsableAsIdentifier(name))
 043            return;
 44
 45        // Leave any value that the host or JavaScript already installed under this name untouched.
 6646        if (engine.Global.HasOwnProperty(name))
 4347            return;
 48
 2349        engine.SetValue(name, TypeReference.CreateTypeReference(engine, type));
 2350    }
 51
 52    private static bool IsUsableAsIdentifier(string name)
 53    {
 6654        if (string.IsNullOrEmpty(name) || (!char.IsLetter(name[0]) && name[0] != '_' && name[0] != '$'))
 055            return false;
 56
 204057        foreach (var c in name)
 58        {
 95459            if (!char.IsLetterOrDigit(c) && c != '_' && c != '$')
 060                return false;
 61        }
 62
 6663        return true;
 64    }
 65
 66    internal static void SyncVariablesContainer(this Engine engine, IOptions<JintOptions> options, string name, object? 
 67    {
 668        if (options.Value.DisableWrappers || options.Value.DisableVariableCopying)
 069            return;
 70
 71        // To ensure both variable accessor syntaxes work, we need to update the variables container in the engine as we
 672        var variablesContainer = (IDictionary<string, object?>)engine.GetValue("variables").ToObject()!;
 673        variablesContainer[name] = ObjectConverterHelper.ProcessVariableValue(engine, value);
 674        engine.SetValue("variables", variablesContainer);
 675    }
 76}