Repository: Seddryck/Didot
Pull request #150: feat: support of mapping values provided in the model to other values
Author: login: Seddryck
Labels: name: new-feature
Created: 2025-03-16T14:32:16Z | Merged: 2025-03-16T15:36:40Z



<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Enhanced template rendering across multiple engines by introducing dynamic mapping support, enabling users to inject custom key-value pairs during rendering.
  - Updated rendering methods now incorporate additional dynamic content based on provided mappings for more flexible template customization.

- **Tests**
  - Expanded test coverage to validate that templates render correctly when utilizing dictionary-based models and mappings.
  - Added specific tests for `DotLiquidWrapper`, `FluidWrapper`, `HandlebarsWrapper`, `StringTemplateWrapper`, verifying successful rendering with dynamic mappings.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/src/Didot.Core/BaseFactory.cs b/src/Didot.Core/BaseFactory.cs
index cb1adb0..edbad70 100644
--- a/src/Didot.Core/BaseFactory.cs
+++ b/src/Didot.Core/BaseFactory.cs
@@ -3,7 +3,6 @@
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
-using Didot.Core.SourceParsers;
 
 namespace Didot.Core;
 public abstract class BaseFactory<T>
diff --git a/src/Didot.Core/ITemplateEngine.cs b/src/Didot.Core/ITemplateEngine.cs
index f6d4a7d..a35e31c 100644
--- a/src/Didot.Core/ITemplateEngine.cs
+++ b/src/Didot.Core/ITemplateEngine.cs
@@ -7,6 +7,7 @@
 namespace Didot.Core;
 public interface ITemplateEngine
 {
+    void AddMappings(string mapKey, IDictionary<string, object> mappings);
     string Render(string template, object model);
     string Render(Stream template, object model);
 }
diff --git a/src/Didot.Core/TemplateEngines/DotLiquidWrapper.cs b/src/Didot.Core/TemplateEngines/DotLiquidWrapper.cs
index 0bc2b48..663e872 100644
--- a/src/Didot.Core/TemplateEngines/DotLiquidWrapper.cs
+++ b/src/Didot.Core/TemplateEngines/DotLiquidWrapper.cs
@@ -9,10 +9,22 @@
 namespace Didot.Core.TemplateEngines;
 public class DotLiquidWrapper : ITemplateEngine
 {
-    public string Render(string template, object model)
+    private Dictionary<string, IDictionary<string, object>> Mappers { get; } = [];
+
+    public void AddMappings(string mapKey, IDictionary<string, object> mappings)
+    {
+        if (!Mappers.TryAdd(mapKey, mappings))
+            Mappers[mapKey] = mappings;
+    }
+
+    public string Render(string source, object model)
     {
-        var templateInstance = Template.Parse(template);
+        var templateInstance = Template.Parse(source);
         var hash = Hash.FromAnonymousObject(model);
+
+        foreach (var (dictName, dictValues) in Mappers)
+            hash[dictName] = dictValues;
+
         return templateInstance.Render(hash);
     }
 
diff --git a/src/Didot.Core/TemplateEngines/FluidWrapper.cs b/src/Didot.Core/TemplateEngines/FluidWrapper.cs
index b5b9e0e..c890e1e 100644
--- a/src/Didot.Core/TemplateEngines/FluidWrapper.cs
+++ b/src/Didot.Core/TemplateEngines/FluidWrapper.cs
@@ -4,6 +4,7 @@
 using System.Text;
 using System.Threading.Tasks;
 using Fluid;
+using Fluid.Values;
 using SmartFormat.Core.Extensions;
 
 namespace Didot.Core.TemplateEngines;
@@ -11,10 +12,33 @@ public class FluidWrapper : ITemplateEngine
 {
     private static readonly FluidParser Parser = new();
 
+    private Dictionary<string, IDictionary<string, object>> Mappers { get; } = [];
+
+    public void AddMappings(string mapKey, IDictionary<string, object> mappings)
+    {
+        if (!Mappers.TryAdd(mapKey, mappings))
+            Mappers[mapKey] = mappings;
+    }
+
+
     public string Render(string source, object model)
     {
         var template = Parser.Parse(source);
         var context = new TemplateContext(model);
+
+        // Register Mappers as Fluid filters
+        foreach (var (dictName, dictValues) in Mappers)
+        {
+            context.Options.Filters.AddFilter(dictName, (input, arguments, ctx) =>
+            {
+                if (input is StringValue keyStr && dictValues.TryGetValue(keyStr.ToStringValue(), out var value))
+                {
+                    return new StringValue(value?.ToString() ?? string.Empty);
+                }
+                return NilValue.Instance;
+            });
+        }
+
         return template.Render(context);
     }
 
diff --git a/src/Didot.Core/TemplateEngines/HandlebarsWrapper.cs b/src/Didot.Core/TemplateEngines/HandlebarsWrapper.cs
index 7093940..e615f71 100644
--- a/src/Didot.Core/TemplateEngines/HandlebarsWrapper.cs
+++ b/src/Didot.Core/TemplateEngines/HandlebarsWrapper.cs
@@ -6,11 +6,18 @@
 using System.Threading.Tasks;
 using HandlebarsDotNet;
 using HandlebarsDotNet.Helpers;
-using HandlebarsDotNet.Helpers.Enums;
 
 namespace Didot.Core.TemplateEngines;
 public class HandlebarsWrapper : ITemplateEngine
 {
+    private Dictionary<string, IDictionary<string, object>> Mappers { get; } = [];
+
+    public void AddMappings(string mapKey, IDictionary<string, object> mappings)
+    {
+        if (!Mappers.TryAdd(mapKey, mappings))
+            Mappers[mapKey] = mappings;
+    }
+
     public string Render(string template, object model)
     {
         var handlebarsContext = CreateContext();
@@ -34,6 +41,18 @@ private IHandlebars CreateContext()
     {
         var handlebarsContext = Handlebars.Create();
         HandlebarsHelpers.Register(handlebarsContext);
+
+        foreach (var (dictName, dictValues) in Mappers)
+        {
+            handlebarsContext.RegisterHelper(dictName, (output, context, args) =>
+            {
+                if (args.Length == 1 && args[0] is string key && dictValues.TryGetValue(key, out var value))
+                {
+                    output.Write(value.ToString());
+                }
+            });
+        }
+
         return handlebarsContext;
     }
 }
diff --git a/src/Didot.Core/TemplateEngines/MorestachioWrapper.cs b/src/Didot.Core/TemplateEngines/MorestachioWrapper.cs
index 50a1bc7..db3cfd8 100644
--- a/src/Didot.Core/TemplateEngines/MorestachioWrapper.cs
+++ b/src/Didot.Core/TemplateEngines/MorestachioWrapper.cs
@@ -10,6 +10,11 @@
 namespace Didot.Core.TemplateEngines;
 public class MorestachioWrapper : ITemplateEngine
 {
+    private Dictionary<string, IDictionary<string, object>> Mappers { get; } = [];
+
+    public void AddMappings(string mapKey, IDictionary<string, object> mappings)
+        => throw new NotImplementedException();
+
     public string Render(string template, object model)
     {
         if (string.IsNullOrWhiteSpace(template))
diff --git a/src/Didot.Core/TemplateEngines/ScribanWrapper.cs b/src/Didot.Core/TemplateEngines/ScribanWrapper.cs
index c55c154..efbb0d3 100644
--- a/src/Didot.Core/TemplateEngines/ScribanWrapper.cs
+++ b/src/Didot.Core/TemplateEngines/ScribanWrapper.cs
@@ -9,6 +9,11 @@
 namespace Didot.Core.TemplateEngines;
 public class ScribanWrapper : ITemplateEngine
 {
+    private Dictionary<string, IDictionary<string, object>> Mappers { get; } = [];
+
+    public void AddMappings(string mapKey, IDictionary<string, object> mappings)
+        => throw new NotImplementedException();
+
     public string Render(string template, object model)
     {
         var templateInstance = Template.Parse(template);
diff --git a/src/Didot.Core/TemplateEngines/SmartFormatWrapper.cs b/src/Didot.Core/TemplateEngines/SmartFormatWrapper.cs
index 8e16360..8d5f79a 100644
--- a/src/Didot.Core/TemplateEngines/SmartFormatWrapper.cs
+++ b/src/Didot.Core/TemplateEngines/SmartFormatWrapper.cs
@@ -9,6 +9,11 @@
 namespace Didot.Core.TemplateEngines;
 public class SmartFormatWrapper : ITemplateEngine
 {
+    private Dictionary<string, IDictionary<string, object>> Mappers { get; } = [];
+
+    public void AddMappings(string mapKey, IDictionary<string, object> mappings)
+        => throw new NotImplementedException();
+
     public string Render(string template, object model)
         => Smart.Format(template, model);
 
diff --git a/src/Didot.Core/TemplateEngines/StringTemplateWrapper.cs b/src/Didot.Core/TemplateEngines/StringTemplateWrapper.cs
index 49af85a..028fff9 100644
--- a/src/Didot.Core/TemplateEngines/StringTemplateWrapper.cs
+++ b/src/Didot.Core/TemplateEngines/StringTemplateWrapper.cs
@@ -9,11 +9,21 @@
 namespace Didot.Core.TemplateEngines;
 public class StringTemplateWrapper : ITemplateEngine
 {
-    public string Render(string template, object model)
+    private Dictionary<string, IDictionary<string, object>> Mappers { get; } = [];
+
+    public void AddMappings(string mapKey, IDictionary<string, object> mappings)
     {
+        if (!Mappers.TryAdd(mapKey, mappings))
+            Mappers[mapKey] = mappings;
+    }
+
+    public string Render(string template, object model)
+    { 
         var templateInstance = new Template(template);
-        var dict = model.GetType().GetProperty("model")!.GetValue(model);
-        templateInstance.Add("model", dict);
+        var extractedModel = model.GetType().GetProperty("model")?.GetValue(model) ?? model;
+        templateInstance.Add("model", extractedModel);
+        foreach (var (key, value) in Mappers)
+            templateInstance.Group.DefineDictionary(key, value);
         return templateInstance.Render();
     }
 
diff --git a/testing/Didot.Core.Testing/TemplateEngines/DotLiquidWrapperTests.cs b/testing/Didot.Core.Testing/TemplateEngines/DotLiquidWrapperTests.cs
index 8648a92..108a733 100644
--- a/testing/Didot.Core.Testing/TemplateEngines/DotLiquidWrapperTests.cs
+++ b/testing/Didot.Core.Testing/TemplateEngines/DotLiquidWrapperTests.cs
@@ -81,4 +81,18 @@ public void Render_Stream_Successful()
         var result = engine.Render(stream, new { model });
         Assert.That(result, Is.EqualTo("Hello World"));
     }
+
+    [Test]
+    public virtual void Render_Dictionary_Successful()
+    {
+        var engine = GetEngine();
+        var model = new Dictionary<string, object>()
+            { { "Name", "Alice"}, {"Lang", "fr" } };
+        var dict = new Dictionary<string, object>()
+            { { "fr", "Bonjour"}, {"en", "Hello" }, {"es", "Hola"} };
+        engine.AddMappings("greetings", dict);
+        using var stream = new MemoryStream(Encoding.UTF8.GetBytes("Greetings: {{ greetings[model.Lang] }} {{ model.Name }}"));
+        var result = engine.Render(stream, new { model });
+        Assert.That(result, Is.EqualTo("Greetings: Bonjour Alice"));
+    }
 }
diff --git a/testing/Didot.Core.Testing/TemplateEngines/FluidWrapperTests.cs b/testing/Didot.Core.Testing/TemplateEngines/FluidWrapperTests.cs
index c968907..341c07c 100644
--- a/testing/Didot.Core.Testing/TemplateEngines/FluidWrapperTests.cs
+++ b/testing/Didot.Core.Testing/TemplateEngines/FluidWrapperTests.cs
@@ -12,4 +12,18 @@ public class FluidWrapperTests : DotLiquidWrapperTests
 {
     protected override ITemplateEngine GetEngine()
         => new FluidWrapper();
+
+    [Test]
+    public override void Render_Dictionary_Successful()
+    {
+        var engine = GetEngine();
+        var model = new Dictionary<string, object>()
+            { { "Name", "Alice"}, {"Lang", "fr" } };
+        var dict = new Dictionary<string, object>()
+            { { "fr", "Bonjour"}, {"en", "Hello" }, {"es", "Hola"} };
+        engine.AddMappings("greetings", dict);
+        using var stream = new MemoryStream(Encoding.UTF8.GetBytes("Greetings: {{ model.Lang | greetings }} {{ model.Name }}"));
+        var result = engine.Render(stream, new { model });
+        Assert.That(result, Is.EqualTo("Greetings: Bonjour Alice"));
+    }
 }
diff --git a/testing/Didot.Core.Testing/TemplateEngines/HandlebarsWrapperTests.cs b/testing/Didot.Core.Testing/TemplateEngines/HandlebarsWrapperTests.cs
index ad74f91..001d22e 100644
--- a/testing/Didot.Core.Testing/TemplateEngines/HandlebarsWrapperTests.cs
+++ b/testing/Didot.Core.Testing/TemplateEngines/HandlebarsWrapperTests.cs
@@ -78,4 +78,18 @@ public void Render_Stream_Successful()
         var result = engine.Render(stream, new { model });
         Assert.That(result, Is.EqualTo("Hello World"));
     }
+
+    [Test]
+    public void Render_Dictionary_Successful()
+    {
+        var engine = new HandlebarsWrapper();
+        var model = new Dictionary<string, object>()
+            { { "Name", "Alice"}, {"Lang", "fr" } };
+        var dict = new Dictionary<string, object>()
+            { { "fr", "Bonjour"}, {"en", "Hello" }, {"es", "Hola"} };
+        engine.AddMappings("greetings", dict);
+        using var stream = new MemoryStream(Encoding.UTF8.GetBytes("Greetings: {{greetings model.Lang}} {{model.Name}}"));
+        var result = engine.Render(stream, new { model });
+        Assert.That(result, Is.EqualTo("Greetings: Bonjour Alice"));
+    }
 }
diff --git a/testing/Didot.Core.Testing/TemplateEngines/StringTemplateWrapperTests.cs b/testing/Didot.Core.Testing/TemplateEngines/StringTemplateWrapperTests.cs
index 5c881bf..742a640 100644
--- a/testing/Didot.Core.Testing/TemplateEngines/StringTemplateWrapperTests.cs
+++ b/testing/Didot.Core.Testing/TemplateEngines/StringTemplateWrapperTests.cs
@@ -79,4 +79,18 @@ public void Render_Stream_Successful()
         var result = engine.Render(stream, new { model });
         Assert.That(result, Is.EqualTo("Hello World"));
     }
+
+    [Test]
+    public void Render_Dictionary_Successful()
+    {
+        var engine = new StringTemplateWrapper();
+        var model = new Dictionary<string, object>()
+            { { "Name", "Alice"}, {"Lang", "fr" } };
+        var dict = new Dictionary<string, object>()
+            { { "fr", "Bonjour"}, {"en", "Hello" }, {"es", "Hola"} };
+        engine.AddMappings("greetings", dict);
+        using var stream = new MemoryStream(Encoding.UTF8.GetBytes("Greetings: <greetings.(model.Lang)> <model.Name>"));
+        var result = engine.Render(stream, new { model });
+        Assert.That(result, Is.EqualTo("Greetings: Bonjour Alice"));
+    }
 }


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 3**

<details>
<summary>🧹 Nitpick comments (2)</summary><blockquote>

<details>
<summary>src/Didot.Core/TemplateEngines/DotLiquidWrapper.cs (1)</summary><blockquote>

`25-33`: **Consider translating the French comment and remove unnecessary null check.**

The null check on line 26 is unnecessary since `Mappers` is initialized with an empty dictionary and can never be null.


```diff
- // Ajouter les dictionnaires comme variables accessibles
- if (Mappers != null)
- {
-     foreach (var (dictName, dictValues) in Mappers)
-     {
-         hash[dictName] = dictValues;
-     }
- }
+ // Add dictionaries as accessible variables
+ foreach (var (dictName, dictValues) in Mappers)
+ {
+     hash[dictName] = dictValues;
+ }
```

</blockquote></details>
<details>
<summary>src/Didot.Core/TemplateEngines/StringTemplateWrapper.cs (1)</summary><blockquote>

`20-27`: **Remove unnecessary null check on Mappers.**

The null check (`Mappers ?? new Dictionary<>()`) is unnecessary since `Mappers` is initialized with an empty dictionary and can never be null.


```diff
- foreach (var (key, value) in Mappers ?? new Dictionary<string, IDictionary<string, object>>())
+ foreach (var (key, value) in Mappers)
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 55d321b19abffcd11ba28884ceb1bc84fd432bf5 and 8452d6699d5e0e6b8e7a2d6036973d72baf0a454.

</details>

<details>
<summary>📒 Files selected for processing (13)</summary>

* `src/Didot.Core/BaseFactory.cs` (0 hunks)
* `src/Didot.Core/ITemplateEngine.cs` (1 hunks)
* `src/Didot.Core/TemplateEngines/DotLiquidWrapper.cs` (1 hunks)
* `src/Didot.Core/TemplateEngines/FluidWrapper.cs` (1 hunks)
* `src/Didot.Core/TemplateEngines/HandlebarsWrapper.cs` (2 hunks)
* `src/Didot.Core/TemplateEngines/MorestachioWrapper.cs` (1 hunks)
* `src/Didot.Core/TemplateEngines/ScribanWrapper.cs` (1 hunks)
* `src/Didot.Core/TemplateEngines/SmartFormatWrapper.cs` (1 hunks)
* `src/Didot.Core/TemplateEngines/StringTemplateWrapper.cs` (1 hunks)
* `testing/Didot.Core.Testing/TemplateEngines/DotLiquidWrapperTests.cs` (1 hunks)
* `testing/Didot.Core.Testing/TemplateEngines/FluidWrapperTests.cs` (1 hunks)
* `testing/Didot.Core.Testing/TemplateEngines/HandlebarsWrapperTests.cs` (1 hunks)
* `testing/Didot.Core.Testing/TemplateEngines/StringTemplateWrapperTests.cs` (1 hunks)

</details>

<details>
<summary>💤 Files with no reviewable changes (1)</summary>

* src/Didot.Core/BaseFactory.cs

</details>

<details>
<summary>🔇 Additional comments (17)</summary><blockquote>

<details>
<summary>src/Didot.Core/ITemplateEngine.cs (1)</summary>

`10-10`: **Well-designed interface addition for mapping support.**

The new `AddMappings` method provides a clear and consistent way for template engines to support value mapping, which aligns perfectly with the PR objective.

</details>
<details>
<summary>testing/Didot.Core.Testing/TemplateEngines/DotLiquidWrapperTests.cs (1)</summary>

`85-97`: **Great test implementation for the new mapping functionality.**

This test thoroughly validates the new mapping feature with a practical multilingual greeting example. It clearly demonstrates how to use the `AddMappings` method and how mapped values can be accessed in templates.

</details>
<details>
<summary>testing/Didot.Core.Testing/TemplateEngines/StringTemplateWrapperTests.cs (1)</summary>

`83-95`: **Nice test implementation for the new mapping feature!**

This test effectively validates that the new mapping feature works correctly with the StringTemplateWrapper. It creates a model with a language code, adds a dictionary mapping language codes to greetings, and then verifies that the template correctly resolves the appropriate greeting based on the language in the model.

</details>
<details>
<summary>testing/Didot.Core.Testing/TemplateEngines/FluidWrapperTests.cs (1)</summary>

`16-28`: **Well-structured test for the new mapping feature**

This test correctly verifies that the Fluid template engine can process mappings added via the AddMappings method. The test pattern is consistent with other template engine tests, ensuring uniform validation across all implementations.

</details>
<details>
<summary>src/Didot.Core/TemplateEngines/FluidWrapper.cs (3)</summary>

`7-7`: **Good import addition for the new feature**

The addition of the Fluid.Values namespace is necessary for handling StringValue and NilValue types in the mapping implementation.

---

`15-21`: **Well-implemented mapping storage functionality**

The implementation for storing mappings is clean and handles the case where a mapping with the same key already exists by updating it.

---

`29-40`: **Good implementation of mapping resolution as Fluid filters**

The implementation correctly registers each mapping dictionary as a Fluid filter. The filter logic properly handles:
1. Checking if the input is a StringValue
2. Looking up the corresponding value in the mapping dictionary
3. Returning either the found value or NilValue.Instance if not found

This allows templates to use the syntax demonstrated in the test: `{{ model.Lang | greetings }}`.

</details>
<details>
<summary>testing/Didot.Core.Testing/TemplateEngines/HandlebarsWrapperTests.cs (1)</summary>

`82-94`: **LGTM: Test coverage for mapping functionality.**

The test case effectively verifies the new mapping functionality by creating a model with language code, registering a dictionary for greetings mappings, and confirming the correct greeting is rendered based on the model's language value.

</details>
<details>
<summary>src/Didot.Core/TemplateEngines/DotLiquidWrapper.cs (3)</summary>

`12-12`: **LGTM: Collection initialization syntax.**

Good use of the collection expression syntax for initializing the empty dictionary.

---

`14-18`: **LGTM: Mapping registration logic.**

The implementation correctly handles both adding new mappings and updating existing ones.

---

`20-23`: **Parameter name change is appropriate.**

Renaming from `template` to `source` better describes what the parameter represents.

</details>
<details>
<summary>src/Didot.Core/TemplateEngines/HandlebarsWrapper.cs (3)</summary>

`13-13`: **LGTM: Collection initialization syntax.**

Good use of the collection expression syntax for initializing the empty dictionary.

---

`15-19`: **LGTM: Mapping registration logic.**

The implementation correctly handles both adding new mappings and updating existing ones.

---

`45-55`: **LGTM: Mapping implementation in Handlebars context.**

The implementation properly registers helper functions that can access mapping values by key. The error handling for non-existent keys is also appropriate.

</details>
<details>
<summary>src/Didot.Core/TemplateEngines/StringTemplateWrapper.cs (3)</summary>

`12-12`: **LGTM: Collection initialization syntax.**

Good use of the collection expression syntax for initializing the empty dictionary.

---

`14-18`: **LGTM: Mapping registration logic.**

The implementation correctly handles both adding new mappings and updating existing ones.

---

`23-24`: **LGTM: Improved model extraction.**

The updated model extraction provides more flexibility by using the null-coalescing operator to fall back to the provided model object when the "model" property doesn't exist.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-16T14:34:26Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 3**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>src/Didot.Core/TemplateEngines/StringTemplateWrapper.cs (1)</summary><blockquote>

`14-18`: **Consider adding XML documentation**

The `AddMappings` method would benefit from XML documentation to explain its purpose and parameter usage, especially since this is implementing a new interface method.


```diff
+    /// <summary>
+    /// Adds or replaces a set of mappings associated with the specified key.
+    /// </summary>
+    /// <param name="mapKey">The key identifying this mapping set</param>
+    /// <param name="mappings">Dictionary of mappings to be used in templates</param>
     public void AddMappings(string mapKey, IDictionary<string, object> mappings)
     {
         if (!Mappers.TryAdd(mapKey, mappings))
             Mappers[mapKey] = mappings;
     }
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 8452d6699d5e0e6b8e7a2d6036973d72baf0a454 and 482d8465731562e5bc9753ae7dda403963c7ed33.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `src/Didot.Core/TemplateEngines/DotLiquidWrapper.cs` (1 hunks)
* `src/Didot.Core/TemplateEngines/StringTemplateWrapper.cs` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* src/Didot.Core/TemplateEngines/DotLiquidWrapper.cs

</details>

<details>
<summary>🔇 Additional comments (1)</summary><blockquote>

<details>
<summary>src/Didot.Core/TemplateEngines/StringTemplateWrapper.cs (1)</summary>

`12-12`: **Dictionary initialization looks good**

The use of the new collection initialization syntax `[]` for creating an empty dictionary is clean and modern.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-16T14:41:42Z

Review comments:
diff_hunk: @@ -9,6 +9,11 @@
 namespace Didot.Core.TemplateEngines;
 public class ScribanWrapper : ITemplateEngine
 {
+    private Dictionary<string, IDictionary<string, object>> Mappers { get; } = [];
+
+    public void AddMappings(string mapKey, IDictionary<string, object> mappings)
+        => throw new NotImplementedException();
path: src/Didot.Core/TemplateEngines/ScribanWrapper.cs
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Incomplete implementation of mapping functionality.**

While the `Mappers` property is defined correctly, the `AddMappings` method only throws `NotImplementedException` and the `Render` methods don't use the mappings. This could lead to confusing runtime errors for API consumers.

Consider either:
1. Completing the implementation for ScribanWrapper, or
2. Adding a more descriptive exception message: `throw new NotImplementedException("Mapping support for Scriban templates is not yet implemented.");`

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-16T14:34:26Z
author_association: NONE
diff_hunk: @@ -9,6 +9,11 @@
 namespace Didot.Core.TemplateEngines;
 public class SmartFormatWrapper : ITemplateEngine
 {
+    private Dictionary<string, IDictionary<string, object>> Mappers { get; } = [];
+
+    public void AddMappings(string mapKey, IDictionary<string, object> mappings)
+        => throw new NotImplementedException();
path: src/Didot.Core/TemplateEngines/SmartFormatWrapper.cs
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Incomplete implementation with potential for shared code.**

Similar to ScribanWrapper, this implementation only provides a stub that throws `NotImplementedException`. Consider adding a more descriptive message: `throw new NotImplementedException("Mapping support for SmartFormat templates is not yet implemented.");`

Additionally, since multiple template engines seem to be following the same implementation pattern, consider if there's an opportunity to reduce duplication through:
1. A base abstract class that implements common functionality
2. An extension method for the mapping logic, or
3. A helper class that can be reused across multiple wrapper implementations

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-16T14:34:26Z
author_association: NONE
diff_hunk: @@ -10,6 +10,11 @@
 namespace Didot.Core.TemplateEngines;
 public class MorestachioWrapper : ITemplateEngine
 {
+    private Dictionary<string, IDictionary<string, object>> Mappers { get; } = [];
+
+    public void AddMappings(string mapKey, IDictionary<string, object> mappings)
+        => throw new NotImplementedException();
path: src/Didot.Core/TemplateEngines/MorestachioWrapper.cs
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Implementation needed for AddMappings method**

The method is currently throwing a NotImplementedException. This should be implemented to maintain consistency with other template engine wrappers that are supporting this new mapping feature.


Consider implementing the method based on the pattern used in other wrappers like FluidWrapper:

```diff
private Dictionary<string, IDictionary<string, object>> Mappers { get; } = [];

public void AddMappings(string mapKey, IDictionary<string, object> mappings)
-    => throw new NotImplementedException();
+{
+    if (!Mappers.TryAdd(mapKey, mappings))
+        Mappers[mapKey] = mappings;
+}
```

The Render method would also need to be updated to utilize these mappings during template processing.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    private Dictionary<string, IDictionary<string, object>> Mappers { get; } = [];

    public void AddMappings(string mapKey, IDictionary<string, object> mappings)
    {
        if (!Mappers.TryAdd(mapKey, mappings))
            Mappers[mapKey] = mappings;
    }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-16T14:34:26Z
author_association: NONE
diff_hunk: @@ -9,11 +9,21 @@
 namespace Didot.Core.TemplateEngines;
 public class StringTemplateWrapper : ITemplateEngine
 {
-    public string Render(string template, object model)
+    private Dictionary<string, IDictionary<string, object>> Mappers { get; } = [];
+
+    public void AddMappings(string mapKey, IDictionary<string, object> mappings)
     {
+        if (!Mappers.TryAdd(mapKey, mappings))
+            Mappers[mapKey] = mappings;
+    }
+
+    public string Render(string template, object model)
+    { 
         var templateInstance = new Template(template);
-        var dict = model.GetType().GetProperty("model")!.GetValue(model);
-        templateInstance.Add("model", dict);
+        var extractedModel = model.GetType().GetProperty("model")?.GetValue(model) ?? model;
+        templateInstance.Add("model", extractedModel);
path: src/Didot.Core/TemplateEngines/StringTemplateWrapper.cs
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Error handling needed for reflection operations**

Reflection operations can throw exceptions (like if the property exists but is not accessible). Consider adding try-catch block to handle potential reflection errors gracefully.


```diff
-        var extractedModel = model.GetType().GetProperty("model")?.GetValue(model) ?? model;
-        templateInstance.Add("model", extractedModel);
+        object extractedModel;
+        try {
+            extractedModel = model.GetType().GetProperty("model")?.GetValue(model) ?? model;
+        } catch (Exception) {
+            // Fallback to original model if reflection fails
+            extractedModel = model;
+        }
+        templateInstance.Add("model", extractedModel);
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
        object extractedModel;
        try {
            extractedModel = model.GetType().GetProperty("model")?.GetValue(model) ?? model;
        } catch (Exception) {
            // Fallback to original model if reflection fails
            extractedModel = model;
        }
        templateInstance.Add("model", extractedModel);
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-16T14:41:42Z
author_association: NONE
diff_hunk: @@ -9,11 +9,21 @@
 namespace Didot.Core.TemplateEngines;
 public class StringTemplateWrapper : ITemplateEngine
 {
-    public string Render(string template, object model)
+    private Dictionary<string, IDictionary<string, object>> Mappers { get; } = [];
+
+    public void AddMappings(string mapKey, IDictionary<string, object> mappings)
     {
+        if (!Mappers.TryAdd(mapKey, mappings))
+            Mappers[mapKey] = mappings;
+    }
+
+    public string Render(string template, object model)
+    { 
         var templateInstance = new Template(template);
-        var dict = model.GetType().GetProperty("model")!.GetValue(model);
-        templateInstance.Add("model", dict);
+        var extractedModel = model.GetType().GetProperty("model")?.GetValue(model) ?? model;
+        templateInstance.Add("model", extractedModel);
+        foreach (var (key, value) in Mappers)
+            templateInstance.Group.DefineDictionary(key, value);
path: src/Didot.Core/TemplateEngines/StringTemplateWrapper.cs
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Potential for more comprehensive test coverage**

The PR comments indicate this file has 50% coverage with 1 missing and 3 partial lines. Consider adding tests that verify the mapping functionality works with edge cases (empty mappings, null values, etc.).

---

🏁 Script executed:

```shell
#!/bin/bash
# Find existing tests for StringTemplateWrapper
echo "Looking for existing tests for StringTemplateWrapper..."
rg -l "StringTemplateWrapper" --glob "**/*Test*.cs"
```

Length of output: 327

---



</details>

**Enhance Mapping Edge-Case Test Coverage**

While tests exist for `StringTemplateWrapper` (see `testing/Didot.Core.Testing/TemplateEngines/StringTemplateWrapperTests.cs`), coverage remains around 50% with some lines partially verified. Specifically, the mapping logic:

```csharp
foreach (var (key, value) in Mappers)
    templateInstance.Group.DefineDictionary(key, value);
```

would benefit from tests that exercise key edge cases. Please consider extending the tests to cover scenarios including:

- An empty `Mappers` collection.
- Mappings containing `null` values.
- Any other boundary conditions that might impact the expected behavior.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-16T14:41:42Z
author_association: NONE
diff_hunk: @@ -9,11 +9,21 @@
 namespace Didot.Core.TemplateEngines;
 public class StringTemplateWrapper : ITemplateEngine
 {
-    public string Render(string template, object model)
+    private Dictionary<string, IDictionary<string, object>> Mappers { get; } = [];
+
+    public void AddMappings(string mapKey, IDictionary<string, object> mappings)
     {
+        if (!Mappers.TryAdd(mapKey, mappings))
+            Mappers[mapKey] = mappings;
+    }
+
+    public string Render(string template, object model)
+    { 
         var templateInstance = new Template(template);
-        var dict = model.GetType().GetProperty("model")!.GetValue(model);
-        templateInstance.Add("model", dict);
+        var extractedModel = model.GetType().GetProperty("model")?.GetValue(model) ?? model;
+        templateInstance.Add("model", extractedModel);
+        foreach (var (key, value) in Mappers)
+            templateInstance.Group.DefineDictionary(key, value);
         return templateInstance.Render();
path: src/Didot.Core/TemplateEngines/StringTemplateWrapper.cs
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Add null check for model parameter**

The reflection operation on line 23 would throw a NullReferenceException if `model` is null. Consider adding a null check to handle this scenario gracefully.


```diff
     public string Render(string template, object model)
     { 
         var templateInstance = new Template(template);
+        if (model == null)
+        {
+            return templateInstance.Render();
+        }
         var extractedModel = model.GetType().GetProperty("model")?.GetValue(model) ?? model;
         templateInstance.Add("model", extractedModel);
         foreach (var (key, value) in Mappers)
             templateInstance.Group.DefineDictionary(key, value);
         return templateInstance.Render();
     }
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    public string Render(string template, object model)
    { 
        var templateInstance = new Template(template);
        if (model == null)
        {
            return templateInstance.Render();
        }
        var extractedModel = model.GetType().GetProperty("model")?.GetValue(model) ?? model;
        templateInstance.Add("model", extractedModel);
        foreach (var (key, value) in Mappers)
            templateInstance.Group.DefineDictionary(key, value);
        return templateInstance.Render();
    }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-16T14:41:42Z
author_association: NONE

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-03-16T14:32:24Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough
This update removes an unused import in the BaseFactory. It introduces a new mapping API by adding the `AddMappings` method to the `ITemplateEngine` interface and implementing similar functionality across various template engine wrappers. Each wrapper now holds a private `Mappers` dictionary and incorporates mapping registration within the rendering process. Some wrappers, such as Morestachio, Scriban, and SmartFormat, currently throw a `NotImplementedException` in their mapping methods. New tests have been added to verify that dictionary-based dynamic mappings are correctly integrated during template rendering.

## Changes

| File(s) | Change Summary |
|---------|----------------|
| `src/Didot.Core/BaseFactory.cs` | Removed unused import of `Didot.Core.SourceParsers`. |
| `src/Didot.Core/ITemplateEngine.cs` | Added new method: `void AddMappings(string mapKey, IDictionary<string, object> mappings);` |
| `src/Didot.Core/TemplateEngines/{DotLiquidWrapper, FluidWrapper, HandlebarsWrapper, MorestachioWrapper, ScribanWrapper, SmartFormatWrapper, StringTemplateWrapper}.cs` | Introduced private `Mappers` dictionary; added `AddMappings` method (with some placeholders throwing `NotImplementedException`); modified `Render` or context methods in DotLiquid, Fluid, Handlebars, and StringTemplate wrappers to incorporate mappings into the rendering process. |
| `testing/Didot.Core.Testing/TemplateEngines/{DotLiquidWrapperTests, FluidWrapperTests, HandlebarsWrapperTests, StringTemplateWrapperTests}.cs` | Added new test method `Render_Dictionary_Successful` to verify mapping-based rendering functionality. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant Client
    participant Engine
    participant Parser
    Client->>Engine: AddMappings(mapKey, mappings)
    Client->>Engine: Render(source, model)
    Engine->>Engine: Merge model with Mappers
    Engine->>Parser: Parse source template
    Parser-->>Engine: Parsed template
    Engine-->>Client: Return rendered result
```

## Poem
> Oh, what a hop in our code-filled glade,  
> Mappers flourish in every upgrade.  
> I scurry through templates with newfound grace,  
> Adding mappings so dynamic, each line a chase.  
> With whiskers twitching in rhythmic delight,  
> I celebrate these changes, coding day and night!  
> 🐇🌟

<!-- walkthrough_end -->

<!-- announcements_start -->

> [!TIP]
> <details>
> <summary>⚡🧪 Multi-step agentic review comment chat (experimental)</summary>
> 
> - We're introducing multi-step agentic chat in review comments. This experimental feature enhances review discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments.
> 						- To enable this feature, set early_access to true under in the settings.
> 
> </details>

<!-- announcements_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Seddryck/Didot&utm_content=150):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE
user: login: codecov-commenter
created_at: 2025-03-16T14:35:18Z
body: ## [Codecov](https://app.codecov.io/gh/Seddryck/Didot/pull/150?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=C%C3%A9dric+L.+Charlier) Report
Attention: Patch coverage is `67.39130%` with `15 lines` in your changes missing coverage. Please review.
> Project coverage is 89.34%. Comparing base [(`55d321b`)](https://app.codecov.io/gh/Seddryck/Didot/commit/55d321b19abffcd11ba28884ceb1bc84fd432bf5?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=C%C3%A9dric+L.+Charlier) to head [(`482d846`)](https://app.codecov.io/gh/Seddryck/Didot/commit/482d8465731562e5bc9753ae7dda403963c7ed33?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=C%C3%A9dric+L.+Charlier).

| [Files with missing lines](https://app.codecov.io/gh/Seddryck/Didot/pull/150?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=C%C3%A9dric+L.+Charlier) | Patch % | Lines |
|---|---|---|
| [src/Didot.Core/TemplateEngines/FluidWrapper.cs](https://app.codecov.io/gh/Seddryck/Didot/pull/150?src=pr&el=tree&filepath=src%2FDidot.Core%2FTemplateEngines%2FFluidWrapper.cs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=C%C3%A9dric+L.+Charlier#diff-c3JjL0RpZG90LkNvcmUvVGVtcGxhdGVFbmdpbmVzL0ZsdWlkV3JhcHBlci5jcw==) | 61.53% | [2 Missing and 3 partials :warning: ](https://app.codecov.io/gh/Seddryck/Didot/pull/150?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=C%C3%A9dric+L.+Charlier) |
| [...idot.Core/TemplateEngines/StringTemplateWrapper.cs](https://app.codecov.io/gh/Seddryck/Didot/pull/150?src=pr&el=tree&filepath=src%2FDidot.Core%2FTemplateEngines%2FStringTemplateWrapper.cs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=C%C3%A9dric+L.+Charlier#diff-c3JjL0RpZG90LkNvcmUvVGVtcGxhdGVFbmdpbmVzL1N0cmluZ1RlbXBsYXRlV3JhcHBlci5jcw==) | 62.50% | [1 Missing and 2 partials :warning: ](https://app.codecov.io/gh/Seddryck/Didot/pull/150?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=C%C3%A9dric+L.+Charlier) |
| [src/Didot.Core/TemplateEngines/DotLiquidWrapper.cs](https://app.codecov.io/gh/Seddryck/Didot/pull/150?src=pr&el=tree&filepath=src%2FDidot.Core%2FTemplateEngines%2FDotLiquidWrapper.cs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=C%C3%A9dric+L.+Charlier#diff-c3JjL0RpZG90LkNvcmUvVGVtcGxhdGVFbmdpbmVzL0RvdExpcXVpZFdyYXBwZXIuY3M=) | 71.42% | [1 Missing and 1 partial :warning: ](https://app.codecov.io/gh/Seddryck/Didot/pull/150?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=C%C3%A9dric+L.+Charlier) |
| [...rc/Didot.Core/TemplateEngines/HandlebarsWrapper.cs](https://app.codecov.io/gh/Seddryck/Didot/pull/150?src=pr&el=tree&filepath=src%2FDidot.Core%2FTemplateEngines%2FHandlebarsWrapper.cs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=C%C3%A9dric+L.+Charlier#diff-c3JjL0RpZG90LkNvcmUvVGVtcGxhdGVFbmdpbmVzL0hhbmRsZWJhcnNXcmFwcGVyLmNz) | 83.33% | [1 Missing and 1 partial :warning: ](https://app.codecov.io/gh/Seddryck/Didot/pull/150?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=C%C3%A9dric+L.+Charlier) |
| [...c/Didot.Core/TemplateEngines/MorestachioWrapper.cs](https://app.codecov.io/gh/Seddryck/Didot/pull/150?src=pr&el=tree&filepath=src%2FDidot.Core%2FTemplateEngines%2FMorestachioWrapper.cs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=C%C3%A9dric+L.+Charlier#diff-c3JjL0RpZG90LkNvcmUvVGVtcGxhdGVFbmdpbmVzL01vcmVzdGFjaGlvV3JhcHBlci5jcw==) | 50.00% | [1 Missing :warning: ](https://app.codecov.io/gh/Seddryck/Didot/pull/150?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=C%C3%A9dric+L.+Charlier) |
| [src/Didot.Core/TemplateEngines/ScribanWrapper.cs](https://app.codecov.io/gh/Seddryck/Didot/pull/150?src=pr&el=tree&filepath=src%2FDidot.Core%2FTemplateEngines%2FScribanWrapper.cs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=C%C3%A9dric+L.+Charlier#diff-c3JjL0RpZG90LkNvcmUvVGVtcGxhdGVFbmdpbmVzL1NjcmliYW5XcmFwcGVyLmNz) | 50.00% | [1 Missing :warning: ](https://app.codecov.io/gh/Seddryck/Didot/pull/150?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=C%C3%A9dric+L.+Charlier) |
| [...c/Didot.Core/TemplateEngines/SmartFormatWrapper.cs](https://app.codecov.io/gh/Seddryck/Didot/pull/150?src=pr&el=tree&filepath=src%2FDidot.Core%2FTemplateEngines%2FSmartFormatWrapper.cs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=C%C3%A9dric+L.+Charlier#diff-c3JjL0RpZG90LkNvcmUvVGVtcGxhdGVFbmdpbmVzL1NtYXJ0Rm9ybWF0V3JhcHBlci5jcw==) | 50.00% | [1 Missing :warning: ](https://app.codecov.io/gh/Seddryck/Didot/pull/150?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=C%C3%A9dric+L.+Charlier) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #150      +/-   ##
==========================================
- Coverage   90.92%   89.34%   -1.58%     
==========================================
  Files          33       33              
  Lines         661      704      +43     
  Branches      109      121      +12     
==========================================
+ Hits          601      629      +28     
- Misses         26       34       +8     
- Partials       34       41       +7     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/Seddryck/Didot/pull/150?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=C%C3%A9dric+L.+Charlier).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=C%C3%A9dric+L.+Charlier).

<details><summary>🚀 New features to boost your workflow: </summary>

- ❄ [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-03-16T14:40:49Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=Seddryck_Didot&pullRequest=150) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [1 New issue](https://sonarcloud.io/project/issues?id=Seddryck_Didot&pullRequest=150&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=Seddryck_Didot&pullRequest=150&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=Seddryck_Didot&pullRequest=150&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=Seddryck_Didot&pullRequest=150&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=Seddryck_Didot&pullRequest=150&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Seddryck_Didot&pullRequest=150)


author_association: NONE