Add Variable Name Validation and Wrapper Control (#6117)

* Refactor directory structure and add variable wrappers option

Renamed TypeDefinitions/Providers to Providers for better clarity. Added a new configuration option to disable generating variable wrappers for scenarios requiring invalid JavaScript variable names.

* Add variable name validation and wrapper control

Introduced methods to validate variable names and filter invalid ones. Integrated `DisableWrappers` option to control the generation of variable wrappers, enhancing flexibility in variable management.

* Remove unused item group from project file

The item group containing the "TypeDefinitions\Providers\" folder was removed from the Elsa.JavaScript.csproj file. This folder was not serving any purpose and its removal helps in cleaning up the project structure.
This commit is contained in:
Sipke Schoorstra 2024-11-13 19:58:00 +01:00 committed by GitHub
parent 50e23ba738
commit 02f4dc9b8c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 189 additions and 64 deletions

View file

@ -71,6 +71,7 @@ const MassTransitBroker massTransitBroker = MassTransitBroker.Memory;
const bool useMultitenancy = false;
const bool useAgents = false;
const bool useSecrets = true;
const bool disableVariableWrappers = false;
var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;
@ -314,6 +315,7 @@ services
.UseJavaScript(options =>
{
options.AllowClrAccess = true;
options.DisableWrappers = disableVariableWrappers;
options.ConfigureEngine(engine =>
{
engine.Execute("function greet(name) { return `Hello ${name}!`; }");

View file

@ -0,0 +1,19 @@
namespace Elsa.CSharp.Extensions;
public static class VariableNameExtensions
{
public static bool IsValidVariableName(this string name)
{
return !string.IsNullOrWhiteSpace(name) && name.All(char.IsLetterOrDigit);
}
public static bool IsInvalidVariableName(this string name)
{
return !IsValidVariableName(name);
}
public static IEnumerable<string> FilterInvalidVariableNames(this IEnumerable<string> names)
{
return names.Where(IsValidVariableName);
}
}

View file

@ -1,9 +1,12 @@
using System.Text;
using Elsa.CSharp.Extensions;
using Elsa.CSharp.Notifications;
using Elsa.CSharp.Options;
using Elsa.Expressions.Models;
using Elsa.Extensions;
using Elsa.Mediator.Contracts;
using JetBrains.Annotations;
using Microsoft.Extensions.Options;
namespace Elsa.CSharp.Handlers;
@ -11,7 +14,7 @@ namespace Elsa.CSharp.Handlers;
/// Configures the C# evaluator with methods to access workflow variables.
/// </summary>
[UsedImplicitly]
public class GenerateArgumentAccessors : INotificationHandler<EvaluatingCSharp>
public class GenerateArgumentAccessors(IOptions<CSharpOptions> options) : INotificationHandler<EvaluatingCSharp>
{
/// <inheritdoc />
public Task HandleAsync(EvaluatingCSharp notification, CancellationToken cancellationToken)
@ -24,17 +27,19 @@ public class GenerateArgumentAccessors : INotificationHandler<EvaluatingCSharp>
sb.AppendLine();
sb.AppendLine("\tpublic T? Get<T>(string name) => Arguments.TryGetValue(name, out var v) ? (T?)v : default;");
sb.AppendLine();
foreach (var argument in arguments)
if (!options.Value.DisableWrappers)
{
// var d = new Dictionary<string, object>();
// d.TryGetValue("", out var f);
var argumentName = argument.Key;
var variableType = argument.Value.GetType();
var friendlyTypeName = variableType.GetFriendlyTypeName(Brackets.Angle);
sb.AppendLine($"\tpublic {friendlyTypeName} {argumentName}");
sb.AppendLine("\t{");
sb.AppendLine($"\t\tget => Get<{friendlyTypeName}>(\"{argumentName}\");");
sb.AppendLine("\t}");
foreach (var argument in arguments.Where(x => x.Key.IsValidVariableName()))
{
var argumentName = argument.Key;
var variableType = argument.Value.GetType();
var friendlyTypeName = variableType.GetFriendlyTypeName(Brackets.Angle);
sb.AppendLine($"\tpublic {friendlyTypeName} {argumentName}");
sb.AppendLine("\t{");
sb.AppendLine($"\t\tget => Get<{friendlyTypeName}>(\"{argumentName}\");");
sb.AppendLine("\t}");
}
}
sb.AppendLine("}");

View file

@ -1,9 +1,12 @@
using System.Text;
using Elsa.CSharp.Extensions;
using Elsa.CSharp.Notifications;
using Elsa.CSharp.Options;
using Elsa.Expressions.Models;
using Elsa.Extensions;
using Elsa.Mediator.Contracts;
using JetBrains.Annotations;
using Microsoft.Extensions.Options;
namespace Elsa.CSharp.Handlers;
@ -11,13 +14,12 @@ namespace Elsa.CSharp.Handlers;
/// Configures the C# evaluator with methods to access workflow variables.
/// </summary>
[UsedImplicitly]
public class GenerateWorkflowInputAccessors : INotificationHandler<EvaluatingCSharp>
public class GenerateWorkflowInputAccessors(IOptions<CSharpOptions> options) : INotificationHandler<EvaluatingCSharp>
{
/// <inheritdoc />
public Task HandleAsync(EvaluatingCSharp notification, CancellationToken cancellationToken)
{
var expressionExecutionContext = notification.Context;
var workflowInputs = expressionExecutionContext.GetWorkflowInputs().ToList();
if (!expressionExecutionContext.TryGetWorkflowExecutionContext(out var workflowExecutionContext))
return Task.CompletedTask;
@ -31,15 +33,19 @@ public class GenerateWorkflowInputAccessors : INotificationHandler<EvaluatingCSh
sb.AppendLine();
sb.AppendLine("\tpublic T? Get<T>(string name) => ExecutionContext.GetInput<T>(name);");
sb.AppendLine();
foreach (var inputDefinition in inputDefinitions)
if (!options.Value.DisableWrappers)
{
var inputName = inputDefinition.Name;
var variableType = inputDefinition.Type;
var friendlyTypeName = variableType.GetFriendlyTypeName(Brackets.Angle);
sb.AppendLine($"\tpublic {friendlyTypeName} {inputName}");
sb.AppendLine("\t{");
sb.AppendLine($"\t\tget => Get<{friendlyTypeName}>(\"{inputName}\");");
sb.AppendLine("\t}");
foreach (var inputDefinition in inputDefinitions.Where(x => x.Name.IsValidVariableName()))
{
var inputName = inputDefinition.Name;
var variableType = inputDefinition.Type;
var friendlyTypeName = variableType.GetFriendlyTypeName(Brackets.Angle);
sb.AppendLine($"\tpublic {friendlyTypeName} {inputName}");
sb.AppendLine("\t{");
sb.AppendLine($"\t\tget => Get<{friendlyTypeName}>(\"{inputName}\");");
sb.AppendLine("\t}");
}
}
sb.AppendLine("}");

View file

@ -1,10 +1,13 @@
using System.Text;
using Elsa.CSharp.Extensions;
using Elsa.CSharp.Notifications;
using Elsa.CSharp.Options;
using Elsa.Expressions.Models;
using Elsa.Extensions;
using Elsa.Mediator.Contracts;
using Humanizer;
using JetBrains.Annotations;
using Microsoft.Extensions.Options;
namespace Elsa.CSharp.Handlers;
@ -12,7 +15,7 @@ namespace Elsa.CSharp.Handlers;
/// Configures the C# evaluator with methods to access workflow variables.
/// </summary>
[UsedImplicitly]
public class GenerateWorkflowVariableAccessors : INotificationHandler<EvaluatingCSharp>
public class GenerateWorkflowVariableAccessors(IOptions<CSharpOptions> options) : INotificationHandler<EvaluatingCSharp>
{
/// <inheritdoc />
public Task HandleAsync(EvaluatingCSharp notification, CancellationToken cancellationToken)
@ -28,16 +31,20 @@ public class GenerateWorkflowVariableAccessors : INotificationHandler<Evaluating
sb.AppendLine("\tpublic object? Get(string name) => ExecutionContext.GetVariable(name);");
sb.AppendLine("\tpublic void Set(string name, object? value) => ExecutionContext.SetVariable(name, value);");
sb.AppendLine();
foreach (var variable in variables)
if (!options.Value.DisableWrappers)
{
var variableName = variable.Name.Pascalize();
var variableType = variable.GetVariableType();
var friendlyTypeName = variableType.GetFriendlyTypeName(Brackets.Angle);
sb.AppendLine($"\tpublic {friendlyTypeName} {variableName}");
sb.AppendLine("\t{");
sb.AppendLine($"\t\tget => Get<{friendlyTypeName}>(\"{variableName}\");");
sb.AppendLine($"\t\tset => Set(\"{variableName}\", value);");
sb.AppendLine("\t}");
foreach (var variable in variables.Where(x => x.Name.IsValidVariableName()))
{
var variableName = variable.Name.Pascalize();
var variableType = variable.GetVariableType();
var friendlyTypeName = variableType.GetFriendlyTypeName(Brackets.Angle);
sb.AppendLine($"\tpublic {friendlyTypeName} {variableName}");
sb.AppendLine("\t{");
sb.AppendLine($"\t\tget => Get<{friendlyTypeName}>(\"{variableName}\");");
sb.AppendLine($"\t\tset => Set(\"{variableName}\", value);");
sb.AppendLine("\t}");
}
}
sb.AppendLine("}");

View file

@ -49,6 +49,12 @@ public class CSharpOptions
typeof(JsonNode).Namespace!, // System.Text.Json.Nodes
typeof(IDictionary<string, object>).Namespace!, // System.Collections.Generic
});
/// <summary>
/// Disables the generation of variable wrappers. E.g. <c>Variables.MyVariable</c> will no longer be available for variables. Instead, you can only access variables using <c>Variables.Get("MyVariable")</c> and the typed <c>Variables.Get&lt;T&gt;("MyVariable")</c> function.
/// This is useful if your application requires the use of invalid JavaScript variable names.
/// </summary>
public bool DisableWrappers { get; set; }
/// <summary>
/// Configures the <see cref="ScriptOptions"/>.

View file

@ -0,0 +1,21 @@
using Elsa.JavaScript.Helpers;
namespace Elsa.JavaScript.Extensions;
public static class VariableNameExtensions
{
public static bool IsValidVariableName(this string name)
{
return VariableNameValidator.IsValidVariableName(name);
}
public static bool IsInvalidVariableName(this string name)
{
return !VariableNameValidator.IsValidVariableName(name);
}
public static IEnumerable<string> FilterInvalidVariableNames(this IEnumerable<string> names)
{
return names.Where(IsValidVariableName);
}
}

View file

@ -13,7 +13,6 @@ using Elsa.JavaScript.Options;
using Elsa.JavaScript.Providers;
using Elsa.JavaScript.Services;
using Elsa.JavaScript.TypeDefinitions.Contracts;
using Elsa.JavaScript.TypeDefinitions.Providers;
using Elsa.JavaScript.TypeDefinitions.Services;
using Elsa.Workflows;
using Microsoft.Extensions.DependencyInjection;

View file

@ -1,29 +1,38 @@
using System.Dynamic;
using Elsa.Expressions.Models;
using Elsa.Extensions;
using Elsa.JavaScript.Extensions;
using Elsa.JavaScript.Helpers;
using Elsa.JavaScript.Notifications;
using Elsa.JavaScript.Options;
using Elsa.Mediator.Contracts;
using Elsa.Workflows.Activities;
using JetBrains.Annotations;
using Jint;
using Jint.Native;
using Microsoft.Extensions.Options;
namespace Elsa.JavaScript.Handlers;
/// A handler that configures the Jint engine with workflow variables.
[UsedImplicitly]
public class ConfigureEngineWithVariables : INotificationHandler<EvaluatingJavaScript>, INotificationHandler<EvaluatedJavaScript>
public class ConfigureEngineWithVariables(IOptions<JintOptions> options) : INotificationHandler<EvaluatingJavaScript>, INotificationHandler<EvaluatedJavaScript>
{
/// <inheritdoc />
public Task HandleAsync(EvaluatingJavaScript notification, CancellationToken cancellationToken)
{
if(options.Value.DisableWrappers)
return Task.CompletedTask;
CopyVariablesIntoEngine(notification);
return Task.CompletedTask;
}
public Task HandleAsync(EvaluatedJavaScript notification, CancellationToken cancellationToken)
{
if(options.Value.DisableWrappers)
return Task.CompletedTask;
CopyVariablesIntoWorkflowExecutionContext(notification);
return Task.CompletedTask;
}
@ -33,7 +42,7 @@ public class ConfigureEngineWithVariables : INotificationHandler<EvaluatingJavaS
var context = notification.Context;
var engine = notification.Engine;
var variablesContainer = (IDictionary<string, object?>)engine.GetValue("variables").ToObject()!;
var inputNames = GetInputNames(context).Distinct().ToList();
var inputNames = GetInputNames(context).FilterInvalidVariableNames().Distinct().ToList();
foreach (var (variableName, variableValue) in variablesContainer)
{
@ -67,7 +76,7 @@ public class ConfigureEngineWithVariables : INotificationHandler<EvaluatingJavaS
{
var engine = notification.Engine;
var context = notification.Context;
var variableNames = context.GetVariableNamesInScope().ToList();
var variableNames = context.GetVariableNamesInScope().FilterInvalidVariableNames().ToList();
var variablesContainer = (IDictionary<string, object?>)new ExpandoObject();
foreach (var variableName in variableNames)

View file

@ -1,24 +1,31 @@
using Elsa.Expressions.Models;
using Elsa.Extensions;
using Elsa.JavaScript.Extensions;
using Elsa.JavaScript.Helpers;
using Elsa.JavaScript.Notifications;
using Elsa.JavaScript.Options;
using Elsa.Mediator.Contracts;
using Humanizer;
using JetBrains.Annotations;
using Jint;
using Microsoft.Extensions.Options;
namespace Elsa.JavaScript.Handlers;
/// A handler that configures the Jint engine with workflow input and output accessors.
[UsedImplicitly]
public class ConfigureEngineWithVariablesAndInputOutputAccessors : INotificationHandler<EvaluatingJavaScript>
public class ConfigureEngineWithVariablesAndInputOutputAccessors(IOptions<JintOptions> options) : INotificationHandler<EvaluatingJavaScript>
{
/// <inheritdoc />
public async Task HandleAsync(EvaluatingJavaScript notification, CancellationToken cancellationToken)
{
if(options.Value.DisableWrappers)
return;
var engine = notification.Engine;
var context = notification.Context;
// The order of the next 3 lines is important.
// The order of the next 3 lines is important.
CreateVariableAccessors(engine, context);
CreateWorkflowInputAccessors(engine, context);
await CreateActivityOutputAccessorsAsync(engine, context);
@ -26,7 +33,7 @@ public class ConfigureEngineWithVariablesAndInputOutputAccessors : INotification
private void CreateVariableAccessors(Engine engine, ExpressionExecutionContext context)
{
var variableNames = context.GetVariableNamesInScope().ToList();
var variableNames = context.GetVariableNamesInScope().FilterInvalidVariableNames().ToList();
foreach (var variableName in variableNames)
{
@ -43,7 +50,7 @@ public class ConfigureEngineWithVariablesAndInputOutputAccessors : INotification
if (context.IsContainedWithinCompositeActivity())
return;
var inputs = context.GetWorkflowInputs().ToDictionary(x => x.Name);
var inputs = context.GetWorkflowInputs().Where(x => x.Name.IsValidVariableName()).ToDictionary(x => x.Name);
if (!context.TryGetWorkflowExecutionContext(out var workflowExecutionContext))
return;
@ -62,7 +69,7 @@ public class ConfigureEngineWithVariablesAndInputOutputAccessors : INotification
var activityOutputs = context.GetActivityOutputs();
await foreach (var activityOutput in activityOutputs)
foreach (var outputName in activityOutput.OutputNames)
foreach (var outputName in activityOutput.OutputNames.FilterInvalidVariableNames())
engine.SetValue($"get{outputName}From{activityOutput.ActivityName}", (Func<object?>)(() => context.GetOutput(activityOutput.ActivityId, outputName)));
}
}

View file

@ -0,0 +1,9 @@
namespace Elsa.JavaScript.Helpers;
public static class VariableNameValidator
{
public static bool IsValidVariableName(string name)
{
return !string.IsNullOrWhiteSpace(name) && name.All(char.IsLetterOrDigit);
}
}

View file

@ -40,6 +40,12 @@ public class JintOptions
/// If the value of <c>ScriptCacheTimeout</c> is <c>null</c>, the scripts are cached indefinitely. If a time value is specified, the scripts will be recompiled after the specified duration has elapsed.
/// </remarks>
public TimeSpan? ScriptCacheTimeout { get; set; } = TimeSpan.FromDays(1);
/// <summary>
/// Disables the generation of variable wrappers. E.g. <c>getMyVariable()</c> will no longer be available for variables. Instead, you can only access variables using <c>getVariable("MyVariable")</c> function.
/// This is useful if your application requires the use of invalid JavaScript variable names.
/// </summary>
public bool DisableWrappers { get; set; }
/// <summary>
/// Configures the Jint engine options.

View file

@ -1,25 +1,31 @@
using Elsa.Extensions;
using Elsa.JavaScript.Extensions;
using Elsa.JavaScript.Options;
using Elsa.JavaScript.TypeDefinitions.Abstractions;
using Elsa.JavaScript.TypeDefinitions.Models;
using Elsa.Workflows;
using Humanizer;
using JetBrains.Annotations;
using Microsoft.Extensions.Options;
namespace Elsa.JavaScript.TypeDefinitions.Providers;
namespace Elsa.JavaScript.Providers;
/// Produces <see cref="FunctionDefinition"/>s for common functions.
[UsedImplicitly]
internal class ActivityOutputFunctionsDefinitionProvider(IActivityRegistryLookupService activityRegistryLookup) : FunctionDefinitionProvider
internal class ActivityOutputFunctionsDefinitionProvider(IActivityRegistryLookupService activityRegistryLookup, IOptions<JintOptions> options) : FunctionDefinitionProvider
{
protected override async ValueTask<IEnumerable<FunctionDefinition>> GetFunctionDefinitionsAsync(TypeDefinitionContext context)
{
if(options.Value.DisableWrappers)
return [];
var nodes = context.WorkflowGraph.Nodes;
var activitiesWithOutputs = nodes.GetActivitiesWithOutputs(activityRegistryLookup).Where(x => x.activity.Name != null);
var activitiesWithOutputs = nodes.GetActivitiesWithOutputs(activityRegistryLookup).Where(x => x.activity.Name != null && x.activity.Name.IsValidVariableName());
var definitions = new List<FunctionDefinition>();
await foreach (var (activity, activityDescriptor) in activitiesWithOutputs)
{
definitions.AddRange(from output in activityDescriptor.Outputs
definitions.AddRange(from output in activityDescriptor.Outputs.Where(x => x.Name.IsValidVariableName())
select output.Name.Pascalize()
into outputPascalName
let activityNamePascalName = activity.Name.Pascalize()

View file

@ -1,15 +1,18 @@
using Elsa.Extensions;
using Elsa.JavaScript.Contracts;
using Elsa.JavaScript.Extensions;
using Elsa.JavaScript.Options;
using Elsa.JavaScript.TypeDefinitions.Abstractions;
using Elsa.JavaScript.TypeDefinitions.Models;
using Humanizer;
using JetBrains.Annotations;
using Microsoft.Extensions.Options;
namespace Elsa.JavaScript.TypeDefinitions.Providers;
namespace Elsa.JavaScript.Providers;
/// Produces <see cref="FunctionDefinition"/>s for common functions.
[UsedImplicitly]
internal class CommonFunctionsDefinitionProvider(ITypeAliasRegistry typeAliasRegistry) : FunctionDefinitionProvider
internal class CommonFunctionsDefinitionProvider(ITypeAliasRegistry typeAliasRegistry, IOptions<JintOptions> options) : FunctionDefinitionProvider
{
protected override IEnumerable<FunctionDefinition> GetFunctionDefinitions(TypeDefinitionContext context)
{
@ -124,18 +127,21 @@ internal class CommonFunctionsDefinitionProvider(ITypeAliasRegistry typeAliasReg
.Parameter("value", "string")
.ReturnType("string"));
// Variable getter and setters.
foreach (var variable in context.WorkflowGraph.Workflow.Variables)
if (!options.Value.DisableWrappers)
{
var pascalName = variable.Name.Pascalize();
var variableType = variable.GetVariableType();
var typeAlias = typeAliasRegistry.TryGetAlias(variableType, out var alias) ? alias : "any";
// Variable getter and setters.
foreach (var variable in context.WorkflowGraph.Workflow.Variables.Where(x => x.Name.IsValidVariableName()))
{
var pascalName = variable.Name.Pascalize();
var variableType = variable.GetVariableType();
var typeAlias = typeAliasRegistry.TryGetAlias(variableType, out var alias) ? alias : "any";
// get{Variable}.
yield return CreateFunctionDefinition(builder => builder.Name($"get{pascalName}").ReturnType(typeAlias));
// get{Variable}.
yield return CreateFunctionDefinition(builder => builder.Name($"get{pascalName}").ReturnType(typeAlias));
// set{Variable}.
yield return CreateFunctionDefinition(builder => builder.Name($"set{pascalName}").Parameter("value", typeAlias));
// set{Variable}.
yield return CreateFunctionDefinition(builder => builder.Name($"set{pascalName}").Parameter("value", typeAlias));
}
}
}
}

View file

@ -3,7 +3,7 @@ using Elsa.JavaScript.TypeDefinitions.Abstractions;
using Elsa.JavaScript.TypeDefinitions.Contracts;
using Elsa.JavaScript.TypeDefinitions.Models;
namespace Elsa.JavaScript.TypeDefinitions.Providers;
namespace Elsa.JavaScript.Providers;
/// <summary>
/// Produces <see cref="FunctionDefinition"/>s for common functions.

View file

@ -1,18 +1,24 @@
using Elsa.JavaScript.Contracts;
using Elsa.JavaScript.Helpers;
using Elsa.JavaScript.Options;
using Elsa.JavaScript.TypeDefinitions.Abstractions;
using Elsa.JavaScript.TypeDefinitions.Models;
using Elsa.Workflows.Activities;
using Humanizer;
using JetBrains.Annotations;
using Microsoft.Extensions.Options;
namespace Elsa.JavaScript.Providers;
/// Produces <see cref="FunctionDefinition"/>s for common functions.
[UsedImplicitly]
internal class InputFunctionsDefinitionProvider(ITypeAliasRegistry typeAliasRegistry) : FunctionDefinitionProvider
internal class InputFunctionsDefinitionProvider(ITypeAliasRegistry typeAliasRegistry, IOptions<JintOptions> options) : FunctionDefinitionProvider
{
protected override ValueTask<IEnumerable<FunctionDefinition>> GetFunctionDefinitionsAsync(TypeDefinitionContext context)
{
if(options.Value.DisableWrappers)
return ValueTask.FromResult<IEnumerable<FunctionDefinition>>([]);
var workflow = context.WorkflowGraph.Workflow;
return ValueTask.FromResult(GetFunctionDefinitionsAsync(workflow));
}
@ -20,7 +26,7 @@ internal class InputFunctionsDefinitionProvider(ITypeAliasRegistry typeAliasRegi
private IEnumerable<FunctionDefinition> GetFunctionDefinitionsAsync(Workflow workflow)
{
// Input argument getters.
foreach (var input in workflow.Inputs)
foreach (var input in workflow.Inputs.Where(x => VariableNameValidator.IsValidVariableName(x.Name)))
{
var pascalName = input.Name.Pascalize();
var variableType = input.Type;

View file

@ -4,7 +4,7 @@ using Elsa.JavaScript.TypeDefinitions.Abstractions;
using Elsa.JavaScript.TypeDefinitions.Contracts;
using Elsa.JavaScript.TypeDefinitions.Models;
namespace Elsa.JavaScript.TypeDefinitions.Providers;
namespace Elsa.JavaScript.Providers;
/// <summary>
/// Produces <see cref="TypeDefinition"/>s for variable types.

View file

@ -1,15 +1,21 @@
using Elsa.Extensions;
using Elsa.JavaScript.Extensions;
using Elsa.JavaScript.Options;
using Elsa.JavaScript.TypeDefinitions.Abstractions;
using Elsa.JavaScript.TypeDefinitions.Models;
using JetBrains.Annotations;
using Microsoft.Extensions.Options;
namespace Elsa.JavaScript.TypeDefinitions.Providers;
namespace Elsa.JavaScript.Providers;
[UsedImplicitly]
internal class WorkflowVariablesTypeDefinitionProvider : TypeDefinitionProvider
internal class WorkflowVariablesTypeDefinitionProvider(IOptions<JintOptions> options) : TypeDefinitionProvider
{
protected override IEnumerable<TypeDefinition> GetTypeDefinitions(TypeDefinitionContext context)
{
if(options.Value.DisableWrappers)
yield break;
var variables = context.WorkflowGraph.Workflow.Variables;
var workflowTypeDefinition = new TypeDefinition
@ -18,7 +24,7 @@ internal class WorkflowVariablesTypeDefinitionProvider : TypeDefinitionProvider
DeclarationKeyword = "class"
};
foreach (var variable in variables)
foreach (var variable in variables.Where(x => x.Name.IsValidVariableName()))
{
var variableType = variable.GetVariableType();
workflowTypeDefinition.Properties.Add(new PropertyDefinition

View file

@ -1,14 +1,19 @@
using Elsa.JavaScript.Options;
using Elsa.JavaScript.TypeDefinitions.Abstractions;
using Elsa.JavaScript.TypeDefinitions.Models;
using JetBrains.Annotations;
using Microsoft.Extensions.Options;
namespace Elsa.JavaScript.TypeDefinitions.Providers;
namespace Elsa.JavaScript.Providers;
[UsedImplicitly]
internal class WorkflowVariablesVariableProvider : VariableDefinitionProvider
internal class WorkflowVariablesVariableProvider(IOptions<JintOptions> options) : VariableDefinitionProvider
{
protected override IEnumerable<VariableDefinition> GetVariableDefinitions(TypeDefinitionContext context)
{
if(options.Value.DisableWrappers)
yield break;
yield return CreateVariableDefinition(x => x.Name("variables").Type("WorkflowVariables"));
}
}