code wiki / _hdl_build / nx_web_render.nx
nx_web_render.nx source
↩ module page · 82 lines · 5474 B
1// nx_web_render.nx -- LIB: the WEB domain CONSUMER for the Nishi builder. Resolves web components from the
2// universal catalog by id and substitutes {KEY} bindings into live, sovereign HTML (no JS, no external fetch),
3// and composes a full page from several components. Closes the web loop: build -> teach -> grow -> CONSUME.
4// Boundary defense (rule 12): binding VALUES are HTML-escaped, so page data can't inject markup. license_tier: ORIGINAL
5import "nx_nishi_builder.nx"
6import "nx_ad_serve.nx"
7import "nx_syscalls.nx"
8
9// 1 if hay[i..] == key followed by '='.
10func nw_keyeq(hay: *u8, i: i64, key: *u8) -> i64 {
11 var j: i64 = 0
12 while key[j] != (0 as u8) { if hay[i+j] != key[j] { return 0 } j = j + 1 }
13 if hay[i+j] != (61 as u8) { return 0 }
14 return 1
15}
16// look up KEY in a "k1=v1|k2=v2|..." bindings string -> out (value until '|' or end). 1 found, 0 not.
17func nw_bind_get(bindings: *u8, key: *u8, out: *u8, cap: i64) -> i64 {
18 let kl: i64 = as_len(key)
19 var i: i64 = 0; var run: i64 = 1; var found: i64 = 0
20 while run == 1 {
21 if bindings[i] == (0 as u8) { run = 0 } else {
22 var boundary: i64 = 0
23 if i == 0 { boundary = 1 } else { if bindings[i-1] == (124 as u8) { boundary = 1 } }
24 if boundary == 1 { if nw_keyeq(bindings, i, key) == 1 {
25 var j: i64 = i + kl + 1; var o: i64 = 0; var vr: i64 = 1
26 while vr == 1 { if bindings[j] == (0 as u8) { vr = 0 } else { if bindings[j] == (124 as u8) { vr = 0 } else { if o < cap - 1 { out[o] = bindings[j]; o = o + 1 } j = j + 1 } } }
27 out[o] = 0 as u8; found = 1; run = 0
28 } }
29 i = i + 1
30 }
31 }
32 return found
33}
34// append a template to out, substituting {KEY} -> binding value (unknown keys drop). returns new off.
35func nw_render(out: *u8, off: i64, tpl: *u8, bindings: *u8) -> i64 {
36 var o: i64 = off; var i: i64 = 0
37 while tpl[i] != (0 as u8) {
38 var handled: i64 = 0
39 if tpl[i] == (123 as u8) {
40 var k: i64 = i + 1; var close: i64 = 0 - 1; var sc: i64 = 1
41 while sc == 1 { if tpl[k] == (0 as u8) { sc = 0 } else { if tpl[k] == (125 as u8) { close = k; sc = 0 } else { k = k + 1 } } }
42 if close >= 0 {
43 let key: *u8 = sys_mmap(64); var ko: i64 = 0; var p: i64 = i + 1
44 while p < close { if ko < 63 { key[ko] = tpl[p]; ko = ko + 1 } p = p + 1 } key[ko] = 0 as u8
45 let val: *u8 = sys_mmap(1024)
46 if nw_bind_get(bindings, key, val, 1024) == 1 { o = as_append(out, o, val) }
47 i = close + 1; handled = 1
48 }
49 }
50 if handled == 0 { out[o] = tpl[i]; o = o + 1; i = i + 1 }
51 }
52 return o
53}
54// resolve a web component (kind,id) from the catalog at `path` and render with `bindings` into out at off.
55func nw_emit_component(path: *u8, kind: *u8, id: *u8, bindings: *u8, out: *u8, off: i64) -> i64 {
56 let tpl: *u8 = sys_mmap(4096)
57 if nb_lookup(path, "web" as *u8, kind, id, tpl) == 0 { return off }
58 return nw_render(out, off, tpl, bindings)
59}
60// add "KEY=<escaped val>|" to a bindings buffer. (Boundary defense: value is HTML-escaped.)
61func nw_bind_add(buf: *u8, off: i64, key: *u8, val: *u8) -> i64 {
62 var o: i64 = as_append(buf, off, key); buf[o] = 61 as u8; o = o + 1
63 o = as_append_escaped(buf, o, val, as_len(val)); buf[o] = 124 as u8; o = o + 1
64 return o
65}
66
67// compose a full page from catalog components (nav + hero + footer). NUL-terminated into out; returns length.
68func nw_emit_page(path: *u8, brand: *u8, title: *u8, sub: *u8, cta: *u8, link: *u8, copyr: *u8, out: *u8) -> i64 {
69 var o: i64 = 0
70 o = as_append(out, o, "<!doctype html><html><head><meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1'><title>" as *u8)
71 o = as_append_escaped(out, o, title, as_len(title))
72 o = as_append(out, o, "</title><style>body{margin:0;font-family:system-ui,sans-serif;color:#16202e}.topbar{display:flex;justify-content:space-between;align-items:center;padding:14px 24px;background:#0b2545;color:#fff}.topbar .brand{color:#fff;text-decoration:none;font-weight:700}.topbar .links a{color:#cfe;margin-left:16px;text-decoration:none}.hero{padding:64px 24px;text-align:center;background:#eef2f7}.hero h1{font-size:2rem;margin:0 0 8px}.btn{display:inline-block;margin-top:16px;padding:12px 22px;background:#0b2545;color:#fff;border-radius:8px;text-decoration:none}.ftr{padding:28px 24px;background:#0b2545;color:#cfe;text-align:center}.ftr nav a{color:#fff;margin:0 8px}</style></head><body>" as *u8)
73 let nb1: *u8 = sys_mmap(512); var b: i64 = nw_bind_add(nb1, 0, "BRAND" as *u8, brand); b = nw_bind_add(nb1, b, "LINKS" as *u8, "Home" as *u8); nb1[b] = 0 as u8
74 o = nw_emit_component(path, "nav" as *u8, "topbar" as *u8, nb1, out, o)
75 let nb2: *u8 = sys_mmap(1024); b = nw_bind_add(nb2, 0, "TITLE" as *u8, title); b = nw_bind_add(nb2, b, "SUB" as *u8, sub); b = nw_bind_add(nb2, b, "LINK" as *u8, link); b = nw_bind_add(nb2, b, "CTA" as *u8, cta); nb2[b] = 0 as u8
76 o = nw_emit_component(path, "section" as *u8, "hero" as *u8, nb2, out, o)
77 let nb3: *u8 = sys_mmap(512); b = nw_bind_add(nb3, 0, "COPY" as *u8, copyr); b = nw_bind_add(nb3, b, "LINKS" as *u8, "Privacy" as *u8); nb3[b] = 0 as u8
78 o = nw_emit_component(path, "section" as *u8, "footer" as *u8, nb3, out, o)
79 o = as_append(out, o, "</body></html>" as *u8)
80 out[o] = 0 as u8
81 return o
82}