From bfd8bd7effe1669c96d27804ec6f699548b7a5d8 Mon Sep 17 00:00:00 2001 From: Spencer Brower <6729162+sbrow@users.noreply.github.com> Date: Fri, 31 Jul 2026 10:32:42 -0400 Subject: [PATCH] feat: Made `starred` no longer a priviledged value. --- TODOS.md | 2 ++ content.odin | 5 ++-- frontmatter.odin | 4 +-- render.odin | 24 ++++++++++++++--- site_test.odin | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 7 deletions(-) diff --git a/TODOS.md b/TODOS.md index a92b421..37f07c2 100644 --- a/TODOS.md +++ b/TODOS.md @@ -44,6 +44,8 @@ - [ ] improve json diagnostics. - i.e. "Missing quotes around string", etc. - [ ] don't use bullshit "sub-tokens", add filters and pipes as proper tokens. +- [ ] Ideas is now in the wrong spot. Date is wrong, and it is showing date + when it shouldn't be. ## Performance diff --git a/content.odin b/content.odin index 7f448c2..534ead9 100644 --- a/content.odin +++ b/content.odin @@ -5,6 +5,7 @@ import ts "treesitter" import "core:fmt" import "core:log" +import "core:encoding/json" import "core:os" import "core:strings" import "core:time" @@ -23,10 +24,10 @@ Page :: struct { weight: Maybe(int), lastmod: string, menus: map[string]Menu_Entry, + params: json.Value, content: string, og: Open_Graph, draft: bool, - starred: bool, _is_index: bool `private`, } @@ -257,7 +258,7 @@ load_page :: proc( page.weight = fm.weight page.lastmod = fm.lastmod page.draft = fm.draft - page.starred = fm.isStarred + page.params = fm.params if section == "" && is_index { page.permalink = "/" diff --git a/frontmatter.odin b/frontmatter.odin index 4a47ade..1c4970e 100644 --- a/frontmatter.odin +++ b/frontmatter.odin @@ -12,10 +12,10 @@ Frontmatter :: struct { publishDate: string, weight: Maybe(int), menus: json.Value, + params: json.Value, layout: string, og: Open_Graph, draft: bool, - isStarred: bool, } // parse_frontmatter splits raw file content into a Frontmatter struct and the @@ -56,12 +56,12 @@ parse_frontmatter :: proc(content: string) -> (fm: Frontmatter, body: string, ok fm.publishDate = json_get_string(obj, "publishDate") fm.weight = json_get_int(obj, "weight") fm.draft = json_get_bool(obj, "draft") - fm.isStarred = json_get_bool(obj, "isStarred") 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 diff --git a/render.odin b/render.odin index c15dfb4..a1bccf9 100644 --- a/render.odin +++ b/render.odin @@ -2,6 +2,7 @@ package main import "mustache" +import "core:encoding/json" import "core:fmt" import "core:log" import "core:os" @@ -15,6 +16,7 @@ Template_Context :: struct { date_format: string, timezone: ^datetime.TZ_Region, og: Open_Graph, + params: json.Value, site: Site_Context, menus: map[string][]Menu_Entry, page: Page, @@ -117,6 +119,19 @@ to_title_case :: proc(s: string, allocator := context.allocator) -> string { return string(out) } +merge_params :: proc(site, page: json.Value) -> json.Value { + if page == nil do return site + if site == nil do return page + site_obj, ok1 := site.(json.Object) + page_obj, ok2 := page.(json.Object) + if !ok1 do return page + if !ok2 do return site + merged := make(json.Object, len(site_obj) + len(page_obj), context.temp_allocator) + for k, v in site_obj { merged[k] = v } + for k, v in page_obj { merged[k] = v } + return merged +} + render_template :: proc( content_tpl: mustache.Template, ctx: Template_Context, @@ -195,7 +210,7 @@ render_site :: proc(site: ^Site) { continue } tpl := get_template(&site.vfs, page.layout, &template_cache) - html := render_page_html(page, site, tpl, partials, ctx, &seen) + html := render_page_html(page, site, tpl, partials, ctx, &errors) if .Minify in site.features { html = minify_html(html) } @@ -224,7 +239,7 @@ render_site :: proc(site: ^Site) { section_tpl, partials, ctx, - &seen, + &errors, ) if .Minify in site.features { html = minify_html(html) @@ -235,7 +250,7 @@ render_site :: proc(site: ^Site) { // Render home page if has_home { home_tpl := get_template(&site.vfs, "home", &template_cache) - home_html := render_home_html(home, site, home_tpl, partials, ctx, &seen) + home_html := render_home_html(home, site, home_tpl, partials, ctx, &errors) if .Minify in site.features { home_html = minify_html(home_html) } @@ -276,6 +291,7 @@ render_page_html :: proc( ctx.title = fmt.tprintf("%s | %s", page.title, site.title) ctx.page = page ctx.og = og_for_page(site.og, page) + ctx.params = merge_params(site.params, page.params) return render_template(content_tpl, ctx, partials, seen) } @@ -299,6 +315,7 @@ render_home_html :: proc( ctx.title = site.title ctx.pages = list_pages ctx.og = og_for_page(site.og, home) + ctx.params = merge_params(site.params, home.params) return render_template(content_tpl, ctx, partials, seen) } @@ -340,6 +357,7 @@ render_section :: proc( ctx.og.is_article = false } ctx.posts = posts + ctx.params = merge_params(site.params, ctx.page.params) return render_template(content_tpl, ctx, partials, seen) } diff --git a/site_test.odin b/site_test.odin index 9514d14..ba9c935 100644 --- a/site_test.odin +++ b/site_test.odin @@ -202,3 +202,70 @@ test_init_site_config_paths :: proc(t: ^testing.T) { testing.expect_value(t, site.output_dir, "/custom/output") testing.expect_value(t, site.layouts_dir, "/custom/layouts") } + +// --- merge_params tests --- + +@(test) +test_merge_params_both_present :: proc(t: ^testing.T) { + site_params, _ := json.parse_string(`{"social": [], "author": "Tester"}`, spec = .JSON) + page_params, _ := json.parse_string(`{"starred": true}`, spec = .JSON) + + merged_val := merge_params(site_params, page_params) + merged, ok := merged_val.(json.Object) + testing.expect(t, ok, "merged should be a json.Object") + + _, has_social := merged["social"] + testing.expect(t, has_social, "site param 'social' should survive merge") + + _, has_author := merged["author"] + testing.expect(t, has_author, "site param 'author' should survive merge") + + starred, has_starred := merged["starred"] + testing.expect(t, has_starred, "page param 'starred' should be present") + starred_bool, _ := starred.(json.Boolean) + testing.expect(t, bool(starred_bool), "starred should be true") +} + +@(test) +test_merge_params_nil_page :: proc(t: ^testing.T) { + site_params, _ := json.parse_string(`{"author": "Tester"}`, spec = .JSON) + + merged_val := merge_params(site_params, nil) + merged, ok := merged_val.(json.Object) + testing.expect(t, ok, "should return site params when page is nil") + + _, has_author := merged["author"] + testing.expect(t, has_author, "site param should survive") +} + +@(test) +test_merge_params_nil_site :: proc(t: ^testing.T) { + page_params, _ := json.parse_string(`{"starred": true}`, spec = .JSON) + + merged_val := merge_params(nil, page_params) + merged, ok := merged_val.(json.Object) + testing.expect(t, ok, "should return page params when site is nil") + + _, has_starred := merged["starred"] + testing.expect(t, has_starred, "page param should survive") +} + +@(test) +test_merge_params_both_nil :: proc(t: ^testing.T) { + merged_val := merge_params(nil, nil) + testing.expect(t, merged_val == nil, "both nil should return nil") +} + +@(test) +test_merge_params_page_overrides_site :: proc(t: ^testing.T) { + site_params, _ := json.parse_string(`{"key": "site_value"}`, spec = .JSON) + page_params, _ := json.parse_string(`{"key": "page_value"}`, spec = .JSON) + + merged_val := merge_params(site_params, page_params) + merged, ok := merged_val.(json.Object) + testing.expect(t, ok) + + val := merged["key"] + str, _ := val.(json.String) + testing.expect_value(t, string(str), "page_value") +}