1
- using DynamicContentUpdater . Entities ;
1
+ #nullable enable
2
+ using DynamicContentUpdater . Entities ;
2
3
using DynamicContentUpdater . Utilities ;
3
4
4
5
using ProgrammerAl . Site . DynamicContentUpdater ;
5
- using ProgrammerAl . Site . Pages ;
6
6
7
7
using System ;
8
8
using System . Collections . Generic ;
9
9
using System . Collections . Immutable ;
10
10
using System . Collections . ObjectModel ;
11
11
using System . Text ;
12
12
13
+ using YamlDotNet . Serialization . NamingConventions ;
14
+ using YamlDotNet . Serialization ;
15
+ using ExCSS ;
16
+ using System . Linq ;
17
+
13
18
namespace DynamicContentUpdater
14
19
{
15
20
public class PostParser
@@ -23,59 +28,96 @@ public PostParser(RuntimeConfig runtimeConfig)
23
28
24
29
public ParsedEntry ParseFromMarkdown ( string rawEntry , string postName )
25
30
{
26
- //Assumes a specific schema
27
- // Line 1: Title: <TITLE HERE>
28
- // Line 2: Published: <YYYY/MM/DD>
29
- // Line 3: Tags:
30
- // Line 4-??: - <Tag Name>
31
- // Line ??: PresentationSlides:
32
- // Line ??-??: - <Slide Url>
33
- // Header Ending: --- <Yes, 3 dashes>
34
- // ## <Some header. Usually "## Receiving the Quest">
35
- // First Paragraph
36
- // Rest of it: The blog post
37
-
38
- int titleStartIndex = rawEntry . IndexOf ( "Title:" ) ;
39
- int titleEndIndex = rawEntry . IndexOf ( "\n " , titleStartIndex ) ;
40
- int titleLineLength = titleEndIndex - titleStartIndex ;
41
- ReadOnlySpan < char > titleLine = rawEntry . AsSpan ( titleStartIndex , titleLineLength ) ;
42
- string title = ParseStringValueFromLine ( titleLine ) ;
43
-
44
- int publishedDateStartIndex = rawEntry . IndexOf ( "Published:" ) ;
45
- int publishedDateEndIndex = rawEntry . IndexOf ( '\n ' , publishedDateStartIndex + 1 ) ;
46
- int publishedDateEndLength = publishedDateEndIndex - publishedDateStartIndex ;
47
- ReadOnlySpan < char > publishedDateLine = rawEntry . AsSpan ( publishedDateStartIndex , publishedDateEndLength ) ;
48
- DateOnly publishedDate = ParseDateTimeFromLine ( publishedDateLine ) ;
49
-
50
- int tagsLineStartIndex = rawEntry . IndexOf ( "Tags:" ) ;
51
- var tags = ParseListSection ( rawEntry , tagsLineStartIndex ) ;
52
-
53
- int slidesLineStartIndex = rawEntry . IndexOf ( "Slides:" ) ;
54
- ImmutableArray < string > slideUrls ;
55
- if ( slidesLineStartIndex == - 1 )
56
- {
57
- slideUrls = ImmutableArray < string > . Empty ;
58
- }
59
- else
60
- {
61
- slideUrls = ParseListSection ( rawEntry , slidesLineStartIndex ) ;
62
- }
31
+ var deserializer = new DeserializerBuilder ( )
32
+ . WithNamingConvention ( PascalCaseNamingConvention . Instance )
33
+ . Build ( ) ;
34
+
35
+ int headerEndIndex = rawEntry . IndexOf ( "---" ) ;
36
+ var headerText = rawEntry . Substring ( 0 , headerEndIndex ) ;
37
+
38
+ var properties = deserializer . Deserialize < PostPropertiesDto > ( headerText ) ;
39
+ AssertProperties ( properties ) ;
40
+
41
+ var tags = properties ! . Tags ! . Select ( x => x ! ) . ToImmutableArray ( ) ;
42
+ var presentations = properties . Presentations ! . Select ( x => new ParsedEntry . PresentationEntry ( x ! . Id ! . Value , x . SlidesUrl , x . SlideImagesUrl ) ) . ToImmutableArray ( ) ;
63
43
64
- int headerCloseIndexStart = rawEntry . IndexOf ( "---" ) + 3 ;
65
- ReadOnlySpan < char > postSpan = rawEntry . AsSpan ( headerCloseIndexStart + 1 ) . Trim ( ) ;
44
+ var postStartIndex = headerEndIndex + 4 ;
45
+ ReadOnlySpan < char > postSpan = rawEntry . AsSpan ( postStartIndex ) . Trim ( ) ;
66
46
string post = SanitizePost ( postSpan , postName ) ;
67
47
68
48
string firstParagraphOfPost = GrabFirstParagraphOfPost ( post ) ;
69
49
70
50
return new ParsedEntry (
71
- title ,
72
- publishedDate ,
51
+ properties . Title ! ,
52
+ properties . Published ! . Value ,
73
53
tags ,
74
- slideUrls ,
54
+ presentations ,
75
55
post ,
76
56
firstParagraphOfPost ) ;
77
57
}
78
58
59
+ private void AssertProperties ( PostPropertiesDto ? properties )
60
+ {
61
+ if ( properties is null )
62
+ {
63
+ throw new Exception ( $ "Post properties object is null") ;
64
+ }
65
+
66
+ AssertProperty ( properties . Title , nameof ( properties . Title ) ) ;
67
+ AssertProperty ( properties . Published , nameof ( properties . Published ) ) ;
68
+ AssertProperty ( properties . Tags , nameof ( properties . Tags ) ) ;
69
+
70
+ //Presentations is optional
71
+ if ( properties . Presentations is object )
72
+ {
73
+ foreach ( var presentation in properties . Presentations )
74
+ {
75
+ if ( presentation is null )
76
+ {
77
+ throw new Exception ( $ "Post presentation is null") ;
78
+ }
79
+
80
+ AssertProperty ( presentation . Id , nameof ( presentation . Id ) ) ;
81
+ AssertProperty ( presentation . SlidesUrl , nameof ( presentation . SlidesUrl ) ) ;
82
+ AssertProperty ( presentation . SlideImagesUrl , nameof ( presentation . SlideImagesUrl ) ) ;
83
+ }
84
+ }
85
+ }
86
+
87
+ private void AssertProperty ( string ? value , string name )
88
+ {
89
+ if ( string . IsNullOrWhiteSpace ( value ) )
90
+ {
91
+ throw new Exception ( $ "Post property is null or empty: { name } ") ;
92
+ }
93
+ }
94
+
95
+ private void AssertProperty ( int ? value , string name )
96
+ {
97
+ if ( ! value . HasValue
98
+ || value . Value == 0 )
99
+ {
100
+ throw new Exception ( $ "Post property is null or empty: { name } ") ;
101
+ }
102
+ }
103
+
104
+ private void AssertProperty ( DateOnly ? value , string name )
105
+ {
106
+ if ( ! value . HasValue )
107
+ {
108
+ throw new Exception ( $ "Post property is null or empty: { name } ") ;
109
+ }
110
+ }
111
+
112
+ private void AssertProperty ( string ? [ ] ? value , string name )
113
+ {
114
+ if ( value is null
115
+ || value . Any ( x => string . IsNullOrWhiteSpace ( x ) ) )
116
+ {
117
+ throw new Exception ( $ "Post array property is null has a null or empty item: { name } ") ;
118
+ }
119
+ }
120
+
79
121
private string GrabFirstParagraphOfPost ( string post )
80
122
{
81
123
string headerText = "##" ;
@@ -128,65 +170,20 @@ private string SanitizePost(ReadOnlySpan<char> postSpan, string postName)
128
170
129
171
return postText ;
130
172
}
173
+ }
131
174
132
- private ImmutableArray < string > ParseListSection ( string text , int sectionTitleStartIndex )
133
- {
134
- var items = new List < string > ( ) ;
135
-
136
- var endOfLineIndex = text . IndexOf ( '\n ' , sectionTitleStartIndex ) ;
137
- var endOfHeaderIndex = text . IndexOf ( "---" ) ;
138
-
139
- //int startIndex = endOfLineIndex;
140
- var nextItemIndex = text . IndexOf ( '-' , endOfLineIndex ) ;
141
- while ( nextItemIndex != - 1
142
- && nextItemIndex < endOfHeaderIndex )
143
- {
144
- var startIndex = nextItemIndex ;
145
- if ( text [ startIndex ] != '-' )
146
- {
147
- break ;
148
- }
149
-
150
- startIndex ++ ; //Skip the dash
151
- var endIndex = text . IndexOf ( '\n ' , startIndex + 1 ) ;
152
-
153
- var length = endIndex - startIndex ;
154
- var line = text . Substring ( startIndex , length ) . Trim ( ) ;
155
-
156
- items . Add ( line ) ;
157
-
158
- nextItemIndex = endIndex + 1 ;
159
- }
160
-
161
- //while ((startIndex = localSpan.IndexOf('-') + 1) > 0)
162
- //{
163
- // localSpan = localSpan.Slice(startIndex);
164
-
165
- // int endIndex = localSpan.IndexOf('\n');
166
- // string tag = localSpan.Slice(0, endIndex).Trim().ToString();
167
- // items.Add(tag);
168
- // localSpan = localSpan.Slice(endIndex + 1);
169
- //}
170
-
171
- return items . ToImmutableArray ( ) ;
172
- }
173
-
174
- private string ParseStringValueFromLine ( ReadOnlySpan < char > textLine )
175
- {
176
- int separatorIndex = textLine . IndexOf ( ':' ) ;
177
- if ( separatorIndex > - 1 )
178
- {
179
- separatorIndex ++ ; //index is first character after the colon
180
- return textLine . Slice ( separatorIndex ) . Trim ( ) . ToString ( ) ;
181
- }
182
-
183
- return "Unknown Error" ;
184
- }
175
+ public class PostPropertiesDto
176
+ {
177
+ public string ? Title { get ; set ; }
178
+ public DateOnly ? Published { get ; set ; }
179
+ public string ? [ ] ? Tags { get ; set ; }
180
+ public PresentationDto ? [ ] ? Presentations { get ; set ; }
185
181
186
- private DateOnly ParseDateTimeFromLine ( ReadOnlySpan < char > textLine )
182
+ public class PresentationDto
187
183
{
188
- string dateTimeString = ParseStringValueFromLine ( textLine ) ;
189
- return DateOnly . ParseExact ( dateTimeString , format : "yyyy/MM/dd" , provider : null ) ;
184
+ public int ? Id { get ; set ; }
185
+ public string ? SlidesUrl { get ; set ; }
186
+ public string ? SlideImagesUrl { get ; set ; }
190
187
}
191
188
}
192
189
}
0 commit comments