Skip to content

Commit 72366b4

Browse files
committed
HTML templating has been implemented -- untested.
JSON validation actually occurs. Code and output have been cleaned up a bit. Implemented style inheritance.
1 parent dd82b33 commit 72366b4

File tree

2 files changed

+89
-53
lines changed

2 files changed

+89
-53
lines changed

src/nerc.nim

+84-48
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
#[ TODO:
2+
- Style inheritance
3+
- Plop in a stylesheet if none is present
4+
- Clean up the code a little, I guess
5+
]#
16
import
27
json,
38
macros,
@@ -30,15 +35,19 @@ type
3035
style: string
3136
config: JsonNode
3237
hasIndex: DirTreeNode
38+
hasCSS: DirTreeNode
39+
hasHTML: DirTreeNode
3340
of itemFile:
3441
fileKind: FileKind
3542

3643

3744
proc getConfig(node: DirTreeNode, key: string): JsonNode {.inline.}
45+
proc genLinks(node: DirTreeNode): string
46+
proc genPath(node: DirTreeNode): string
3847
proc removeSuffixInsensitive(s, suffix: string): string
39-
proc convertMarkdownToNercPage(tree: DirTreeNode)
48+
proc convertMarkdownToNercPage(node: DirTreeNode)
4049
proc buildDirTree(node: DirTreeNode, depth: uint)
41-
proc printTree(tree: DirTreeNode)
50+
proc printTree(node: DirTreeNode)
4251
proc genSidebar( tree: DirTreeNode, currentItem: DirTreeNode): string
4352
proc populateDirs(treeRoot: DirTreeNode)
4453

@@ -58,8 +67,14 @@ const
5867
DefaultStyle = staticRead("res/styles.css")
5968
DefaultJson = staticRead("res/config.json")
6069

61-
let DefaultConfig = parseJson(DefaultJson)
70+
var defaultconfig: JsonNode
6271

72+
try:
73+
defaultconfig = parseJson(DefaultJson)
74+
except JsonParsingError:
75+
echo "[ERROR] Built-in config.json does not pass validation. Fix error and recompile."
76+
77+
let DefaultConfig = defaultconfig
6378

6479
var
6580
pageTitle: string
@@ -69,7 +84,7 @@ var
6984
htmlFooterLeft: string
7085
htmlFooterRight: string
7186

72-
fsTree: DirTreeNode = DirTreeNode(depth: 0, label: "Main", path: ".", kind: itemDir)
87+
fsTree: DirTreeNode = DirTreeNode(depth: 0, name: "Main", label: "Main", path: ".", kind: itemDir)
7388

7489

7590
fsTree.html = DefaultTemplate
@@ -82,14 +97,24 @@ proc removeSuffixInsensitive(s, suffix: string): string =
8297
return s[0 ..< s.len - suffix.len]
8398
return s
8499

100+
proc getTemplate(node: DirTreeNode): string =
101+
if node.hasHTML != nil:
102+
if node.html != "":
103+
return node.html
104+
105+
if node.parent != nil:
106+
return node.parent.getTemplate()
107+
108+
return DefaultTemplate
109+
85110

86-
proc getConfig(node: DirTreeNode, key: string): JsonNode {.inline.} =
111+
proc getConfig(node: DirTreeNode, key: string): JsonNode =
87112
if not node.config.isNil:
88113
if node.config.hasKey(key):
89114
return node.config[key]
90115

91116
if node.parent != nil:
92-
return getConfig(node.parent, key)
117+
return node.parent.getConfig(key)
93118

94119
return DefaultConfig[key]
95120

@@ -103,22 +128,28 @@ proc genLinks(node: DirTreeNode): string =
103128
if node.config.isNil: return node.parent.genLinks()
104129
let config: JsonNode = node.getConfig("links")
105130

106-
if config.kind != JObject:
107-
#echo "[LINKS] Not generating links."
131+
if config.kind != JArray:
108132
return node.parent.genLinks()
109133

110-
for label, link in config.pairs():
134+
for item in config:
135+
if item.kind != JObject: continue
136+
if not item.hasKey("label") and not item.hasKey("link"): continue
137+
if item["label"].kind != JString: continue
138+
if item["link"].kind != JString: continue
139+
let
140+
label = item["label"].getStr()
141+
link = item["link"].getStr()
142+
111143
separator = if addSeparator: "&nbsp;|&nbsp;" else: ""
112144

113-
if label == "" and link.getStr() == "SPACER":
145+
if label == "" and link == "SPACER":
114146
links = links & "<div class=\"spacer\" ></div>"
115147
addSeparator = false
116148
continue
117149

118-
links = links & separator & "<a href=\"" & link.getStr() & "\">" & label & "</a>"
150+
links = links & separator & "<a href=\"" & link & "\">" & label & "</a>"
119151
addSeparator = true
120152

121-
#echo "[LINKS] " & links
122153
return links
123154

124155

@@ -129,29 +160,32 @@ proc genPath(node: DirTreeNode): string =
129160
return path
130161

131162

132-
proc convertMarkdownToNercPage(tree: DirTreeNode) =
133-
echo tree.path[2..^1] & " : " & tree.name & "\n"
134-
if tree.kind == itemDir: return
163+
proc convertMarkdownToNercPage(node: DirTreeNode) =
164+
if node.kind == itemDir: return
135165

136-
var outPath: string = tree.path[2..^1]
166+
var outPath: string = node.path[2..^1]
137167
outPath.removeSuffix(".md")
138168
if toLowerAscii(outPath).endsWith("readme"):
139169
outpath = outPath.removeSuffixInsensitive("readme") & "index"
140170
outPath = outPath & ".htm"
141171

142-
let mdFile = readFile(tree.path[2..^1])
172+
let mdFile = readFile(node.path[2..^1])
143173

144-
var htmlTxt = DefaultTemplate
145-
if htmlTxt.contains(PageTitleTag): htmlTxt = htmlTxt.replace( PageTitleTag, tree.parent.getConfig("page title").getStr() & " - " & tree.name )
146-
if htmlTxt.contains(LinksTag): htmlTxt = htmlTxt.replace( LinksTag, tree.parent.genLinks() )
147-
if htmlTxt.contains(SiteTitleTag): htmlTxt = htmlTxt.replace( SiteTitleTag, tree.parent.getConfig("site title").getStr() )
148-
if htmlTxt.contains(SubtitleTag): htmlTxt = htmlTxt.replace( SubtitleTag, tree.parent.getConfig("subtitle").getStr() )
149-
if htmlTxt.contains(SidebarTag): htmlTxt = htmlTxt.replace( SidebarTag, fsTree.genSidebar(tree) )
174+
var
175+
htmlTxt = node.parent.getTemplate()
176+
pageTitle: string = ""
177+
if "readme" != node.label.toLowerAscii(): pageTitle = " - " & node.label
178+
if htmlTxt.contains(PageTitleTag): htmlTxt = htmlTxt.replace( PageTitleTag, node.parent.getConfig("page title").getStr() & pageTitle )
179+
if htmlTxt.contains(LinksTag): htmlTxt = htmlTxt.replace( LinksTag, node.parent.genLinks() )
180+
if htmlTxt.contains(SiteTitleTag): htmlTxt = htmlTxt.replace( SiteTitleTag, node.parent.getConfig("site title").getStr() )
181+
if htmlTxt.contains(SubtitleTag): htmlTxt = htmlTxt.replace( SubtitleTag, node.parent.getConfig("subtitle").getStr() )
182+
if htmlTxt.contains(SidebarTag): htmlTxt = htmlTxt.replace( SidebarTag, fsTree.genSidebar(node) )
150183
if htmlTxt.contains(ContentTag): htmlTxt = htmlTxt.replace( ContentTag, mdFile.markdown() )
151-
if htmlTxt.contains(FooterLeftTag): htmlTxt = htmlTxt.replace( FooterLeftTag, tree.parent.getConfig("footer left").getStr() )
152-
if htmlTxt.contains(FooterRightTag): htmlTxt = htmlTxt.replace( FooterRightTag, tree.parent.getConfig("footer right").getStr() )
184+
if htmlTxt.contains(FooterLeftTag): htmlTxt = htmlTxt.replace( FooterLeftTag, node.parent.getConfig("footer left").getStr() )
185+
if htmlTxt.contains(FooterRightTag): htmlTxt = htmlTxt.replace( FooterRightTag, node.parent.getConfig("footer right").getStr() )
153186

154187
writefile(outPath, htmlTxt)
188+
echo "[GENERATED]: ", outPath
155189

156190

157191
proc buildDirTree(node: DirTreeNode, depth: uint) =
@@ -161,55 +195,56 @@ proc buildDirTree(node: DirTreeNode, depth: uint) =
161195
if name[0] == '.': continue # Skip hidden files and directories (such as .git)
162196
if kind == pcFile:
163197
var new_node: DirTreeNode = DirTreeNode(depth: depth, kind: itemFile, name: name, path: path & '/' & name, parent: node)
164-
echo "[FILE] " & name
198+
165199
if name.toLowerAscii().endsWith(".md"):
166200
new_node.fileKind = fileMarkdown
167201
new_node.label = name.split('.')[0].replace('_', ' ')
168-
echo "[LABEL] " & new_node.label
169202
if "readme" == new_node.label.toLowerAscii(): node.hasIndex = new_node
170203
#convertMarkdownToNercPage(path)
171204
elif name.toLowerAscii() == "config.json":
172-
echo new_node.path[2..^1]
173205
var file: string = readFile(new_node.path[2..^1])
174-
echo file
175-
node.config = parseJson(file)
206+
try:
207+
node.config = parseJson(file)
208+
except JsonParsingError:
209+
echo "[ERROR] ", name, " at ", path, " did not pass validation and will be ignored."
176210
continue
211+
177212
elif name.toLowerAscii() == "template.htm":
178213
node.html = readFile(new_node.path)
179214
continue
215+
180216
elif name.toLowerAscii() == "styles.css":
181217

182218
continue
219+
183220
elif name.toLowerAscii().endsWith(".html"):
184221
new_node.fileKind = fileHTML
185222
else: continue
223+
186224
new_node.parent = node
187-
#echo "\t", path & "/" & name
188225
node.contents.add(new_node)
189226

190227
elif kind == pcDir:
191228
var new_node: DirTreeNode = DirTreeNode(depth: depth, kind: itemDir, name: name, label: name.split('.')[0].replace('_', ' '), path: path & '/' & name, parent: node)
192-
#echo path & "/" & name
193-
echo "[DIR] " & name
194-
echo "[LABEL] " & new_node.label
195229
new_node.parent = node
196230
buildDirTree(new_node, depth+1)
197231
node.contents.add(new_node)
198232

199233

200-
proc printTree(tree: DirTreeNode) =
201-
if tree.kind == itemFile:
202-
203-
case tree.fileKind
204-
of fileMarkdown: echo tree.depth, repeat('\t', tree.depth), tree.name, " : Markdown"
205-
of fileJSON: echo tree.depth, repeat('\t', tree.depth), tree.name, " : JSON"
206-
of fileTemplate: echo tree.depth, repeat('\t', tree.depth), tree.name, " : Template"
207-
of fileHTML: echo tree.depth, repeat('\t', tree.depth), tree.name, " : HTML"
234+
proc printTree(node: DirTreeNode) =
235+
if node.kind == itemFile:
236+
var fileType: string
237+
case node.fileKind
238+
of fileMarkdown: fileType = "Markdown"
239+
of fileJSON: fileType = "JSON"
240+
of fileTemplate: fileType = "Template"
241+
of fileHTML: fileType = "HTML"
242+
echo "[FILE]", repeat('\t', node.depth), node.name, " : "
208243

209-
elif tree.kind == itemDir:
210-
echo repeat('\t', tree.depth), tree.path, " : ", tree.name, " : ", tree.contents.len()
244+
elif node.kind == itemDir:
245+
echo "[DIR]", repeat('\t', node.depth), node.path, " : ", node.name, " : ", node.contents.len()
211246

212-
for item in tree.contents:
247+
for item in node.contents:
213248
printTree(item)
214249
continue
215250

@@ -233,8 +268,7 @@ proc genSidebar(tree: DirTreeNode, currentItem: DirTreeNode): string =
233268

234269
if "index" == toLowerAscii(label): return ""
235270
if tree == currentItem: label = ">> " & label & " <<"
236-
237-
echo path
271+
238272
return repeat('\t', tree.depth) & "<li class=\"page\"><a href=\"" & path & "\">" & label & "</a></li>\n"
239273

240274
elif tree.kind == itemDir:
@@ -250,7 +284,6 @@ proc genSidebar(tree: DirTreeNode, currentItem: DirTreeNode): string =
250284
for item in tree.contents:
251285
itemList = itemList & genSidebar(item, currentItem)
252286

253-
echo "Generated Path: " & path
254287
if tree.hasIndex != nil: label = "<a href=\"" & path & "\">" & label & "</a>\n"
255288
itemList =
256289
"<li class=\"dir\">" & label & "<ul>\n" &
@@ -278,8 +311,11 @@ proc main() =
278311
if isValidFileName(args[0]):
279312
echo args[0]
280313

314+
echo "Scanning..."
281315
buildDirTree(fsTree, 1)
282316
printTree(fsTree)
317+
echo "\nGenerating pages..."
283318
populateDirs(fsTree)
319+
echo "\nDone!"
284320

285321
main()

src/res/config.json

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
22
"page title": "Default nerc site",
3-
"links": {
4-
"Main": "/",
5-
"": "SPACER",
6-
"nerc": "https://github.com/8bitprodigy/nerc",
7-
},
3+
"links": [
4+
{"label":"Main", "link": "/"},
5+
{"label":"", "link": "SPACER"},
6+
{"label":"nerc", "link": "https://github.com/8bitprodigy/nerc"},
7+
],
88
"site title": "Default nerc site",
99
"subtitle": "These settings can be overridden by putting a config.json file in the root of this nerc site.",
1010
"footer left": "This page was generated by&nbsp;<a href=\"https://github.com/8bitprodigy/nerc\">nerc</a>.",

0 commit comments

Comments
 (0)