diff --git a/lib/hyperscript/compiler.sx b/lib/hyperscript/compiler.sx index 6a47db8e..912ac999 100644 --- a/lib/hyperscript/compiler.sx +++ b/lib/hyperscript/compiler.sx @@ -999,7 +999,23 @@ (hs-to-sx (nth ast 1)) (hs-to-sx (nth ast 2))))) ((= head (quote do)) - (cons (quote do) (map hs-to-sx (rest ast)))) + (let + ((compiled (map hs-to-sx (rest ast)))) + (if + (= (len compiled) 1) + (first compiled) + (let + ((last-cmd (nth compiled (- (len compiled) 1))) + (init-cmds (reverse (rest (reverse compiled))))) + (reduce + (fn + (body cmd) + (list + (quote let) + (list (list (quote it) cmd)) + body)) + last-cmd + (reverse init-cmds)))))) ((= head (quote wait)) (list (quote hs-wait) (nth ast 1))) ((= head (quote wait-for)) (emit-wait-for ast)) ((= head (quote log)) diff --git a/lib/hyperscript/parser.sx b/lib/hyperscript/parser.sx index 23462934..45c695b3 100644 --- a/lib/hyperscript/parser.sx +++ b/lib/hyperscript/parser.sx @@ -1270,7 +1270,7 @@ (let ((url (if (nil? url-atom) url-atom (parse-arith (parse-poss url-atom))))) (let - ((fmt (if (match-kw "as") (let ((f (tp-val))) (adv!) f) "json"))) + ((fmt (if (match-kw "as") (let ((f (tp-val))) (adv!) f) "text"))) (list (quote fetch) url fmt))))))) (define parse-call-args diff --git a/lib/hyperscript/runtime.sx b/lib/hyperscript/runtime.sx index 7379936e..2b157b2a 100644 --- a/lib/hyperscript/runtime.sx +++ b/lib/hyperscript/runtime.sx @@ -285,13 +285,7 @@ hs-fetch (fn (url format) - (let - ((response (perform (list (quote io-fetch) url)))) - (cond - ((= format "json") (perform (list (quote io-parse-json) response))) - ((= format "text") (perform (list (quote io-parse-text) response))) - ((= format "html") (perform (list (quote io-parse-html) response))) - (true response))))) + (perform (list "io-fetch" url (if format format "text"))))) (define hs-coerce diff --git a/shared/static/wasm/sx/hs-compiler.sx b/shared/static/wasm/sx/hs-compiler.sx index 6a47db8e..912ac999 100644 --- a/shared/static/wasm/sx/hs-compiler.sx +++ b/shared/static/wasm/sx/hs-compiler.sx @@ -999,7 +999,23 @@ (hs-to-sx (nth ast 1)) (hs-to-sx (nth ast 2))))) ((= head (quote do)) - (cons (quote do) (map hs-to-sx (rest ast)))) + (let + ((compiled (map hs-to-sx (rest ast)))) + (if + (= (len compiled) 1) + (first compiled) + (let + ((last-cmd (nth compiled (- (len compiled) 1))) + (init-cmds (reverse (rest (reverse compiled))))) + (reduce + (fn + (body cmd) + (list + (quote let) + (list (list (quote it) cmd)) + body)) + last-cmd + (reverse init-cmds)))))) ((= head (quote wait)) (list (quote hs-wait) (nth ast 1))) ((= head (quote wait-for)) (emit-wait-for ast)) ((= head (quote log)) diff --git a/shared/static/wasm/sx/hs-parser.sx b/shared/static/wasm/sx/hs-parser.sx index 23462934..45c695b3 100644 --- a/shared/static/wasm/sx/hs-parser.sx +++ b/shared/static/wasm/sx/hs-parser.sx @@ -1270,7 +1270,7 @@ (let ((url (if (nil? url-atom) url-atom (parse-arith (parse-poss url-atom))))) (let - ((fmt (if (match-kw "as") (let ((f (tp-val))) (adv!) f) "json"))) + ((fmt (if (match-kw "as") (let ((f (tp-val))) (adv!) f) "text"))) (list (quote fetch) url fmt))))))) (define parse-call-args diff --git a/shared/static/wasm/sx/hs-runtime.sx b/shared/static/wasm/sx/hs-runtime.sx index 7379936e..2b157b2a 100644 --- a/shared/static/wasm/sx/hs-runtime.sx +++ b/shared/static/wasm/sx/hs-runtime.sx @@ -285,13 +285,7 @@ hs-fetch (fn (url format) - (let - ((response (perform (list (quote io-fetch) url)))) - (cond - ((= format "json") (perform (list (quote io-parse-json) response))) - ((= format "text") (perform (list (quote io-parse-text) response))) - ((= format "html") (perform (list (quote io-parse-html) response))) - (true response))))) + (perform (list "io-fetch" url (if format format "text"))))) (define hs-coerce diff --git a/tests/hs-run-fast.js b/tests/hs-run-fast.js index 1c25ffe9..d9f287ae 100644 --- a/tests/hs-run-fast.js +++ b/tests/hs-run-fast.js @@ -192,6 +192,8 @@ const _fetchRoutes = { '/test': { status: 200, body: 'yay', json: '{"foo":1}', html: '
yay
' }, '/test-json': { status: 200, body: '{"foo":1}', json: '{"foo":1}' }, '/404': { status: 404, body: 'the body' }, + '/number': { status: 200, body: '1.2' }, + '/users/Joe': { status: 200, body: 'Joe', json: '{"name":"Joe"}' }, }; function _mockFetch(url) { const route = _fetchRoutes[url] || _fetchRoutes['/test']; @@ -201,10 +203,19 @@ function _mockFetch(url) { globalThis._driveAsync=function driveAsync(r,d){d=d||0;if(d>500||!r||!r.suspended)return;if(_testDeadline && Date.now()>_testDeadline)throw new Error('TIMEOUT: wall clock exceeded');const req=r.request;const items=req&&(req.items||req);const op=items&&items[0];const opName=typeof op==='string'?op:(op&&op.name)||String(op); function doResume(v){try{const x=r.resume(v);driveAsync(x,d+1);}catch(e){}} if(opName==='io-sleep'||opName==='wait')doResume(null); - else if(opName==='io-fetch'){const url=items&&items[1];doResume(_mockFetch(typeof url==='string'?url:'/test'));} - else if(opName==='io-parse-text'){const resp=items&&items[1];doResume(resp&&resp._body?resp._body:'');} - else if(opName==='io-parse-json'){const resp=items&&items[1];try{doResume(JSON.parse(resp&&resp._json?resp._json:'{}'));}catch(e){doResume(null);}} - else if(opName==='io-parse-html'){const resp=items&&items[1];const frag=new El('fragment');frag.nodeType=11;frag.innerHTML=resp&&resp._html?resp._html:'';frag.textContent=frag.innerHTML.replace(/<[^>]*>/g,'');doResume(frag);} + else if(opName==='io-fetch'){ + const url=typeof items[1]==='string'?items[1]:'/test'; + const fmt=typeof items[2]==='string'?items[2]:'text'; + const route=_fetchRoutes[url]||_fetchRoutes['/test']; + if(fmt==='json'){try{doResume(JSON.parse(route.json||route.body||'{}'));}catch(e){doResume(null);}} + else if(fmt==='html'){const frag=new El('fragment');frag.nodeType=11;frag.innerHTML=route.html||route.body||'';frag.textContent=frag.innerHTML.replace(/<[^>]*>/g,'');doResume(frag);} + else if(fmt==='response')doResume({ok:(route.status||200)<400,status:route.status||200,url}); + else if(fmt==='Number'||fmt==='number')doResume(parseFloat(route.body||'0')); + else doResume(route.body||''); + } + else if(opName==='io-parse-text'){const resp=items&&items[1];doResume(resp&&resp._body?resp._body:typeof resp==='string'?resp:'');} + else if(opName==='io-parse-json'){const resp=items&&items[1];try{doResume(JSON.parse(typeof resp==='string'?resp:resp&&resp._json?resp._json:'{}'));}catch(e){doResume(null);}} + else if(opName==='io-parse-html'){const frag=new El('fragment');frag.nodeType=11;doResume(frag);} else if(opName==='io-settle')doResume(null); else if(opName==='io-wait-event')doResume(null); else if(opName==='io-transition')doResume(null);