Skip to content

Commit

Permalink
Add visitors support (#650)
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastienros authored May 17, 2024
1 parent bbb64b3 commit ad788d3
Show file tree
Hide file tree
Showing 128 changed files with 1,569 additions and 468 deletions.
34 changes: 34 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[*.cs]

# IDE0022: Use block body for method
csharp_style_expression_bodied_methods = when_on_single_line

# IDE0022: Use expression body for method
dotnet_diagnostic.IDE0022.severity = silent

# IDE0008: Use explicit type
csharp_style_var_for_built_in_types = true

# IDE0008: Use explicit type
csharp_style_var_elsewhere = true

# IDE0008: Use explicit type
csharp_style_var_when_type_is_apparent = true

# IDE0290: Use primary constructor
csharp_style_prefer_primary_constructors = false

# IDE0046: Convert to conditional expression
dotnet_diagnostic.IDE0046.severity = silent

# IDE0305: Simplify collection initialization
dotnet_diagnostic.IDE0305.severity = suggestion

# IDE0028: Simplify collection initialization
dotnet_diagnostic.IDE0028.severity = suggestion

# IDE0090: Use 'new(...)'
dotnet_diagnostic.IDE0090.severity = suggestion

# IDE0045: Convert to conditional expression
dotnet_diagnostic.IDE0045.severity = suggestion
1 change: 0 additions & 1 deletion Fluid.Tests/ArrayFiltersTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using Fluid.Filters;
using Xunit;
using System.Threading.Tasks;
using Fluid.Ast;
using Fluid.Tests.Extensibility;

namespace Fluid.Tests
Expand Down
2 changes: 2 additions & 0 deletions Fluid.Tests/IfStatementTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ public AwaitedExpression(FluidValue result)
_result = result;
}

protected override Expression Accept(AstVisitor visitor) => this;

public override async ValueTask<FluidValue> EvaluateAsync(TemplateContext context)
{
await Task.Delay(10);
Expand Down
77 changes: 77 additions & 0 deletions Fluid.Tests/VisitorTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using Fluid.Tests.Visitors;
using Fluid.Values;
using Xunit;

namespace Fluid.Tests
{
public class VisitorTest
{
[Fact]
public void ShouldReplaceTwos()
{
var template = new FluidParser().Parse("{{ 1 | plus: 2 }}");
var visitor = new ReplaceTwosVisitor(NumberValue.Create(4));
var changed = visitor.VisitTemplate(template);

var result = changed.Render();

Assert.Equal("5", result);
}

[Fact]
public void ShouldSubtract()
{
var template = new FluidParser().Parse("{{ 1 | plus: 2 }}");
var visitor = new ReplacePlusFiltersVisitor();
var changed = visitor.VisitTemplate(template);

var result = changed.Render();

Assert.Equal("-1", result);
}


[Fact]
public void ShouldDoNothing()
{
var template = new FluidParser().Parse("{{ 1 | plus: 2 }}");
var visitor = new RemovePlusFiltersVisitor();
var changed = visitor.VisitTemplate(template);

var result = changed.Render();

Assert.Equal("1", result);
}

[Fact]
public void ShouldDetectForLoopUsage()
{
var template1 = new FluidParser().Parse(@"
{% for page in pages -%}
{%- if forloop.length > 0 -%}
{{ page.title }}{% unless forloop.last %}, {% endunless -%}
{%- endif -%}
{% endfor %}"
);

var template2 = new FluidParser().Parse(@"
{% for page in pages -%}
{%- if pages.length > 0 -%}
{{ page.title }}{% unless pages.last %}, {% endunless -%}
{%- endif -%}
{% endfor %}"
);

var visitor = new IdentifierIsAccessedVisitor("forloop");

visitor.VisitTemplate(template1);
var result1 = visitor.IsAccessed;

visitor.VisitTemplate(template2);
var result2 = visitor.IsAccessed;

Assert.True(result1);
Assert.False(result2);
}
}
}
37 changes: 37 additions & 0 deletions Fluid.Tests/Visitors/PropertyIsAccessedVisitor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Fluid.Ast;
using System.Linq;

namespace Fluid.Tests.Visitors
{
internal class IdentifierIsAccessedVisitor : AstVisitor
{
private readonly string _identifier;

public IdentifierIsAccessedVisitor(string identifier)
{
_identifier = identifier;
}

public bool IsAccessed { get; private set; }

public override IFluidTemplate VisitTemplate(IFluidTemplate template)
{
// Initialize the result each time a template is visited with the same visitor instance

IsAccessed = false;
return base.VisitTemplate(template);
}

protected override Expression VisitMemberExpression(MemberExpression memberExpression)
{
var firstSegment = memberExpression.Segments.FirstOrDefault() as IdentifierSegment;

if (firstSegment != null)
{
IsAccessed |= firstSegment.Identifier == _identifier;
}

return base.VisitMemberExpression(memberExpression);
}
}
}
17 changes: 17 additions & 0 deletions Fluid.Tests/Visitors/RemovePlusFiltersVisitor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Fluid.Ast;

namespace Fluid.Tests.Visitors
{
internal class RemovePlusFiltersVisitor : AstRewriter
{
protected override Expression VisitFilterExpression(FilterExpression filterExpression)
{
if (filterExpression.Name == "plus")
{
return filterExpression.Input;
}

return filterExpression;
}
}
}
17 changes: 17 additions & 0 deletions Fluid.Tests/Visitors/ReplacePlusFiltersVisitor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Fluid.Ast;

namespace Fluid.Tests.Visitors
{
internal class ReplacePlusFiltersVisitor : AstRewriter
{
protected override Expression VisitFilterExpression(FilterExpression filterExpression)
{
if (filterExpression.Name == "plus")
{
return new FilterExpression(filterExpression.Input, "minus", filterExpression.Parameters);
}

return filterExpression;
}
}
}
25 changes: 25 additions & 0 deletions Fluid.Tests/Visitors/ReplaceTwosVisitor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Fluid.Ast;
using Fluid.Values;

namespace Fluid.Tests.Visitors
{
internal class ReplaceTwosVisitor : AstRewriter
{
private readonly FluidValue _replacement;

public ReplaceTwosVisitor(FluidValue replacement)
{
_replacement = replacement;
}

protected override Expression VisitLiteralExpression(LiteralExpression literalExpression)
{
if (literalExpression.Value is NumberValue n && n.ToNumberValue() == 2)
{
return new LiteralExpression(_replacement);
}

return literalExpression;
}
}
}
5 changes: 5 additions & 0 deletions Fluid.sln
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MinimalApis.LiquidViews", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fluid.MinimalApisSample", "Fluid.MinimalApisSample\Fluid.MinimalApisSample.csproj", "{6390F2D4-564B-455E-9C02-3DB998E5BD09}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D1E1DE19-67EF-43C8-BC9A-53E60D65ECFE}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down
5 changes: 1 addition & 4 deletions Fluid/Accessors/AsyncDelegateAccessor.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
using System;
using System.Threading.Tasks;

namespace Fluid.Accessors
namespace Fluid.Accessors
{
public sealed class AsyncDelegateAccessor : AsyncDelegateAccessor<object, object>
{
Expand Down
5 changes: 1 addition & 4 deletions Fluid/Accessors/AsyncDelegateAccessorOfT.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
using System;
using System.Threading.Tasks;

namespace Fluid.Accessors
namespace Fluid.Accessors
{
public class AsyncDelegateAccessor<T, TResult> : IAsyncMemberAccessor
{
Expand Down
4 changes: 1 addition & 3 deletions Fluid/Accessors/DelegateAccessor.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;

namespace Fluid.Accessors
namespace Fluid.Accessors
{
public sealed class DelegateAccessor : DelegateAccessor<object, object>
{
Expand Down
4 changes: 1 addition & 3 deletions Fluid/Accessors/DelegateAccessorOfT.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;

namespace Fluid.Accessors
namespace Fluid.Accessors
{
public class DelegateAccessor<T, TResult> : IMemberAccessor
{
Expand Down
3 changes: 1 addition & 2 deletions Fluid/Accessors/PropertyInfoAccessor.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Reflection;
using System.Reflection;

namespace Fluid.Accessors
{
Expand Down
6 changes: 3 additions & 3 deletions Fluid/Ast/AssignStatement.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System.IO;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using System.Text.Encodings.Web;
using Fluid.Values;

namespace Fluid.Ast
Expand Down Expand Up @@ -37,5 +35,7 @@ static async ValueTask<Completion> Awaited(ValueTask<FluidValue> task, TemplateC
context.SetValue(Identifier, task.Result);
return new ValueTask<Completion>(Completion.Normal);
}

protected internal override Statement Accept(AstVisitor visitor) => visitor.VisitAssignStatement(this);
}
}
Loading

0 comments on commit ad788d3

Please sign in to comment.