Skip to content

Commit 98dc675

Browse files
committed
Merge branch 'master' into feature/help
2 parents bec51f4 + a6a386a commit 98dc675

7 files changed

Lines changed: 285 additions & 20 deletions

File tree

src/SolidifyProject.Engine.Infrastructure/Models/PageModel.cs

Lines changed: 107 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ public sealed class PageModel : TextContentModel
2020

2121
private static readonly string[] CUSTOM_ATTRIBUTE_PREFIX_SEPARATOR = {"."};
2222
private static readonly string[] CUSTOM_ATTRIBUTE_PREFIX = {"Custom"};
23+
24+
private static readonly string[] MODEL_ATTRIBUTE_PREFIX = {"Model"};
2325

2426
public string Title { get; set; }
2527
public string Url { get; set; }
@@ -39,11 +41,17 @@ public sealed class PageModel : TextContentModel
3941
/// Raw content after separator
4042
/// </summary>
4143
public string Content { get; set; }
44+
45+
public dynamic Model { get; set; }
4246

43-
public override void Parse()
47+
public PageModel()
4448
{
4549
Custom = new ExpandoObject();
46-
50+
Model = new ExpandoObject();
51+
}
52+
53+
public override void Parse()
54+
{
4755
var lines = ContentRaw.Split(END_OF_LINE, StringSplitOptions.None);
4856

4957
var attributeLines = lines
@@ -57,7 +65,18 @@ public override void Parse()
5765

5866
var contentLines = lines.SkipWhile(x => !SEPARATOR.Equals(x)).Skip(1);
5967
ParseContent(contentLines);
60-
68+
}
69+
70+
public void MapDataToModel(ExpandoObject data)
71+
{
72+
if (Model is ExpandoObject)
73+
{
74+
MapDataToPageModel(Model, data);
75+
}
76+
else
77+
{
78+
Model = getValueFromDataObject(Model, data);
79+
}
6180
}
6281

6382
private void ParseAttributeLine(string line)
@@ -100,6 +119,12 @@ private void ParseAttributeLine(string line)
100119
return;
101120
}
102121

122+
if (MODEL_ATTRIBUTE_PREFIX.Any(x => x.Equals(attributeName, StringComparison.OrdinalIgnoreCase)))
123+
{
124+
Model = attributeValue;
125+
return;
126+
}
127+
103128
if (CUSTOM_ATTRIBUTE_PREFIX_SEPARATOR.Any(x => attributeName.Contains(x)))
104129
{
105130
var customAttributeNames = attributeName.Split(CUSTOM_ATTRIBUTE_PREFIX_SEPARATOR, StringSplitOptions.RemoveEmptyEntries);
@@ -109,38 +134,106 @@ private void ParseAttributeLine(string line)
109134
}
110135
else
111136
{
112-
throw new ArgumentException($"Unknown name format of custom attribute \"{attributeName}\" at line \"{line}\"");
137+
if (customAttributeNames.Length >= 2 && MODEL_ATTRIBUTE_PREFIX.Any(x =>
138+
x.Equals(customAttributeNames[0], StringComparison.InvariantCultureIgnoreCase)))
139+
{
140+
ParseCustomAttribute(Model, customAttributeNames.Skip(1), attributeValue);
141+
}
142+
else
143+
{
144+
throw new ArgumentException(
145+
$"Unknown name format of custom attribute \"{attributeName}\" at line \"{line}\"");
146+
}
113147
}
114-
148+
115149
return;
116150
}
151+
117152

118153
throw new ArgumentException($"Unknown attribute \"{attributeName}\" at line \"{line}\"");
119154
}
120155

121156
private void ParseCustomAttribute(ExpandoObject obj, IEnumerable<string> attributeNames, string attributeValue)
122157
{
123-
ICollection<KeyValuePair<string, object>> node = obj;
158+
IDictionary<string, object> node = obj;
124159
var currentSection = attributeNames.First();
125-
object currentValue;
126-
160+
127161
if (attributeNames.Count() > 1)
128162
{
129-
var subNode = new ExpandoObject();
130-
currentValue = subNode;
131-
ParseCustomAttribute(subNode, attributeNames.Skip(1), attributeValue);
163+
ExpandoObject currentNode;
164+
if (node.ContainsKey(currentSection))
165+
{
166+
currentNode = node[currentSection] as ExpandoObject;
167+
}
168+
else
169+
{
170+
currentNode = new ExpandoObject();
171+
node.Add(new KeyValuePair<string, object>(currentSection, currentNode));
172+
}
173+
174+
ParseCustomAttribute(currentNode, attributeNames.Skip(1), attributeValue);
132175
}
133176
else
134177
{
135-
currentValue = attributeValue;
178+
node.Add(new KeyValuePair<string, object>(currentSection, attributeValue));
136179
}
137-
138-
node.Add(new KeyValuePair<string, object>(currentSection, currentValue));
139180
}
140181

141182
private void ParseContent(IEnumerable<string> lines)
142183
{
143184
Content = string.Join("\r\n", lines);
144185
}
186+
187+
private void MapDataToPageModel(ExpandoObject model, ExpandoObject data)
188+
{
189+
IDictionary<string, object> modelDict = model;
190+
Dictionary<string, object> objectToIterate = model.ToDictionary(k => k.Key, v => v.Value);
191+
foreach (var keyValuePair in objectToIterate)
192+
{
193+
if (keyValuePair.Value is ExpandoObject expObject)
194+
{
195+
MapDataToPageModel(expObject, data);
196+
}
197+
else
198+
{
199+
modelDict[keyValuePair.Key] = getValueFromDataObject(keyValuePair.Value as string, data);
200+
}
201+
}
202+
}
203+
204+
private object getValueFromDataObject(string path, ExpandoObject data)
205+
{
206+
var attributeNames = path.Split('.');
207+
if (attributeNames.Length == 0)
208+
{
209+
return null;
210+
}
211+
212+
if (attributeNames.First() == "Data")
213+
{
214+
if (attributeNames.Length == 1)
215+
{
216+
return data;
217+
}
218+
219+
attributeNames = attributeNames.Skip(1).ToArray();
220+
}
221+
222+
object value = data;
223+
foreach (var attribute in attributeNames)
224+
{
225+
IDictionary<string, object> dict = value as IDictionary<string, object>;
226+
227+
if (dict == null)
228+
{
229+
dict = value.GetType().GetProperties()
230+
.ToDictionary(x => x.Name, x => x.GetValue(value, null));
231+
}
232+
233+
value = dict[attribute];
234+
}
235+
236+
return value;
237+
}
145238
}
146239
}

src/SolidifyProject.Engine.Infrastructure/Services/OrchestrationService.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ private async Task ProcessPageByIdAsync(string pageId, ExpandoObject dataModel)
5656
await LoggerService.WriteLogMessage($"{DateTime.Now.ToLongTimeString()}: [Page:Started] \"{pageId}\"");
5757

5858
var page = await PageModelReaderService.LoadContentByIdAsync(pageId).ConfigureAwait(false);
59-
59+
60+
page.MapDataToModel(dataModel);
61+
6062
var html = await TemplateService.RenderTemplateAsync(page.Content, page, dataModel);
6163
html = await MarkupService.RenderMarkupAsync(html).ConfigureAwait(false);
6264
page.Content = html;

src/SolidifyProject.Engine.Services/TemplateService/MustacheTemplateService.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Dynamic;
34
using System.IO;
5+
using System.Linq;
46
using System.Threading.Tasks;
57
using Nustache.Core;
68
using SolidifyProject.Engine.Infrastructure.Interfaces;
@@ -30,7 +32,8 @@ public Task<string> RenderTemplateAsync(string template, PageModel pageModel, Ex
3032
throw new ArgumentNullException(nameof(pageModel));
3133
}
3234

33-
var model = new { Page = pageModel, Data = dataModel };
35+
36+
var model = new { Page = pageModel, Data = dataModel, Model = pageModel.Model };
3437

3538
var result = Render.StringToString(template, model, getTemplate, new RenderContextBehaviour
3639
{
@@ -62,5 +65,6 @@ private Template getTemplate(string key)
6265

6366
return task.Result;
6467
}
68+
6569
}
6670
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
<div>
2-
<i>{{ Data.disclaimer }}</i>
2+
<i>{{ Model.disclaimer }}</i>
33
</div>

src/Test/SolidifyProject.Engine.Test.Integration/_TestData/Pages/about.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
url: pages/about-me.html
22
template: default.hjs
3+
Model.disclaimer: Data.disclaimer
34

45
title: Solidify Project - About ME
56

src/Test/SolidifyProject.Engine.Test.Integration/_TestData/Pages/home.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
url: index.html
22
template: default.hjs
3+
Model.disclaimer: Data.disclaimer
34

45
title: Static Site Generator - Home
56

0 commit comments

Comments
 (0)