diff --git a/README.md b/README.md deleted file mode 100644 index 2271a22..0000000 --- a/README.md +++ /dev/null @@ -1,11 +0,0 @@ - -Run in an empty directory to setup basic files: -``` -deno run -Ar https://gitea.hptrow.me/SethTrowbridge/gale/raw/branch/master/scripts/scaffold.ts -``` - -- `deno task work` starts the dev server -- `deno task scan` scans the deno.json for type declaration files (be sure to then restart the Deno language server) -- `deno task html` creates an index.html for use when static file hosting (the dev serve will create its own index.html if none exists in the file system) - -`entry` in the import map points to the starting file \ No newline at end of file diff --git a/app.js b/app.js deleted file mode 100644 index ea3e7e5..0000000 --- a/app.js +++ /dev/null @@ -1,45 +0,0 @@ -const {DOM, Tag, Div} = Gale({ - Button: { - padding: "20px", - background: "orange", - ".Inner": { - fontSize: "10rem" - } - }, - Outline: { - border: "2px solid orange" - }, - Window:{ - height: "100vh", - border: "2px solid black", - display: "flex", - flexDirection: "row", - alignItems: "end", - justifyContent: "center", - gap: "10px" - }, - Ability:{ - width: "50px", - height: "50px", - background: "red", - transition: "all 0.4s", - ":hover":{ - transform:"scale(1.1)" - } - }, - Orange:{ - background:"orange" - } -}); - -const UI =()=> -{ - return Div.Window( - Div.Ability({class:Tag("Ability", "Orange")}), - Div.Ability(), - Div.Ability(), - Div.Ability.Orange(), - ) -} - -van.add(document.body, UI()); \ No newline at end of file diff --git a/app.tsx b/app.tsx new file mode 100644 index 0000000..7ed9a1e --- /dev/null +++ b/app.tsx @@ -0,0 +1,9 @@ +import * as React from ">/npm:react"; + +export function App(){ + return <> +
lol hey!
+ +} + +export default "lol" \ No newline at end of file diff --git a/deno.json b/deno.json index 02b9813..e508a14 100644 --- a/deno.json +++ b/deno.json @@ -1,19 +1,13 @@ { - "compilerOptions": - { - "checkJs": true, - "lib": ["deno.window", "DOM"], - "types": ["GALE@HOST/types.d.ts"] - }, - "tasks": - { - "work": "deno run -Ar GALE@HOST/scripts/dev_server.ts", - "scan": "deno run -Ar GALE@HOST/scripts/refresh_types.ts", - "html": "deno run -Ar GALE@HOST/scripts/scaffold.ts --html" - }, - "imports": - { - "GALE@HOST/":"./", - "GALE@ENTRY":"./app.js" - } -} \ No newline at end of file + "tasks": { + "dev": "deno -A --unstable-bundle --watch server.ts" + }, + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "react" + }, + "imports": { + "@std/assert": "jsr:@std/assert@1", + "react":"npm:react" + } +} diff --git a/deno.lock b/deno.lock index 9b82683..e6de917 100644 --- a/deno.lock +++ b/deno.lock @@ -1,111 +1,26 @@ { "version": "5", "specifiers": { - "jsr:@std/media-types@*": "1.1.0", - "npm:vanjs-core@*": "1.5.5", - "npm:vanjs-core@^1.5.5": "1.5.5", - "npm:vanjs-ext@~0.6.3": "0.6.3" - }, - "jsr": { - "@std/media-types@1.1.0": { - "integrity": "c9d093f0c05c3512932b330e3cc1fe1d627b301db33a4c2c2185c02471d6eaa4" - } + "npm:react@*": "19.2.0" }, "npm": { - "vanjs-core@1.5.5": { - "integrity": "sha512-BC9MjbXYIRqnwncXfacT6upJpVmIKyrV2MjZi8NuCK+yc9RP0hfdghTpmEuYswXOfkLarDPPcYK4X6q68T9e+g==" - }, - "vanjs-ext@0.6.3": { - "integrity": "sha512-Jmaeqx9nCjelwDVSQEaRtt7R4Y/Kj/zJBG3bZSiIPj8Wtr8nEFRsJX9K5qcGl1o3cGEEFBE9suyoSqs/6tiOBg==", - "dependencies": [ - "vanjs-core" - ] + "react@19.2.0": { + "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==" } }, "redirects": { - "https://deno.land/std/path/mod.ts": "https://deno.land/std@0.224.0/path/mod.ts" + "https://esm.sh/type-detect@^4.0.0?target=denonext": "https://esm.sh/type-detect@4.1.0?target=denonext" }, "remote": { - "https://deno.land/std@0.224.0/assert/assert.ts": "09d30564c09de846855b7b071e62b5974b001bb72a4b797958fe0660e7849834", - "https://deno.land/std@0.224.0/assert/assertion_error.ts": "ba8752bd27ebc51f723702fac2f54d3e94447598f54264a6653d6413738a8917", - "https://deno.land/std@0.224.0/path/_common/assert_path.ts": "dbdd757a465b690b2cc72fc5fb7698c51507dec6bfafce4ca500c46b76ff7bd8", - "https://deno.land/std@0.224.0/path/_common/basename.ts": "569744855bc8445f3a56087fd2aed56bdad39da971a8d92b138c9913aecc5fa2", - "https://deno.land/std@0.224.0/path/_common/common.ts": "ef73c2860694775fe8ffcbcdd387f9f97c7a656febf0daa8c73b56f4d8a7bd4c", - "https://deno.land/std@0.224.0/path/_common/constants.ts": "dc5f8057159f4b48cd304eb3027e42f1148cf4df1fb4240774d3492b5d12ac0c", - "https://deno.land/std@0.224.0/path/_common/dirname.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8", - "https://deno.land/std@0.224.0/path/_common/format.ts": "92500e91ea5de21c97f5fe91e178bae62af524b72d5fcd246d6d60ae4bcada8b", - "https://deno.land/std@0.224.0/path/_common/from_file_url.ts": "d672bdeebc11bf80e99bf266f886c70963107bdd31134c4e249eef51133ceccf", - "https://deno.land/std@0.224.0/path/_common/glob_to_reg_exp.ts": "6cac16d5c2dc23af7d66348a7ce430e5de4e70b0eede074bdbcf4903f4374d8d", - "https://deno.land/std@0.224.0/path/_common/normalize.ts": "684df4aa71a04bbcc346c692c8485594fc8a90b9408dfbc26ff32cf3e0c98cc8", - "https://deno.land/std@0.224.0/path/_common/normalize_string.ts": "33edef773c2a8e242761f731adeb2bd6d683e9c69e4e3d0092985bede74f4ac3", - "https://deno.land/std@0.224.0/path/_common/relative.ts": "faa2753d9b32320ed4ada0733261e3357c186e5705678d9dd08b97527deae607", - "https://deno.land/std@0.224.0/path/_common/strip_trailing_separators.ts": "7024a93447efcdcfeaa9339a98fa63ef9d53de363f1fbe9858970f1bba02655a", - "https://deno.land/std@0.224.0/path/_common/to_file_url.ts": "7f76adbc83ece1bba173e6e98a27c647712cab773d3f8cbe0398b74afc817883", - "https://deno.land/std@0.224.0/path/_interface.ts": "8dfeb930ca4a772c458a8c7bbe1e33216fe91c253411338ad80c5b6fa93ddba0", - "https://deno.land/std@0.224.0/path/_os.ts": "8fb9b90fb6b753bd8c77cfd8a33c2ff6c5f5bc185f50de8ca4ac6a05710b2c15", - "https://deno.land/std@0.224.0/path/basename.ts": "7ee495c2d1ee516ffff48fb9a93267ba928b5a3486b550be73071bc14f8cc63e", - "https://deno.land/std@0.224.0/path/common.ts": "03e52e22882402c986fe97ca3b5bb4263c2aa811c515ce84584b23bac4cc2643", - "https://deno.land/std@0.224.0/path/constants.ts": "0c206169ca104938ede9da48ac952de288f23343304a1c3cb6ec7625e7325f36", - "https://deno.land/std@0.224.0/path/dirname.ts": "85bd955bf31d62c9aafdd7ff561c4b5fb587d11a9a5a45e2b01aedffa4238a7c", - "https://deno.land/std@0.224.0/path/extname.ts": "593303db8ae8c865cbd9ceec6e55d4b9ac5410c1e276bfd3131916591b954441", - "https://deno.land/std@0.224.0/path/format.ts": "6ce1779b0980296cf2bc20d66436b12792102b831fd281ab9eb08fa8a3e6f6ac", - "https://deno.land/std@0.224.0/path/from_file_url.ts": "911833ae4fd10a1c84f6271f36151ab785955849117dc48c6e43b929504ee069", - "https://deno.land/std@0.224.0/path/glob_to_regexp.ts": "7f30f0a21439cadfdae1be1bf370880b415e676097fda584a63ce319053b5972", - "https://deno.land/std@0.224.0/path/is_absolute.ts": "4791afc8bfd0c87f0526eaa616b0d16e7b3ab6a65b62942e50eac68de4ef67d7", - "https://deno.land/std@0.224.0/path/is_glob.ts": "a65f6195d3058c3050ab905705891b412ff942a292bcbaa1a807a74439a14141", - "https://deno.land/std@0.224.0/path/join.ts": "ae2ec5ca44c7e84a235fd532e4a0116bfb1f2368b394db1c4fb75e3c0f26a33a", - "https://deno.land/std@0.224.0/path/join_globs.ts": "5b3bf248b93247194f94fa6947b612ab9d3abd571ca8386cf7789038545e54a0", - "https://deno.land/std@0.224.0/path/mod.ts": "f6bd79cb08be0e604201bc9de41ac9248582699d1b2ee0ab6bc9190d472cf9cd", - "https://deno.land/std@0.224.0/path/normalize.ts": "4155743ccceeed319b350c1e62e931600272fad8ad00c417b91df093867a8352", - "https://deno.land/std@0.224.0/path/normalize_glob.ts": "cc89a77a7d3b1d01053b9dcd59462b75482b11e9068ae6c754b5cf5d794b374f", - "https://deno.land/std@0.224.0/path/parse.ts": "77ad91dcb235a66c6f504df83087ce2a5471e67d79c402014f6e847389108d5a", - "https://deno.land/std@0.224.0/path/posix/_util.ts": "1e3937da30f080bfc99fe45d7ed23c47dd8585c5e473b2d771380d3a6937cf9d", - "https://deno.land/std@0.224.0/path/posix/basename.ts": "d2fa5fbbb1c5a3ab8b9326458a8d4ceac77580961b3739cd5bfd1d3541a3e5f0", - "https://deno.land/std@0.224.0/path/posix/common.ts": "26f60ccc8b2cac3e1613000c23ac5a7d392715d479e5be413473a37903a2b5d4", - "https://deno.land/std@0.224.0/path/posix/constants.ts": "93481efb98cdffa4c719c22a0182b994e5a6aed3047e1962f6c2c75b7592bef1", - "https://deno.land/std@0.224.0/path/posix/dirname.ts": "76cd348ffe92345711409f88d4d8561d8645353ac215c8e9c80140069bf42f00", - "https://deno.land/std@0.224.0/path/posix/extname.ts": "e398c1d9d1908d3756a7ed94199fcd169e79466dd88feffd2f47ce0abf9d61d2", - "https://deno.land/std@0.224.0/path/posix/format.ts": "185e9ee2091a42dd39e2a3b8e4925370ee8407572cee1ae52838aed96310c5c1", - "https://deno.land/std@0.224.0/path/posix/from_file_url.ts": "951aee3a2c46fd0ed488899d024c6352b59154c70552e90885ed0c2ab699bc40", - "https://deno.land/std@0.224.0/path/posix/glob_to_regexp.ts": "76f012fcdb22c04b633f536c0b9644d100861bea36e9da56a94b9c589a742e8f", - "https://deno.land/std@0.224.0/path/posix/is_absolute.ts": "cebe561ad0ae294f0ce0365a1879dcfca8abd872821519b4fcc8d8967f888ede", - "https://deno.land/std@0.224.0/path/posix/is_glob.ts": "8a8b08c08bf731acf2c1232218f1f45a11131bc01de81e5f803450a5914434b9", - "https://deno.land/std@0.224.0/path/posix/join.ts": "7fc2cb3716aa1b863e990baf30b101d768db479e70b7313b4866a088db016f63", - "https://deno.land/std@0.224.0/path/posix/join_globs.ts": "a9475b44645feddceb484ee0498e456f4add112e181cb94042cdc6d47d1cdd25", - "https://deno.land/std@0.224.0/path/posix/mod.ts": "2301fc1c54a28b349e20656f68a85f75befa0ee9b6cd75bfac3da5aca9c3f604", - "https://deno.land/std@0.224.0/path/posix/normalize.ts": "baeb49816a8299f90a0237d214cef46f00ba3e95c0d2ceb74205a6a584b58a91", - "https://deno.land/std@0.224.0/path/posix/normalize_glob.ts": "9c87a829b6c0f445d03b3ecadc14492e2864c3ebb966f4cea41e98326e4435c6", - "https://deno.land/std@0.224.0/path/posix/parse.ts": "09dfad0cae530f93627202f28c1befa78ea6e751f92f478ca2cc3b56be2cbb6a", - "https://deno.land/std@0.224.0/path/posix/relative.ts": "3907d6eda41f0ff723d336125a1ad4349112cd4d48f693859980314d5b9da31c", - "https://deno.land/std@0.224.0/path/posix/resolve.ts": "08b699cfeee10cb6857ccab38fa4b2ec703b0ea33e8e69964f29d02a2d5257cf", - "https://deno.land/std@0.224.0/path/posix/to_file_url.ts": "7aa752ba66a35049e0e4a4be5a0a31ac6b645257d2e031142abb1854de250aaf", - "https://deno.land/std@0.224.0/path/posix/to_namespaced_path.ts": "28b216b3c76f892a4dca9734ff1cc0045d135532bfd9c435ae4858bfa5a2ebf0", - "https://deno.land/std@0.224.0/path/relative.ts": "ab739d727180ed8727e34ed71d976912461d98e2b76de3d3de834c1066667add", - "https://deno.land/std@0.224.0/path/resolve.ts": "a6f977bdb4272e79d8d0ed4333e3d71367cc3926acf15ac271f1d059c8494d8d", - "https://deno.land/std@0.224.0/path/to_file_url.ts": "88f049b769bce411e2d2db5bd9e6fd9a185a5fbd6b9f5ad8f52bef517c4ece1b", - "https://deno.land/std@0.224.0/path/to_namespaced_path.ts": "b706a4103b104cfadc09600a5f838c2ba94dbcdb642344557122dda444526e40", - "https://deno.land/std@0.224.0/path/windows/_util.ts": "d5f47363e5293fced22c984550d5e70e98e266cc3f31769e1710511803d04808", - "https://deno.land/std@0.224.0/path/windows/basename.ts": "6bbc57bac9df2cec43288c8c5334919418d784243a00bc10de67d392ab36d660", - "https://deno.land/std@0.224.0/path/windows/common.ts": "26f60ccc8b2cac3e1613000c23ac5a7d392715d479e5be413473a37903a2b5d4", - "https://deno.land/std@0.224.0/path/windows/constants.ts": "5afaac0a1f67b68b0a380a4ef391bf59feb55856aa8c60dfc01bd3b6abb813f5", - "https://deno.land/std@0.224.0/path/windows/dirname.ts": "33e421be5a5558a1346a48e74c330b8e560be7424ed7684ea03c12c21b627bc9", - "https://deno.land/std@0.224.0/path/windows/extname.ts": "165a61b00d781257fda1e9606a48c78b06815385e7d703232548dbfc95346bef", - "https://deno.land/std@0.224.0/path/windows/format.ts": "bbb5ecf379305b472b1082cd2fdc010e44a0020030414974d6029be9ad52aeb6", - "https://deno.land/std@0.224.0/path/windows/from_file_url.ts": "ced2d587b6dff18f963f269d745c4a599cf82b0c4007356bd957cb4cb52efc01", - "https://deno.land/std@0.224.0/path/windows/glob_to_regexp.ts": "e45f1f89bf3fc36f94ab7b3b9d0026729829fabc486c77f414caebef3b7304f8", - "https://deno.land/std@0.224.0/path/windows/is_absolute.ts": "4a8f6853f8598cf91a835f41abed42112cebab09478b072e4beb00ec81f8ca8a", - "https://deno.land/std@0.224.0/path/windows/is_glob.ts": "8a8b08c08bf731acf2c1232218f1f45a11131bc01de81e5f803450a5914434b9", - "https://deno.land/std@0.224.0/path/windows/join.ts": "8d03530ab89195185103b7da9dfc6327af13eabdcd44c7c63e42e27808f50ecf", - "https://deno.land/std@0.224.0/path/windows/join_globs.ts": "a9475b44645feddceb484ee0498e456f4add112e181cb94042cdc6d47d1cdd25", - "https://deno.land/std@0.224.0/path/windows/mod.ts": "2301fc1c54a28b349e20656f68a85f75befa0ee9b6cd75bfac3da5aca9c3f604", - "https://deno.land/std@0.224.0/path/windows/normalize.ts": "78126170ab917f0ca355a9af9e65ad6bfa5be14d574c5fb09bb1920f52577780", - "https://deno.land/std@0.224.0/path/windows/normalize_glob.ts": "9c87a829b6c0f445d03b3ecadc14492e2864c3ebb966f4cea41e98326e4435c6", - "https://deno.land/std@0.224.0/path/windows/parse.ts": "08804327b0484d18ab4d6781742bf374976de662f8642e62a67e93346e759707", - "https://deno.land/std@0.224.0/path/windows/relative.ts": "3e1abc7977ee6cc0db2730d1f9cb38be87b0ce4806759d271a70e4997fc638d7", - "https://deno.land/std@0.224.0/path/windows/resolve.ts": "8dae1dadfed9d46ff46cc337c9525c0c7d959fb400a6308f34595c45bdca1972", - "https://deno.land/std@0.224.0/path/windows/to_file_url.ts": "40e560ee4854fe5a3d4d12976cef2f4e8914125c81b11f1108e127934ced502e", - "https://deno.land/std@0.224.0/path/windows/to_namespaced_path.ts": "4ffa4fb6fae321448d5fe810b3ca741d84df4d7897e61ee29be961a6aac89a4c", - "https://vanjs.org/code/van-1.5.5.nomodule.min.js": "32403d4dd6203a46513f000fd64b18e4eaef0823bf757ca0092e70130d059aa3", - "https://vanjs.org/code/van-x-0.6.3.nomodule.min.js": "e4b7de89bf2f84c22669ce7bcef592fb398d9dcf8b8a36f4562b8ac6354b1f2f" + "https://esm.sh/deep-eql@4.1.3": "324a95b802d9f87b5ed66afdf079a0c47cd1cac3db59e9face0969be8eb980f7", + "https://esm.sh/deep-eql@4.1.3/denonext/deep-eql.mjs": "53319cc47b4be171d3a1aeeef9f3160a818e08b35baf9018cd14093f79e2910c", + "https://esm.sh/type-detect@4.1.0/denonext/type-detect.mjs": "ea850c5962bd47b0157c7e4cf38376cb7fb9fb3ad2438be0a724dbbadda5b94e", + "https://esm.sh/type-detect@4.1.0?target=denonext": "7257f955377cabc9a54bfa18f3bd16e12e40a090f25bf238299325d562e92fca" + }, + "workspace": { + "dependencies": [ + "jsr:@std/assert@1", + "npm:react@*" + ] } } diff --git a/dist/bundle_entry.js b/dist/bundle_entry.js deleted file mode 100644 index 085ad67..0000000 --- a/dist/bundle_entry.js +++ /dev/null @@ -1,3 +0,0 @@ -var ue=Object.defineProperty;var _e=(e,t)=>{for(var r in t)ue(e,r,{get:t[r],enumerable:!0})};var u=Object.getPrototypeOf,b,L,S,A,Q={isConnected:1},me=1e3,O,we={},Se=u(Q),U=u(u),_,Y=(e,t,r,l)=>(e??(setTimeout(r,l),new Set)).add(t),Z=(e,t,r)=>{let l=S;S=t;try{return e(r)}catch(n){return console.error(n),r}finally{S=l}},D=e=>e.filter(t=>t._dom?.isConnected),q=e=>O=Y(O,e,()=>{for(let t of O)t._bindings=D(t._bindings),t._listeners=D(t._listeners);O=_},me),$={get val(){return S?._getters?.add(this),this.rawVal},get oldVal(){return S?._getters?.add(this),this._oldVal},set val(e){S?._setters?.add(this),e!==this.rawVal&&(this.rawVal=e,this._bindings.length+this._listeners.length?(L?.add(this),b=Y(b,this,ve)):this._oldVal=e)}},j=e=>({__proto__:$,rawVal:e,_oldVal:e,_bindings:[],_listeners:[]}),V=(e,t)=>{let r={_getters:new Set,_setters:new Set},l={f:e},n=A;A=[];let a=Z(e,r,t);a=(a??document).nodeType?a:new Text(a);for(let o of r._getters)r._setters.has(o)||(q(o),o._bindings.push(l));for(let o of A)o._dom=a;return A=n,l._dom=a},M=(e,t=j(),r)=>{let l={_getters:new Set,_setters:new Set},n={f:e,s:t};n._dom=r??A?.push(n)??Q,t.val=Z(e,l,t.rawVal);for(let a of l._getters)l._setters.has(a)||(q(a),a._listeners.push(n));return t},ee=(e,...t)=>{for(let r of t.flat(1/0)){let l=u(r??0),n=l===$?V(()=>r.val):l===U?V(r):r;n!=_&&e.append(n)}return e},te=(e,t,...r)=>{let[{is:l,...n},...a]=u(r[0]??0)===Se?r:[{},...r],o=e?document.createElementNS(e,t,{is:l}):document.createElement(t,{is:l});for(let[d,h]of Object.entries(n)){let y=p=>p?Object.getOwnPropertyDescriptor(p,d)??y(u(p)):_,P=t+","+d,c=we[P]??=y(u(o))?.set??0,i=d.startsWith("on")?(p,g)=>{let f=d.slice(2);o.removeEventListener(f,g),o.addEventListener(f,p)}:c?c.bind(o):o.setAttribute.bind(o,d),s=u(h??0);d.startsWith("on")||s===U&&(h=M(h),s=$),s===$?V(()=>(i(h.val,h._oldVal),o)):i(h)}return ee(o,a)},z=e=>({get:(t,r)=>te.bind(_,e,r)}),re=(e,t)=>t?t!==e&&e.replaceWith(t):e.remove(),ve=()=>{let e=0,t=[...b].filter(l=>l.rawVal!==l._oldVal);do{L=new Set;for(let l of new Set(t.flatMap(n=>n._listeners=D(n._listeners))))M(l.f,l.s,l._dom),l._dom=_}while(++e<100&&(t=[...L]).length);let r=[...b].filter(l=>l.rawVal!==l._oldVal);b=_;for(let l of new Set(r.flatMap(n=>n._bindings=D(n._bindings))))re(l._dom,V(l.f,l._dom)),l._dom=_;for(let l of r)l._oldVal=l.rawVal},x={tags:new Proxy(e=>new Proxy(te,z(e)),z()),hydrate:(e,t)=>re(e,V(t,e)),add:ee,state:j,derive:M};var R={};_e(R,{calc:()=>De,compact:()=>B,list:()=>Fe,noreactive:()=>xe,raw:()=>ce,reactive:()=>K,replace:()=>ge,stateFields:()=>Ne});var{fromEntries:ne,entries:T,keys:k,hasOwn:X,getPrototypeOf:I,create:Ae,assign:be}=Object,{get:oe,set:le,deleteProperty:Ve,ownKeys:Ce}=Reflect,{state:E,derive:Te,add:Pe}=x,N,Oe=1e3,J,W,w=Symbol(),ae=Symbol(),G=Symbol(),m=Symbol(),C=Symbol(),ie=Symbol(),De=e=>(e[ae]=1,e),v=e=>e instanceof Object&&!(e instanceof Function)&&!e[ie],se=e=>{if(e?.[ae]){let t=E();return Te(()=>{let r=e();v(t.rawVal)&&v(r)?ge(t.rawVal,r):t.val=K(r)}),t}else return E(K(e))},$e=e=>{let t=Array.isArray(e)?[]:{__proto__:I(e)};for(let[r,l]of T(e))t[r]=se(l);return t[G]=[],t[m]=E(1),t},de={get:(e,t,r)=>t===w?e:X(e,t)?Array.isArray(e)&&t==="length"?(e[m].val,e.length):e[t].val:oe(e,t,r),set:(e,t,r,l)=>X(e,t)?Array.isArray(e)&&t==="length"?(r!==e.length&&++e[m].val,e.length=r,1):(e[t].val=K(r),1):t in e?le(e,t,r,l):le(e,t,se(r))&&(++e[m].val,F(e).forEach(fe.bind(J,l,t,e[t],W)),1),deleteProperty:(e,t)=>(Ve(e,t)&&Ke(e,t),++e[m].val),ownKeys:e=>(e[m].val,Ce(e))},K=e=>!v(e)||e[w]?e:new Proxy($e(e),de),xe=e=>(e[ie]=1,e),Ne=e=>e[w],Ee=I(E()),Ge=e=>new Proxy(e,{get:(t,r,l)=>I(t[r]??0)===Ee?{val:ce(t[r].rawVal)}:oe(t,r,l)}),ce=e=>e?.[w]?new Proxy(Ge(e[w]),de):e,F=e=>e[G]=e[G].filter(t=>t._containerDom.isConnected),fe=(e,t,r,l,{_containerDom:n,f:a})=>{let o=Array.isArray(e),d=o?Number(t):t;Pe(n,()=>n[C][t]=a(r,()=>delete e[t],d)),o&&!l&&d!==e.length-1&&n.insertBefore(n.lastChild,n[C][k(e).find(h=>Number(h)>d)])},Ke=(e,t)=>{for(let r of F(e)){let l=r._containerDom[C];l[t]?.remove(),delete l[t]}},Ie=e=>(N??(N=(setTimeout(()=>(N.forEach(F),N=J),Oe),new Set))).add(e),Fe=(e,t,r)=>{let l={_containerDom:e instanceof Function?e():e,f:r},n=t[w];l._containerDom[C]={},n[G].push(l),Ie(n);for(let[a,o]of T(n))fe(t,a,o,1,l);return l._containerDom},he=(e,t)=>{for(let[n,a]of T(t)){let o=e[n];v(o)&&v(a)?he(o,a):e[n]=a}for(let n in e)X(t,n)||delete e[n];let r=k(t),l=Array.isArray(e);if(l||k(e).some((n,a)=>n!==r[a])){let n=e[w];if(l)e.length=t.length;else{++n[m].val;let a={...n};for(let o of r)delete n[o];for(let o of r)n[o]=a[o]}for(let{_containerDom:a}of F(n)){let{firstChild:o,[C]:d}=a;for(let h of r)o===d[h]?o=o.nextSibling:a.insertBefore(d[h],o)}}return e},ge=(e,t)=>{W=1;try{return he(e,t instanceof Function?Array.isArray(e)?t(e.filter(r=>1)):ne(t(T(e))):t)}finally{W=J}},B=e=>Array.isArray(e)?e.filter(t=>1).map(B):v(e)?be(Ae(I(e)),ne(T(e).map(([t,r])=>[t,B(r)]))):e;var ye=(e,t="")=>{let r="@",l=":",n=".",a="^",o=(c,i,s)=>{let p=Object.keys(i).map(g=>{let f=i[g];switch(g[0]){case r:return o(`@media(max-width:${g.substring(r.length)})`,f,s);case l:return o(`&${g}`,f,s);case n:return o(`${g}${s}`,f,s);case a:return o(`&:hover .${g.substring(a.length)}${s}`,f,s)}return`${g.replace(/([a-z])([A-Z])/g,"$1-$2")}: ${f};`});return`${c}{${p.join(` -`)}}`},d=(c,i)=>{let s=i.lastIndexOf(c)+c.length;return s?i.substring(s):i},h=c=>{let i=van.tags[c],s=[],p=new Proxy((...g)=>{let f=i(...g);return f.className=s.join(y+" ")+y+" "+f.className,s=[],f},{get(g,f){return s.push(f.substring(f.lastIndexOf(".")+1)),p}});return p},y=t?"_"+t:"",P=Object.keys(e).map(c=>o("."+c+y,e[c],y)).join(` -`);return globalThis.document?.head.insertAdjacentHTML("beforeend",``),{Tag(...c){return c.map(i=>d(a,d(n,i))).join(y+" ")+y},CSS:P,DOM:new Proxy({},{get(c,i){return h(i)}}),Div:new Proxy({},{get(c,i){return h("div")[i]}})}};globalThis.van=x;globalThis.vanX=R;globalThis.Gale=ye;var H=new URL(import.meta.url).searchParams;vanX.Store=(e,t)=>{let r=localStorage.getItem(t),l=vanX.reactive(r?JSON.parse(r):e);return van.derive(()=>localStorage.setItem(t,JSON.stringify(vanX.compact(l)))),l};H.has("hmr")&&await import("/proxy/src/hmr.js");var pe=H.get("root")||"/";fetch(pe+"deno.json").then(e=>e.json()).then(e=>{let t=(l,n)=>{let a=document.createElement("script");return a.type=l,a.textContent=n,document.head.appendChild(a),a},r=e.imports;for(let l in r){let n=r[l];n.startsWith("./")&&(r[l]=pe+n.substring(2))}H.has("map")&&t("importmap",JSON.stringify({imports:r})),t("module","").src=r["GALE@ENTRY"]}); diff --git a/hmr/hmr-listen.tsx b/hmr/hmr-listen.tsx new file mode 100644 index 0000000..cd029b3 --- /dev/null +++ b/hmr/hmr-listen.tsx @@ -0,0 +1,31 @@ +import { HMR } from "./hmr-react.tsx"; +import { GroupSignal, GroupSignalHook } from "./hmr-signal.tsx"; + +const FileListeners = new Map() as Mapvoid>>; +export const FileListen =(inPath:string, inHandler:()=>void)=> +{ + const members = FileListeners.get(inPath)??[]; + members.push(inHandler); + FileListeners.set(inPath, members); +}; + +const Socket:WebSocket = new WebSocket("ws://"+document.location.host); +Socket.addEventListener('message', async(event:{data:string})=> +{ + // When a file changes, dynamically re-import it to get the updated members + // send the updated members to any listeners for that file + + GroupSignal.reset(); + + const reImport = await import(document.location.origin+event.data+"?reload="+Math.random()); + FileListeners.get(event.data)?.forEach(reExport=>reExport(reImport)); + + GroupSignal.swap(); + + GroupSignalHook.reset(); + HMR.update(); + GroupSignalHook.reset(); + +}); +Socket.addEventListener("error", ()=>{clearInterval(SocketTimer); console.log("HMR socket lost")}) +const SocketTimer = setInterval(()=>{Socket.send("ping")}, 5000); \ No newline at end of file diff --git a/hmr/hmr-react.tsx b/hmr/hmr-react.tsx new file mode 100644 index 0000000..9f1f6a9 --- /dev/null +++ b/hmr/hmr-react.tsx @@ -0,0 +1,176 @@ +import * as ReactParts from "react-original"; + +/* + +Each custom component is secretly modified to have an extra state and id. +When there is an HMR update, this state is changed, forcing it to re-render. + +Each *user-created* React.useState is secretly modified and accompanied by an ID. +Every time its state is set, the HMR.statesNew map for this ID is set to contain the new state and updater. +When a component is removed, any of it's states in HMR.statesNew are also removed. +(HMR.statesNew is the "running total" of all states currently at play). + +--- + +When a state is interacted with: +- statesNew for this id is set +- the internal state is also set in the traditional way + +When there is an HMR update: +- All custom components are re-rendered... + for each useState(value) call that then happens in the re-render: + - if there is a "statesOld" value for this state, use that and ignore the passed value, otherwise use the passed value + - if this state has not been interacted with since the last reload (statesNew is empty at this id), set statesNew with whatever is in statesOld +- statesNew is moved into *statesOld* +- statesNew is cleared. + +*/ +export const HMR = +{ + reloads:1, + RegisteredComponents: new Map() as Mapvoid>, + statesNew: new Map() as Map, + statesOld: new Map() as Map, + wireframe: false, + RegisterComponent(reactID:string, value:()=>void):void + { + this.RegisteredComponents.set(reactID, value); + }, + update() + { + this.reloads++; + this.RegisteredComponents.forEach(handler=>handler()); + this.RegisteredComponents.clear(); + this.statesOld = this.statesNew; + this.statesNew = new Map(); + } +}; + + +export type StateType = boolean|number|string|Record +export type StateCapture = {state:StateType, set:ReactParts.StateUpdater, reload:number}; +type FuncArgs = [element:keyof ReactParts.JSX.IntrinsicElements, props:Record, children:ReactParts.JSX.Element[]]; + + +const H = ReactParts.createElement; +const MapIndex =(inMap:Map, inIndex:number)=> +{ + let index = 0; + for(const kvp of inMap) + { + if(index == inIndex) + { + return kvp; + } + index++; + } + return false; +}; + +const ProxyCreate =(...args:FuncArgs)=> (typeof args[0] == "string") ? H(...args) : H(ProxyElement, {__args:args, ...args[1]}); + +const ProxyElement = (props:{__args:FuncArgs})=> +{ + const [stateGet, stateSet] = ReactParts.useState(0); + const id = ReactParts.useId(); + HMR.RegisterComponent(id, ()=>stateSet(stateGet+1)); + + const child = H(...props.__args); + + if(HMR.wireframe) + { + return H("div", {style:{padding:"10px", border:"2px solid red"}}, + H("p", null, stateGet), + child + ); + } + else + { + return child; + } +}; + +const ProxyState =(argNew:StateType)=> +{ + // does statesOld have an entry for this state? use that instead of the passed arg + const check = MapIndex(HMR.statesOld, HMR.statesNew.size); + const argOld = check ? check[1].state : argNew; + + const id = ReactParts.useId(); + const [stateGet, stateSet] = ReactParts.useState(argOld); + + // state updates due to clicks, interactivity, etc. since the last reload may already be in statesNew for this slot. + // DONT overwrite it. + if(!HMR.statesNew.get(id)) + { + HMR.statesNew.set(id, {state:stateGet, set:stateSet, reload:HMR.reloads}); + } + + const lastKnowReloads = HMR.reloads; + ReactParts.useEffect(()=>{ + return ()=>{ + if(HMR.reloads == lastKnowReloads)/*i have no idea what this does. this may have to be re-introduced when routing is added*/ + { + // this is a switch/ui change, not a HMR reload change + const oldState = MapIndex(HMR.statesOld, HMR.statesNew.size-1); + oldState && HMR.statesOld.set(oldState[0], {...oldState[1], state:argNew}); + } + + HMR.statesNew.delete(id); + } + }, []); + + + // do we need to account for the function set? + function proxySetter ( inArg:StateType|((old:StateType)=>StateType) ) + { + const stateUser = {state:inArg as StateType, set:stateSet, reload:HMR.reloads}; + if(typeof inArg == "function") + { + //const passedFunction = inArg; + stateSet((oldState:StateType)=> + { + const output = inArg(oldState); + stateUser.state = output; + HMR.statesNew.set(id, stateUser); + return output; + }); + } + else + { + HMR.statesNew.set(id, stateUser); + stateSet(inArg); + } + } + return [stateGet, proxySetter]; + +}; + +type Storelike = Record +const ProxyReducer =(inReducer:(inState:Storelike, inAction:string)=>Storelike, inState:Storelike, inInit?:(inState:Storelike)=>Storelike)=> +{ + const check = MapIndex(HMR.statesOld, HMR.statesNew.size); + const argOld = check ? check[1].state : (inInit ? inInit(inState) : inState); + + const intercept =(inInterceptState:Storelike, inInterceptAction:string)=> + { + const capture = inReducer(inInterceptState, inInterceptAction); + const stateUser = {state:capture, set:()=>{}, reload:HMR.reloads}; + HMR.statesNew.set(id, stateUser); + return capture; + }; + + const id = ReactParts.useId(); + const [state, dispatch] = ReactParts.useReducer(intercept, argOld as Storelike); + + if(!HMR.statesNew.get(id)) + { + HMR.statesNew.set(id, {state:state, set:()=>{}, reload:HMR.reloads}); + } + + return [state, dispatch]; +}; + +export * from "react-original"; +export {ProxyCreate as createElement, ProxyState as useState, ProxyReducer as useReducer }; +export default {...ReactParts, createElement:ProxyCreate, useState:ProxyState, useReducer:ProxyReducer}; \ No newline at end of file diff --git a/hmr/hmr-signal.tsx b/hmr/hmr-signal.tsx new file mode 100644 index 0000000..b37f696 --- /dev/null +++ b/hmr/hmr-signal.tsx @@ -0,0 +1,47 @@ +import * as SignalsParts from "signals-original"; +import DeepEqual from "https://esm.sh/deep-eql@4.1.3"; + +type Entry = [signal:SignalsParts.Signal, initArg:T]; + +function ProxyGroup(inFunc:(initArg:T)=>SignalsParts.Signal) +{ + let recordEntry:Entry[] = []; + let recordEntryNew:Entry[] = []; + let recordIndex = 0; + const reset =()=> recordIndex = 0; + const swap =()=> + { + recordEntry = recordEntryNew; + recordEntryNew = [] as Entry[]; + }; + const proxy =(arg:T)=> + { + const lookupOld = recordEntry[recordIndex]; + if(lookupOld && DeepEqual(lookupOld[1], arg)) + { + recordEntryNew[recordIndex] = lookupOld; + recordIndex++; + return lookupOld[0]; + } + else + { + const sig = inFunc(arg); + recordEntryNew[recordIndex] = [sig, arg]; + recordEntry[recordIndex] = [sig, arg]; + recordIndex++; + return sig; + } + }; + return {reset, swap, proxy}; +} + +export const GroupSignal = ProxyGroup(SignalsParts.signal); +export const GroupSignalHook = ProxyGroup(SignalsParts.useSignal); + + +const proxySignal = GroupSignal.proxy; +const proxySignalHook = GroupSignalHook.proxy; + +export * from "signals-original"; +export { proxySignal as signal, proxySignalHook as useSignal }; +export default {...SignalsParts, signal:proxySignal, useSignal:proxySignalHook}; \ No newline at end of file diff --git a/hmr/hmr-static.tsx b/hmr/hmr-static.tsx new file mode 100644 index 0000000..bc4882c --- /dev/null +++ b/hmr/hmr-static.tsx @@ -0,0 +1,144 @@ +type GlyphCheck = (inGlyph:string)=>boolean +const isAlphaLike:GlyphCheck =(inGlyph:string)=> +{ + const inCode = inGlyph.charCodeAt(0); + + if(inCode >= 97 && inCode <= 122) + { + return true; + } + + if(inCode >= 65 && inCode <= 90) + { + return true; + } + + return `$_.`.includes(inGlyph); +} +const isWhiteSpace:GlyphCheck =(inGlyph:string)=> `\n\r\t `.includes(inGlyph); +const isQuote:GlyphCheck =(inGlyph:string)=>`"'\``.includes(inGlyph) +const isNot =(inCheck:GlyphCheck)=> (inGlyph:string)=>!inCheck(inGlyph); +const contiguous =(inText:string, inStart:number, inTest:GlyphCheck):number=> +{ + let ok = true; + let index = inStart; + let count = 0; + while(ok && count < inText.length) + { + count++; + ok = inTest(inText.charAt(index++)); + } + return index-1; +} + +const findNextExport =(inFile:string, inIndex=0, inLocal:Array, inForeign:Array)=> +{ + const pos = inFile.indexOf("export", inIndex); + if(pos !== -1) + { + if(!isAlphaLike(inFile.charAt(pos-1)) || !isAlphaLike(inFile.charAt(pos+6))) + { + + const nextCharInd = contiguous(inFile, pos+6, isWhiteSpace); + const nextChar = inFile[nextCharInd]; + + //console.log(inFile.substring(pos, nextCharInd+1), `>>${nextChar}<<`) + + if(nextChar === "*") + { + const firstQuoteInd = contiguous(inFile, nextCharInd+1, isNot(isQuote) ); + const secondQuoteInd = contiguous(inFile, firstQuoteInd+1, isNot(isQuote) ); + //console.log("ASTERISK:", inFile.substring(pos, secondQuoteInd+1)); + inForeign.push(inFile.substring(nextCharInd, secondQuoteInd+1)); + } + else if(nextChar == "{") + { + const endBracketInd = contiguous(inFile, nextCharInd, (inGlyph:string)=>inGlyph!=="}"); + const nextLetterInd = contiguous(inFile, endBracketInd+1, isWhiteSpace); + if(inFile.substring(nextLetterInd, nextLetterInd+4) == "from") + { + const firstQuoteInd = contiguous(inFile, nextLetterInd+4, isNot(isQuote) ); + const secondQuoteInd = contiguous(inFile, firstQuoteInd+1, isNot(isQuote) ); + //console.log(`BRACKET foreign: >>${inFile.substring(nextCharInd, secondQuoteInd+1)}<<`); + inForeign.push(inFile.substring(nextCharInd, secondQuoteInd+1)); + } + else + { + const members = inFile.substring(nextCharInd+1, endBracketInd).replace(/\s/g, ''); + members.split(",").forEach(part=> + { + const renamed = part.split(" as "); + inLocal.push(renamed[1] || renamed[0]); + }); + } + + } + else if(isAlphaLike(nextChar)) + { + const keywordEndInd = contiguous(inFile, nextCharInd, isAlphaLike); + const keyword = inFile.substring(nextCharInd, keywordEndInd); + if(keyword === "default") + { + inLocal.push(keyword); + //console.log(`MEMBER: >>${keyword})}<<`); + } + else if(["const", "let", "var", "function", "class"].includes(keyword)) + { + const varStartInd = contiguous(inFile, keywordEndInd+1, isWhiteSpace); + const varEndInd = contiguous(inFile, varStartInd+1, isAlphaLike); + //console.log(`MEMBER: >>${inFile.substring(varStartInd, varEndInd)}<<`); + inLocal.push(inFile.substring(varStartInd, varEndInd)) + } + } + } + + return pos + 7; + } + else + { + return false; + } +}; + +export const ModuleShape =(inText:string)=> +{ + let match = 0 as number|false; + let count = 0; + const local = [] as string[]; + const foreign = [] as string[]; + while(match !== false && count <200) + { + count++; + match = findNextExport(inText, match, local, foreign); + } + return[local, foreign] as [local:string[], foreign:string[]]; +}; + +export const ModuleProxy =(inText:string, inPath:string)=> +{ + const [local, foreign] = ModuleShape(inText); + console.log("shape local", local); + return ` +import {FileListen} from ">/hmr/hmr-listen.tsx"; +import * as Import from "${inPath}?reload=${new Date().getTime()}"; +${ local.map(m=>`let proxy_${m} = Import.${m}; export { proxy_${m} as ${m} };`).join("\n") } +FileListen("${inPath}", (updatedModule)=> +{ + ${ local.map(m=>`proxy_${m} = updatedModule.${m};`).join("\n") } +}); +${ foreign.join(";\n") }`; +}; + + +// /////////////////////////////////////////////// +// const [local, global] = Exports(` +// // export in comment +// export * from "react"; +// const fakeexport =()=>{}; +// export{ thing1 as remapped, thing2} +// export { thing1 as remapped, thing2} from 'React'; +// export +// export const func=()=>{}; +// `); +// +// console.log(local, global); \ No newline at end of file diff --git a/index.html b/index.html index 5fcd8a4..a82cdde 100644 --- a/index.html +++ b/index.html @@ -1,8 +1,12 @@ - - - - - - + + + + Document + + + + \ No newline at end of file diff --git a/scripts/assemble_files.ts b/scripts/assemble_files.ts deleted file mode 100644 index f0c2388..0000000 --- a/scripts/assemble_files.ts +++ /dev/null @@ -1,13 +0,0 @@ -export const Root = import.meta.resolve("../"); -export const Load =async(file:string)=> await fetch(Root + file).then(resp=>resp.text()); -export const Save =async(text:string, name:string)=> await Deno.writeTextFile(name, text); - -const index = await Load("index.html"); - -export const HTML = index.replace( -``, -` - - -`); - diff --git a/scripts/bundle.ts b/scripts/bundle.ts deleted file mode 100644 index 4379ab3..0000000 --- a/scripts/bundle.ts +++ /dev/null @@ -1,61 +0,0 @@ -export interface DenoBundleOptions { - entry: string; - output?: string; - outdir?: string; - check?: boolean | "all"; - noCheck?: boolean | "remote"; - frozen?: boolean; - importMap?: string; - lock?: string; - noLock?: boolean; - noNpm?: boolean; - noRemote?: boolean; - nodeModulesDir?: boolean; - reload?: boolean | string[]; - vendor?: boolean; - allowImport?: string[]; - allowScripts?: string[]; - cert?: string; - codeSplitting?: boolean; - conditions?: string[]; - config?: string; - denyImport?: string[]; - inlineImports?: boolean; - minify?: boolean; - noConfig?: boolean; - packages?: "bundle" | "external"; - platform?: "browser" | "deno"; - preload?: string[]; - sourcemap?: "linked" | "inline" | "external"; - watch?: boolean; -} - -export default (options: DenoBundleOptions):{ out: string; err: string; }=> -{ - const argify =(str: string)=> "--"+str.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()); - const args: string[] = ["bundle"]; - const { entry, ...rest } = options; - - for (const [key, value] of Object.entries(rest)) - { - let flag = argify(key); - if (value !== true) - { - if(!value) - { - continue; - } - flag = flag + "=" + (Array.isArray(value) ? value.join(",") : value); - } - args.push(flag); - } - args.push(entry); - - console.log(args); - - const command = new Deno.Command("deno", {args}); - const result = command.outputSync(); - const decode = new TextDecoder("utf-8"); - const output = (str:Uint8Array)=> decode.decode(str).replace(/\x1b\[[0-9;]*m/g,"").replace(/\n+$/, ""); - return { out: output(result.stdout), err: output(result.stderr) } -} \ No newline at end of file diff --git a/scripts/bundle_entry.ts b/scripts/bundle_entry.ts deleted file mode 100644 index 7e7c1a8..0000000 --- a/scripts/bundle_entry.ts +++ /dev/null @@ -1,34 +0,0 @@ -import Van from "npm:vanjs-core@^1.5.5"; -globalThis.van = Van; - -import * as VanX from "npm:vanjs-ext@^0.6.3"; -globalThis.vanX = VanX; - -import Gale from "../src/gale.js"; -globalThis.Gale = Gale; - -const args = new URL(import.meta.url).searchParams; - -//Store -vanX.Store=(e,t)=>{const a=localStorage.getItem(t),r=vanX.reactive(a?JSON.parse(a):e);return van.derive((()=>localStorage.setItem(t,JSON.stringify(vanX.compact(r))))),r}; - -if(args.has("hmr")) -{ - const path = "/proxy/"+"src/hmr.js"; - await import(path); -} - -const root = args.get("root")||"/"; -fetch(root+"deno.json") -.then(text=>text.json()) -.then(json=>{ - const Script=(t,e)=>{let n=document.createElement("script"); n.type=t; n.textContent=e; document.head.appendChild(n); return n;}; - const imports = json.imports; - for(let n in imports) - { - const path=imports[n]; - path.startsWith("./")&&(imports[n]=root+path.substring(2)) - } - args.has("map") && Script("importmap",JSON.stringify({imports})); - Script("module", "").src=imports["GALE@ENTRY"]; -}); \ No newline at end of file diff --git a/scripts/bundle_subprocess.ts b/scripts/bundle_subprocess.ts deleted file mode 100644 index 7711e3f..0000000 --- a/scripts/bundle_subprocess.ts +++ /dev/null @@ -1,13 +0,0 @@ -import Bundler from "./bundle.ts"; - -const result = Bundler({ - entry: "scripts/bundle_entry.ts", - outdir: "dist", - inlineImports: true, - minify: true, - codeSplitting: true, - platform: "browser", - noLock: true, -}); - -console.log(result); \ No newline at end of file diff --git a/scripts/dev_server.ts b/scripts/dev_server.ts deleted file mode 100644 index 41319b1..0000000 --- a/scripts/dev_server.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { contentType } from "jsr:@std/media-types"; -import {HTML, Root} from "./assemble_files.ts"; - -// Parse the port from the command-line arguments, defaulting to 8000 -const port = parseInt(Deno.args[0] || "8000", 10); -const sockets: WebSocket[] = []; - -function extension(path: string): string { - // Remove trailing slash if it exists - const normalizedPath = path.endsWith("/") ? path.slice(0, -1) : path; - // Get the last part of the path - const lastPart = normalizedPath.split("/").pop() || ""; - // Check if the last part contains a "." - return lastPart.split(".")[1] || ""; -} - -// Start the HTTP server using Deno.serve -Deno.serve({ port }, async (req: Request) => { - const path = new URL(req.url).pathname; - - // Handle WebSocket connections - if (path === "/ws") { - const { socket, response } = Deno.upgradeWebSocket(req); - sockets.push(socket); - return response; - } - - // Serve static files or the predefined HTML for non-file routes - const ext = extension(path); - - // Serve the predefined HTML for non-file routes - if (!ext) { - return new Response(HTML, { - headers: { "Content-Type": "text/html" }, - }); - } - - - - try - { - const proxyPrefix = "/proxy/"; - let streamable; - if(path.startsWith(proxyPrefix)) - { - const file = await fetch(Root + path.slice(proxyPrefix.length)); - streamable = file.body; - } - else - { - const file = await Deno.open("." + path, { read: true }); - streamable = file.readable; - } - - return new Response(streamable, { - headers: { "Content-Type": contentType(ext) || "application/javascript" }, - }); - } - catch (err) - { - if (err instanceof Deno.errors.NotFound) { - return new Response("File not found", { status: 404 }); - } else { - return new Response("Internal server error", { status: 500 }); - } - } -}); - -// Start watching for file changes -const watcher = Deno.watchFs("."); -for await (const event of watcher) { - if (event.kind === "modify") { - for (const ws of sockets) { - if (ws.readyState === WebSocket.OPEN) { - ws.send("reload"); - continue; - } - } - } -} diff --git a/scripts/refresh_types.ts b/scripts/refresh_types.ts deleted file mode 100644 index 35ddd96..0000000 --- a/scripts/refresh_types.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { resolve, toFileUrl } from "https://deno.land/std/path/mod.ts"; - -async function main() -{ - // Read and parse the deno.json file - const denoJson = JSON.parse(await Deno.readTextFile("./deno.json")); - - // Check if compilerOptions and types are defined - if (denoJson.compilerOptions?.types) - { - const types:string[] = denoJson.compilerOptions.types; - - // Iterate over each type file and cache it - for (const typeFile of types) - { - let lookup:string = typeFile; - console.log(`found ambient type file`, lookup); - - if(typeFile.startsWith(".")) - { - lookup = toFileUrl(resolve(Deno.cwd(), typeFile)).href; - } - console.log(`Scan found types: ${lookup}`); - await import(lookup); // This will cache the file - } - - console.log("Scan complete; be sure to restart the Deno Language Server!!"); - - } else { - console.log("No types found in compilerOptions."); - } -} - -main().catch((error) => { - console.error("Error:", error); - Deno.exit(1); -}); \ No newline at end of file diff --git a/scripts/scaffold.ts b/scripts/scaffold.ts deleted file mode 100644 index d56f9cf..0000000 --- a/scripts/scaffold.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { parseArgs } from "jsr:@std/cli/parse-args"; -import {HTML, Save, Load, Root} from "./assemble_files.ts"; - -const args = parseArgs(Deno.args); -if(args.html) -{ - Save(HTML, "index.html"); -} -else -{ - const config = await Load("deno.json"); - const json = JSON.parse(config); - json.imports["GALE@HOST/"] = Root; - Save(JSON.stringify(json, null, "\t"), "deno.json"); - Save(await Load("app.js"), "app.js"); -} diff --git a/server.ts b/server.ts new file mode 100644 index 0000000..b08b57f --- /dev/null +++ b/server.ts @@ -0,0 +1,140 @@ +import { ModuleProxy } from "./hmr/hmr-static.tsx"; + +const keyProxy = encodeURI(">"); +const keyAdjacent = "^"; +const keyReload = "reload"; +const keysRemote = ["npm:", "jsr:", "http"]; +const keysExtension = ["ts", "tsx"]; +const extractExtension =(path)=> +{ + return path.substring(path.lastIndexOf(".")+1); +} + +const RootRunning = new URL(`file://${Deno.cwd()}`).toString(); +const RootSiblings = import.meta.resolve("./"); + +console.log(RootRunning); +console.log(RootSiblings); + +const bakeConfigPackage:Deno.bundle.Options = +{ + entrypoints:[""], + platform: "browser", + write: false, + minify: true, +} +const bakeConfigLocal:Deno.bundle.Options = {...bakeConfigPackage, minify:false, sourcemap:"inline", inlineImports:false }; +async function BakeForce(path:string, type?:"package") +{ + console.log("baking", path); + const config = type ? bakeConfigPackage : bakeConfigLocal; + config.entrypoints[0] = type ? path : RootRunning+path; + const result = await Deno.bundle(config); + + if(result.outputFiles) + { + const body = result.outputFiles.map(file=>file.text()).join("\n"); + const save:CachedTranspile = [body, type ? "" : ModuleProxy(body, path)]; + BakeCache[path] = save; + return save; + } + return undefined; +}; +async function BakeCheck(path:string, type?:"package") +{ + const lookup:CachedTranspile = await BakeCache[path]; + if(!lookup) + { + return BakeForce(path, type); + } + return lookup; +} +type CachedTranspile = [file:string, profile:string] +const BakeCache:Record = {} + + +const JSResponse =(body:string)=>new Response(body, {headers:{"content-type":"application/javascript"}}); + +Deno.serve(async(req:Request)=> +{ + const url = new URL(req.url); + const parts = url.pathname.split("/").filter(part=>part); + + const lastPart = parts.at(-1); + const extension = extractExtension(lastPart); + + console.log("REQUEST:", parts, extension); + + if(parts[0] == keyProxy) + { + const proxiedPath = parts.slice(1).join("/"); + console.log("PROXIED:", proxiedPath); + const transpiled = await BakeCheck(proxiedPath, "package"); + return JSResponse(transpiled[0]); + } + if(keysExtension.includes(extension)) + { + const transpiled = await BakeCheck(url.pathname); + return JSResponse(transpiled[url.searchParams.has(keyReload) ? 0 : 1]); + } + + if(req.headers.get("upgrade") == "websocket") + { + try + { + const { response, socket } = Deno.upgradeWebSocket(req); + socket.onopen = () => SocketsLive.add(socket); + socket.onclose = () => SocketsLive.delete(socket); + socket.onmessage = () => {}; + socket.onerror = (e) => console.log("Socket errored:", e); + return response; + } + catch(e){ console.log("Socket errored:", e); } + } + + return new Response(); +}); + +const SocketsLive:Set = new Set(); +const SocketsSend =(inData:string)=>{ for (const socket of SocketsLive){ socket.send(inData); } } + +const Watcher =async()=> +{ + let blocking = false; + const filesChanged:Map = new Map(); + for await (const event of Deno.watchFs(Deno.cwd())) + { + event.paths.forEach( path => filesChanged.set(path, event.kind) ); + if(!blocking) + { + blocking = true; + setTimeout(async()=> + { + for await (const [path, action] of filesChanged) + { + const extension = extractExtension(path); + + if(keysExtension.includes(extension)) + { + console.log("File change", path); + const key = path.substring(Deno.cwd().length).replaceAll("\\", "/"); + if(action != "remove") + { + BakeForce(path); + SocketsSend(key); + } + else + { + delete BakeCache[key]; + } + } + } + filesChanged.clear(); + blocking = false; + } + , 1000); + } + } +} + +Watcher(); \ No newline at end of file diff --git a/shadow.html b/shadow.html deleted file mode 100644 index 37f2ad2..0000000 --- a/shadow.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - Shadow DOM Example - - - - - - - - - \ No newline at end of file diff --git a/src/gale-2.js b/src/gale-2.js deleted file mode 100644 index a88df10..0000000 --- a/src/gale-2.js +++ /dev/null @@ -1,54 +0,0 @@ - - -Sheet({ - fontSize:`12px` -},{ - 1024: - { - fontSize:`14px` - } -}) - -function Prox() -{ - const obj = new Proxy({}, { - get(target, propName, receiver) - { - console.log("get:", propName) - return obj; - }, - set(target, propName, value, receiver) - { - console.log("set:", propName) - return true; - } - }) - return obj; -} - - - -// -// const sheet = {}; -// -// sheet -// .Font.size`8px`.color`#aabbcc` -// [512] -// .Font.size`10px` -// [1024] -// .Font.size`12px` -// -// -// sheet(1024, -// Font.size`12px`.color`#aabbcc` -// )(512, -// Font.size`10px`); -// - - -const p1 = Prox(); - -p1.read - -p1.write = 123; - diff --git a/src/gale.js b/src/gale.js deleted file mode 100644 index 6b5471a..0000000 --- a/src/gale.js +++ /dev/null @@ -1,89 +0,0 @@ -/** @type {Gale.CreateSheet} */ -export default (sheet, hash="")=> -{ - const KeyQuery = "@"; - const KeyState = ":"; - const KeyChild = "."; - const KeyGroup = "^"; - - /** @type {Gale.Tier} */ - const Tier=(selector, obj, suffix)=> - { - const styles = Object.keys(obj).map((key)=> - { - const value = obj[key]; - switch(key[0]) - { - case KeyQuery : - return Tier(`@media(max-width:${key.substring(KeyQuery.length)})`, value, suffix); - case KeyState : - return Tier(`&${key}`, value, suffix); - case KeyChild : - return Tier(`${key}${suffix}`, value, suffix); - case KeyGroup : - return Tier(`&:hover .${key.substring(KeyGroup.length)}${suffix}`, value, suffix); - } - return `${ key.replace(/([a-z])([A-Z])/g, '$1-$2') }: ${value};` - }); - - return `${selector}{${styles.join("\n")}}`; - } - - /** @type {(needle:string, str:string)=>string} */ - const extractLast =(needle, str)=>{ - const ind = str.lastIndexOf(needle)+needle.length; - return ind ? str.substring(ind) : str; - } - - const collect =(tagName)=> - { - const pending = van.tags[tagName]; - let mentioned = []; - const collector = new Proxy( - (...args)=> - { - const element = pending(...args); - element.className = mentioned.join(id+" ")+id + " " + element.className; - mentioned = []; - return element; - }, - { - get(_, prop) - { - mentioned.push(prop.substring(prop.lastIndexOf(".")+1)); - return collector; - } - } - ); - return collector; - } - - const id = hash ? "_"+hash : ""; - const css = Object.keys(sheet).map(key=>Tier("."+key+id, sheet[key], id)).join(`\n`); - globalThis.document?.head.insertAdjacentHTML("beforeend", ``); - - return { - Tag(...args){ - return args.map((arg)=>extractLast(KeyGroup, extractLast(KeyChild, arg))).join(id+" ")+id; - }, - CSS: css, - DOM: new Proxy( - {}, - { - get(_, prop) - { - return collect(prop) - } - } - ), - Div: new Proxy( - {}, - { - get(_, prop) - { - return collect("div")[prop] - } - } - ) - } -} \ No newline at end of file diff --git a/src/hmr.js b/src/hmr.js deleted file mode 100644 index b5735da..0000000 --- a/src/hmr.js +++ /dev/null @@ -1,118 +0,0 @@ - -let Time = 0; -/** @type {Record} */ -let Temp = {}; -function Tick() -{ - for(const k in Temp) - { - sessionStorage.setItem(k, Temp[k]); - } - Temp = {}; - Time = 0; -} - -/** @type {(key:string, value:string)=>void} */ -function Save(key, value) -{ - Temp[key] = value; - if(!Time) - { - Time = setTimeout(Tick, 500); - } -}; - -/** @type {(key:string)=>string|null} */ -function Load(key) -{ - const value = sessionStorage.getItem(key); - return value; -} - -/** @type {string|undefined} */ -let _ID = undefined; -let _index = 0; - -/** @type {(id:string|undefined = undefined)=>void} */ -function StartID(id) -{ - _index = 0; - _ID = id; -} - -function NextID() -{ - return _ID ? _ID + "_" + (_index++) + "_" : ""; -} - - -//bind Van -const origninalState = globalThis.van.state; -globalThis.van.state =(value, key="")=> -{ - const type = typeof value; - let reader =d=>d; - let writer =d=>d?.toString() || null; - - switch(type) - { - case "boolean" : - reader =(data)=> data === "true"; break; - case "number" : - reader = parseFloat; break; - case "object" : - reader = JSON.parse; - writer = JSON.stringify; - break; - } - - const fullKey = "HMR_" + NextID() + key; - const stringValue = Load(fullKey); - const signal = origninalState((stringValue ? reader(stringValue) : value)); - van.derive(()=>Save(fullKey, writer(signal.val))); - - return signal; -}; - -//bind VanX -const originalReactive = globalThis.vanX.reactive; -globalThis.vanX = {...globalThis.VanX, reactive:(obj, id)=> -{ - StartID(id); - const state = originalReactive(obj); - StartID(); - return state; -}}; - -// added in devmode to index.html -new WebSocket('ws://'+window.location.host+'/ws').addEventListener('message',e=>e.data==='reload'&&window.location.reload()); - -vanX.Store =(obj, key)=> -{ - let checkInit = JSON.stringify(obj); - let checkStore = localStorage.getItem(key+"check"); - localStorage.setItem(key+"check", checkInit); - - let recallJSON; - if(checkInit == checkStore) - { - let recallText = localStorage.getItem(key); - try - { - recallJSON = JSON.parse(recallText) || obj; - } - catch(e) - { - recallJSON = obj; - } - } - else - { - - recallJSON = obj; - } - - const store = vanX.reactive( recallJSON ); - van.derive(() => localStorage.setItem(key, JSON.stringify(vanX.compact(store)))); - return store; -} diff --git a/types.d.ts b/types.d.ts deleted file mode 100644 index c1f0b78..0000000 --- a/types.d.ts +++ /dev/null @@ -1,71 +0,0 @@ -import type * as VAN from "https://vanjs.org/code/van-1.5.5.d.ts"; -import type * as VANX from "https://vanjs.org/code/van-x-0.6.3.d.ts"; -type Replace = Omit & { readonly [P in K]: R }; -declare module "vanjs-core" { export type State = VAN.State } -declare global -{ - namespace Van { export type * from "https://vanjs.org/code/van-1.5.5.d.ts"; } - namespace VanX { export type * from "https://vanjs.org/code/van-x-0.6.3.d.ts"; } - const van: Replace(arg:T, HMRKey?:string)=>VAN.State> - const vanX: Replace(obj: T, HMRKey?:string) => T> & {Store:(obj:T, key:string)=>T} -} - -declare global { - - namespace Gale { - type KeyQuery = "@"; - type KeyState = ":"; - type KeyChild = "."; - type KeyGroup = "^"; - type UserStyles = Partial & {[key: `${KeyQuery|KeyState|KeyChild|KeyGroup}${string}`]: UserStyles } - type UserSheet = Record - type CollectKeys = {[Key in keyof Obj]: Obj[Key] extends object ? Key | CollectKeys : Key }[keyof Obj] - type FilterKeys = Keys extends `${KeyChild|KeyGroup}${infer Rest}` ? Keys : never - type CrossMultiply = A extends string ? B extends string ? `${A}${B}` : never : never - type CrossMultiplyRecord = keyof Rec | { [K in keyof Rec]: K extends string ? CrossMultiply>> : never }[keyof Rec] - type Tier = (selector:string, obj:UserStyles, suffix:string)=>string; - type CreateSheet = (sheet:UserSheet&T, hash?:string)=>{ - Tag:(...args:CrossMultiplyRecord[])=>string, - CSS:string, - DOM:Elemental>, - Div:Circular, Van.TagFunc> - } - - - type Elemental = {[K in keyof HTMLElementTagNameMap]: Van.TagFunc&Circular>} - - type Circular = { - [K in Keys]: Circular&Func - }; - } - - const Gale:Gale.CreateSheet - -} - - -declare global -{ - namespace JSS - { - - type Block = Partial> - type Responsive = Record - type Unit = "px" | "em" | "rem" | "%" | "vh" | "vw" | "vmin" | "vmax" | "cm" | "mm" | "in" | "pt" | "pc" | "ch" | "ex" - type UnitValue = `${number}${Unit}` | [amount:number, unit:Unit] - - type HexNumber = "1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"|"0"|"a"|"b"|"c"|"d"|"e"|"f" - type HexTriplet = `#${HexNumber}${HexNumber}${HexNumber}` - type HexColor = `#${HexNumber}${HexNumber}${HexNumber}${HexNumber}${HexNumber}${HexNumber}` - - type Rules = { - fontSize: UnitValue, - letterSpacing: UnitValue - } - - type SheetGen =(mobile:Block, conditions?:Responsive)=> void - } - - const Sheet:JSS.SheetGen -} -