code wiki / _hdl_build / nx_studio_tiers.nx

nx_studio_tiers.nx source

↩ module page · 148 lines · 8052 B

1// nx_studio_tiers.nx -- CAPABILITY-ADAPTIVE WYSIWYG (operator's idea: let users select, by their capability, 2// HOW they want to build). The editor offers tiers -- GUIDED (novice/elderly: answer a few fields, the 3// structure is guaranteed), BLOCK (intermediate: arrange blocks), FREE-FORM (power: place freely) -- but ALL 4// tiers normalize to the ONE governed, portable .site data model and build through the SAME sovereign engine 5// (se_build_site). So escaping, the publish-time UX gate, and portability are INVARIANT across tiers: no 6// capability tier can escape governance. tier_normalize is the single funnel. 7// GUIDED : a compact answer set (brand|.. headline|.. cta|.. ..) -> a COMPLETE compliant .site by 8// construction (every required block is in the template; missing answers fall back to defaults), 9// so a novice CANNOT produce a broken page. 10// FREE-FORM: a .site plus layout-only `place|idx|x|y` lines -> the placement lines are stripped to the 11// governed block .site (free placement is a presentation hint, never a way around the engine). 12// BLOCK : already a .site -> passthrough. 13// license_tier: ORIGINAL 14import "nx_sitegen_studio.nx" 15import "nx_sitegen_freeform.nx" 16import "nx_syscalls.nx" 17const TIER_MAGIC_65536: i64 = 65536 18const TIER_MAGIC_65535: i64 = 65535 19 20const TIER_GUIDED: i64 = 0 21const TIER_BLOCK: i64 = 1 22const TIER_FREEFORM: i64 = 2 23 24func tn_strlen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 25func tn_puts(out: *u8, off: i64, s: *u8) -> i64 { var o: i64=off; var k: i64=0; while s[k]!=(0 as u8){out[o]=s[k];o=o+1;k=k+1} return o } 26func tn_putrange(out: *u8, off: i64, src: *u8, a: i64, b: i64) -> i64 { var o: i64=off; var j: i64=a; while j<b { out[o]=src[j]; o=o+1; j=j+1 } if o>off { if (out[o-1] as i64)==13 { o=o-1 } } return o } 27 28// does input[ls..le) start with key followed by '|'? return value-start index, or -1. 29func tn_linematch(input: *u8, ls: i64, le: i64, key: *u8, klen: i64) -> i64 { 30 if ls+klen+1 > le { return 0-1 } 31 var i: i64=0 32 while i<klen { if (input[ls+i] as i64)!=(key[i] as i64){return 0-1} i=i+1 } 33 if (input[ls+klen] as i64)!=124 { return 0-1 } // '|' 34 return ls+klen+1 35} 36 37// append the value of input's first "key|value" line, or `dflt` if the key is absent. returns new off. 38func tn_appget(out: *u8, off: i64, input: *u8, n: i64, key: *u8, dflt: *u8) -> i64 { 39 let klen: i64 = tn_strlen(key) 40 var ls: i64=0; var i: i64=0 41 var fvs: i64=0-1; var fve: i64=0; var done: i64=0 42 while i<=n { 43 if done==0 { 44 var eol: i64=0 45 if i==n { eol=1 } 46 if i<n { if (input[i] as i64)==10 { eol=1 } } 47 if eol==1 { 48 let vs: i64 = tn_linematch(input, ls, i, key, klen) 49 if vs>=0 { fvs=vs; fve=i; done=1 } 50 ls=i+1 51 } 52 } 53 i=i+1 54 } 55 if fvs>=0 { return tn_putrange(out, off, input, fvs, fve) } 56 return tn_puts(out, off, dflt) 57} 58 59// normalize a tier-specific editor input into the canonical governed .site text in out; return its length. 60func tier_normalize(tier: i64, input: *u8, n: i64, out: *u8, cap: i64) -> i64 { 61 if tier == TIER_GUIDED { 62 var o: i64 = 0 63 o = tn_puts(out, o, "title|" as *u8); o = tn_appget(out, o, input, n, "brand" as *u8, "Your Brand" as *u8) 64 o = tn_puts(out, o, "\nheader|" as *u8); o = tn_appget(out, o, input, n, "brand" as *u8, "Your Brand" as *u8) 65 o = tn_puts(out, o, "|" as *u8); o = tn_appget(out, o, input, n, "cta" as *u8, "Contact us" as *u8) 66 o = tn_puts(out, o, "|" as *u8); o = tn_appget(out, o, input, n, "cta_href" as *u8, "#contact" as *u8) 67 o = tn_puts(out, o, "\nhero|" as *u8); o = tn_appget(out, o, input, n, "headline" as *u8, "Welcome" as *u8) 68 o = tn_puts(out, o, "|" as *u8); o = tn_appget(out, o, input, n, "sub" as *u8, "How we can help you." as *u8) 69 o = tn_puts(out, o, "|" as *u8); o = tn_appget(out, o, input, n, "cta" as *u8, "Contact us" as *u8) 70 o = tn_puts(out, o, "|" as *u8); o = tn_appget(out, o, input, n, "cta_href" as *u8, "#contact" as *u8) 71 o = tn_puts(out, o, "\nsearch|" as *u8); o = tn_appget(out, o, input, n, "search" as *u8, "/search" as *u8) 72 o = tn_puts(out, o, "|Search...\ncards|What we offer\ncard|" as *u8); o = tn_appget(out, o, input, n, "card_title" as *u8, "Our service" as *u8) 73 o = tn_puts(out, o, "|" as *u8); o = tn_appget(out, o, input, n, "card_body" as *u8, "What we do for you." as *u8) 74 o = tn_puts(out, o, "\nsteps|How it works\nstep|" as *u8); o = tn_appget(out, o, input, n, "step1" as *u8, "Get in touch" as *u8) 75 o = tn_puts(out, o, "\nstep|" as *u8); o = tn_appget(out, o, input, n, "step2" as *u8, "We help you" as *u8) 76 o = tn_puts(out, o, "\ntrust|\nsig|" as *u8); o = tn_appget(out, o, input, n, "trust" as *u8, "Trusted service" as *u8) 77 o = tn_puts(out, o, "\nfooter|" as *u8); o = tn_appget(out, o, input, n, "footer" as *u8, "Your Brand" as *u8) 78 o = tn_puts(out, o, "\n" as *u8) 79 return o 80 } 81 if tier == TIER_FREEFORM { 82 // strip layout-only "place|..." lines; keep the governed block lines (placement = presentation hint) 83 var o: i64 = 0 84 var ls: i64=0; var i: i64=0 85 while i<=n { 86 var eol: i64=0 87 if i==n { eol=1 } 88 if i<n { if (input[i] as i64)==10 { eol=1 } } 89 if eol==1 { 90 if tn_linematch(input, ls, i, "place" as *u8, 5) < 0 { 91 o = tn_putrange(out, o, input, ls, i) 92 out[o]=10 as u8; o=o+1 93 } 94 ls=i+1 95 } 96 i=i+1 97 } 98 return o 99 } 100 // TIER_BLOCK (default): passthrough -- it is already a .site 101 var o: i64 = 0 102 var j: i64 = 0 103 while j<n { out[o]=input[j]; o=o+1; j=j+1 } 104 return o 105} 106 107// does s[a..b) (trailing CR trimmed) equal the null-terminated literal lit? 108func tn_range_eq(s: *u8, a: i64, b: i64, lit: *u8) -> i64 { 109 var e: i64 = b 110 if e>a { if (s[e-1] as i64)==13 { e=e-1 } } 111 var i: i64 = a 112 var k: i64 = 0 113 while i<e { 114 if lit[k]==(0 as u8) { return 0 } 115 if (s[i] as i64)!=(lit[k] as i64) { return 0 } 116 i=i+1; k=k+1 117 } 118 if lit[k]==(0 as u8) { return 1 } 119 return 0 120} 121 122// THE GOVERNED TIER-AWARE ENDPOINT: hand it the raw POST body. An optional first line `tier|<guided|block| 123// freeform>` selects the capability tier (default = block); the REST is that tier's input. It normalizes via 124// the single funnel (tier_normalize) and builds through the sovereign engine (se_build_site). So the daemon 125// route just forwards the request body here -- the tier is data, governance is invariant. Returns built length 126// (0 = refused). 127func se_build_tier(payload: *u8, n: i64, out: *u8, cap: i64) -> i64 { 128 var tier: i64 = TIER_BLOCK 129 var body_start: i64 = 0 130 var eol1: i64 = n 131 var i: i64 = 0 132 while i < n { if (payload[i] as i64)==10 { eol1=i; i=n } else { i=i+1 } } 133 let vs: i64 = tn_linematch(payload, 0, eol1, "tier" as *u8, 4) 134 if vs >= 0 { 135 if tn_range_eq(payload, vs, eol1, "guided" as *u8)==1 { tier=TIER_GUIDED } 136 if tn_range_eq(payload, vs, eol1, "freeform" as *u8)==1 { tier=TIER_FREEFORM } 137 if tn_range_eq(payload, vs, eol1, "block" as *u8)==1 { tier=TIER_BLOCK } 138 body_start = eol1 + 1 139 if body_start > n { body_start = n } 140 } 141 let bn: i64 = n - body_start 142 // FREE-FORM tier -> the canvas profile (its own page profile, free placement + escaped + portable). 143 // GUIDED/BLOCK (+ default) -> normalize to the governed block .site funnel, then the block engine. 144 if tier == TIER_FREEFORM { return se_build_freeform(payload + body_start, bn, out, cap) } 145 let site: *u8 = sys_mmap(TIER_MAGIC_65536) 146 let sn: i64 = tier_normalize(tier, payload + body_start, bn, site, TIER_MAGIC_65535) 147 return se_build_site(site, sn, out, cap) 148}