< Summary

Information
Class: Elsa.Expressions.Liquid.Handlers.ConfigureLiquidEngine
Assembly: Elsa.Expressions.Liquid
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Expressions.Liquid/Handlers/ConfigureLiquidEngine.cs
Line coverage
12%
Covered lines: 5
Uncovered lines: 34
Coverable lines: 39
Total lines: 101
Line coverage: 12.8%
Branch coverage
0%
Covered branches: 0
Total branches: 20
Branch coverage: 0%
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(...)0%7280%
GetConfigurationValue(...)100%210%
ToFluidValue(...)100%210%
GetVariable(...)0%620%
GetInput(...)0%110100%
GetVariableInScope(...)100%210%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Expressions.Liquid/Handlers/ConfigureLiquidEngine.cs

#LineLine coverage
 1using System.Dynamic;
 2using Elsa.Expressions.Models;
 3using Elsa.Extensions;
 4using Elsa.Expressions.Liquid.Helpers;
 5using Elsa.Expressions.Liquid.Notifications;
 6using Elsa.Expressions.Liquid.Options;
 7using Elsa.Mediator.Contracts;
 8using Elsa.Workflows.Management.Options;
 9using Elsa.Workflows.Memory;
 10using Fluid;
 11using Fluid.Values;
 12using Microsoft.Extensions.Configuration;
 13using Microsoft.Extensions.Options;
 14
 15namespace Elsa.Expressions.Liquid.Handlers;
 16
 17/// <summary>
 18/// Configures the liquid templating engine before evaluating a liquid expression.
 19/// </summary>
 20internal class ConfigureLiquidEngine : INotificationHandler<RenderingLiquidTemplate>
 21{
 22    private readonly IConfiguration _configuration;
 23    private readonly ManagementOptions _managementOptions;
 24    private readonly FluidOptions _fluidOptions;
 25
 26    /// <summary>
 27    /// Constructor.
 28    /// </summary>
 31929    public ConfigureLiquidEngine(IConfiguration configuration, IOptions<FluidOptions> fluidOptions, IOptions<ManagementO
 30    {
 31931        _configuration = configuration;
 31932        _managementOptions = managementOptions.Value;
 31933        _fluidOptions = fluidOptions.Value;
 31934    }
 35
 36    /// <inheritdoc />
 37    public Task HandleAsync(RenderingLiquidTemplate notification, CancellationToken cancellationToken)
 38    {
 039        var context = notification.TemplateContext;
 040        var options = context.Options;
 041        var memberAccessStrategy = options.MemberAccessStrategy;
 42
 043        memberAccessStrategy.Register<ExpandoObject>();
 044        memberAccessStrategy.Register<LiquidPropertyAccessor, FluidValue>((x, name) => x.GetValueAsync(name));
 045        memberAccessStrategy.Register<ExpandoObject, object>((x, name) => ((IDictionary<string, object>)x!)[name]);
 046        memberAccessStrategy.Register<ExpressionExecutionContext, LiquidPropertyAccessor>("Variables", x => new LiquidPr
 047        memberAccessStrategy.Register<ExpressionExecutionContext, LiquidPropertyAccessor>("Input", x => new LiquidProper
 048        memberAccessStrategy.Register<ExpressionExecutionContext, string?>("CorrelationId", x => x.GetWorkflowExecutionC
 049        memberAccessStrategy.Register<ExpressionExecutionContext, string>("WorkflowDefinitionId", x => x.GetWorkflowExec
 050        memberAccessStrategy.Register<ExpressionExecutionContext, string>("WorkflowDefinitionVersionId", x => x.GetWorkf
 051        memberAccessStrategy.Register<ExpressionExecutionContext, int>("WorkflowDefinitionVersion", x => x.GetWorkflowEx
 052        memberAccessStrategy.Register<ExpressionExecutionContext, string>("WorkflowInstanceId", x => x.GetActivityExecut
 53
 054        if (_fluidOptions.AllowConfigurationAccess)
 55        {
 056            memberAccessStrategy.Register<ExpressionExecutionContext, LiquidPropertyAccessor>("Configuration", x => new 
 057            memberAccessStrategy.Register<ConfigurationSectionWrapper, ConfigurationSectionWrapper?>((source, name) => s
 58        }
 59
 60        // Register all variable types.
 061        foreach (var variableDescriptor in _managementOptions.VariableDescriptors.Where(x => x.Type is { IsClass: true, 
 062            memberAccessStrategy.Register(variableDescriptor.Type);
 63
 064        return Task.CompletedTask;
 65    }
 66
 067    private ConfigurationSectionWrapper GetConfigurationValue(string name) => new(_configuration.GetSection(name));
 068    private Task<FluidValue> ToFluidValue(object? input, TemplateOptions options) => Task.FromResult(FluidValue.Create(i
 69
 70    private Task<FluidValue> GetVariable(ExpressionExecutionContext context, string key, TemplateOptions options)
 71    {
 072        var value = GetVariableInScope(context, key);
 073        return Task.FromResult(value == null ? NilValue.Instance : FluidValue.Create(value, options));
 74    }
 75
 76    private Task<FluidValue> GetInput(ExpressionExecutionContext context, string key, TemplateOptions options)
 77    {
 78        // First, check if the current activity has inputs
 079        if (context.TryGetActivityExecutionContext(out var activityExecutionContext) &&
 080            activityExecutionContext.ActivityInput.TryGetValue(key, out var activityValue))
 81        {
 082            return Task.FromResult(activityValue == null ? NilValue.Instance : FluidValue.Create(activityValue, options)
 83        }
 84
 85        // Fall back to workflow inputs if activity inputs don't contain the key
 086        var workflowExecutionContext = context.GetWorkflowExecutionContext();
 087        var input = workflowExecutionContext.Input.TryGetValue(key, out var workflowValue) ? workflowValue : default;
 88
 089        return Task.FromResult(input == null ? NilValue.Instance : FluidValue.Create(workflowValue, options));
 90    }
 91
 92    private static object? GetVariableInScope(ExpressionExecutionContext context, string variableName)
 93    {
 094        var q = from variable in context.EnumerateVariablesInScope()
 095            where variable.Name == variableName
 096            where variable.TryGet(context, out _)
 097            select variable.Get(context);
 98
 099        return q.FirstOrDefault();
 100    }
 101}