code wiki / (root) / nx_build_site.nx

nx_build_site.nx source

↩ module page · 546 lines · 22971 B

1// nx_build_site.nx -- bits-up site builder. Replaces 2// nishi-pages/build/build.py (530 LOC Python) with NishiLang 3// substrate. Per user *"no python nothing but nishi from bits up"*. 4// 5// Pipeline: 6// 1. Read content/site.yaml -> NxYamlDoc site vars (lifted to site.*) 7// 2. Read theme templates: layout.html, index.html, post.html, page.html 8// 3. For each .md in content/posts/: 9// nx_build_doc round-trip 10// emit a post-summary HTML block (for the homepage posts list) 11// write dist/posts/<slug>.html 12// 4. For each .md in content/pages/: 13// nx_build_doc round-trip with PAGE template 14// write dist/pages/<slug>.html 15// 5. Build the homepage: 16// substitute site.* + posts_html (concatenated summaries) 17// wrap with layout.html 18// write dist/index.html 19// 20// What this v1 does NOT do (queued): 21// - Dynamic directory walking (uses a hardcoded list of slugs) 22// - dist/404.html generation 23// - style.css copy to dist/assets/ 24// - server/pages.nx route emit 25// These are easy follow-ups that compose with what's here. 26// 27// Memory budget (one rendering pass): 28// ~64K per .md scratch 29// ~32K per template 30// ~256K total site arena 31// 32// nx_safety_envelope: 33// intended_use: sovereign substrate builder for nishi-pages 34// sil_target: SIL2 35// evidence: bench/nx_build_site_smoke.nx renders a fixture 36// tree end-to-end and asserts output bytes 37// verdict: NOT_YET_EVALUATED -- pending smoke 38 39import "nx_syscalls_x86_64.nx" 40import "nx_yaml_subset.nx" 41import "nx_frontmatter.nx" 42import "nx_http_template.nx" 43import "nx_md_render.nx" 44import "nx_build_doc.nx" 45 46// ---- Sealed verdicts ---- 47 48const NX_BS_OK: i64 = 0 49const NX_BS_BAD_INPUT: i64 = 1 50const NX_BS_READ_FAIL: i64 = 2 51const NX_BS_WRITE_FAIL: i64 = 3 52const NX_BS_RENDER_FAIL: i64 = 4 53const NX_BS_PATH_TOO_LONG: i64 = 5 54const NX_BS_VERDICT_N: i64 = 6 55 56// ---- Path scratch sizing ---- 57 58const NX_BS_PATH_CAP: i64 = 512 59const NX_BS_HTML_CAP: i64 = 65536 // 64K per rendered page 60 61// ---- Helpers ---- 62 63func _bs_bcopy(dst: *u8, dst_off: i64, dst_cap: i64, 64 src: *u8, src_n: i64) -> i64 { 65 if dst_off + src_n > dst_cap { return -1 } 66 var i: i64 = 0 67 while i < src_n { 68 dst[dst_off + i] = src[i] 69 i = i + 1 70 } 71 return dst_off + src_n 72} 73 74// Join path components: out = base + "/" + name + suffix. Returns 75// resulting length, or -1 on overflow. Caller pre-allocates out 76// with at least NX_BS_PATH_CAP capacity. 77func nx_bs_join(out: *u8, out_cap: i64, 78 base: *u8, base_n: i64, 79 name: *u8, name_n: i64, 80 suffix: *u8, suffix_n: i64) -> i64 { 81 let want: i64 = base_n + 1 + name_n + suffix_n 82 if want >= out_cap { return -1 } 83 var p: i64 = 0 84 var i: i64 = 0 85 while i < base_n { out[p] = base[i]; p = p + 1; i = i + 1 } 86 out[p] = 47; p = p + 1 // '/' 87 var j: i64 = 0 88 while j < name_n { out[p] = name[j]; p = p + 1; j = j + 1 } 89 var k: i64 = 0 90 while k < suffix_n { out[p] = suffix[k]; p = p + 1; k = k + 1 } 91 out[p] = 0 // NUL-terminate for syscalls 92 return p 93} 94 95// Read whole file into a freshly-mmap'd buffer. Returns buf + sets 96// *out_n; returns NULL on read failure. Composes with sys_read_file_x86_64 97// but adds path-as-bytes helper. 98func nx_bs_read_file(path: *u8, out_n: *i64) -> *u8 { 99 let buf: *u8 = sys_read_file_x86_64(path, out_n) 100 return buf 101} 102 103// Write buf+n to path. Returns 0/-errno. 104func nx_bs_write_file(path: *u8, buf: *u8, n: i64) -> i64 { 105 let fd: i64 = sys_openat_wr(path, 0x1A4) // 0644 106 if fd < 0 { return fd } 107 let wn: i64 = sys_write(fd, buf, n) 108 sys_close(fd) 109 if wn != n { return -1 } 110 return 0 111} 112 113// ---- Per-doc render ---- 114// 115// Renders ONE .md file by reading source, splitting frontmatter, 116// parsing YAML, populating vars, applying inner_tmpl + layout_tmpl. 117// Caller passes site_yaml + slug + which inner template (post or page). 118// Writes the rendered HTML to `out_html_buf` (caller-provided); 119// returns the byte count or -err. 120 121func nx_bs_render_doc(md_path: *u8, 122 site_yaml: *NxYamlDoc, 123 slug: *u8, slug_n: i64, 124 inner_tmpl: *u8, inner_n: i64, 125 layout_tmpl: *u8, layout_n: i64, 126 out_html_buf: *u8, out_html_cap: i64) -> i64 { 127 // 1. Read source. 128 let src_n: *i64 = sys_mmap(16) as *i64 129 let src: *u8 = nx_bs_read_file(md_path, src_n) 130 if src as i64 == 0 { return NX_BS_READ_FAIL } 131 132 // 2. Split frontmatter. 133 let yoff: *i64 = sys_mmap(16) as *i64 134 let ylen: *i64 = sys_mmap(16) as *i64 135 let boff: *i64 = sys_mmap(16) as *i64 136 let blen: *i64 = sys_mmap(16) as *i64 137 let fmv: i64 = nx_frontmatter_split(src, src_n[0], yoff, ylen, boff, blen) 138 if fmv != NX_FM_OK { return NX_BS_RENDER_FAIL } 139 140 // 3. Parse YAML frontmatter. 141 let entries: *NxYamlEntry = sys_mmap(NX_YAML_ENTRY_BYTES * 16) as *NxYamlEntry 142 let ykeys: *u8 = sys_mmap(512) 143 let yvals: *u8 = sys_mmap(2048) 144 let yd: *NxYamlDoc = sys_mmap(NX_YAML_DOC_BYTES) as *NxYamlDoc 145 nx_yaml_doc_init(yd, entries, 16, ykeys, 512, yvals, 2048) 146 let ybytes: *u8 = (src as i64 + yoff[0]) as *u8 147 let yv: i64 = nx_yaml_parse(yd, ybytes, ylen[0]) 148 if yv != NX_YAML_OK { return NX_BS_RENDER_FAIL } 149 150 // 4. Build inner var table. 151 let bv: *NxBuildVars = sys_mmap(NX_BUILD_VARS_BYTES) as *NxBuildVars 152 nx_build_vars_init(bv) 153 if nx_build_vars_add_yaml(bv, "page." as *u8, 5, yd) != 0 { return NX_BS_RENDER_FAIL } 154 if nx_build_vars_add_yaml(bv, "site." as *u8, 5, site_yaml) != 0 { return NX_BS_RENDER_FAIL } 155 if nx_build_vars_add(bv, "slug" as *u8, 4, slug, slug_n) != 0 { return NX_BS_RENDER_FAIL } 156 157 // Render markdown body -> HTML via nx_md_render (sovereign substrate). 158 // The inner template substitutes {{ body | raw }} so the HTML is 159 // emitted verbatim (no double-escape). 160 let bptr: *u8 = (src as i64 + boff[0]) as *u8 161 let body_html: *u8 = sys_mmap(NX_BS_HTML_CAP) 162 let body_html_n: i64 = nx_md_render(bptr, blen[0], body_html) 163 if nx_build_vars_add(bv, "body" as *u8, 4, body_html, body_html_n) != 0 { return NX_BS_RENDER_FAIL } 164 165 // 5. Apply inner template. 166 let inner_buf: *u8 = sys_mmap(NX_BS_HTML_CAP) 167 let inner_out_n: *i64 = sys_mmap(16) as *i64 168 if nx_build_apply_template(inner_tmpl, inner_n, bv, 169 inner_buf, NX_BS_HTML_CAP, inner_out_n) != NXT_OK { 170 return NX_BS_RENDER_FAIL 171 } 172 173 // 6. Build OUTER var table (vars get sealed at seal-time so we need 174 // a fresh table with `content` added). 175 let bv2: *NxBuildVars = sys_mmap(NX_BUILD_VARS_BYTES) as *NxBuildVars 176 nx_build_vars_init(bv2) 177 if nx_build_vars_add_yaml(bv2, "page." as *u8, 5, yd) != 0 { return NX_BS_RENDER_FAIL } 178 if nx_build_vars_add_yaml(bv2, "site." as *u8, 5, site_yaml) != 0 { return NX_BS_RENDER_FAIL } 179 if nx_build_vars_add(bv2, "content" as *u8, 7, inner_buf, inner_out_n[0]) != 0 { return NX_BS_RENDER_FAIL } 180 181 // 7. Apply layout. 182 let final_n: *i64 = sys_mmap(16) as *i64 183 if nx_build_apply_template(layout_tmpl, layout_n, bv2, 184 out_html_buf, out_html_cap, final_n) != NXT_OK { 185 return NX_BS_RENDER_FAIL 186 } 187 188 return final_n[0] 189} 190 191// ---- Build site driver ---- 192// 193// Walks a HARDCODED list of slugs (v1; dynamic walk via nx_dir is 194// queued). Caller passes: 195// base_dir = path to nishi-pages root 196// post_slugs[] = list of post slug strings (NUL-terminated) 197// n_post_slugs 198// page_slugs[] = list of page slug strings 199// n_page_slugs 200// 201// For each slug, reads content/posts/<slug>.md (or pages/), renders, 202// writes to dist/posts/<slug>.html (or dist/pages/). Then builds 203// the homepage by reading themes/default/index.html, substituting 204// site.* vars + a pre-built posts_html block, wrapping with layout. 205 206// Read the four theme templates into mmap'd buffers + return them via 207// out-pointers. Returns 0 on OK or NX_BS_READ_FAIL. 208func nx_bs_load_theme(base_dir: *u8, base_n: i64, 209 layout_out: **u8, layout_n_out: *i64, 210 index_out: **u8, index_n_out: *i64, 211 post_out: **u8, post_n_out: *i64, 212 page_out: **u8, page_n_out: *i64) -> i64 { 213 let path: *u8 = sys_mmap(NX_BS_PATH_CAP) 214 215 nx_bs_join(path, NX_BS_PATH_CAP, base_dir, base_n, 216 "themes/default" as *u8, 14, "/layout.html" as *u8, 12) 217 let l: *u8 = nx_bs_read_file(path, layout_n_out) 218 if l as i64 == 0 { return NX_BS_READ_FAIL } 219 layout_out[0] = l 220 221 nx_bs_join(path, NX_BS_PATH_CAP, base_dir, base_n, 222 "themes/default" as *u8, 14, "/index.html" as *u8, 11) 223 let i_tmpl: *u8 = nx_bs_read_file(path, index_n_out) 224 if i_tmpl as i64 == 0 { return NX_BS_READ_FAIL } 225 index_out[0] = i_tmpl 226 227 nx_bs_join(path, NX_BS_PATH_CAP, base_dir, base_n, 228 "themes/default" as *u8, 14, "/post.html" as *u8, 10) 229 let p_tmpl: *u8 = nx_bs_read_file(path, post_n_out) 230 if p_tmpl as i64 == 0 { return NX_BS_READ_FAIL } 231 post_out[0] = p_tmpl 232 233 nx_bs_join(path, NX_BS_PATH_CAP, base_dir, base_n, 234 "themes/default" as *u8, 14, "/page.html" as *u8, 10) 235 let pg_tmpl: *u8 = nx_bs_read_file(path, page_n_out) 236 if pg_tmpl as i64 == 0 { return NX_BS_READ_FAIL } 237 page_out[0] = pg_tmpl 238 239 return NX_BS_OK 240} 241 242// Read site.yaml from base_dir/content/site.yaml. Returns parsed 243// NxYamlDoc or NULL on fail. 244func nx_bs_load_site_yaml(base_dir: *u8, base_n: i64) -> *NxYamlDoc { 245 let path: *u8 = sys_mmap(NX_BS_PATH_CAP) 246 nx_bs_join(path, NX_BS_PATH_CAP, base_dir, base_n, 247 "content" as *u8, 7, "/site.yaml" as *u8, 10) 248 let y_n: *i64 = sys_mmap(16) as *i64 249 let y_bytes: *u8 = nx_bs_read_file(path, y_n) 250 if y_bytes as i64 == 0 { return 0 as *NxYamlDoc } 251 252 let entries: *NxYamlEntry = sys_mmap(NX_YAML_ENTRY_BYTES * 16) as *NxYamlEntry 253 let keys: *u8 = sys_mmap(1024) 254 let vals: *u8 = sys_mmap(2048) 255 let doc: *NxYamlDoc = sys_mmap(NX_YAML_DOC_BYTES) as *NxYamlDoc 256 nx_yaml_doc_init(doc, entries, 16, keys, 1024, vals, 2048) 257 if nx_yaml_parse(doc, y_bytes, y_n[0]) != NX_YAML_OK { return 0 as *NxYamlDoc } 258 return doc 259} 260 261// Render one post: read content/posts/<slug>.md, apply post + layout, 262// write to dist/posts/<slug>.html. 263func nx_bs_render_one_post(base_dir: *u8, base_n: i64, 264 slug: *u8, slug_n: i64, 265 site_yaml: *NxYamlDoc, 266 post_tmpl: *u8, post_n: i64, 267 layout_tmpl: *u8, layout_n: i64) -> i64 { 268 let src_path: *u8 = sys_mmap(NX_BS_PATH_CAP) 269 // base_dir/content/posts/<slug>.md 270 var p: i64 = 0 271 p = _bs_bcopy(src_path, p, NX_BS_PATH_CAP, base_dir, base_n) 272 p = _bs_bcopy(src_path, p, NX_BS_PATH_CAP, "/content/posts/" as *u8, 15) 273 p = _bs_bcopy(src_path, p, NX_BS_PATH_CAP, slug, slug_n) 274 p = _bs_bcopy(src_path, p, NX_BS_PATH_CAP, ".md" as *u8, 3) 275 src_path[p] = 0 276 277 let final_html: *u8 = sys_mmap(NX_BS_HTML_CAP) 278 let n: i64 = nx_bs_render_doc(src_path, site_yaml, 279 slug, slug_n, 280 post_tmpl, post_n, 281 layout_tmpl, layout_n, 282 final_html, NX_BS_HTML_CAP) 283 if n < 0 { return n } 284 285 let out_path: *u8 = sys_mmap(NX_BS_PATH_CAP) 286 var q: i64 = 0 287 q = _bs_bcopy(out_path, q, NX_BS_PATH_CAP, base_dir, base_n) 288 q = _bs_bcopy(out_path, q, NX_BS_PATH_CAP, "/dist/posts/" as *u8, 12) 289 q = _bs_bcopy(out_path, q, NX_BS_PATH_CAP, slug, slug_n) 290 q = _bs_bcopy(out_path, q, NX_BS_PATH_CAP, ".html" as *u8, 5) 291 out_path[q] = 0 292 293 return nx_bs_write_file(out_path, final_html, n) 294} 295 296// ---- Post summary builder ---- 297// 298// Emits ONE <article class="post-summary">...</article> chunk for 299// the homepage's posts-list section. Caller passes the post's 300// slug + parsed-frontmatter NxYamlDoc; this helper looks up title, 301// date, description and appends the HTML chunk to `out` at offset 302// `out_off`. Returns new offset, or -1 on overflow. 303 304func nx_bs_append_post_summary(out: *u8, out_off: i64, out_cap: i64, 305 slug: *u8, slug_n: i64, 306 yaml: *NxYamlDoc) -> i64 { 307 let off1: *i64 = sys_mmap(16) as *i64 308 let len1: *i64 = sys_mmap(16) as *i64 309 let off2: *i64 = sys_mmap(16) as *i64 310 let len2: *i64 = sys_mmap(16) as *i64 311 let off3: *i64 = sys_mmap(16) as *i64 312 let len3: *i64 = sys_mmap(16) as *i64 313 314 let has_title: i64 = nx_yaml_lookup(yaml, "title" as *u8, 5, off1, len1) 315 let has_date: i64 = nx_yaml_lookup(yaml, "date" as *u8, 4, off2, len2) 316 let has_desc: i64 = nx_yaml_lookup(yaml, "description" as *u8, 11, off3, len3) 317 318 var p: i64 = out_off 319 p = _bs_bcopy(out, p, out_cap, "<article class=\"post-summary\">\n <h3><a href=\"/posts/" as *u8, 55) 320 if p < 0 { return -1 } 321 p = _bs_bcopy(out, p, out_cap, slug, slug_n) 322 if p < 0 { return -1 } 323 p = _bs_bcopy(out, p, out_cap, "\">" as *u8, 2) 324 if p < 0 { return -1 } 325 if has_title == 1 { 326 let title_ptr: *u8 = (yaml.values as i64 + off1[0]) as *u8 327 p = _bs_bcopy(out, p, out_cap, title_ptr, len1[0]) 328 if p < 0 { return -1 } 329 } 330 p = _bs_bcopy(out, p, out_cap, "</a></h3>\n <time datetime=\"" as *u8, 30) 331 if p < 0 { return -1 } 332 if has_date == 1 { 333 let date_ptr: *u8 = (yaml.values as i64 + off2[0]) as *u8 334 p = _bs_bcopy(out, p, out_cap, date_ptr, len2[0]) 335 if p < 0 { return -1 } 336 p = _bs_bcopy(out, p, out_cap, "\">" as *u8, 2) 337 if p < 0 { return -1 } 338 p = _bs_bcopy(out, p, out_cap, date_ptr, len2[0]) 339 if p < 0 { return -1 } 340 } 341 p = _bs_bcopy(out, p, out_cap, "</time>\n <p>" as *u8, 15) 342 if p < 0 { return -1 } 343 if has_desc == 1 { 344 let desc_ptr: *u8 = (yaml.values as i64 + off3[0]) as *u8 345 p = _bs_bcopy(out, p, out_cap, desc_ptr, len3[0]) 346 if p < 0 { return -1 } 347 } 348 p = _bs_bcopy(out, p, out_cap, "</p>\n </article>\n " as *u8, 20) 349 if p < 0 { return -1 } 350 return p 351} 352 353// Read a post's frontmatter into out_yaml (caller-allocated NxYamlDoc). 354// Returns NX_BS_OK or -err. Body is ignored (caller doesn't need it). 355func nx_bs_load_post_yaml(base_dir: *u8, base_n: i64, 356 slug: *u8, slug_n: i64, 357 out_yaml: *NxYamlDoc) -> i64 { 358 let path: *u8 = sys_mmap(NX_BS_PATH_CAP) 359 var p: i64 = 0 360 p = _bs_bcopy(path, p, NX_BS_PATH_CAP, base_dir, base_n) 361 p = _bs_bcopy(path, p, NX_BS_PATH_CAP, "/content/posts/" as *u8, 15) 362 p = _bs_bcopy(path, p, NX_BS_PATH_CAP, slug, slug_n) 363 p = _bs_bcopy(path, p, NX_BS_PATH_CAP, ".md" as *u8, 3) 364 path[p] = 0 365 366 let src_n: *i64 = sys_mmap(16) as *i64 367 let src: *u8 = nx_bs_read_file(path, src_n) 368 if src as i64 == 0 { return NX_BS_READ_FAIL } 369 370 let yoff: *i64 = sys_mmap(16) as *i64 371 let ylen: *i64 = sys_mmap(16) as *i64 372 let boff: *i64 = sys_mmap(16) as *i64 373 let blen: *i64 = sys_mmap(16) as *i64 374 if nx_frontmatter_split(src, src_n[0], yoff, ylen, boff, blen) != NX_FM_OK { 375 return NX_BS_RENDER_FAIL 376 } 377 378 let ybytes: *u8 = (src as i64 + yoff[0]) as *u8 379 if nx_yaml_parse(out_yaml, ybytes, ylen[0]) != NX_YAML_OK { return NX_BS_RENDER_FAIL } 380 return NX_BS_OK 381} 382 383// ---- Homepage rendering ---- 384// 385// Builds dist/index.html. Iterates the post-slugs list (caller- 386// provided concatenated names + lengths array), reads each post's 387// frontmatter, appends one summary chunk to a posts_html buffer, 388// then renders index.html with site.* + posts_html, wraps with 389// layout.html. 390 391func nx_bs_render_homepage(base_dir: *u8, base_n: i64, 392 site_yaml: *NxYamlDoc, 393 index_tmpl: *u8, index_n: i64, 394 layout_tmpl: *u8, layout_n: i64, 395 post_slug_ptrs: **u8, 396 post_slug_lens: *i64, 397 n_posts: i64) -> i64 { 398 // 1. Build posts_html by iterating posts. 399 let posts_html: *u8 = sys_mmap(16384) 400 var posts_off: i64 = 0 401 var i: i64 = 0 402 while i < n_posts { 403 // Per-post yaml + entries. 404 let entries: *NxYamlEntry = sys_mmap(NX_YAML_ENTRY_BYTES * 16) as *NxYamlEntry 405 let keys: *u8 = sys_mmap(512) 406 let vals: *u8 = sys_mmap(2048) 407 let yd: *NxYamlDoc = sys_mmap(NX_YAML_DOC_BYTES) as *NxYamlDoc 408 nx_yaml_doc_init(yd, entries, 16, keys, 512, vals, 2048) 409 410 let slug_ptr: *u8 = post_slug_ptrs[i] 411 let slug_n: i64 = post_slug_lens[i] 412 if nx_bs_load_post_yaml(base_dir, base_n, slug_ptr, slug_n, yd) != NX_BS_OK { 413 return NX_BS_RENDER_FAIL 414 } 415 let new_off: i64 = nx_bs_append_post_summary(posts_html, posts_off, 16384, 416 slug_ptr, slug_n, yd) 417 if new_off < 0 { return NX_BS_RENDER_FAIL } 418 posts_off = new_off 419 i = i + 1 420 } 421 422 // 2. Build inner var table for index.html. 423 let bv: *NxBuildVars = sys_mmap(NX_BUILD_VARS_BYTES) as *NxBuildVars 424 nx_build_vars_init(bv) 425 if nx_build_vars_add_yaml(bv, "site." as *u8, 5, site_yaml) != 0 { return NX_BS_RENDER_FAIL } 426 if nx_build_vars_add(bv, "page.title" as *u8, 10, "Nishi Family" as *u8, 12) != 0 { return NX_BS_RENDER_FAIL } 427 if nx_build_vars_add(bv, "page.description" as *u8, 16, "Nishi Family home" as *u8, 17) != 0 { return NX_BS_RENDER_FAIL } 428 if nx_build_vars_add(bv, "posts_html" as *u8, 10, posts_html, posts_off) != 0 { return NX_BS_RENDER_FAIL } 429 430 // 3. Render index.html inner. 431 let inner_buf: *u8 = sys_mmap(NX_BS_HTML_CAP) 432 let inner_n: *i64 = sys_mmap(16) as *i64 433 if nx_build_apply_template(index_tmpl, index_n, bv, 434 inner_buf, NX_BS_HTML_CAP, inner_n) != NXT_OK { 435 return NX_BS_RENDER_FAIL 436 } 437 438 // 4. Wrap with layout. 439 let bv2: *NxBuildVars = sys_mmap(NX_BUILD_VARS_BYTES) as *NxBuildVars 440 nx_build_vars_init(bv2) 441 if nx_build_vars_add_yaml(bv2, "site." as *u8, 5, site_yaml) != 0 { return NX_BS_RENDER_FAIL } 442 if nx_build_vars_add(bv2, "page.title" as *u8, 10, "Nishi Family" as *u8, 12) != 0 { return NX_BS_RENDER_FAIL } 443 if nx_build_vars_add(bv2, "page.description" as *u8, 16, "Nishi Family home" as *u8, 17) != 0 { return NX_BS_RENDER_FAIL } 444 if nx_build_vars_add(bv2, "content" as *u8, 7, inner_buf, inner_n[0]) != 0 { return NX_BS_RENDER_FAIL } 445 446 let final_buf: *u8 = sys_mmap(NX_BS_HTML_CAP) 447 let final_n: *i64 = sys_mmap(16) as *i64 448 if nx_build_apply_template(layout_tmpl, layout_n, bv2, 449 final_buf, NX_BS_HTML_CAP, final_n) != NXT_OK { 450 return NX_BS_RENDER_FAIL 451 } 452 453 // 5. Write dist/index.html. 454 let out_path: *u8 = sys_mmap(NX_BS_PATH_CAP) 455 var q: i64 = 0 456 q = _bs_bcopy(out_path, q, NX_BS_PATH_CAP, base_dir, base_n) 457 q = _bs_bcopy(out_path, q, NX_BS_PATH_CAP, "/dist/index.html" as *u8, 16) 458 out_path[q] = 0 459 460 return nx_bs_write_file(out_path, final_buf, final_n[0]) 461} 462 463// ---- dist/404.html ---- 464 465func nx_bs_render_404(base_dir: *u8, base_n: i64, 466 site_yaml: *NxYamlDoc, 467 layout_tmpl: *u8, layout_n: i64) -> i64 { 468 let body: *u8 = "<section><h1>404</h1><p>This page has not been written yet.</p></section>" as *u8 469 let body_n: i64 = 72 470 471 let bv: *NxBuildVars = sys_mmap(NX_BUILD_VARS_BYTES) as *NxBuildVars 472 nx_build_vars_init(bv) 473 nx_build_vars_add_yaml(bv, "site." as *u8, 5, site_yaml) 474 nx_build_vars_add(bv, "page.title" as *u8, 10, "Not Found" as *u8, 9) 475 nx_build_vars_add(bv, "page.description" as *u8, 16, "Page not found." as *u8, 15) 476 nx_build_vars_add(bv, "content" as *u8, 7, body, body_n) 477 478 let final_buf: *u8 = sys_mmap(NX_BS_HTML_CAP) 479 let final_n: *i64 = sys_mmap(16) as *i64 480 if nx_build_apply_template(layout_tmpl, layout_n, bv, 481 final_buf, NX_BS_HTML_CAP, final_n) != NXT_OK { 482 return NX_BS_RENDER_FAIL 483 } 484 485 let out_path: *u8 = sys_mmap(NX_BS_PATH_CAP) 486 var q: i64 = 0 487 q = _bs_bcopy(out_path, q, NX_BS_PATH_CAP, base_dir, base_n) 488 q = _bs_bcopy(out_path, q, NX_BS_PATH_CAP, "/dist/404.html" as *u8, 14) 489 out_path[q] = 0 490 491 return nx_bs_write_file(out_path, final_buf, final_n[0]) 492} 493 494// ---- Asset copy: themes/default/style.css -> dist/assets/style.css ---- 495 496func nx_bs_copy_style_css(base_dir: *u8, base_n: i64) -> i64 { 497 let src_path: *u8 = sys_mmap(NX_BS_PATH_CAP) 498 var p: i64 = 0 499 p = _bs_bcopy(src_path, p, NX_BS_PATH_CAP, base_dir, base_n) 500 p = _bs_bcopy(src_path, p, NX_BS_PATH_CAP, "/themes/default/style.css" as *u8, 25) 501 src_path[p] = 0 502 503 let src_n: *i64 = sys_mmap(16) as *i64 504 let src: *u8 = nx_bs_read_file(src_path, src_n) 505 if src as i64 == 0 { return NX_BS_READ_FAIL } 506 507 let out_path: *u8 = sys_mmap(NX_BS_PATH_CAP) 508 var q: i64 = 0 509 q = _bs_bcopy(out_path, q, NX_BS_PATH_CAP, base_dir, base_n) 510 q = _bs_bcopy(out_path, q, NX_BS_PATH_CAP, "/dist/assets/style.css" as *u8, 22) 511 out_path[q] = 0 512 513 return nx_bs_write_file(out_path, src, src_n[0]) 514} 515 516func nx_bs_render_one_page(base_dir: *u8, base_n: i64, 517 slug: *u8, slug_n: i64, 518 site_yaml: *NxYamlDoc, 519 page_tmpl: *u8, page_n: i64, 520 layout_tmpl: *u8, layout_n: i64) -> i64 { 521 let src_path: *u8 = sys_mmap(NX_BS_PATH_CAP) 522 var p: i64 = 0 523 p = _bs_bcopy(src_path, p, NX_BS_PATH_CAP, base_dir, base_n) 524 p = _bs_bcopy(src_path, p, NX_BS_PATH_CAP, "/content/pages/" as *u8, 15) 525 p = _bs_bcopy(src_path, p, NX_BS_PATH_CAP, slug, slug_n) 526 p = _bs_bcopy(src_path, p, NX_BS_PATH_CAP, ".md" as *u8, 3) 527 src_path[p] = 0 528 529 let final_html: *u8 = sys_mmap(NX_BS_HTML_CAP) 530 let n: i64 = nx_bs_render_doc(src_path, site_yaml, 531 slug, slug_n, 532 page_tmpl, page_n, 533 layout_tmpl, layout_n, 534 final_html, NX_BS_HTML_CAP) 535 if n < 0 { return n } 536 537 let out_path: *u8 = sys_mmap(NX_BS_PATH_CAP) 538 var q: i64 = 0 539 q = _bs_bcopy(out_path, q, NX_BS_PATH_CAP, base_dir, base_n) 540 q = _bs_bcopy(out_path, q, NX_BS_PATH_CAP, "/dist/pages/" as *u8, 12) 541 q = _bs_bcopy(out_path, q, NX_BS_PATH_CAP, slug, slug_n) 542 q = _bs_bcopy(out_path, q, NX_BS_PATH_CAP, ".html" as *u8, 5) 543 out_path[q] = 0 544 545 return nx_bs_write_file(out_path, final_html, n) 546}