< Summary

Information
Class: Elsa.Extensions.EngineOptionsExtensions
Assembly: Elsa.Expressions.JavaScript
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Expressions.JavaScript/Extensions/EngineOptionsExtensions.cs
Line coverage
90%
Covered lines: 10
Uncovered lines: 1
Coverable lines: 11
Total lines: 67
Line coverage: 90.9%
Branch coverage
77%
Covered branches: 14
Total branches: 18
Branch coverage: 77.7%
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(...)100%22100%
IsUsableAsIdentifier(...)75%171683.33%

File(s)

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

#LineLine coverage
 1using Jint;
 2using Jint.Runtime.Interop;
 3
 4// ReSharper disable once CheckNamespace
 5namespace Elsa.Extensions;
 6
 7/// <summary>
 8/// Extends <see cref="Jint.Options"/>.
 9/// </summary>
 10public static class EngineOptionsExtensions
 11{
 12    /// <summary>
 13    /// Registers the specified type <c>T</c> with every engine built from these options.
 14    /// </summary>
 171015    public static Jint.Options RegisterType<T>(this Jint.Options options) => options.RegisterType(typeof(T));
 16
 17    /// <summary>
 18    /// Registers the specified type with every engine built from these options, under its type name.
 19    /// </summary>
 20    /// <remarks>
 21    /// <para>
 22    /// The type reference is built the first time a script reads the name. Registering a type therefore costs a
 23    /// property definition rather than the reflection needed to describe the type, which matters because a fresh
 24    /// engine is built for every expression evaluation and most expressions use none of the registered types.
 25    /// </para>
 26    /// <para>
 27    /// Types whose name cannot be written as a JavaScript identifier are skipped: a constructed generic type such
 28    /// as <c>IDictionary&lt;string, object&gt;</c> is named <c>IDictionary`2</c> and an array type such as
 29    /// <c>byte[]</c> is named <c>Byte[]</c>. Registered, those would only be reachable through bracket notation —
 30    /// <c>globalThis['Byte[]']</c> — and every constructed generic type of the same arity would claim the same
 31    /// global.
 32    /// </para>
 33    /// <para>
 34    /// Registering the same name twice is allowed and the last registration wins. Several handlers contribute type
 35    /// registrations and their sets overlap — <c>Guid</c>, <c>DateTime</c>, <c>DateTimeOffset</c>, <c>TimeSpan</c>
 36    /// and <c>LogPersistenceMode</c> are registered both as common types and as workflow variable types — but a
 37    /// duplicate now costs one property definition and describes nothing, and both registrations name the same
 38    /// <see cref="Type"/>, so which one survives is not observable. Registration happens while the engine is being
 39    /// built, so every host extension point — the per-evaluation <c>configureEngine</c> callback,
 40    /// <c>JintOptions.ConfigureEngine</c> and <c>JintOptions.ConfigureEngineOptions</c> — runs afterwards and a
 41    /// global installed there is never replaced by a type registration.
 42    /// </para>
 43    /// </remarks>
 44    public static Jint.Options RegisterType(this Jint.Options options, Type type)
 45    {
 586846        var name = type.Name;
 47
 586848        if (!IsUsableAsIdentifier(name))
 85549            return options;
 50
 504151        return options.AddLazyGlobal(name, engine => TypeReference.CreateTypeReference(engine, type));
 52    }
 53
 54    private static bool IsUsableAsIdentifier(string name)
 55    {
 586856        if (string.IsNullOrEmpty(name) || (!char.IsLetter(name[0]) && name[0] != '_' && name[0] != '$'))
 057            return false;
 58
 12545159        foreach (var c in name)
 60        {
 5728561            if (!char.IsLetterOrDigit(c) && c != '_' && c != '$')
 85562                return false;
 63        }
 64
 501365        return true;
 66    }
 67}