all repos — hastysite @ 8cbb70edff18e18a1d7ebabde109e773c9fa4626

A high-performance static site generator.

Implemented build/rebuild command.
h3rald h3rald@h3rald.com
Sun, 06 Nov 2016 16:23:09 +0100
commit

8cbb70edff18e18a1d7ebabde109e773c9fa4626

parent

85e13f4f5f14ba66d8e373c40c4c1c0966cc48e7

2 files changed, 128 insertions(+), 58 deletions(-)

jump to
M hastysite.nimhastysite.nim

@@ -7,7 +7,8 @@ os,

securehash, sequtils, tables, - critbits + critbits, + streams import minim,

@@ -27,6 +28,7 @@ temp*: string

tempContents: string HastyFiles = object rules*: string + scripts*: string metadata: string checksums: string modified: seq[JsonNode]

@@ -37,8 +39,108 @@ dirs*: HastyDirs

files*: HastyFiles NoMetadataException* = ref Exception DictionaryRequiredException* = ref Exception + MetadataRequiredException* = ref Exception +#### MiNiM Library + +proc hastysite_module*(i: In, hs: HastySite) = + i.define("hastysite") + + .symbol("metadata") do (i: In): + i.push i.fromJson(hs.metadata) + + .symbol("settings") do (i: In): + i.push i.fromJson(hs.settings) + + .symbol("modified") do (i: In): + var modified = newSeq[MinValue](0) + for j in hs.files.modified: + modified.add i.fromJson(j) + i.push modified.newVal(i.scope) + + .symbol("output") do (i: In): + i.push hs.dirs.output.newVal + .symbol("input-fread") do (i: In): + var d: MinValue + i.reqDictionary d + let t = d.dget("type".newVal).getString + let path = d.dget("path".newVal).getString + var contents = "" + if t == "content": + contents = readFile(hs.dirs.tempContents/path) + else: + contents = readFile(hs.dirs.assets/path) + i.push contents.newVal + + .symbol("output-fwrite") do (i: In): + var d: MinValue + i.reqDictionary d + let id = d.dget("id".newVal).getString + let ext = d.dget("ext".newVal).getString + var contents = "" + try: + contents = d.dget("contents".newVal).getString + except: + raise MetadataRequiredException(msg: "Metadata key 'contents' not found in dictionary.") + let outfile = hs.dirs.output/id&ext + outfile.parentDir.createDir + writeFile(outfile, contents) + + .symbol("copy2output") do (i: In): + var d: MinValue + i.reqDictionary d + let t = d.dget("type".newVal).getString + let path = d.dget("path".newVal).getString + var infile, outfile: string + if t == "content": + infile = hs.dirs.tempContents/path + outfile = hs.dirs.output/path + else: + infile = hs.dirs.assets/path + outfile = hs.dirs.output/path + echo " - Copying: ", infile, " -> ", outfile + outfile.parentDir.createDir + copyFileWithPermissions(infile, outfile) + + .symbol("content?") do (i: In): + var d: MinValue + i.reqDictionary d + let t = d.dget("type".newVal).getString + let r = t == "content" + i.push r.newVal + + .symbol("asset?") do (i: In): + var d: MinValue + i.reqDictionary d + let t = d.dget("type".newVal).getString + let r = t == "asset" + i.push r.newVal + + .symbol("mustache") do (i: In): + var t, c: MinValue + i.reqQuotationAndString c, t + if not c.isDictionary: + raise DictionaryRequiredException(msg: "No dictionary provided as template context.") + let ctx = newContext(%c) + let tplname = t.getString & ".mustache" + let tpl = readFile(hs.dirs.templates/tplname) + i.push tpl.render(ctx, hs.dirs.templates).newval + + .symbol("markdown") do (i: In): + var t, c: MinValue + i.reqQuotationAndString c, t + if not c.isDictionary: + raise DictionaryRequiredException(msg: "No dictionary provided for markdown processor fields.") + let options = HastyOptions(toc: false, output: nil, css: nil, watermark: nil, fragment: true) + var fields = initTable[string, proc():string]() + for item in c.qVal: + fields[item.qVal[0].getString] = proc(): string = return $$item.qVal[1] + var hastyscribe = newHastyScribe(options, fields) + i.push hastyscribe.compileFragment(t.getString).newVal + + .finalize() + #### Helper Functions proc preprocessContent(file, dir: string, obj: var JsonNode): string =

@@ -91,8 +193,8 @@ return default

proc confirmClean(hs: HastySite): bool = stdout.write("Delete directory '$1' and all its contents? [Y/n] " % hs.dirs.temp) - let confirm = stdin.readChar - return confirm == 'Y' or confirm == 'y' + let confirm = $stdin.readChar + return confirm == "\n" or confirm == "Y" or confirm == "y" proc quitIfNotExists(file: string) = if not file.fileExists:

@@ -109,22 +211,30 @@ result["assets"] = newJObject()

proc contentMetadata(f, dir: string, meta: JsonNode): JsonNode = result = newJObject() - var fdata = f.splitFile - for key, value in meta["contents"][result["path"].getStr].pairs: - result[key] = value - result["path"] = %f.replace(dir & DirSep, "") + let fdata = f.splitFile + let path = f.replace(dir & DirSep, "") + if meta.hasKey("contents") and meta["contents"].hasKey(path): + for key, value in meta["contents"][path].pairs: + result[key] = value + result["path"] = %path result["type"] = %"content" - result["id"] = %fdata.dir.joinPath(fdata.name) + result["id"] = %path.changeFileExt("") result["ext"] = %fdata.ext proc assetMetadata(f, dir: string): JsonNode = result = newJObject() - var fdata = f.splitFile - result["path"] = %f.replace(dir & DirSep, "") + let fdata = f.splitFile + let path = f.replace(dir & DirSep, "") + result["path"] = %path result["type"] = %"asset" - result["id"] = %fdata.dir.joinPath(fdata.name) + result["id"] = %path.changeFileExt("") result["ext"] = %fdata.ext +proc interpret(hs: HastySite, file: string, debugging = false) = + var i = newMinInterpreter(debugging, file, file.parentDir) + i.hastysite_module(hs) + i.interpret(newFileStream(file, fmRead)) + #### Main Functions proc newHastySite*(file: string): HastySite =

@@ -137,6 +247,7 @@ result.dirs.output = json.get("output", "output")

result.dirs.temp = json.get("temp", "temp") result.dirs.tempContents = result.dirs.temp / result.dirs.contents result.files.rules = json.get("rules", "rules.min") + result.files.scripts = json.get("scripts", "scripts.min") result.files.metadata = result.dirs.temp / "metadata.json" result.files.checksums = result.dirs.temp / "checksums.json"

@@ -156,6 +267,7 @@ let contents = toSeq(hs.dirs.tempContents.walkDirRec())

let assets = toSeq(hs.dirs.assets.walkDirRec()) let assetDir = hs.dirs.assets let contentDir = hs.dirs.tempContents + hs.metadata = hs.files.metadata.parseFile let meta = hs.metadata let modContentFiles = filter(contents) do (f: string) -> bool: checkContent(contentDir, f, cs) let modAssetFiles = filter(assets) do (f: string) -> bool: checkAsset(assetDir, f, cs)

@@ -175,6 +287,7 @@ for key, value in json.pairs:

createDir(dir/value.getStr) json["title"] = %"My Web Site" json["rules"] = %"rules.min" + json["scripts"] = %"scripts.min" writeFile(dir/json["rules"].getStr, "") writeFile(dir/"settings.json", json.pretty)

@@ -184,54 +297,12 @@

proc build*(hs: var HastySite) = echo "Preprocessing..." hs.preprocess() + echo "Detecting changes..." hs.detectChanges() - # TODO - echo hs.files.modified - -#### MiNiM Library - -proc hastysite_module*(i: In, hs: HastySite) = - i.define("hastysite") - - .symbol("metadata") do (i: In): - i.push i.fromJson(hs.metadata) - - .symbol("settings") do (i: In): - i.push i.fromJson(hs.settings) - - .symbol("modified") do (i: In): - var modified = newSeq[MinValue](0) - for j in hs.files.modified: - modified.add i.fromJson(j) - i.push modified.newVal(i.scope) - - .symbol("output") do (i: In): - i.push hs.dirs.output.newVal - - .symbol("mustache") do (i: In): - var t, c: MinValue - i.reqQuotationAndString c, t - if not c.isDictionary: - raise DictionaryRequiredException(msg: "No dictionary provided as template context.") - let ctx = newContext(%c) - let tplname = t.getString & ".mustache" - let tpl = readFile(hs.dirs.templates/tplname) - i.push tpl.render(ctx, hs.dirs.templates).newval + echo "Processing rules..." + hs.interpret(hs.files.rules) + echo "All done." - .symbol("markdown") do (i: In): - var t, c: MinValue - i.reqQuotationAndString c, t - if not c.isDictionary: - raise DictionaryRequiredException(msg: "No dictionary provided for markdown processor fields.") - let options = HastyOptions(toc: false, output: nil, css: nil, watermark: nil, fragment: true) - var fields = initTable[string, proc():string]() - for items in c.qVal: - fields[c.qVal[0].getString] = proc(): string = return $$c.qVal[1] - var hastyscribe = newHastyScribe(options, fields) - i.push hastyscribe.compileFragment(t.getString).newVal - - .finalize() - when isMainModule: import
M vendor/moustachu.nimvendor/moustachu.nim

@@ -177,7 +177,6 @@ indentation = token.value

renderings.add(indentation) of TokenType.partial: - echo pwd var partialTemplate = pwd.joinPath(token.value & ".mustache").readFile partialTemplate = partialTemplate.replace("\n", "\n" & indentation) if indentation != "":