mirror of
https://github.com/sbrow/thor.git
synced 2026-08-26 11:23:32 -04:00
120 lines
2.9 KiB
Odin
120 lines
2.9 KiB
Odin
package main
|
|
|
|
import "core:encoding/json"
|
|
import "core:log"
|
|
import "core:strings"
|
|
|
|
Frontmatter :: struct {
|
|
title: string,
|
|
description: string,
|
|
date: string,
|
|
lastmod: string,
|
|
publishDate: string,
|
|
weight: Maybe(int),
|
|
menus: json.Value,
|
|
params: json.Value,
|
|
layout: string,
|
|
og: Open_Graph,
|
|
draft: bool,
|
|
}
|
|
|
|
// parse_frontmatter splits raw file content into a Frontmatter struct and the
|
|
// remaining markdown body. The frontmatter is a JSON object delimited by { }
|
|
// at the start of the file.
|
|
parse_frontmatter :: proc(content: string) -> (fm: Frontmatter, body: string, ok: bool) {
|
|
body = content
|
|
|
|
if !strings.has_prefix(content, "{\n") {
|
|
return
|
|
}
|
|
end := strings.index(content, "\n}\n")
|
|
if end < 0 {
|
|
return
|
|
} else {
|
|
end += 2
|
|
}
|
|
|
|
json_str := content[:end + 1]
|
|
body = strings.trim_left(content[end + 1:], " \t\r\n")
|
|
|
|
value, err := json.parse_string(json_str, spec = .JSON)
|
|
if err != nil {
|
|
log.errorf("failed to parse frontmatter JSON: %v", err)
|
|
return
|
|
}
|
|
defer json.destroy_value(value)
|
|
|
|
obj, ok2 := value.(json.Object)
|
|
if !ok2 {
|
|
return
|
|
}
|
|
|
|
fm.title = json_get_string(obj, "title")
|
|
fm.description = json_get_string(obj, "description")
|
|
fm.date = json_get_string(obj, "date")
|
|
fm.lastmod = json_get_string(obj, "lastmod")
|
|
fm.publishDate = json_get_string(obj, "publishDate")
|
|
fm.weight = json_get_int(obj, "weight")
|
|
fm.draft = json_get_bool(obj, "draft")
|
|
if v, ok := obj["menus"]; ok {
|
|
fm.menus = v
|
|
}
|
|
fm.layout = json_get_string(obj, "layout")
|
|
fm.og = json_get_open_graph(obj, "og")
|
|
if v, ok := obj["params"]; ok { fm.params = v }
|
|
|
|
ok = true
|
|
return
|
|
}
|
|
|
|
json_get_string :: proc(obj: json.Object, key: string) -> string {
|
|
if v, ok := obj[key]; ok {
|
|
if s, ok2 := v.(json.String); ok2 {
|
|
return strings.clone(s)
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
json_get_bool :: proc(obj: json.Object, key: string) -> bool {
|
|
if v, ok := obj[key]; ok {
|
|
if b, ok2 := v.(json.Boolean); ok2 {
|
|
return b
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
json_get_int :: proc(obj: json.Object, key: string) -> Maybe(int) {
|
|
if v, ok := obj[key]; ok {
|
|
switch val in v {
|
|
case json.Integer:
|
|
return int(val)
|
|
case json.Float:
|
|
return int(val)
|
|
case json.Boolean, json.String, json.Array, json.Object, json.Null:
|
|
return nil
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
json_get_open_graph :: proc(obj: json.Object, key: string) -> Open_Graph {
|
|
og: Open_Graph
|
|
if v, ok := obj[key]; ok {
|
|
if inner, ok2 := v.(json.Object); ok2 {
|
|
og.title = json_get_string(inner, "title")
|
|
og.type = json_get_string(inner, "type")
|
|
og.image = json_get_string(inner, "image")
|
|
og.url = json_get_string(inner, "url")
|
|
og.description = json_get_string(inner, "description")
|
|
og.locale = json_get_string(inner, "locale")
|
|
og.site_name = json_get_string(inner, "site_name")
|
|
og.published_time = json_get_string(inner, "published_time")
|
|
og.modified_time = json_get_string(inner, "modified_time")
|
|
og.section = json_get_string(inner, "section")
|
|
}
|
|
}
|
|
return og
|
|
}
|