Skip to content

Commit

Permalink
Merge pull request #85 from delegateas/dev
Browse files Browse the repository at this point in the history
New RELEASE
  • Loading branch information
thygesteffensen authored Aug 23, 2022
2 parents 0e708df + 942eec5 commit c6575df
Show file tree
Hide file tree
Showing 75 changed files with 762 additions and 664 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/.releaserc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ plugins:
- assets:
- path: ../../artifacts/ExpressionEngine.*.nupkg
label: Parser DLL
- path: ../../artifacts/Documentation.md
label: Documentation

- - "@semantic-release/exec"
- publishCmd: "dotnet nuget push ..\\..\\artifacts\\Delegate.ExpressionEngine.*.nupkg --source https://nuget.pkg.github.com/delegateas/index.json --api-key ${process.env.GITHUB_TOKEN}"
Expand Down
9 changes: 2 additions & 7 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,9 @@ jobs:
- name: Archive build to artifacts
uses: actions/[email protected]
with:
name: build
name: Build
path: |
build/netcoreapp3.1/
build/net5.0/
Documentation.md
retention-days: 5

- name: Archive documentation to artifacts
uses: actions/[email protected]
with:
name: Documentation
path: Documentation.md
15 changes: 12 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,28 @@ jobs:

- name: Cleaning
run: dotnet clean
if: ${{ env.RELEASE_VERSION }}

- name: Restore NuGet packages
run: dotnet restore ExpressionEngine.sln
if: ${{ env.RELEASE_VERSION }}

- name: Package Parser
run: dotnet pack -c Release -p:PackageVersion=${env:RELEASE_VERSION} -o ./artifacts
if: ${{ env.RELEASE_VERSION }}

- name: Install Xml to Markdown tool
run: dotnet new tool-manifest && dotnet tool install EAVFW.Extensions.Docs.TransformToMarkdown --version 1.0.0
if: ${{ env.RELEASE_VERSION }}

- name: Generate docs
run: dotnet tool run tomd --input ExpressionEngine/bin/Release/net5.0/ExpressionEngine.xml --output artifacts/Documentation.md
if: ${{ env.RELEASE_VERSION }}

- name: Release to GitHub and NuGet
working-directory: .\\.github\\workflows
env:
CI_NUGET_API_KEY: ${{ secrets.NUGETAPIKEY }}
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
GIT_AUTHOR_NAME: thygesteffensen
GIT_AUTHOR_EMAIL: [email protected]
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-release
if: ${{ env.RELEASE_VERSION }}
33 changes: 25 additions & 8 deletions ExpressionEngine/ExpressionGrammar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ namespace ExpressionEngine
{
public class ExpressionGrammar
{
private readonly IList<IFunctionDefinition> _functionDefinitions;
private readonly Parser<IRule> _method;
private readonly Parser<Task<ValueContainer>> _input;

public ExpressionGrammar(IEnumerable<IFunction> functions)
public ExpressionGrammar(IEnumerable<FunctionMetadata> functions, IEnumerable<IFunctionDefinition> functionDefinitions, IServiceProvider serviceProvider)
{
var functionCollection = functions ?? throw new ArgumentNullException(nameof(functions));
_functionDefinitions = functionDefinitions?.ToList();

var functionCollection = functions.ToList() ?? throw new ArgumentNullException(nameof(functions));

#region BasicAuxParsers

Expand All @@ -28,10 +31,12 @@ public ExpressionGrammar(IEnumerable<IFunction> functions)
constString => new ConstantRule(new ValueContainer(constString, true))
);

Parser<IRule> decimalInvariant =
Parse.DecimalInvariant.Select(x => new ConstantRule(new ValueContainer(x, true)));

Parser<IRule> number = decimalInvariant.Or(integer);
Parser<IRule> number = // decimalInvariant.Or(integer);
from sign in Parse.Char('-').Or(Parse.Char('+')).Optional()
from number1 in Parse.DecimalInvariant.Or(Parse.Digit.AtLeastOnce().Text())
select sign.IsDefined && sign.Get().Equals('-')
? new ConstantRule(new ValueContainer('-' + number1, true))
: new ConstantRule(new ValueContainer(number1, true));

Parser<string> simpleString =
Parse.AnyChar.Except(Parse.Char('@')).AtLeastOnce().Text();
Expand Down Expand Up @@ -87,7 +92,7 @@ from args in argument.Token().DelimitedBy(Parse.Char(',')).Optional()
from mandatoryLetter in Parse.Letter
from rest in Parse.LetterOrDigit.Many().Text()
from args in arguments.Contained(lParenthesis, rParenthesis)
select new ExpressionRule(functionCollection, mandatoryLetter + rest,
select new ExpressionRule(functionCollection, serviceProvider, mandatoryLetter + rest,
args.IsEmpty
? null
: args.Get());
Expand Down Expand Up @@ -122,13 +127,25 @@ from t in simpleString.Or(allowedCharacters).Many()

public async ValueTask<string> EvaluateToString(string input)
{
var output = await _input.Parse(input);
var output = await PreAnalyzeAndParse(input);

return output.GetValue<string>();
}

public async ValueTask<ValueContainer> EvaluateToValueContainer(string input)
{
return await PreAnalyzeAndParse(input);
}

private async ValueTask<ValueContainer> PreAnalyzeAndParse(string input)
{
if (_functionDefinitions != null)
{
input = _functionDefinitions.Aggregate(input,
(current, functionDefinition) =>
current.Replace(functionDefinition.From, functionDefinition.To));
}

return await _input.Parse(input);
}
}
Expand Down
178 changes: 122 additions & 56 deletions ExpressionEngine/FlowRunnerDependencyExtension.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using ExpressionEngine.Functions.Base;
using System;
using ExpressionEngine.Functions.Base;
using ExpressionEngine.Functions.CustomException;
using ExpressionEngine.Functions.Implementations.CollectionFunctions;
using ExpressionEngine.Functions.Implementations.ConversionFunctions;
using ExpressionEngine.Functions.Implementations.LogicalComparisonFunctions;
Expand All @@ -8,8 +10,15 @@

namespace ExpressionEngine
{
/// <summary>
/// Selection of extension methods
/// </summary>
public static class FlowRunnerDependencyExtension
{
/// <summary>
/// Add necessary dependencies inorder to use expression engine.
/// </summary>
/// <param name="services"><see cref="IServiceCollection"/> to add dependencies</param>
public static void AddExpressionEngine(this IServiceCollection services)
{
services.AddScoped<IExpressionEngine, ExpressionEngine>();
Expand All @@ -21,81 +30,138 @@ public static void AddExpressionEngine(this IServiceCollection services)
AddLogicalComparisonFunctions(services);
AddMathFunctions(services);

services.AddTransient<IFunction, LengthFunction>();
services.AddTransient<IFunction, GreaterFunction>();
services.RegisterTransientFunctionAlias<LengthFunction>("length");
services.RegisterTransientFunctionAlias<GreaterFunction>("greater");
}

/// <summary>
/// Register function to be used in expression, function implementation must implement <see cref="IFunction"/>.
/// </summary>
/// <param name="services">Services which to add function metadata</param>
/// <param name="functionName">name of function used to invoke it</param>
/// <typeparam name="T">Function implementation</typeparam>
public static void RegisterTransientFunctionAlias<T>(this IServiceCollection services, string functionName)
where T : class, IFunction
{
services.AddTransient<T>();
services.AddSingleton(new FunctionMetadata(typeof(T), functionName));
}

/// <summary>
/// Register function to be used in expression, function implementation must implement <see cref="IFunction"/>.
/// </summary>
/// <param name="services">Services which to add function metadata</param>
/// <param name="functionName">name of function used to invoke it</param>
/// <typeparam name="T">Function implementation</typeparam>
public static void RegisterScopedFunctionAlias<T>(this IServiceCollection services, string functionName)
where T : class, IFunction
{
services.AddScoped<T>();
services.AddSingleton(new FunctionMetadata(typeof(T), functionName));
}

/// <summary>
/// Register function to be used in expression, function implementation must implement <see cref="IFunction"/>.
/// </summary>
/// <param name="services">Services which to add function metadata</param>
/// <param name="functionName">name of function used to invoke it</param>
/// <param name="implementationFactory"></param>
/// <typeparam name="T">Function implementation</typeparam>
public static void RegisterScopedFunctionAlias<T>(this IServiceCollection services, string functionName,
Func<IServiceProvider, T> implementationFactory)
where T : class, IFunction
{
services.AddScoped(implementationFactory);
services.AddSingleton(new FunctionMetadata(typeof(T), functionName));
}

/// <summary>
/// Added FunctionDefinition to service collection.
/// </summary>
/// <param name="services"></param>
/// <param name="fromFunctionName">The name of the function, without function parenthesis</param>
/// <param name="toExpression">The full expression which is inserted</param>
public static void AddFunctionDefinition(this IServiceCollection services, string fromFunctionName, string toExpression)
{
if (fromFunctionName.EndsWith("()"))
{
throw new ArgumentError($"{nameof(fromFunctionName)} cannot end in ()");
}

services.AddSingleton<IFunctionDefinition>(new FunctionDefinition{From = fromFunctionName + "()", To = toExpression});
}

private static void AddStringFunctions(IServiceCollection services)
{
services.AddTransient<IFunction, ConcatFunction>();
services.AddTransient<IFunction, EndsWithFunction>();
services.AddTransient<IFunction, FormatNumberFunction>();
services.AddTransient<IFunction, GuidFunction>();
services.AddTransient<IFunction, IndexOfFunction>();
services.AddTransient<IFunction, LastIndexOfFunction>();
services.AddTransient<IFunction, LengthFunction>();
services.AddTransient<IFunction, ReplaceFunction>();
services.AddTransient<IFunction, SplitFunction>();
services.AddTransient<IFunction, StartsWithFunction>();
services.AddTransient<IFunction, SubstringFunction>();
services.AddTransient<IFunction, ToLowerFunction>();
services.AddTransient<IFunction, ToUpperFunction>();
services.AddTransient<IFunction, TrimFunction>();
services.RegisterTransientFunctionAlias<ConcatFunction>("concat");
services.RegisterTransientFunctionAlias<EndsWithFunction>("endsWith");
services.RegisterTransientFunctionAlias<FormatNumberFunction>("formatNumber");
services.RegisterTransientFunctionAlias<GuidFunction>("guid");
services.RegisterTransientFunctionAlias<IndexOfFunction>("indexOf");
services.RegisterTransientFunctionAlias<LastIndexOfFunction>("lastIndexOf");
services.RegisterTransientFunctionAlias<LengthFunction>("length");
services.RegisterTransientFunctionAlias<ReplaceFunction>("replace");
services.RegisterTransientFunctionAlias<SplitFunction>("split");
services.RegisterTransientFunctionAlias<StartsWithFunction>("startsWith");
services.RegisterTransientFunctionAlias<SubstringFunction>("substring");
services.RegisterTransientFunctionAlias<ToLowerFunction>("toLower");
services.RegisterTransientFunctionAlias<ToUpperFunction>("toUpper");
services.RegisterTransientFunctionAlias<TrimFunction>("trim");
}

private static void AddCollectionFunction(IServiceCollection services)
{
services.AddTransient<IFunction, ContainsFunction>();
services.AddTransient<IFunction, EmptyFunction>();
services.AddTransient<IFunction, FirstFunction>();
services.AddTransient<IFunction, InterSectionFunction>();
services.AddTransient<IFunction, JoinFunction>();
services.AddTransient<IFunction, LastFunction>();
services.AddTransient<IFunction, LengthFunction>();
services.AddTransient<IFunction, SkipFunction>();
services.AddTransient<IFunction, TakeFunction>();
services.AddTransient<IFunction, UnionFunction>();
services.RegisterTransientFunctionAlias<ContainsFunction>("contains");
services.RegisterTransientFunctionAlias<EmptyFunction>("empty");
services.RegisterTransientFunctionAlias<FirstFunction>("first");
services.RegisterTransientFunctionAlias<InterSectionFunction>("intersection");
services.RegisterTransientFunctionAlias<JoinFunction>("join");
services.RegisterTransientFunctionAlias<LastFunction>("last");
services.RegisterTransientFunctionAlias<LengthFunction>("length");
services.RegisterTransientFunctionAlias<SkipFunction>("skip");
services.RegisterTransientFunctionAlias<TakeFunction>("take");
services.RegisterTransientFunctionAlias<UnionFunction>("union");
}

private static void AddConversionFunction(IServiceCollection services)
{
services.AddTransient<IFunction, ArrayFunction>();
services.AddTransient<IFunction, Base64Function>();
services.AddTransient<IFunction, Base64ToBinaryFunction>();
services.AddTransient<IFunction, Base64ToStringFunction>();
services.AddTransient<IFunction, BinaryFunction>();
services.AddTransient<IFunction, BoolFunction>();
services.AddTransient<IFunction, CreateArrayFunction>();
services.AddTransient<IFunction, DataUriFunction>();
services.AddTransient<IFunction, DataUriToBinaryFunction>();
services.AddTransient<IFunction, FloatFunction>();
services.AddTransient<IFunction, IntFunction>();
services.RegisterTransientFunctionAlias<ArrayFunction>("array");
services.RegisterTransientFunctionAlias<Base64Function>("base64");
services.RegisterTransientFunctionAlias<Base64ToBinaryFunction>("base64ToBinary");
services.RegisterTransientFunctionAlias<Base64ToStringFunction>("base64ToString");
services.RegisterTransientFunctionAlias<BinaryFunction>("binary");
services.RegisterTransientFunctionAlias<BoolFunction>("bool");
services.RegisterTransientFunctionAlias<CreateArrayFunction>("createArray");
services.RegisterTransientFunctionAlias<DataUriFunction>("dataUri");
services.RegisterTransientFunctionAlias<DataUriToBinaryFunction>("dataUriToBinary");
services.RegisterTransientFunctionAlias<FloatFunction>("float");
services.RegisterTransientFunctionAlias<IntFunction>("int");
}

private static void AddLogicalComparisonFunctions(IServiceCollection services)
{
services.AddTransient<IFunction, AndFunction>();
services.AddTransient<IFunction, EqualFunction>();
services.AddTransient<IFunction, GreaterFunction>();
services.AddTransient<IFunction, GreaterOrEqualsFunction>();
services.AddTransient<IFunction, IfFunction>();
services.AddTransient<IFunction, LessFunction>();
services.AddTransient<IFunction, LessOrEqualsFunction>();
services.AddTransient<IFunction, NotFunction>();
services.AddTransient<IFunction, OrFunction>();
services.RegisterTransientFunctionAlias<AndFunction>("and");
services.RegisterTransientFunctionAlias<EqualFunction>("equal");
services.RegisterTransientFunctionAlias<GreaterFunction>("greater");
services.RegisterTransientFunctionAlias<GreaterOrEqualsFunction>("greaterOrEquals");
services.RegisterTransientFunctionAlias<IfFunction>("if");
services.RegisterTransientFunctionAlias<LessFunction>("less");
services.RegisterTransientFunctionAlias<LessOrEqualsFunction>("lessOrEquals");
services.RegisterTransientFunctionAlias<NotFunction>("not");
services.RegisterTransientFunctionAlias<OrFunction>("or");
}

private static void AddMathFunctions(IServiceCollection services)
{
services.AddTransient<IFunction, AddFunction>();
services.AddTransient<IFunction, DivFunction>();
services.AddTransient<IFunction, MaxFunction>();
services.AddTransient<IFunction, MinFunction>();
services.AddTransient<IFunction, ModFunction>();
services.AddTransient<IFunction, MulFunction>();
services.AddTransient<IFunction, RandFunction>();
services.AddTransient<IFunction, RangeFunction>();
services.AddTransient<IFunction, SubFunction>();
services.RegisterTransientFunctionAlias<AddFunction>("add");
services.RegisterTransientFunctionAlias<DivFunction>("div");
services.RegisterTransientFunctionAlias<MaxFunction>("max");
services.RegisterTransientFunctionAlias<MinFunction>("min");
services.RegisterTransientFunctionAlias<ModFunction>("mod");
services.RegisterTransientFunctionAlias<MulFunction>("mul");
services.RegisterTransientFunctionAlias<RandFunction>("rand");
services.RegisterTransientFunctionAlias<RangeFunction>("range");
services.RegisterTransientFunctionAlias<SubFunction>("sub");
}
}
}
18 changes: 18 additions & 0 deletions ExpressionEngine/FunctionDefinition.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace ExpressionEngine
{
/// <summary>
/// A Function Definition is a map to a collected set of functions.
/// - currentCellValue() -> formvalue(logicalName())[idx()][attributeLogicalName()]
/// </summary>
public class FunctionDefinition : IFunctionDefinition
{
/// <summary>
/// The from 'function name' which is replaced
/// </summary>
public string From { get; set; }
/// <summary>
/// The replacement
/// </summary>
public string To { get; set; }
}
}
Loading

0 comments on commit c6575df

Please sign in to comment.