From 23988996620f9c81f85482527fd4dcbd9fc93145 Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Tue, 1 Aug 2023 10:19:39 -0400 Subject: [PATCH 01/11] add config hunter --- cli.tsx | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ deno.json | 7 +++-- deno.lock | 28 ------------------ 3 files changed, 89 insertions(+), 31 deletions(-) create mode 100644 cli.tsx delete mode 100644 deno.lock diff --git a/cli.tsx b/cli.tsx new file mode 100644 index 0000000..b0ffa78 --- /dev/null +++ b/cli.tsx @@ -0,0 +1,85 @@ +import { parse as JSONC } from "https://deno.land/x/jsonct@v0.1.0/mod.ts"; + +export async function HuntConfig() +{ + const Root = new URL(`file://${Deno.cwd().replaceAll("\\", "/")}`).toString(); + let path:string, resp:Response, text="", json; + try + { + path = "./deno.json" + resp = await fetch(Root + "/" + path); + text = await resp.text(); + } + catch(e) + { + try + { + path = "./deno.jsonc"; + resp = await fetch(Root + "/" + path); + text = await resp.text(); + } + catch(e) + { + try + { + path = Root+"/.vscode/settings.json" + resp = await fetch(path); + json = await resp.json(); + path = json["deno.config"]; + if(path) + { + resp = await fetch(Root + "/" + path); + text = await resp.text(); + } + } + catch(e) + { + path = ""; + } + } + } + + if(text) + { + try + { + json = JSONC(text); + } + catch(e) + { + // malformed json + } + } + + return {text, path, json}; +} + +export async function SubProcess(args:string[]) +{ + const command = new Deno.Command( + `deno`, + { + args, + stdin: "piped", + stdout: "piped" + } + ); + + const child = command.spawn(); + + // open a file and pipe the subprocess output to it. + const writableStream = new WritableStream({ + write(chunk: Uint8Array): Promise { + Deno.stdout.write(chunk); + return Promise.resolve(); + }, + }); + child.stdout.pipeTo(writableStream); + + // manually close stdin + child.stdin.close(); + const status = await child.status; +} + +const conf = await HuntConfig(); +console.log(conf); \ No newline at end of file diff --git a/deno.json b/deno.json index e1872f0..2cbba0c 100644 --- a/deno.json +++ b/deno.json @@ -1,11 +1,12 @@ { "compilerOptions": { "lib": ["deno.window", "dom"], "jsx": "react-jsx", - "jsxImportSource": "https://esm.sh/preact@10.15.1/compat" + "jsxImportSource": "react" }, "imports": { "react":"https://esm.sh/preact@10.15.1/compat", + "react/":"https://esm.sh/preact@10.15.1/compat/", "react-original":"https://esm.sh/preact@10.15.1/compat", "able/": "http://localhost:4507/" }, @@ -13,7 +14,7 @@ { "local": "deno run -A --reload=http://localhost:4507 --no-lock ./run-local.tsx --port=1234", "serve": "deno run -A --reload=http://localhost:4507 --no-lock ./run-serve.tsx --port=1234", - "debug": "deno run -A --reload=http://localhost:4507 --inspect-wait --no-lock ./run-serve.tsx --port=1234", - "deploy":"deno run -A --no-lock --reload=http://localhost:4507 http://localhost:4507/run-deploy.tsx" + "debug": "deno run -A --reload=http://localhost:4507 --no-lock --inspect-wait ./run-serve.tsx --port=1234", + "cloud": "deno run -A --reload=http://localhost:4507 --no-lock ./run-deploy.tsx" } } \ No newline at end of file diff --git a/deno.lock b/deno.lock deleted file mode 100644 index f98e488..0000000 --- a/deno.lock +++ /dev/null @@ -1,28 +0,0 @@ -{ - "version": "2", - "remote": { - "http://localhost:4507/hmr-static.tsx": "b88a33a019b7a6090d05a43d15843b36fe294196c4423c753fe3654ab369f1b1", - "http://localhost:4507/run-local.tsx": "2c0bf9b994677f2c0bb6ef26616960f25f61e3f8b4767891a95896fb7752a74e", - "http://localhost:4507/run-serve.tsx": "400828ea6457485c3bfcfe3bfdd60b1844e6e66f56a3606d250ce9a7481c6ead", - "http://localhost:4507/run.tsx": "f7f2a90d2bda35e5de3b307e36666120439f516d88f44a4388a3251679a99e3e", - "https://deno.land/std@0.180.0/media_types/_db.ts": "7606d83e31f23ce1a7968cbaee852810c2cf477903a095696cdc62eaab7ce570", - "https://deno.land/std@0.180.0/media_types/_util.ts": "916efbd30b6148a716f110e67a4db29d6949bf4048997b754415dd7e42c52378", - "https://deno.land/std@0.180.0/media_types/content_type.ts": "c682589a0aeb016bfed355cc1ed6fbb3ead2ea48fc0000ac5de6a5730613ad1c", - "https://deno.land/std@0.180.0/media_types/extension.ts": "7a4ef2813d7182f724a941f38161525996e4a67abc3cf6a0f9bc2168d73a0f0e", - "https://deno.land/std@0.180.0/media_types/extensions_by_type.ts": "4358023feac696e6e9d49c0f1e76a859f03ca254df57812f31f8536890c3a443", - "https://deno.land/std@0.180.0/media_types/format_media_type.ts": "1e35e16562e5c417401ffc388a9f8f421f97f0ee06259cbe990c51bae4e6c7a8", - "https://deno.land/std@0.180.0/media_types/get_charset.ts": "8be15a1fd31a545736b91ace56d0e4c66ea0d7b3fdc5c90760e8202e7b4b1fad", - "https://deno.land/std@0.180.0/media_types/mod.ts": "d3f0b99f85053bc0b98ecc24eaa3546dfa09b856dc0bbaf60d8956d2cdd710c8", - "https://deno.land/std@0.180.0/media_types/parse_media_type.ts": "bed260d868ea271445ae41d748e7afed9b5a7f407d2777ead08cecf73e9278de", - "https://deno.land/std@0.180.0/media_types/type_by_extension.ts": "6076a7fc63181d70f92ec582fdea2c927eb2cfc7f9c9bee9d6add2aca86f2355", - "https://deno.land/std@0.180.0/media_types/vendor/mime-db.v1.52.0.ts": "6925bbcae81ca37241e3f55908d0505724358cda3384eaea707773b2c7e99586", - "https://esm.sh/@swc/wasm-web@1.3.62": "e077889c90bd43ad29e9cf086818efc334bdf31b933575e0c27972173053a3c6", - "https://esm.sh/preact@10.15.1/compat/jsx-runtime": "3f191e04473646ff8f5f76fb4378fc502a7cc892d9e147584d4f7531981bc86b", - "https://esm.sh/stable/preact@10.15.1/denonext/compat.js": "bad6b5b4d4fdfa5975b7a8d30410bd6877247f058e4952799fab39f66a94b8cf", - "https://esm.sh/stable/preact@10.15.1/denonext/compat/jsx-runtime.js": "e5c016fa258601ca873ba29188e56cede90372a0bdb52e58b0dfb801f2e2f219", - "https://esm.sh/stable/preact@10.15.1/denonext/hooks.js": "5c989ad368cf4f2cb3a5d7d1801843d9348c599fe3e7731d04728f7b845d724e", - "https://esm.sh/stable/preact@10.15.1/denonext/jsx-runtime.js": "52806054f5b3477005ab4bdc17de3d219ccc6c130d0cd803c45667b0cac2f6ed", - "https://esm.sh/stable/preact@10.15.1/denonext/preact.mjs": "30710ac1d5ff3711ae0c04eddbeb706f34f82d97489f61aaf09897bc75d2a628", - "https://esm.sh/v130/@swc/wasm-web@1.3.62/denonext/wasm-web.mjs": "57046d46c9ef1398a294ba7447034f5966e48866a05c309cccec4bb4d6e7c61b" - } -} -- 2.34.1 From 35f8e64a26b210b54a96aa02d771bc6c2c29b716 Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Tue, 1 Aug 2023 15:30:31 -0400 Subject: [PATCH 02/11] installer started --- cli.tsx | 52 ++++++++++++++++++++++++++++++++++------ deno.json => deno__.json | 4 ++-- install__/deno.jsonc | 41 +++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 9 deletions(-) rename deno.json => deno__.json (91%) create mode 100644 install__/deno.jsonc diff --git a/cli.tsx b/cli.tsx index b0ffa78..7740e3f 100644 --- a/cli.tsx +++ b/cli.tsx @@ -1,12 +1,11 @@ import { parse as JSONC } from "https://deno.land/x/jsonct@v0.1.0/mod.ts"; - +const Root = new URL(`file://${Deno.cwd().replaceAll("\\", "/")}`).toString(); export async function HuntConfig() { - const Root = new URL(`file://${Deno.cwd().replaceAll("\\", "/")}`).toString(); let path:string, resp:Response, text="", json; try { - path = "./deno.json" + path = "deno.json" resp = await fetch(Root + "/" + path); text = await resp.text(); } @@ -14,7 +13,7 @@ export async function HuntConfig() { try { - path = "./deno.jsonc"; + path = "deno.jsonc"; resp = await fetch(Root + "/" + path); text = await resp.text(); } @@ -26,6 +25,7 @@ export async function HuntConfig() resp = await fetch(path); json = await resp.json(); path = json["deno.config"]; + json = undefined; if(path) { resp = await fetch(Root + "/" + path); @@ -51,7 +51,18 @@ export async function HuntConfig() } } - return {text, path, json}; + return {path, text, json}; +} + +async function Prompt(question: string):Promise +{ + const buf = new Uint8Array(1024); + await Deno.stdout.write(new TextEncoder().encode(question)); + const bytes = await Deno.stdin.read(buf); + if (bytes) { + return new TextDecoder().decode(buf.subarray(0, bytes)).trim(); + } + throw new Error("Unexpected end of input"); } export async function SubProcess(args:string[]) @@ -81,5 +92,32 @@ export async function SubProcess(args:string[]) const status = await child.status; } -const conf = await HuntConfig(); -console.log(conf); \ No newline at end of file +const config = await HuntConfig(); +if(!config.path) +{ + try + { + const resp = await Prompt("No Deno configuration found. Create one? [y/n]"); + if(resp == "y") + { + const pathServer = import.meta.resolve("./"); + const pathConfig = pathServer + "install__/deno.jsonc"; + + console.log(pathServer, pathConfig); + + const resp = await fetch(pathConfig); + const text = await resp.text(); + Deno.writeTextFileSync(Deno.cwd()+"/deno.jsonc", text.replaceAll("{{server}}", pathServer)); + } + else + { + throw(""); + } + } + catch(e) + { + console.log(e, "(Exiting...)"); + Deno.exit(); + } +} +console.log(config); \ No newline at end of file diff --git a/deno.json b/deno__.json similarity index 91% rename from deno.json rename to deno__.json index 2cbba0c..1e16461 100644 --- a/deno.json +++ b/deno__.json @@ -8,13 +8,13 @@ "react":"https://esm.sh/preact@10.15.1/compat", "react/":"https://esm.sh/preact@10.15.1/compat/", "react-original":"https://esm.sh/preact@10.15.1/compat", - "able/": "http://localhost:4507/" + ">able/": "http://localhost:4507/" }, "tasks": { "local": "deno run -A --reload=http://localhost:4507 --no-lock ./run-local.tsx --port=1234", "serve": "deno run -A --reload=http://localhost:4507 --no-lock ./run-serve.tsx --port=1234", + "cloud": "deno run -A --reload=http://localhost:4507 --no-lock ./run-deploy.tsx", "debug": "deno run -A --reload=http://localhost:4507 --no-lock --inspect-wait ./run-serve.tsx --port=1234", - "cloud": "deno run -A --reload=http://localhost:4507 --no-lock ./run-deploy.tsx" } } \ No newline at end of file diff --git a/install__/deno.jsonc b/install__/deno.jsonc new file mode 100644 index 0000000..8dce7ac --- /dev/null +++ b/install__/deno.jsonc @@ -0,0 +1,41 @@ +{ + "imports": + { + "react":"https://esm.sh/preact@10.15.1/compat", // (required) Specifier for 'react' + "react/":"https://esm.sh/preact@10.15.1/compat/", // (conditional) This allows the use of JSX without explicitly importing React into a module. If you choose to remove this (and make importing react required), also remove "jsx" and "jsxImportSource" from "compilerOptions" (below) + ">able/": "{{server}}" // (required) Specifier 'able'. (See note below about "isomorphic proxies") + }, + + "tasks": + { + "local": "deno run -A --reload=http://localhost:4507 --no-lock ./run-local.tsx --port=1234", + "serve": "deno run -A --reload=http://localhost:4507 --no-lock ./run-serve.tsx --port=1234", + "cloud": "deno run -A --reload=http://localhost:4507 --no-lock ./run-deploy.tsx", + "debug": "deno run -A --reload=http://localhost:4507 --no-lock --inspect-wait ./run-serve.tsx --port=1234" + }, + + "compilerOptions": + { + "lib": ["deno.window", "dom"], // makes the Deno Language Server OK with browser-specific code + "jsx": "react-jsx", // see "react/" import above + "jsxImportSource": "react" // ^ + } + +/* + + Imports prefixed with ">" are "isomorphic proxies." + In addition to functioning normally as bare module specifiers for Deno, **these imports are added as routes when the server starts**. + Assuming the specifier points to remotely a hosted directory containing typescript files, requests to your running Able server on these proxy routes are actually fetched from the remote, then transpiled (and cached), then send back as a response. + For example, after the Able server starts, if it sees a web request to '/>able/iso-elements.tsx' it would actually return a browser-friendly transpiled copy of what was on the remote. + Conversely, if the Deno Language Server were to see: `import * as Iso from ">able/iso-elements.tsx";` in one of your modules, + that will be resolved normally with the import map and Deno will just receive the tsx file as-is from the remote, typings and all, so intellisense will work in your IDE. + + While ">able/" is a required "import proxy" to pull in Able source code, you are free to use this convention to also add your own proxies as you see fit. + E.g. adding this record to imports: + ">your-import/": "https://raw.githubusercontent.com/your-name/your-lib/master/" + will give both Deno and browsers running your Able project everything they need + import CoolComponent from ">your-import/cc.tsx"; + ... + +*/ +} \ No newline at end of file -- 2.34.1 From 2d2ba6fa2ba6ca9b78d3df06e0a0cfa4f4b9079c Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Tue, 1 Aug 2023 17:23:19 -0400 Subject: [PATCH 03/11] install function --- cli.tsx | 76 ++++++++++++++++++++++++++++++++++++-------- deno.jsonc | 43 +++++++++++++++++++++++++ install__/api.tsx | 4 +++ install__/app.tsx | 1 + install__/deno.jsonc | 4 ++- 5 files changed, 113 insertions(+), 15 deletions(-) create mode 100644 deno.jsonc create mode 100644 install__/api.tsx create mode 100644 install__/app.tsx diff --git a/cli.tsx b/cli.tsx index 7740e3f..2a3c83c 100644 --- a/cli.tsx +++ b/cli.tsx @@ -1,12 +1,14 @@ import { parse as JSONC } from "https://deno.land/x/jsonct@v0.1.0/mod.ts"; -const Root = new URL(`file://${Deno.cwd().replaceAll("\\", "/")}`).toString(); +const RootFile = new URL(`file://${Deno.cwd().replaceAll("\\", "/")}`).toString(); +const RootHost = import.meta.resolve("./"); + export async function HuntConfig() { let path:string, resp:Response, text="", json; try { path = "deno.json" - resp = await fetch(Root + "/" + path); + resp = await fetch(RootFile + "/" + path); text = await resp.text(); } catch(e) @@ -14,21 +16,21 @@ export async function HuntConfig() try { path = "deno.jsonc"; - resp = await fetch(Root + "/" + path); + resp = await fetch(RootFile + "/" + path); text = await resp.text(); } catch(e) { try { - path = Root+"/.vscode/settings.json" + path = RootFile+"/.vscode/settings.json" resp = await fetch(path); json = await resp.json(); path = json["deno.config"]; json = undefined; if(path) { - resp = await fetch(Root + "/" + path); + resp = await fetch(RootFile + "/" + path); text = await resp.text(); } } @@ -54,6 +56,11 @@ export async function HuntConfig() return {path, text, json}; } +export async function HuntImport() +{ + +} + async function Prompt(question: string):Promise { const buf = new Uint8Array(1024); @@ -92,26 +99,63 @@ export async function SubProcess(args:string[]) const status = await child.status; } +export async function Install(file:string, handler:(content:string)=>string = (s)=>s) +{ + const pathFile = RootHost + "install__/" + file; + + try{ + const check = await Deno.readTextFile(Deno.cwd()+"/"+file); + const replace = await Prompt(`The file "${file}" already exists. Replace it? [y/n]`); + if(replace == "y") + { + throw("") + } + console.log(`Skipping "${file}" for now.`); + } + catch(e) + { + const resp = await fetch(pathFile); + const text = await resp.text(); + await Deno.writeTextFile(Deno.cwd()+"/"+file, handler(text)); + } +} + const config = await HuntConfig(); if(!config.path) { + const pathServer = import.meta.resolve("./"); try { - const resp = await Prompt("No Deno configuration found. Create one? [y/n]"); - if(resp == "y") + const resp1 = await Prompt("No Deno configuration found. Create one? [y/n]"); + if(resp1 == "y") { - const pathServer = import.meta.resolve("./"); - const pathConfig = pathServer + "install__/deno.jsonc"; + const resp2 = await Prompt("Do you also want to add starter files? [y/n]"); + let replaceApp = "./path/to/app.tsx"; + let replaceApi = "./path/to/api.tsx"; + let replaceCommentApp = "// (required) module with default export ()=>React.JSX.Element"; + let replaceCommentApi = "// (optional) module with default export (req:Request, url:URL)=>Promise"; + if(resp2 == "y") + { + replaceApp = "./app.tsx"; + replaceApi = "./api.tsx"; + replaceCommentApp = ""; + replaceCommentApi = ""; - console.log(pathServer, pathConfig); + await Install("app.tsx"); + await Install("api.tsx"); + } - const resp = await fetch(pathConfig); - const text = await resp.text(); - Deno.writeTextFileSync(Deno.cwd()+"/deno.jsonc", text.replaceAll("{{server}}", pathServer)); + await Install("deno.jsonc", (s)=>s + .replace("{{server}}", RootHost) + .replace("{{app}}", replaceApp) + .replace("{{api}}", replaceApi) + .replace("{{commentApp}}", replaceCommentApp) + .replace("{{commentApi}}", replaceCommentApi) + ); } else { - throw(""); + throw("Config declined."); } } catch(e) @@ -119,5 +163,9 @@ if(!config.path) console.log(e, "(Exiting...)"); Deno.exit(); } +} +else if(config.json) +{ + } console.log(config); \ No newline at end of file diff --git a/deno.jsonc b/deno.jsonc new file mode 100644 index 0000000..ead660c --- /dev/null +++ b/deno.jsonc @@ -0,0 +1,43 @@ +{ + "imports": + { + "react":"https://esm.sh/preact@10.15.1/compat", // (required) Specifier for 'react' + "react/":"https://esm.sh/preact@10.15.1/compat/", // (conditional) This allows the use of JSX without explicitly importing React into a module. If you choose to remove this (and make importing react required), also remove "jsx" and "jsxImportSource" from "compilerOptions" (below) + ">able/": "http://localhost:4507/", // (required) Specifier 'able'. (See note below about "isomorphic proxies") + // (required) module with default export ()=>React.JSX.Element">able/app.tsx": "./path/to/app.tsx", + // (optional) module with default export (req:Request, url:URL)=>Promise">able/api.tsx": "./path/to/api.tsx" + }, + + "tasks": + { + "local": "deno run -A --reload=http://localhost:4507 --no-lock ./run-local.tsx --port=1234", + "serve": "deno run -A --reload=http://localhost:4507 --no-lock ./run-serve.tsx --port=1234", + "cloud": "deno run -A --reload=http://localhost:4507 --no-lock ./run-deploy.tsx", + "debug": "deno run -A --reload=http://localhost:4507 --no-lock --inspect-wait ./run-serve.tsx --port=1234" + }, + + "compilerOptions": + { + "lib": ["deno.window", "dom"], // makes the Deno Language Server OK with browser-specific code + "jsx": "react-jsx", // see "react/" import above + "jsxImportSource": "react" // ^ + } + +/* + + Imports prefixed with ">" are "isomorphic proxies." + In addition to functioning normally as bare module specifiers for Deno, **these imports are added as routes when the server starts**. + Assuming the specifier points to remotely a hosted directory containing typescript files, requests to your running Able server on these proxy routes are actually fetched from the remote, then transpiled (and cached), then send back as a response. + For example, after the Able server starts, if it sees a web request to '/>able/iso-elements.tsx' it would actually return a browser-friendly transpiled copy of what was on the remote. + Conversely, if the Deno Language Server were to see: `import * as Iso from ">able/iso-elements.tsx";` in one of your modules, + that will be resolved normally with the import map and Deno will just receive the tsx file as-is from the remote, typings and all, so intellisense will work in your IDE. + + While ">able/" is a required "import proxy" to pull in Able source code, you are free to use this convention to also add your own proxies as you see fit. + E.g. adding this record to imports: + ">your-import/": "https://raw.githubusercontent.com/your-name/your-lib/master/" + will give both Deno and browsers running your Able project everything they need + import CoolComponent from ">your-import/cc.tsx"; + ... + +*/ +} \ No newline at end of file diff --git a/install__/api.tsx b/install__/api.tsx new file mode 100644 index 0000000..777ecae --- /dev/null +++ b/install__/api.tsx @@ -0,0 +1,4 @@ +export default (req:Request):Response|false=> +{ + return false; +} \ No newline at end of file diff --git a/install__/app.tsx b/install__/app.tsx new file mode 100644 index 0000000..2308168 --- /dev/null +++ b/install__/app.tsx @@ -0,0 +1 @@ +export default ()=>{}; \ No newline at end of file diff --git a/install__/deno.jsonc b/install__/deno.jsonc index 8dce7ac..de8f769 100644 --- a/install__/deno.jsonc +++ b/install__/deno.jsonc @@ -3,7 +3,9 @@ { "react":"https://esm.sh/preact@10.15.1/compat", // (required) Specifier for 'react' "react/":"https://esm.sh/preact@10.15.1/compat/", // (conditional) This allows the use of JSX without explicitly importing React into a module. If you choose to remove this (and make importing react required), also remove "jsx" and "jsxImportSource" from "compilerOptions" (below) - ">able/": "{{server}}" // (required) Specifier 'able'. (See note below about "isomorphic proxies") + ">able/": "{{server}}", // (required) Specifier 'able'. (See note below about "isomorphic proxies") + {{commentApp}}">able/app.tsx": "{{app}}", + {{commentApi}}">able/api.tsx": "{{api}}" }, "tasks": -- 2.34.1 From c558ecb6d2e5069a29f27b6e1b92f6ee0b3d816a Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Tue, 1 Aug 2023 22:42:23 -0400 Subject: [PATCH 04/11] import map and settings started --- cli.tsx | 133 +++++++++++++++++++++++++++++++++++++++++++---------- deno.jsonc | 7 ++- 2 files changed, 112 insertions(+), 28 deletions(-) diff --git a/cli.tsx b/cli.tsx index 2a3c83c..45da634 100644 --- a/cli.tsx +++ b/cli.tsx @@ -2,6 +2,9 @@ import { parse as JSONC } from "https://deno.land/x/jsonct@v0.1.0/mod.ts"; const RootFile = new URL(`file://${Deno.cwd().replaceAll("\\", "/")}`).toString(); const RootHost = import.meta.resolve("./"); +type ConfigCheck = {path?:string, text?:string, json?:Record>}; +type ConfigCheckPair = [config:ConfigCheck, imports:ConfigCheck]; + export async function HuntConfig() { let path:string, resp:Response, text="", json; @@ -30,7 +33,8 @@ export async function HuntConfig() json = undefined; if(path) { - resp = await fetch(RootFile + "/" + path); + path = RootFile + "/" + path + resp = await fetch(path); text = await resp.text(); } } @@ -49,16 +53,33 @@ export async function HuntConfig() } catch(e) { - // malformed json + // malformed config } } - return {path, text, json}; -} - -export async function HuntImport() -{ + let imports:ConfigCheck = {}; + if(json && json.imports) + { + imports.json = json; + imports.text = JSON.stringify(json.imports); + imports.path = path; + } + else if(json && !json.imports && json.importMap) + { + try + { + imports.path = RootFile + "/" + json.importMap; + resp = await fetch(imports.path); + imports.text = await resp.text(); + imports.json = JSONC(text); + } + catch(e) + { + // malformed import map + } + } + return [{path, text, json}, imports] as ConfigCheckPair } async function Prompt(question: string):Promise @@ -120,16 +141,16 @@ export async function Install(file:string, handler:(content:string)=>string = (s } } -const config = await HuntConfig(); -if(!config.path) +try { - const pathServer = import.meta.resolve("./"); - try + let [config, imports] = await HuntConfig(); + console.log(`1) Checking for Deno configuration...`) + if(!config.path) { - const resp1 = await Prompt("No Deno configuration found. Create one? [y/n]"); + const resp1 = await Prompt(" ! No Deno configuration found. Create one? [y/n]"); if(resp1 == "y") { - const resp2 = await Prompt("Do you also want to add starter files? [y/n]"); + const resp2 = await Prompt(" ? Do you also want to add starter files? [y/n]"); let replaceApp = "./path/to/app.tsx"; let replaceApi = "./path/to/api.tsx"; let replaceCommentApp = "// (required) module with default export ()=>React.JSX.Element"; @@ -144,6 +165,10 @@ if(!config.path) await Install("app.tsx"); await Install("api.tsx"); } + else + { + // config initialized with no app or api + } await Install("deno.jsonc", (s)=>s .replace("{{server}}", RootHost) @@ -152,20 +177,80 @@ if(!config.path) .replace("{{commentApp}}", replaceCommentApp) .replace("{{commentApi}}", replaceCommentApi) ); + + [config, imports] = await HuntConfig(); } else { - throw("Config declined."); + throw(" X Config is required."); } - } - catch(e) - { - console.log(e, "(Exiting...)"); - Deno.exit(); - } -} -else if(config.json) -{ + } + +/* +const inputString = `Some text 'imports' more text { some content }`; +const regex = /(?<=(['"`])imports\1[^{}]*{)/; + +const match = inputString.search(regex); + +if (match !== -1) { + console.log("Index of '{':", match); +} else { + console.log("'{': Not found."); +} +*/ + + console.log(`2) Verifying configuration...`) + if(config.json && imports.json?.imports) + { + const importMap = imports.json.imports as Record; + let changes = false; + if(!importMap["react"]) + { + const resp = await Prompt(` ! Import map has no specifier for React. Add it now? (will use Preact compat) [y/n]`); + if(resp == "y") + { + importMap["react"] = "https://esm.sh/preact@10.16.0/compat"; + changes = true; + } + else + { + throw(" X A React import is required."); + } + } + if(!importMap[">able/"]) + { + const resp = await Prompt(` ! Import map has no specifier for Able (">able/"). Add it now? [y/n]`); + if(resp == "y") + { + importMap[">able/"] = RootHost; + changes = true; + } + else + { + throw(" X Able is required."); + } + } + + const compOpts = imports.json.compilerOptions as Record; + if(compOpts) + { + const compJSX = compOpts["jsx"]; + const compJSXImportSource = compOpts["jsxImportSource"] + if(compJSX || compJSXImportSource) + { + if(!importMap["react/"]) + { + //const resp = await Prompt(` ! Import map has no specifier for React ("react"). Add it now? [y/n]`); + } + } + } + + + } +} +catch(e) +{ + console.log(e, "\n (Able Exiting...)"); + Deno.exit(); } -console.log(config); \ No newline at end of file diff --git a/deno.jsonc b/deno.jsonc index ead660c..b2935dc 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -1,11 +1,10 @@ { "imports": { - "react":"https://esm.sh/preact@10.15.1/compat", // (required) Specifier for 'react' "react/":"https://esm.sh/preact@10.15.1/compat/", // (conditional) This allows the use of JSX without explicitly importing React into a module. If you choose to remove this (and make importing react required), also remove "jsx" and "jsxImportSource" from "compilerOptions" (below) - ">able/": "http://localhost:4507/", // (required) Specifier 'able'. (See note below about "isomorphic proxies") - // (required) module with default export ()=>React.JSX.Element">able/app.tsx": "./path/to/app.tsx", - // (optional) module with default export (req:Request, url:URL)=>Promise">able/api.tsx": "./path/to/api.tsx" + ">able/": "file:///C:/Web%20Projects/able-baker/", // (required) Specifier 'able'. (See note below about "isomorphic proxies") + ">able/app.tsx": "./app.tsx", + ">able/api.tsx": "./api.tsx" }, "tasks": -- 2.34.1 From 29768761cb1614a1d34c30bbb88dcdd44c67ede9 Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Wed, 2 Aug 2023 06:07:34 -0400 Subject: [PATCH 05/11] use deno confirm --- cli.tsx | 50 ++++++++++++++++++++------------------------------ 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/cli.tsx b/cli.tsx index 45da634..afce937 100644 --- a/cli.tsx +++ b/cli.tsx @@ -82,17 +82,6 @@ export async function HuntConfig() return [{path, text, json}, imports] as ConfigCheckPair } -async function Prompt(question: string):Promise -{ - const buf = new Uint8Array(1024); - await Deno.stdout.write(new TextEncoder().encode(question)); - const bytes = await Deno.stdin.read(buf); - if (bytes) { - return new TextDecoder().decode(buf.subarray(0, bytes)).trim(); - } - throw new Error("Unexpected end of input"); -} - export async function SubProcess(args:string[]) { const command = new Deno.Command( @@ -126,12 +115,12 @@ export async function Install(file:string, handler:(content:string)=>string = (s try{ const check = await Deno.readTextFile(Deno.cwd()+"/"+file); - const replace = await Prompt(`The file "${file}" already exists. Replace it? [y/n]`); - if(replace == "y") + const replace = confirm(`⚠️🚧 The file "${file}" already exists. Replace it?`); + if(replace) { throw("") } - console.log(`Skipping "${file}" for now.`); + console.log(`Using pre-existing "${file}" for now.`); } catch(e) { @@ -141,21 +130,22 @@ export async function Install(file:string, handler:(content:string)=>string = (s } } +console.info(`👷 Checking your project`) try { let [config, imports] = await HuntConfig(); - console.log(`1) Checking for Deno configuration...`) if(!config.path) { - const resp1 = await Prompt(" ! No Deno configuration found. Create one? [y/n]"); - if(resp1 == "y") + //const resp1 = await Prompt(" ! No Deno configuration found. Create one? [y/n]"); + const resp1 = confirm("🚨🚧 No Deno configuration found. Create one?"); + if(resp1) { - const resp2 = await Prompt(" ? Do you also want to add starter files? [y/n]"); + const resp2 = confirm("⚠️🚧 Do you also want to add starter files?"); let replaceApp = "./path/to/app.tsx"; let replaceApi = "./path/to/api.tsx"; let replaceCommentApp = "// (required) module with default export ()=>React.JSX.Element"; let replaceCommentApi = "// (optional) module with default export (req:Request, url:URL)=>Promise"; - if(resp2 == "y") + if(resp2) { replaceApp = "./app.tsx"; replaceApi = "./api.tsx"; @@ -182,7 +172,7 @@ try } else { - throw(" X Config is required."); + throw("⛔ Config is required."); } } @@ -200,35 +190,34 @@ if (match !== -1) { } */ - console.log(`2) Verifying configuration...`) if(config.json && imports.json?.imports) { const importMap = imports.json.imports as Record; - let changes = false; + let changes = ``; if(!importMap["react"]) { - const resp = await Prompt(` ! Import map has no specifier for React. Add it now? (will use Preact compat) [y/n]`); - if(resp == "y") + const resp = confirm(`🚨🔧 Import map has no specifier for React ("react"). Fix it now? (Will use Preact compat)`); + if(resp) { importMap["react"] = "https://esm.sh/preact@10.16.0/compat"; - changes = true; + changes += `"react": "https://esm.sh/preact@10.16.0/compat",\n`; } else { - throw(" X A React import is required."); + throw(`⛔ A React import ("react") is required.`); } } if(!importMap[">able/"]) { - const resp = await Prompt(` ! Import map has no specifier for Able (">able/"). Add it now? [y/n]`); - if(resp == "y") + const resp = confirm(`🚨🔧 Import map has no specifier for Able (">able/"). Fix it now?`); + if(resp) { importMap[">able/"] = RootHost; - changes = true; + changes += `">able": "${RootHost}",\n`; } else { - throw(" X Able is required."); + throw(`⛔ The Able import (">able/") is required.`); } } @@ -254,3 +243,4 @@ catch(e) console.log(e, "\n (Able Exiting...)"); Deno.exit(); } +console.log(`🚗 Good to go!`); -- 2.34.1 From 67b5f03a7a8536dae074ab5df465bfd4595b28a9 Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Thu, 10 Aug 2023 22:37:53 -0400 Subject: [PATCH 06/11] hunt config --- cli.tsx | 307 +++++++++++++++++++++++++++++++++++------------------ deno.jsonc | 2 +- sub.tsx | 7 ++ sup.tsx | 37 +++++++ 4 files changed, 250 insertions(+), 103 deletions(-) create mode 100644 sub.tsx create mode 100644 sup.tsx diff --git a/cli.tsx b/cli.tsx index afce937..667df90 100644 --- a/cli.tsx +++ b/cli.tsx @@ -1,6 +1,41 @@ +import * as Env from "https://deno.land/std@0.194.0/dotenv/mod.ts"; +import * as Arg from "https://deno.land/std@0.194.0/flags/mod.ts"; import { parse as JSONC } from "https://deno.land/x/jsonct@v0.1.0/mod.ts"; const RootFile = new URL(`file://${Deno.cwd().replaceAll("\\", "/")}`).toString(); const RootHost = import.meta.resolve("./"); +let arg = await Arg.parse(Deno.args); +let env = await Env.load(); +const collect =async(inKey:string, inArg:Record, inEnv:Record):Promise=> +{ + const scanArg = inArg[inKey]; + const scanEnvFile = inEnv[inKey]; + const scanEnvDeno = Deno.env.get(inKey); + + if(scanArg) + { + console.log(`Using "${inKey}" from passed argument.`); + return scanArg; + } + if(scanEnvFile) + { + console.log(`Using "${inKey}" from .env file.`); + return scanEnvFile; + } + if(scanEnvDeno) + { + console.log(`Using "${inKey}" from environment variable.`); + return scanEnvDeno; + } + + const scanUser = prompt(`No "${inKey}" found. Enter one here:`); + if(!scanUser || scanUser?.length < 3) + { + console.log("Exiting..."); + Deno.exit(); + } + return scanUser; +}; + type ConfigCheck = {path?:string, text?:string, json?:Record>}; type ConfigCheckPair = [config:ConfigCheck, imports:ConfigCheck]; @@ -130,117 +165,185 @@ export async function Install(file:string, handler:(content:string)=>string = (s } } -console.info(`👷 Checking your project`) -try + + +export async function Check() { - let [config, imports] = await HuntConfig(); - if(!config.path) + console.info(`👷 Checking your project`) + try { - //const resp1 = await Prompt(" ! No Deno configuration found. Create one? [y/n]"); - const resp1 = confirm("🚨🚧 No Deno configuration found. Create one?"); - if(resp1) + let [config, imports] = await HuntConfig(); + if(!config.path) { - const resp2 = confirm("⚠️🚧 Do you also want to add starter files?"); - let replaceApp = "./path/to/app.tsx"; - let replaceApi = "./path/to/api.tsx"; - let replaceCommentApp = "// (required) module with default export ()=>React.JSX.Element"; - let replaceCommentApi = "// (optional) module with default export (req:Request, url:URL)=>Promise"; - if(resp2) + //const resp1 = await Prompt(" ! No Deno configuration found. Create one? [y/n]"); + const resp1 = confirm("🚨🚧 No Deno configuration found. Create one?"); + if(resp1) { - replaceApp = "./app.tsx"; - replaceApi = "./api.tsx"; - replaceCommentApp = ""; - replaceCommentApi = ""; - - await Install("app.tsx"); - await Install("api.tsx"); - } - else - { - // config initialized with no app or api - } - - await Install("deno.jsonc", (s)=>s - .replace("{{server}}", RootHost) - .replace("{{app}}", replaceApp) - .replace("{{api}}", replaceApi) - .replace("{{commentApp}}", replaceCommentApp) - .replace("{{commentApi}}", replaceCommentApi) - ); - - [config, imports] = await HuntConfig(); - } - else - { - throw("⛔ Config is required."); - } - - } - -/* -const inputString = `Some text 'imports' more text { some content }`; -const regex = /(?<=(['"`])imports\1[^{}]*{)/; - -const match = inputString.search(regex); - -if (match !== -1) { - console.log("Index of '{':", match); -} else { - console.log("'{': Not found."); -} -*/ - - if(config.json && imports.json?.imports) - { - const importMap = imports.json.imports as Record; - let changes = ``; - if(!importMap["react"]) - { - const resp = confirm(`🚨🔧 Import map has no specifier for React ("react"). Fix it now? (Will use Preact compat)`); - if(resp) - { - importMap["react"] = "https://esm.sh/preact@10.16.0/compat"; - changes += `"react": "https://esm.sh/preact@10.16.0/compat",\n`; - } - else - { - throw(`⛔ A React import ("react") is required.`); - } - } - if(!importMap[">able/"]) - { - const resp = confirm(`🚨🔧 Import map has no specifier for Able (">able/"). Fix it now?`); - if(resp) - { - importMap[">able/"] = RootHost; - changes += `">able": "${RootHost}",\n`; - } - else - { - throw(`⛔ The Able import (">able/") is required.`); - } - } - - const compOpts = imports.json.compilerOptions as Record; - if(compOpts) - { - const compJSX = compOpts["jsx"]; - const compJSXImportSource = compOpts["jsxImportSource"] - if(compJSX || compJSXImportSource) - { - if(!importMap["react/"]) + const resp2 = confirm("⚠️🚧 Do you also want to add starter files?"); + let replaceApp = "./path/to/app.tsx"; + let replaceApi = "./path/to/api.tsx"; + let replaceCommentApp = "// (required) module with default export ()=>React.JSX.Element"; + let replaceCommentApi = "// (optional) module with default export (req:Request, url:URL)=>Promise"; + if(resp2) { - //const resp = await Prompt(` ! Import map has no specifier for React ("react"). Add it now? [y/n]`); + replaceApp = "./app.tsx"; + replaceApi = "./api.tsx"; + replaceCommentApp = ""; + replaceCommentApi = ""; + + await Install("app.tsx"); + await Install("api.tsx"); } - } + else + { + // config initialized with no app or api + } + + await Install("deno.jsonc", (s)=>s + .replace("{{server}}", RootHost) + .replace("{{app}}", replaceApp) + .replace("{{api}}", replaceApi) + .replace("{{commentApp}}", replaceCommentApp) + .replace("{{commentApi}}", replaceCommentApi) + ); + + [config, imports] = await HuntConfig(); + } + else + { + throw("⛔ Config is required."); + } + + } + + /* + const inputString = `Some text 'imports' more text { some content }`; + const regex = /(?<=(['"`])imports\1[^{}]*{)/; + + const match = inputString.search(regex); + + if (match !== -1) { + console.log("Index of '{':", match); + } else { + console.log("'{': Not found."); + } + */ + + if(!config.json) + { + throw("⛔ Config is malformed."); + } + else if(!imports.json?.imports) + { + const resp = confirm(`🚨🔧 Configuration has no import map. Fix it now?`); + if(resp) + { + + } } + if(config.json && imports.json?.imports) + { + const importMap = imports.json.imports as Record; + let changes = ``; + if(!importMap["react"]) + { + const resp = confirm(`🚨🔧 Import map has no specifier for React ("react"). Fix it now? (Will use Preact compat)`); + if(resp) + { + importMap["react"] = "https://esm.sh/preact@10.16.0/compat"; + changes += `"react": "https://esm.sh/preact@10.16.0/compat",\n`; + } + else + { + throw(`⛔ A React import ("react") is required.`); + } + } + if(!importMap[">able/"]) + { + const resp = confirm(`🚨🔧 Import map has no specifier for Able (">able/"). Fix it now?`); + if(resp) + { + importMap[">able/"] = RootHost; + changes += `">able": "${RootHost}",\n`; + } + else + { + throw(`⛔ The Able import (">able/") is required.`); + } + } + + const compOpts = imports.json.compilerOptions as Record; + if(compOpts) + { + const compJSX = compOpts["jsx"]; + const compJSXImportSource = compOpts["jsxImportSource"] + if(compJSX || compJSXImportSource) + { + if(!importMap["react/"]) + { + //const resp = await Prompt(` ! Import map has no specifier for React ("react"). Add it now? [y/n]`); + } + } + } + + + } } + catch(e) + { + console.log(e, "\n (Able Exiting...)"); + Deno.exit(); + } + console.log(`🚗 Good to go!`); + } -catch(e) + +if(arg._.length) { - console.log(e, "\n (Able Exiting...)"); - Deno.exit(); -} -console.log(`🚗 Good to go!`); + + const [config, imports] = await HuntConfig(); + + switch(arg._[0]) + { + case "work" : + { + await SubProcess(["run", `--config=${config.path}`, RootHost+"run.tsx", "--dev", ...Deno.args]); + } + case "host" : + { + await SubProcess(["run", `--config=${config.path}`, RootHost+"run.tsx", ...Deno.args]); + } + case "push" : + { + let useToken = await collect("DENO_DEPLOY_TOKEN", arg, env); + let useProject = await collect("DENO_DEPLOY_PROJECT", arg, env); + + let scanProd:string[]|string|null = prompt(`Do you want to deploy to *production*?`); + if(scanProd) + { + scanProd = prompt(`Are you sure? This will update the live project at "${useProject}"`); + scanProd = scanProd ? ["--prod"] : []; + } + else + { + scanProd = []; + } + + await SubProcess([ + "run", + "-A", + "--no-lock", + `--config=${config.path}`, + "https://deno.land/x/deploy/deployctl.ts", + "deploy", + `--project=${useProject}`, + `--token=${useToken}`, + `--import-map=${imports.path}`, + RootHost+"run.tsx", + ...scanProd, + ...Deno.args]); + } + } +} \ No newline at end of file diff --git a/deno.jsonc b/deno.jsonc index b2935dc..8b9e02f 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -12,7 +12,7 @@ "local": "deno run -A --reload=http://localhost:4507 --no-lock ./run-local.tsx --port=1234", "serve": "deno run -A --reload=http://localhost:4507 --no-lock ./run-serve.tsx --port=1234", "cloud": "deno run -A --reload=http://localhost:4507 --no-lock ./run-deploy.tsx", - "debug": "deno run -A --reload=http://localhost:4507 --no-lock --inspect-wait ./run-serve.tsx --port=1234" + "debug": "deno run -A --no-lock --inspect-wait ./cli.tsx work --port=1234" }, "compilerOptions": diff --git a/sub.tsx b/sub.tsx new file mode 100644 index 0000000..b11c13a --- /dev/null +++ b/sub.tsx @@ -0,0 +1,7 @@ +import { parse } from "https://deno.land/std@0.194.0/flags/mod.ts"; + +let arg = parse(Deno.args); + +console.log(arg); + +console.log(Deno.env.get("super")) diff --git a/sup.tsx b/sup.tsx new file mode 100644 index 0000000..beef02b --- /dev/null +++ b/sup.tsx @@ -0,0 +1,37 @@ +import * as Env from "https://deno.land/std@0.194.0/dotenv/mod.ts"; +import * as Arg from "https://deno.land/std@0.194.0/flags/mod.ts"; + +let arg = Arg.parse(Deno.args); +let env = await Env.load(); + +Deno.env.set("super", "its super"); + +export async function SubProcess(args:string[]) +{ + const command = new Deno.Command( + `deno`, + { + args, + stdin: "piped", + stdout: "piped" + } + ); + + const child = command.spawn(); + + // open a file and pipe the subprocess output to it. + const writableStream = new WritableStream({ + write(chunk: Uint8Array): Promise { + Deno.stdout.write(chunk); + return Promise.resolve(); + }, + }); + child.stdout.pipeTo(writableStream); + + // manually close stdin + child.stdin.close(); + const status = await child.status; +} + + +SubProcess(["run", "-A", "sub.tsx", "keyword!", "--passed=yep"]); \ No newline at end of file -- 2.34.1 From b602ffcbcc570e2bdd8c6bca76de85bf3a7d816e Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Sat, 12 Aug 2023 20:30:44 -0400 Subject: [PATCH 07/11] checker started --- checker.tsx | 246 ++++++++++++++++++++++++++++++++++++++++++++++++++ cli.tsx | 241 +------------------------------------------------ deno.jsonc | 40 +------- deno.lock | 8 ++ run-serve.tsx | 82 ++++++++--------- 5 files changed, 295 insertions(+), 322 deletions(-) create mode 100644 checker.tsx create mode 100644 deno.lock diff --git a/checker.tsx b/checker.tsx new file mode 100644 index 0000000..3d7cdb4 --- /dev/null +++ b/checker.tsx @@ -0,0 +1,246 @@ +import { parse as JSONC } from "https://deno.land/x/jsonct@v0.1.0/mod.ts"; + +type ConfigCheck = {path?:string, text?:string, json?:Record>}; +type ConfigCheckPair = [config:ConfigCheck, imports:ConfigCheck]; + +export const RootHost = import.meta.resolve("./"); +export const Root = new URL(`file://${Deno.cwd().replaceAll("\\", "/")}`).toString(); +export async function HuntConfig() +{ + let path:string, resp:Response, text="", json; + try + { + path = "deno.json" + resp = await fetch(Root + "/" + path); + text = await resp.text(); + } + catch(e) + { + try + { + path = "deno.jsonc"; + resp = await fetch(Root + "/" + path); + text = await resp.text(); + } + catch(e) + { + try + { + path = ".vscode/settings.json"; + resp = await fetch(Root + "/" + path); + json = await resp.json(); + path = json["deno.config"]; + json = undefined; + if(path) + { + resp = await fetch(Root + "/" + path); + text = await resp.text(); + } + } + catch(e) + { + path = ""; + } + } + } + + if(text) + { + try + { + json = JSONC(text); + } + catch(e) + { + // malformed config + json = undefined; + } + } + + let imports:ConfigCheck = {}; + if(json && json.imports) + { + imports.json = json; + imports.text = JSON.stringify(json); + imports.path = path; + } + else if(json && !json.imports && json.importMap) + { + try + { + imports.path = json.importMap; + resp = await fetch(Root + "/" + imports.path); + imports.text = await resp.text(); + imports.json = JSONC(text); + } + catch(e) + { + // malformed import map + } + } + + return [{path, text, json}, imports] as ConfigCheckPair +} + +export async function Install(file:string, handler:(content:string)=>string = (s)=>s) +{ + const pathFile = RootHost + "install__/" + file; + + try{ + const check = await Deno.readTextFile(Deno.cwd()+"/"+file); + const replace = confirm(`⚠️🚧 The file "${file}" already exists. Replace it?`); + if(replace) + { + throw("") + } + console.log(`Using pre-existing "${file}" for now.`); + } + catch(e) + { + const resp = await fetch(pathFile); + const text = await resp.text(); + await Deno.writeTextFile(Deno.cwd()+"/"+file, handler(text)); + } +} + + + +export async function Check() +{ + console.info(`👷 Checking your project`); + try + { + let [config, imports] = await HuntConfig(); + if(!config.path) + { + if(confirm("🚨🚧 No Deno configuration found. Create a new one?")) + { + await Install("deno.jsonc"); + + Check(); + return; + } + else + { + throw("⛔ Configuration is required."); + } + } + + else if(!imports.json || !imports.json?.imports) + { + const resp = confirm(`🚨🔧 Configuration found, but has no import map. Fix it now?`); + if(resp) + { + const text = config.text||""; + const startBracket = text.indexOf("{"); + + config.text = `{ + "imports": {}${startBracket < 0 ? "\n}\n" : ",\n"}` + text.substring(startBracket+1); + + await Deno.writeTextFile(Deno.cwd()+"/"+config.path, config.text); + + Check(); + return; + + } + else + { + throw("⛔ Import maps are required."); + } + } + + if(config.json && imports.text && imports.json?.imports) + { + const importMap = imports.json.imports as Record; + let changes = ``; + + const match = imports.text.search(/(?<=(['"`])imports\1[^{}]*{)/); + const part1 = imports.text.substring(0, match); + const part2 = imports.text.substring(match); + + const bake =async()=> await Deno.writeTextFile(Deno.cwd()+"/"+config.path, part1 + changes + part2); + + if(!importMap["react"]) + { + const resp = confirm(`🚨🔧 Import map has no specifier for React ("react"). Fix it now? (Will use Preact compat)`); + if(resp) + { + changes += `"react": "https://esm.sh/preact@10.16.0/compat",\n`; + if(!importMap["react/"]) + { + changes += `"react/": "https://esm.sh/preact@10.16.0/compat/",\n`; + } + await bake(); + } + else + { + throw(`⛔ A React import ("react") is required.`); + } + } + if(!importMap[">able/"]) + { + const resp = confirm(`🚨🔧 Import map has no specifier for Able (">able/"). Fix it now?`); + if(resp) + { + changes += `">able/": "${RootHost}",\n`; + await bake(); + } + else + { + throw(`⛔ The Able import (">able/") is required.`); + } + } + if(!importMap[">able/app.tsx"]) + { + const resp = confirm(`🚨🔧 Import map has no specifier for your starter app (">able/app.tsx"). Fix it now?`); + if(resp) + { + changes += `">able/app.tsx": "./app.tsx",\n`; + await bake(); + await Install("app.tsx"); + } + else + { + throw(`⛔ The "starter app" import (">able/app.tsx") is required.`); + } + } + if(!importMap[">able/api.tsx"]) + { + const resp = confirm(`🚨🔧 OPTIONAL: Import map has no specifier for your backend app (">able/api.tsx"). Fix it now?`); + if(resp) + { + changes += `">able/api.tsx": "./api.tsx",\n`; + await bake(); + await Install("api.tsx"); + } + } + + + const compOpts = imports.json.compilerOptions as Record; + if(compOpts) + { + const compJSX = compOpts["jsx"]; + const compJSXImportSource = compOpts["jsxImportSource"] + if(compJSX || compJSXImportSource) + { + if(!importMap["react/"]) + { + //const resp = await Prompt(` ! Import map has no specifier for React ("react"). Add it now? [y/n]`); + } + } + } + + + } + } + catch(e) + { + console.log(e, "\n (Able Exiting...)"); + Deno.exit(); + } + console.log(`🚗 Good to go!`); + +} + + +Check(); \ No newline at end of file diff --git a/cli.tsx b/cli.tsx index 667df90..25159c1 100644 --- a/cli.tsx +++ b/cli.tsx @@ -1,8 +1,7 @@ import * as Env from "https://deno.land/std@0.194.0/dotenv/mod.ts"; import * as Arg from "https://deno.land/std@0.194.0/flags/mod.ts"; -import { parse as JSONC } from "https://deno.land/x/jsonct@v0.1.0/mod.ts"; -const RootFile = new URL(`file://${Deno.cwd().replaceAll("\\", "/")}`).toString(); -const RootHost = import.meta.resolve("./"); +import { RootHost, HuntConfig, Install, Check } from "./checker.tsx"; + let arg = await Arg.parse(Deno.args); let env = await Env.load(); const collect =async(inKey:string, inArg:Record, inEnv:Record):Promise=> @@ -37,86 +36,6 @@ const collect =async(inKey:string, inArg:Record, inEnv:Record>}; -type ConfigCheckPair = [config:ConfigCheck, imports:ConfigCheck]; - -export async function HuntConfig() -{ - let path:string, resp:Response, text="", json; - try - { - path = "deno.json" - resp = await fetch(RootFile + "/" + path); - text = await resp.text(); - } - catch(e) - { - try - { - path = "deno.jsonc"; - resp = await fetch(RootFile + "/" + path); - text = await resp.text(); - } - catch(e) - { - try - { - path = RootFile+"/.vscode/settings.json" - resp = await fetch(path); - json = await resp.json(); - path = json["deno.config"]; - json = undefined; - if(path) - { - path = RootFile + "/" + path - resp = await fetch(path); - text = await resp.text(); - } - } - catch(e) - { - path = ""; - } - } - } - - if(text) - { - try - { - json = JSONC(text); - } - catch(e) - { - // malformed config - } - } - - let imports:ConfigCheck = {}; - if(json && json.imports) - { - imports.json = json; - imports.text = JSON.stringify(json.imports); - imports.path = path; - } - else if(json && !json.imports && json.importMap) - { - try - { - imports.path = RootFile + "/" + json.importMap; - resp = await fetch(imports.path); - imports.text = await resp.text(); - imports.json = JSONC(text); - } - catch(e) - { - // malformed import map - } - } - - return [{path, text, json}, imports] as ConfigCheckPair -} - export async function SubProcess(args:string[]) { const command = new Deno.Command( @@ -144,162 +63,6 @@ export async function SubProcess(args:string[]) const status = await child.status; } -export async function Install(file:string, handler:(content:string)=>string = (s)=>s) -{ - const pathFile = RootHost + "install__/" + file; - - try{ - const check = await Deno.readTextFile(Deno.cwd()+"/"+file); - const replace = confirm(`⚠️🚧 The file "${file}" already exists. Replace it?`); - if(replace) - { - throw("") - } - console.log(`Using pre-existing "${file}" for now.`); - } - catch(e) - { - const resp = await fetch(pathFile); - const text = await resp.text(); - await Deno.writeTextFile(Deno.cwd()+"/"+file, handler(text)); - } -} - - - -export async function Check() -{ - console.info(`👷 Checking your project`) - try - { - let [config, imports] = await HuntConfig(); - if(!config.path) - { - //const resp1 = await Prompt(" ! No Deno configuration found. Create one? [y/n]"); - const resp1 = confirm("🚨🚧 No Deno configuration found. Create one?"); - if(resp1) - { - const resp2 = confirm("⚠️🚧 Do you also want to add starter files?"); - let replaceApp = "./path/to/app.tsx"; - let replaceApi = "./path/to/api.tsx"; - let replaceCommentApp = "// (required) module with default export ()=>React.JSX.Element"; - let replaceCommentApi = "// (optional) module with default export (req:Request, url:URL)=>Promise"; - if(resp2) - { - replaceApp = "./app.tsx"; - replaceApi = "./api.tsx"; - replaceCommentApp = ""; - replaceCommentApi = ""; - - await Install("app.tsx"); - await Install("api.tsx"); - } - else - { - // config initialized with no app or api - } - - await Install("deno.jsonc", (s)=>s - .replace("{{server}}", RootHost) - .replace("{{app}}", replaceApp) - .replace("{{api}}", replaceApi) - .replace("{{commentApp}}", replaceCommentApp) - .replace("{{commentApi}}", replaceCommentApi) - ); - - [config, imports] = await HuntConfig(); - } - else - { - throw("⛔ Config is required."); - } - - } - - /* - const inputString = `Some text 'imports' more text { some content }`; - const regex = /(?<=(['"`])imports\1[^{}]*{)/; - - const match = inputString.search(regex); - - if (match !== -1) { - console.log("Index of '{':", match); - } else { - console.log("'{': Not found."); - } - */ - - if(!config.json) - { - throw("⛔ Config is malformed."); - } - else if(!imports.json?.imports) - { - const resp = confirm(`🚨🔧 Configuration has no import map. Fix it now?`); - if(resp) - { - - } - } - - - if(config.json && imports.json?.imports) - { - const importMap = imports.json.imports as Record; - let changes = ``; - if(!importMap["react"]) - { - const resp = confirm(`🚨🔧 Import map has no specifier for React ("react"). Fix it now? (Will use Preact compat)`); - if(resp) - { - importMap["react"] = "https://esm.sh/preact@10.16.0/compat"; - changes += `"react": "https://esm.sh/preact@10.16.0/compat",\n`; - } - else - { - throw(`⛔ A React import ("react") is required.`); - } - } - if(!importMap[">able/"]) - { - const resp = confirm(`🚨🔧 Import map has no specifier for Able (">able/"). Fix it now?`); - if(resp) - { - importMap[">able/"] = RootHost; - changes += `">able": "${RootHost}",\n`; - } - else - { - throw(`⛔ The Able import (">able/") is required.`); - } - } - - const compOpts = imports.json.compilerOptions as Record; - if(compOpts) - { - const compJSX = compOpts["jsx"]; - const compJSXImportSource = compOpts["jsxImportSource"] - if(compJSX || compJSXImportSource) - { - if(!importMap["react/"]) - { - //const resp = await Prompt(` ! Import map has no specifier for React ("react"). Add it now? [y/n]`); - } - } - } - - - } - } - catch(e) - { - console.log(e, "\n (Able Exiting...)"); - Deno.exit(); - } - console.log(`🚗 Good to go!`); - -} - if(arg._.length) { diff --git a/deno.jsonc b/deno.jsonc index 8b9e02f..6c923cd 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -1,42 +1,6 @@ { - "imports": - { - "react/":"https://esm.sh/preact@10.15.1/compat/", // (conditional) This allows the use of JSX without explicitly importing React into a module. If you choose to remove this (and make importing react required), also remove "jsx" and "jsxImportSource" from "compilerOptions" (below) - ">able/": "file:///C:/Web%20Projects/able-baker/", // (required) Specifier 'able'. (See note below about "isomorphic proxies") - ">able/app.tsx": "./app.tsx", - ">able/api.tsx": "./api.tsx" - }, + "imports": {}, - "tasks": - { - "local": "deno run -A --reload=http://localhost:4507 --no-lock ./run-local.tsx --port=1234", - "serve": "deno run -A --reload=http://localhost:4507 --no-lock ./run-serve.tsx --port=1234", - "cloud": "deno run -A --reload=http://localhost:4507 --no-lock ./run-deploy.tsx", - "debug": "deno run -A --no-lock --inspect-wait ./cli.tsx work --port=1234" - }, - - "compilerOptions": - { - "lib": ["deno.window", "dom"], // makes the Deno Language Server OK with browser-specific code - "jsx": "react-jsx", // see "react/" import above - "jsxImportSource": "react" // ^ - } - -/* - - Imports prefixed with ">" are "isomorphic proxies." - In addition to functioning normally as bare module specifiers for Deno, **these imports are added as routes when the server starts**. - Assuming the specifier points to remotely a hosted directory containing typescript files, requests to your running Able server on these proxy routes are actually fetched from the remote, then transpiled (and cached), then send back as a response. - For example, after the Able server starts, if it sees a web request to '/>able/iso-elements.tsx' it would actually return a browser-friendly transpiled copy of what was on the remote. - Conversely, if the Deno Language Server were to see: `import * as Iso from ">able/iso-elements.tsx";` in one of your modules, - that will be resolved normally with the import map and Deno will just receive the tsx file as-is from the remote, typings and all, so intellisense will work in your IDE. + //imports? - While ">able/" is a required "import proxy" to pull in Able source code, you are free to use this convention to also add your own proxies as you see fit. - E.g. adding this record to imports: - ">your-import/": "https://raw.githubusercontent.com/your-name/your-lib/master/" - will give both Deno and browsers running your Able project everything they need - import CoolComponent from ">your-import/cc.tsx"; - ... - -*/ } \ No newline at end of file diff --git a/deno.lock b/deno.lock new file mode 100644 index 0000000..2be9e7a --- /dev/null +++ b/deno.lock @@ -0,0 +1,8 @@ +{ + "version": "2", + "remote": { + "https://deno.land/x/jsonct@v0.1.0/mod.ts": "dba7e7f3529be6369f5c718e3a18b69f15ffa176006d2a7565073ce6c5bd9f3f", + "https://deno.land/x/jsonct@v0.1.0/src/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462", + "https://deno.land/x/jsonct@v0.1.0/src/parse.ts": "a3a016822446b0584b40bae9098df480db5590a9915c9e3c623ba2801cf1b8df" + } +} diff --git a/run-serve.tsx b/run-serve.tsx index 90bd739..84d9b38 100644 --- a/run-serve.tsx +++ b/run-serve.tsx @@ -1,70 +1,62 @@ import * as MIME from "https://deno.land/std@0.180.0/media_types/mod.ts"; import * as SWCW from "https://esm.sh/@swc/wasm-web@1.3.62"; - +import { HuntConfig } from "./checker.tsx"; import CustomServe from ">able/api.tsx"; export const Root = new URL(`file://${Deno.cwd().replaceAll("\\", "/")}`).toString(); + type DenoConfig = {imports:Record}; const ImportMap:DenoConfig = {imports:{}}; -let ImportMapOriginal = {}; let ImportMapProxies:Record = {}; + const ImportMapReload =async()=> { - let json:DenoConfig; - const path = Root+"/deno.json"; - try - { - const resp = await fetch(path); - json = await resp.json(); - if(!json?.imports) - { throw new Error("imports not specified in deno.json") } - ImportMapOriginal = json; - } - catch(e) - { - console.log(`error reading deno config "${path}" message:"${e}"`); - return; - } + const [, {json, path}] = await HuntConfig(); + const imports = (json as DenoConfig).imports; - if(!json.imports["react"]) + if(imports) { - console.log(`"react" specifier not defined in import map`); - } - else if(!json.imports["react/"]) - { - json.imports["react/"] = json.imports["react"]+"/"; - } - - if(!json.imports["able:app"]) - { - console.log(`"able:app" specifier not defined in import map.`); - } - - - ImportMapProxies = {}; - Object.entries(json.imports).forEach(([key, value])=> - { - if(value.startsWith("./")) + if(imports["react"]) { - json.imports[key] = value.substring(1); + console.log(`"react" specifier not defined in import map`); + } - if(key.startsWith(">")) + else if(!imports["react/"]) + { + imports["react/"] = imports["react"]+"/"; + } + + ImportMapProxies = {}; + Object.entries(imports).forEach(([key, value])=> { if(value.startsWith("./")) { - ImportMapProxies[encodeURI(key)] = value.substring(1); - json.imports[key] = value.substring(1); + imports[key] = value.substring(1); } - else + if(key.startsWith(">")) { - ImportMapProxies["/"+encodeURI(key)] = value; - json.imports[key] = "/"+key; + if(value.startsWith("./")) + { + ImportMapProxies[encodeURI(key)] = value.substring(1); + imports[key] = value.substring(1); + } + else + { + ImportMapProxies["/"+encodeURI(key)] = value; + imports[key] = "/"+key; + } } - } - }); + }); + + ImportMap.imports = Configuration.Remap(imports, Configuration); + + } + else + { + + } - ImportMap.imports = Configuration.Remap(json.imports, Configuration); }; export type CustomHTTPHandler = (inReq:Request, inURL:URL, inExt:string|false, inMap:{imports:Record}, inConfig:Configuration)=>void|false|Response|Promise; -- 2.34.1 From 783970f2c008f427c42b5b95f676d9305c55f505 Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Sun, 13 Aug 2023 11:00:48 -0400 Subject: [PATCH 08/11] improved checking and options --- app.tsx | 4 +- checker.tsx | 205 +++++++++++++++++++++++++++------------------- deno.jsonc | 18 +++- deno.lock | 8 -- deno__.json | 2 +- install__/app.tsx | 4 +- 6 files changed, 142 insertions(+), 99 deletions(-) delete mode 100644 deno.lock diff --git a/app.tsx b/app.tsx index 2308168..b92be06 100644 --- a/app.tsx +++ b/app.tsx @@ -1 +1,3 @@ -export default ()=>{}; \ No newline at end of file +export default ()=>
+

App!

+
; \ No newline at end of file diff --git a/checker.tsx b/checker.tsx index 3d7cdb4..81b791e 100644 --- a/checker.tsx +++ b/checker.tsx @@ -29,6 +29,7 @@ export async function HuntConfig() path = ".vscode/settings.json"; resp = await fetch(Root + "/" + path); json = await resp.json(); + path = json["deno.config"]; json = undefined; if(path) @@ -44,7 +45,7 @@ export async function HuntConfig() } } - if(text) + if(path) { try { @@ -52,7 +53,6 @@ export async function HuntConfig() } catch(e) { - // malformed config json = undefined; } } @@ -60,18 +60,27 @@ export async function HuntConfig() let imports:ConfigCheck = {}; if(json && json.imports) { + // config.imports imports.json = json; imports.text = JSON.stringify(json); imports.path = path; } else if(json && !json.imports && json.importMap) { + // config.importMap try { imports.path = json.importMap; resp = await fetch(Root + "/" + imports.path); imports.text = await resp.text(); - imports.json = JSONC(text); + try + { + imports.json = JSONC(imports.text); + } + catch(e) + { + imports.json = undefined; + } } catch(e) { @@ -82,7 +91,7 @@ export async function HuntConfig() return [{path, text, json}, imports] as ConfigCheckPair } -export async function Install(file:string, handler:(content:string)=>string = (s)=>s) +export async function Install(file:string, overrideName?:string, handler?:(content:string)=>string) { const pathFile = RootHost + "install__/" + file; @@ -99,135 +108,164 @@ export async function Install(file:string, handler:(content:string)=>string = (s { const resp = await fetch(pathFile); const text = await resp.text(); - await Deno.writeTextFile(Deno.cwd()+"/"+file, handler(text)); + const name = overrideName || file; + await Deno.writeTextFile(Deno.cwd()+"/"+name, handler ? handler(text) : text); } } - - export async function Check() { - console.info(`👷 Checking your project`); try { let [config, imports] = await HuntConfig(); + //console.log(config, imports); if(!config.path) { - if(confirm("🚨🚧 No Deno configuration found. Create a new one?")) - { - await Install("deno.jsonc"); - - Check(); - return; - } - else - { - throw("⛔ Configuration is required."); - } + console.log(`🛠️ No Deno configuration found. Creating "deno.jsonc" now.`); + await Deno.writeTextFile(Deno.cwd()+"/deno.jsonc", `{"imports":{}}`); + Check(); + return; } - - else if(!imports.json || !imports.json?.imports) + else if(!config.json) { - const resp = confirm(`🚨🔧 Configuration found, but has no import map. Fix it now?`); - if(resp) + if(confirm(`🚧 Deno configuration is malformed. Replace "${config.path}" with a new one?.`)) { - const text = config.text||""; - const startBracket = text.indexOf("{"); - - config.text = `{ - "imports": {}${startBracket < 0 ? "\n}\n" : ",\n"}` + text.substring(startBracket+1); - - await Deno.writeTextFile(Deno.cwd()+"/"+config.path, config.text); - + await Deno.writeTextFile(Deno.cwd()+"/"+config.path, `{"imports":{}}`); Check(); return; - } else { - throw("⛔ Import maps are required."); + throw("⛔ Invalid configuration."); } } + else if(!imports.json) + { + if(imports.path != config.path) + { + if(confirm(`🚧 External import map "${imports.path}" is missing or malformed. Replace it with defaults?.`)) + { + await Deno.writeTextFile(Deno.cwd()+"/"+imports.path, `{"imports":{}}`); + Check(); + return; + } + else + { + throw("⛔ Invalid configuration."); + } + } + } + else if(!imports.json?.imports) + { + imports.json.imports = {}; + } - if(config.json && imports.text && imports.json?.imports) + if(config.json && imports.json?.imports) { const importMap = imports.json.imports as Record; - let changes = ``; - - const match = imports.text.search(/(?<=(['"`])imports\1[^{}]*{)/); - const part1 = imports.text.substring(0, match); - const part2 = imports.text.substring(match); - - const bake =async()=> await Deno.writeTextFile(Deno.cwd()+"/"+config.path, part1 + changes + part2); + const bake =async(obj:ConfigCheck)=> await Deno.writeTextFile(Deno.cwd()+"/"+obj.path, JSON.stringify(obj.json, null, "\t")); if(!importMap["react"]) { - const resp = confirm(`🚨🔧 Import map has no specifier for React ("react"). Fix it now? (Will use Preact compat)`); - if(resp) - { - changes += `"react": "https://esm.sh/preact@10.16.0/compat",\n`; - if(!importMap["react/"]) - { - changes += `"react/": "https://esm.sh/preact@10.16.0/compat/",\n`; - } - await bake(); - } - else - { - throw(`⛔ A React import ("react") is required.`); - } + console.log(`🛠️ Adding React import specifier ("react")`); + importMap["react"] = `https://esm.sh/preact@10.16.0/compat`; + importMap["react/"] = `https://esm.sh/preact@10.16.0/compat/`; + await bake(imports); + console.log(`🚦 NOTE: Deno will need to cache "react" for intellisense to work properly.`) + } if(!importMap[">able/"]) { - const resp = confirm(`🚨🔧 Import map has no specifier for Able (">able/"). Fix it now?`); - if(resp) - { - changes += `">able/": "${RootHost}",\n`; - await bake(); - } - else - { - throw(`⛔ The Able import (">able/") is required.`); - } + console.log(`🛠️ Adding Able import specifier (">able/").`); + importMap[">able/"] = `${RootHost}`; + await bake(imports); } + if(!importMap[">able/app.tsx"]) { - const resp = confirm(`🚨🔧 Import map has no specifier for your starter app (">able/app.tsx"). Fix it now?`); + const resp = confirm(`🤔 OPTIONAL: Import map has no specifier for your starter app (">able/app.tsx"). Create one?`); if(resp) { - changes += `">able/app.tsx": "./app.tsx",\n`; - await bake(); + importMap[">able/app.tsx"] = `./app.tsx`; + await bake(imports); await Install("app.tsx"); } - else + } + else + { + try { - throw(`⛔ The "starter app" import (">able/app.tsx") is required.`); + const app = await import(importMap[">able/app.tsx"]); + // @ts-ignore + const result = app.default().$$typeof; + } + catch(e) + { + console.log(e); + if(confirm(`🚧 Your starter app ("${importMap[">able/app.tsx"]}") does not export a default function that returns VDOM nodes. Replace it?`)) + { + await Install("app.tsx", importMap[">able/app.tsx"]); + } + else + { + throw("⛔ Starter app has incorrect export types."); + } } } + if(!importMap[">able/api.tsx"]) { - const resp = confirm(`🚨🔧 OPTIONAL: Import map has no specifier for your backend app (">able/api.tsx"). Fix it now?`); + const resp = confirm(`🤔 OPTIONAL: Import map has no specifier for your starter backend app (">able/api.tsx"). Create one?`); if(resp) { - changes += `">able/api.tsx": "./api.tsx",\n`; - await bake(); + importMap[">able/api.tsx"] = "./api.tsx"; + await bake(imports); await Install("api.tsx"); } } - - - const compOpts = imports.json.compilerOptions as Record; - if(compOpts) + else { - const compJSX = compOpts["jsx"]; - const compJSXImportSource = compOpts["jsxImportSource"] - if(compJSX || compJSXImportSource) + try { - if(!importMap["react/"]) + const api = await import(importMap[">able/api.tsx"]); + const result = api.default(new Request(new URL("https://fake-deno-testing-domain.com/"))); + } + catch(e) + { + if(confirm(`🚧 Your starter backend app ("${importMap[">able/api.tsx"]}") does not export a default function that accepts a Request. Replace it?`)) { - //const resp = await Prompt(` ! Import map has no specifier for React ("react"). Add it now? [y/n]`); + await Install("api.tsx", importMap[">able/api.tsx"]); } - } + else + { + throw("⛔ Starter backend app has incorrect export types."); + } + } + } + + + const options = + { + "lib": ["deno.window", "dom", "dom.asynciterable"], + "jsx": "react-jsx", + "jsxImportSource": "react" + } + + const compOpts = config.json.compilerOptions as Record || {}; + const compJSX = compOpts.jsx == options.jsx; + const compJSXImportSource = compOpts.jsxImportSource == options.jsxImportSource; + const compLib:string[] = compOpts.lib as string[] || []; + let compLibHasAll = true; + options.lib.forEach(item=> !compLib.includes(item) && (compLibHasAll = false)) + + if(!compOpts || !compJSX || !compJSXImportSource || !compLibHasAll) + { + console.log(`🛠️ Adding values to "compilerOptions" configuration.`); + compOpts.jsx = options.jsx; + compOpts.jsxImportSource = options.jsxImportSource; + compOpts.lib = [...compLib, ...options.lib]; + config.json.compilerOptions = compOpts; + await bake(config); } @@ -242,5 +280,4 @@ export async function Check() } - Check(); \ No newline at end of file diff --git a/deno.jsonc b/deno.jsonc index 6c923cd..8b3930c 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -1,6 +1,16 @@ { - "imports": {}, - - //imports? - + "imports": { + "react": "https://esm.sh/preact@10.16.0/compat", + "react/": "https://esm.sh/preact@10.16.0/compat/", + ">able/": "file:///C:/Web%20Projects/able-baker/" + }, + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "react", + "lib": [ + "deno.window", + "dom", + "dom.asynciterable" + ] + } } \ No newline at end of file diff --git a/deno.lock b/deno.lock deleted file mode 100644 index 2be9e7a..0000000 --- a/deno.lock +++ /dev/null @@ -1,8 +0,0 @@ -{ - "version": "2", - "remote": { - "https://deno.land/x/jsonct@v0.1.0/mod.ts": "dba7e7f3529be6369f5c718e3a18b69f15ffa176006d2a7565073ce6c5bd9f3f", - "https://deno.land/x/jsonct@v0.1.0/src/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462", - "https://deno.land/x/jsonct@v0.1.0/src/parse.ts": "a3a016822446b0584b40bae9098df480db5590a9915c9e3c623ba2801cf1b8df" - } -} diff --git a/deno__.json b/deno__.json index 1e16461..cc26f5d 100644 --- a/deno__.json +++ b/deno__.json @@ -8,7 +8,7 @@ "react":"https://esm.sh/preact@10.15.1/compat", "react/":"https://esm.sh/preact@10.15.1/compat/", "react-original":"https://esm.sh/preact@10.15.1/compat", - ">able/": "http://localhost:4507/" + }, "tasks": { diff --git a/install__/app.tsx b/install__/app.tsx index 2308168..b92be06 100644 --- a/install__/app.tsx +++ b/install__/app.tsx @@ -1 +1,3 @@ -export default ()=>{}; \ No newline at end of file +export default ()=>
+

App!

+
; \ No newline at end of file -- 2.34.1 From acda59303d009a06d3909064d9e0bd724fb2eb23 Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Sun, 13 Aug 2023 22:58:15 -0400 Subject: [PATCH 09/11] wording --- checker.tsx | 10 ++++------ deno.jsonc | 3 ++- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/checker.tsx b/checker.tsx index 81b791e..80ec776 100644 --- a/checker.tsx +++ b/checker.tsx @@ -183,8 +183,7 @@ export async function Check() if(!importMap[">able/app.tsx"]) { - const resp = confirm(`🤔 OPTIONAL: Import map has no specifier for your starter app (">able/app.tsx"). Create one?`); - if(resp) + if(confirm(`🤔 OPTIONAL: Your import map does not override the default/empty FRONT-END app with the specifier ">able/app.tsx". Create this file and add the specifier?`)) { importMap[">able/app.tsx"] = `./app.tsx`; await bake(imports); @@ -202,21 +201,20 @@ export async function Check() catch(e) { console.log(e); - if(confirm(`🚧 Your starter app ("${importMap[">able/app.tsx"]}") does not export a default function that returns VDOM nodes. Replace it?`)) + if(confirm(`🚧 Your FRONT-END app ("${importMap[">able/app.tsx"]}") does not export a default function that returns VDOM nodes. Replace it?`)) { await Install("app.tsx", importMap[">able/app.tsx"]); } else { - throw("⛔ Starter app has incorrect export types."); + throw("⛔ Your FRONT-END app has incorrect export types."); } } } if(!importMap[">able/api.tsx"]) { - const resp = confirm(`🤔 OPTIONAL: Import map has no specifier for your starter backend app (">able/api.tsx"). Create one?`); - if(resp) + if(confirm(`🤔 OPTIONAL: Your import map does not override the default/empty BACK-END api with the specifier ">able/api.tsx". Create this file and add the specifier?`)) { importMap[">able/api.tsx"] = "./api.tsx"; await bake(imports); diff --git a/deno.jsonc b/deno.jsonc index 8b3930c..fb2636d 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -2,7 +2,8 @@ "imports": { "react": "https://esm.sh/preact@10.16.0/compat", "react/": "https://esm.sh/preact@10.16.0/compat/", - ">able/": "file:///C:/Web%20Projects/able-baker/" + ">able/": "file:///C:/Web%20Projects/able-baker/", + ">able/app.tsx": "./app.tsx" }, "compilerOptions": { "jsx": "react-jsx", -- 2.34.1 From 27579986754fe8d2b2a171dd2c16360a964fe325 Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Mon, 28 Aug 2023 22:16:56 -0400 Subject: [PATCH 10/11] config checking --- .gitingore | 1 + checker.tsx | 139 ++++++++++++++++++++++++++++++-------------------- cli.tsx | 25 +++++++-- deno.jsonc | 9 +++- run-serve.tsx | 10 ---- sub.tsx | 7 --- sup.tsx | 37 -------------- 7 files changed, 112 insertions(+), 116 deletions(-) create mode 100644 .gitingore delete mode 100644 sub.tsx delete mode 100644 sup.tsx diff --git a/.gitingore b/.gitingore new file mode 100644 index 0000000..941fcf1 --- /dev/null +++ b/.gitingore @@ -0,0 +1 @@ +deno.lock \ No newline at end of file diff --git a/checker.tsx b/checker.tsx index 80ec776..01a117b 100644 --- a/checker.tsx +++ b/checker.tsx @@ -115,9 +115,12 @@ export async function Install(file:string, overrideName?:string, handler?:(conte export async function Check() { + let [config, imports] = await HuntConfig(); + console.log(`Checking directory "${Root}"`); + console.log("Found", config, imports); try { - let [config, imports] = await HuntConfig(); + //console.log(config, imports); if(!config.path) { @@ -181,63 +184,25 @@ export async function Check() await bake(imports); } - if(!importMap[">able/app.tsx"]) - { - if(confirm(`🤔 OPTIONAL: Your import map does not override the default/empty FRONT-END app with the specifier ">able/app.tsx". Create this file and add the specifier?`)) - { - importMap[">able/app.tsx"] = `./app.tsx`; - await bake(imports); - await Install("app.tsx"); - } - } - else - { - try - { - const app = await import(importMap[">able/app.tsx"]); - // @ts-ignore - const result = app.default().$$typeof; - } - catch(e) - { - console.log(e); - if(confirm(`🚧 Your FRONT-END app ("${importMap[">able/app.tsx"]}") does not export a default function that returns VDOM nodes. Replace it?`)) - { - await Install("app.tsx", importMap[">able/app.tsx"]); - } - else - { - throw("⛔ Your FRONT-END app has incorrect export types."); - } - } - } + const tasks:Record = { + "check": `deno run -A --no-lock ${RootHost}cli.tsx check`, + "local": `deno run -A --no-lock ${RootHost}cli.tsx local`, + "debug": `deno run -A --no-lock ${RootHost}cli.tsx debug`, + "serve": `deno run -A --no-lock ${RootHost}cli.tsx serve`, + "cloud": `deno run -A --no-lock ${RootHost}cli.tsx cloud` + }; - if(!importMap[">able/api.tsx"]) + const confTasks = (config.json.tasks || {}) as Record; + for(const key in tasks) { - if(confirm(`🤔 OPTIONAL: Your import map does not override the default/empty BACK-END api with the specifier ">able/api.tsx". Create this file and add the specifier?`)) + if(tasks[key] !== confTasks[key]) { - importMap[">able/api.tsx"] = "./api.tsx"; - await bake(imports); - await Install("api.tsx"); - } - } - else - { - try - { - const api = await import(importMap[">able/api.tsx"]); - const result = api.default(new Request(new URL("https://fake-deno-testing-domain.com/"))); - } - catch(e) - { - if(confirm(`🚧 Your starter backend app ("${importMap[">able/api.tsx"]}") does not export a default function that accepts a Request. Replace it?`)) + if(confirm(`🤔 OPTIONAL: The tasks defined in your config contain missing or modified values. Update tasks?`)) { - await Install("api.tsx", importMap[">able/api.tsx"]); - } - else - { - throw("⛔ Starter backend app has incorrect export types."); + config.json.tasks = {...confTasks, ...tasks}; + await bake(config); } + break; } } @@ -267,6 +232,70 @@ export async function Check() } + if(!importMap[">able/app.tsx"]) + { + if(confirm(`🤔 OPTIONAL: Your import map does not override the default/empty FRONT-END app with the specifier ">able/app.tsx". Create this file and add the specifier?`)) + { + importMap[">able/app.tsx"] = `./app.tsx`; + await bake(imports); + await Install("app.tsx"); + } + } + else + { + /* + try + { + const app = await import(importMap[">able/app.tsx"]); + // @ts-ignore + const result = app.default().$$typeof; + } + catch(e) + { + console.log(e); + if(confirm(`🚧 Your FRONT-END app ("${importMap[">able/app.tsx"]}") does not export a default function that returns VDOM nodes. Replace it?`)) + { + await Install("app.tsx", importMap[">able/app.tsx"]); + } + else + { + throw("⛔ Your FRONT-END app has incorrect export types."); + } + } + */ + } + + if(!importMap[">able/api.tsx"]) + { + if(confirm(`🤔 OPTIONAL: Your import map does not override the default/empty BACK-END api with the specifier ">able/api.tsx". Create this file and add the specifier?`)) + { + importMap[">able/api.tsx"] = "./api.tsx"; + await bake(imports); + await Install("api.tsx"); + } + } + else + { + /* + try + { + const api = await import(importMap[">able/api.tsx"]); + const result = api.default(new Request(new URL("https://fake-deno-testing-domain.com/"))); + } + catch(e) + { + if(confirm(`🚧 Your starter backend app ("${importMap[">able/api.tsx"]}") does not export a default function that accepts a Request. Replace it?`)) + { + await Install("api.tsx", importMap[">able/api.tsx"]); + } + else + { + throw("⛔ Starter backend app has incorrect export types."); + } + } + */ + } + } } catch(e) @@ -276,6 +305,4 @@ export async function Check() } console.log(`🚗 Good to go!`); -} - -Check(); \ No newline at end of file +} \ No newline at end of file diff --git a/cli.tsx b/cli.tsx index 25159c1..8264873 100644 --- a/cli.tsx +++ b/cli.tsx @@ -35,7 +35,6 @@ const collect =async(inKey:string, inArg:Record, inEnv:Recordable/": "file:///C:/Web%20Projects/able-baker/", + ">able/": "http://localhost:4507/", ">able/app.tsx": "./app.tsx" }, + "tasks": { + "check": "deno run -A --no-lock http://localhost:4507/cli.tsx check", + "local": "deno run -A --no-lock http://localhost:4507/cli.tsx local", + "debug": "deno run -A --no-lock http://localhost:4507/cli.tsx debug", + "serve": "deno run -A --no-lock http://localhost:4507/cli.tsx serve", + "cloud": "deno run -A --no-lock http://localhost:4507/cli.tsx cloud" + }, "compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "react", diff --git a/run-serve.tsx b/run-serve.tsx index 84d9b38..78bbb24 100644 --- a/run-serve.tsx +++ b/run-serve.tsx @@ -17,16 +17,6 @@ const ImportMapReload =async()=> if(imports) { - if(imports["react"]) - { - console.log(`"react" specifier not defined in import map`); - - } - else if(!imports["react/"]) - { - imports["react/"] = imports["react"]+"/"; - } - ImportMapProxies = {}; Object.entries(imports).forEach(([key, value])=> { diff --git a/sub.tsx b/sub.tsx deleted file mode 100644 index b11c13a..0000000 --- a/sub.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { parse } from "https://deno.land/std@0.194.0/flags/mod.ts"; - -let arg = parse(Deno.args); - -console.log(arg); - -console.log(Deno.env.get("super")) diff --git a/sup.tsx b/sup.tsx deleted file mode 100644 index beef02b..0000000 --- a/sup.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import * as Env from "https://deno.land/std@0.194.0/dotenv/mod.ts"; -import * as Arg from "https://deno.land/std@0.194.0/flags/mod.ts"; - -let arg = Arg.parse(Deno.args); -let env = await Env.load(); - -Deno.env.set("super", "its super"); - -export async function SubProcess(args:string[]) -{ - const command = new Deno.Command( - `deno`, - { - args, - stdin: "piped", - stdout: "piped" - } - ); - - const child = command.spawn(); - - // open a file and pipe the subprocess output to it. - const writableStream = new WritableStream({ - write(chunk: Uint8Array): Promise { - Deno.stdout.write(chunk); - return Promise.resolve(); - }, - }); - child.stdout.pipeTo(writableStream); - - // manually close stdin - child.stdin.close(); - const status = await child.status; -} - - -SubProcess(["run", "-A", "sub.tsx", "keyword!", "--passed=yep"]); \ No newline at end of file -- 2.34.1 From 4ef3cc47a5d5632ed922a146fad006e977c07d18 Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Sun, 24 Sep 2023 09:19:50 -0400 Subject: [PATCH 11/11] more cli fixes --- .vscode/settings.json | 3 +- checker.tsx | 132 +++++++-------------------------------- cli.tsx | 17 +++-- deno.jsonc | 10 +-- example-config/app.tsx | 56 ----------------- example-config/deno.json | 19 ------ example-script/app.tsx | 56 ----------------- example-script/deno.json | 15 ----- example-script/run__.tsx | 9 --- install__/deno.jsonc | 43 ------------- run-local.tsx | 4 ++ run-serve.tsx | 4 +- 12 files changed, 48 insertions(+), 320 deletions(-) delete mode 100644 example-config/app.tsx delete mode 100644 example-config/deno.json delete mode 100644 example-script/app.tsx delete mode 100644 example-script/deno.json delete mode 100644 example-script/run__.tsx delete mode 100644 install__/deno.jsonc diff --git a/.vscode/settings.json b/.vscode/settings.json index 8675ad5..b943dbc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,3 @@ { - "deno.enable": true, - "deno.unstable": true + "deno.enable": true } \ No newline at end of file diff --git a/checker.tsx b/checker.tsx index 01a117b..a5f1100 100644 --- a/checker.tsx +++ b/checker.tsx @@ -7,6 +7,7 @@ export const RootHost = import.meta.resolve("./"); export const Root = new URL(`file://${Deno.cwd().replaceAll("\\", "/")}`).toString(); export async function HuntConfig() { + console.log("hunting in", Root); let path:string, resp:Response, text="", json; try { @@ -116,16 +117,14 @@ export async function Install(file:string, overrideName?:string, handler?:(conte export async function Check() { let [config, imports] = await HuntConfig(); - console.log(`Checking directory "${Root}"`); - console.log("Found", config, imports); try { //console.log(config, imports); if(!config.path) { - console.log(`🛠️ No Deno configuration found. Creating "deno.jsonc" now.`); - await Deno.writeTextFile(Deno.cwd()+"/deno.jsonc", `{"imports":{}}`); + console.log(`🛠️ No Deno configuration found. Creating "deno.json" now.`); + await Deno.writeTextFile(Deno.cwd()+"/deno.json", `{"imports":{}}`); Check(); return; } @@ -168,20 +167,22 @@ export async function Check() const importMap = imports.json.imports as Record; const bake =async(obj:ConfigCheck)=> await Deno.writeTextFile(Deno.cwd()+"/"+obj.path, JSON.stringify(obj.json, null, "\t")); - if(!importMap["react"]) + importMap["react"] = `https://esm.sh/preact@10.17.1/compat`; + importMap["react/"] = `https://esm.sh/preact@10.17.1/compat/`; + importMap["@preact/signals"] = `https://esm.sh/@preact/signals@1.2.1`; + importMap[">able/"] = `${RootHost}`; + if(!importMap[">able/app.tsx"]) { - console.log(`🛠️ Adding React import specifier ("react")`); - importMap["react"] = `https://esm.sh/preact@10.16.0/compat`; - importMap["react/"] = `https://esm.sh/preact@10.16.0/compat/`; - await bake(imports); - console.log(`🚦 NOTE: Deno will need to cache "react" for intellisense to work properly.`) - + importMap[">able/app.tsx"] = `./app.tsx`; + await Install("app.tsx"); } - if(!importMap[">able/"]) + if(!importMap[">able/api.tsx"]) { - console.log(`🛠️ Adding Able import specifier (">able/").`); - importMap[">able/"] = `${RootHost}`; - await bake(imports); + if(confirm(`🤔 OPTIONAL: Add backend ">able/api.tsx"?`)) + { + importMap[">able/api.tsx"] = "./api.tsx"; + await Install("api.tsx"); + } } const tasks:Record = { @@ -191,21 +192,8 @@ export async function Check() "serve": `deno run -A --no-lock ${RootHost}cli.tsx serve`, "cloud": `deno run -A --no-lock ${RootHost}cli.tsx cloud` }; - const confTasks = (config.json.tasks || {}) as Record; - for(const key in tasks) - { - if(tasks[key] !== confTasks[key]) - { - if(confirm(`🤔 OPTIONAL: The tasks defined in your config contain missing or modified values. Update tasks?`)) - { - config.json.tasks = {...confTasks, ...tasks}; - await bake(config); - } - break; - } - } - + config.json.tasks = {...confTasks, ...tasks}; const options = { @@ -213,89 +201,15 @@ export async function Check() "jsx": "react-jsx", "jsxImportSource": "react" } - const compOpts = config.json.compilerOptions as Record || {}; - const compJSX = compOpts.jsx == options.jsx; - const compJSXImportSource = compOpts.jsxImportSource == options.jsxImportSource; const compLib:string[] = compOpts.lib as string[] || []; - let compLibHasAll = true; - options.lib.forEach(item=> !compLib.includes(item) && (compLibHasAll = false)) - - if(!compOpts || !compJSX || !compJSXImportSource || !compLibHasAll) - { - console.log(`🛠️ Adding values to "compilerOptions" configuration.`); - compOpts.jsx = options.jsx; - compOpts.jsxImportSource = options.jsxImportSource; - compOpts.lib = [...compLib, ...options.lib]; - config.json.compilerOptions = compOpts; - await bake(config); - } - - - if(!importMap[">able/app.tsx"]) - { - if(confirm(`🤔 OPTIONAL: Your import map does not override the default/empty FRONT-END app with the specifier ">able/app.tsx". Create this file and add the specifier?`)) - { - importMap[">able/app.tsx"] = `./app.tsx`; - await bake(imports); - await Install("app.tsx"); - } - } - else - { - /* - try - { - const app = await import(importMap[">able/app.tsx"]); - // @ts-ignore - const result = app.default().$$typeof; - } - catch(e) - { - console.log(e); - if(confirm(`🚧 Your FRONT-END app ("${importMap[">able/app.tsx"]}") does not export a default function that returns VDOM nodes. Replace it?`)) - { - await Install("app.tsx", importMap[">able/app.tsx"]); - } - else - { - throw("⛔ Your FRONT-END app has incorrect export types."); - } - } - */ - } - - if(!importMap[">able/api.tsx"]) - { - if(confirm(`🤔 OPTIONAL: Your import map does not override the default/empty BACK-END api with the specifier ">able/api.tsx". Create this file and add the specifier?`)) - { - importMap[">able/api.tsx"] = "./api.tsx"; - await bake(imports); - await Install("api.tsx"); - } - } - else - { - /* - try - { - const api = await import(importMap[">able/api.tsx"]); - const result = api.default(new Request(new URL("https://fake-deno-testing-domain.com/"))); - } - catch(e) - { - if(confirm(`🚧 Your starter backend app ("${importMap[">able/api.tsx"]}") does not export a default function that accepts a Request. Replace it?`)) - { - await Install("api.tsx", importMap[">able/api.tsx"]); - } - else - { - throw("⛔ Starter backend app has incorrect export types."); - } - } - */ - } + compOpts.jsx = options.jsx; + compOpts.jsxImportSource = options.jsxImportSource; + compOpts.lib = [...compLib, ...options.lib]; + config.json.compilerOptions = compOpts; + await bake(imports); + await bake(config); } } catch(e) diff --git a/cli.tsx b/cli.tsx index 8264873..13b9f3e 100644 --- a/cli.tsx +++ b/cli.tsx @@ -68,7 +68,9 @@ if(arg._.length) { const [config, imports] = await HuntConfig(); - + + console.log("able subprocesses running with ", config.path); + switch(arg._[0]) { case "check" : @@ -80,17 +82,19 @@ if(arg._.length) case "local" : { - await SubProcess(["run", `--config=${config.path}`, RootHost+"run.tsx", "--dev", ...Deno.args]); + await SubProcess(["run", `-A`, `--no-lock`, `--config=${config.path}`, RootHost+"run.tsx", "--dev", ...Deno.args]); break; } case "debug" : { - await SubProcess(["run", `--config=${config.path}`, `--inspect-brk`, RootHost+"run.tsx", "--dev", ...Deno.args]); + await SubProcess(["run", `-A`, `--no-lock`, `--config=${config.path}`, `--inspect-brk`, RootHost+"run.tsx", "--dev", ...Deno.args]); break; } case "serve" : { - await SubProcess(["run", `--config=${config.path}`, RootHost+"run.tsx", ...Deno.args]); + const args = ["run", `-A`, `--no-lock`, `--config=${config.path}`, RootHost+"run.tsx", ...Deno.args]; + console.log("args are", args); + await SubProcess(args); break; } case "cloud" : @@ -123,5 +127,10 @@ if(arg._.length) ...scanProd, ...Deno.args]); } + case "upgrade" : + { + await SubProcess(["install", `-A`, `-r`, `-f`, `--no-lock`, `--config=${config.path}`, RootHost+"cli.tsx", ...Deno.args]); + break; + } } } \ No newline at end of file diff --git a/deno.jsonc b/deno.jsonc index a1945eb..95b17a3 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -1,16 +1,18 @@ { "imports": { - "react": "https://esm.sh/preact@10.16.0/compat", - "react/": "https://esm.sh/preact@10.16.0/compat/", + "react": "https://esm.sh/preact@10.17.1/compat", + "react/": "https://esm.sh/preact@10.17.1/compat/", ">able/": "http://localhost:4507/", - ">able/app.tsx": "./app.tsx" + ">able/app.tsx": "./app.tsx", + "@preact/signals": "https://esm.sh/@preact/signals@1.2.1" }, "tasks": { "check": "deno run -A --no-lock http://localhost:4507/cli.tsx check", "local": "deno run -A --no-lock http://localhost:4507/cli.tsx local", "debug": "deno run -A --no-lock http://localhost:4507/cli.tsx debug", "serve": "deno run -A --no-lock http://localhost:4507/cli.tsx serve", - "cloud": "deno run -A --no-lock http://localhost:4507/cli.tsx cloud" + "cloud": "deno run -A --no-lock http://localhost:4507/cli.tsx cloud", + "install": "deno install -A -r -f http://localhost:4507/cli.tsx" }, "compilerOptions": { "jsx": "react-jsx", diff --git a/example-config/app.tsx b/example-config/app.tsx deleted file mode 100644 index 88f14aa..0000000 --- a/example-config/app.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { Router, Switch, Case } from ">able/iso-elements.tsx"; - -import React from "react"; - -const CTXString = React.createContext("lol"); - -type StateBinding = [get:T, set:React.StateUpdater]; -const CTXState = React.createContext(null) as React.Context|null>; -const Outer =(props:{children:React.JSX.Element})=> -{ - const binding = React.useState(11); - return - {props.children} - -}; -const Inner =()=> -{ - const [stateGet, stateSet] = React.useContext(CTXState) || ["default", ()=>{}]; - return -}; - - -type Store = {name:string, age:number} -const reducer =(inState:Store, inAction:number)=> -{ - return {...inState, age:inState.age+inAction}; -} - -const builder =(inState:Store):Store=> -{ - inState.age = 100; - return inState; -} - - -export default ()=> -{ - const [Store, Dispatch] = React.useReducer(reducer, {name:"seth", age:24} as Store, builder) - return - -
-

Title

-

subtitle

-

- -

-
- - - - - - -
-
; -} diff --git a/example-config/deno.json b/example-config/deno.json deleted file mode 100644 index ae6483b..0000000 --- a/example-config/deno.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "imports": - { - "react": "https://esm.sh/preact@10.15.1/compat", - ">able/": "http://localhost:4507/", - ">able/app.tsx": "./app.tsx" - }, - "tasks": - { - "serve": "deno run -A --no-lock --config=deno.json --reload=http://localhost:4507 http://localhost:4507/run.tsx", - "local": "deno run -A --no-lock --config=deno.json --reload=http://localhost:4507 http://localhost:4507/run.tsx --dev", - "debug": "deno run -A --no-lock --config=deno.json --reload=http://localhost:4507 --inspect-wait http://localhost:4507/run.tsx", - "cloud": "deno run -A --no-lock --config=deno.json --reload=http://localhost:4507 http://localhost:4507/run.tsx --dep" - }, - "compilerOptions": - { - "lib": ["deno.window", "dom"] - } -} \ No newline at end of file diff --git a/example-script/app.tsx b/example-script/app.tsx deleted file mode 100644 index 88f14aa..0000000 --- a/example-script/app.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { Router, Switch, Case } from ">able/iso-elements.tsx"; - -import React from "react"; - -const CTXString = React.createContext("lol"); - -type StateBinding = [get:T, set:React.StateUpdater]; -const CTXState = React.createContext(null) as React.Context|null>; -const Outer =(props:{children:React.JSX.Element})=> -{ - const binding = React.useState(11); - return - {props.children} - -}; -const Inner =()=> -{ - const [stateGet, stateSet] = React.useContext(CTXState) || ["default", ()=>{}]; - return -}; - - -type Store = {name:string, age:number} -const reducer =(inState:Store, inAction:number)=> -{ - return {...inState, age:inState.age+inAction}; -} - -const builder =(inState:Store):Store=> -{ - inState.age = 100; - return inState; -} - - -export default ()=> -{ - const [Store, Dispatch] = React.useReducer(reducer, {name:"seth", age:24} as Store, builder) - return - -
-

Title

-

subtitle

-

- -

-
- - - - - - -
-
; -} diff --git a/example-script/deno.json b/example-script/deno.json deleted file mode 100644 index c8e26a5..0000000 --- a/example-script/deno.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { "lib": ["deno.window", "dom"] }, - "imports": - { - "react": "https://esm.sh/preact@10.15.1/compat", - ">able/": "http://localhost:4507/" - }, - "tasks": - { - "local": "deno run -A --no-lock --reload=http://localhost:4507 run__.tsx --dev", - "serve": "deno run -A --no-lock --reload=http://localhost:4507 run__.tsx", - "debug": "deno run -A --no-lock --reload=http://localhost:4507 --inspect-wait run__.tsx", - "cloud": "deno run -A --no-lock --reload=http://localhost:4507 run__.tsx --dep" - } -} \ No newline at end of file diff --git a/example-script/run__.tsx b/example-script/run__.tsx deleted file mode 100644 index 8bc8091..0000000 --- a/example-script/run__.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import Configure from ">able/run.tsx"; - -Configure({ - Start:"/app.tsx", - Serve() - { - return false; - } -}) \ No newline at end of file diff --git a/install__/deno.jsonc b/install__/deno.jsonc deleted file mode 100644 index de8f769..0000000 --- a/install__/deno.jsonc +++ /dev/null @@ -1,43 +0,0 @@ -{ - "imports": - { - "react":"https://esm.sh/preact@10.15.1/compat", // (required) Specifier for 'react' - "react/":"https://esm.sh/preact@10.15.1/compat/", // (conditional) This allows the use of JSX without explicitly importing React into a module. If you choose to remove this (and make importing react required), also remove "jsx" and "jsxImportSource" from "compilerOptions" (below) - ">able/": "{{server}}", // (required) Specifier 'able'. (See note below about "isomorphic proxies") - {{commentApp}}">able/app.tsx": "{{app}}", - {{commentApi}}">able/api.tsx": "{{api}}" - }, - - "tasks": - { - "local": "deno run -A --reload=http://localhost:4507 --no-lock ./run-local.tsx --port=1234", - "serve": "deno run -A --reload=http://localhost:4507 --no-lock ./run-serve.tsx --port=1234", - "cloud": "deno run -A --reload=http://localhost:4507 --no-lock ./run-deploy.tsx", - "debug": "deno run -A --reload=http://localhost:4507 --no-lock --inspect-wait ./run-serve.tsx --port=1234" - }, - - "compilerOptions": - { - "lib": ["deno.window", "dom"], // makes the Deno Language Server OK with browser-specific code - "jsx": "react-jsx", // see "react/" import above - "jsxImportSource": "react" // ^ - } - -/* - - Imports prefixed with ">" are "isomorphic proxies." - In addition to functioning normally as bare module specifiers for Deno, **these imports are added as routes when the server starts**. - Assuming the specifier points to remotely a hosted directory containing typescript files, requests to your running Able server on these proxy routes are actually fetched from the remote, then transpiled (and cached), then send back as a response. - For example, after the Able server starts, if it sees a web request to '/>able/iso-elements.tsx' it would actually return a browser-friendly transpiled copy of what was on the remote. - Conversely, if the Deno Language Server were to see: `import * as Iso from ">able/iso-elements.tsx";` in one of your modules, - that will be resolved normally with the import map and Deno will just receive the tsx file as-is from the remote, typings and all, so intellisense will work in your IDE. - - While ">able/" is a required "import proxy" to pull in Able source code, you are free to use this convention to also add your own proxies as you see fit. - E.g. adding this record to imports: - ">your-import/": "https://raw.githubusercontent.com/your-name/your-lib/master/" - will give both Deno and browsers running your Able project everything they need - import CoolComponent from ">your-import/cc.tsx"; - ... - -*/ -} \ No newline at end of file diff --git a/run-local.tsx b/run-local.tsx index bef5370..94553e5 100644 --- a/run-local.tsx +++ b/run-local.tsx @@ -16,6 +16,10 @@ Configure({ { syntax: "typescript", tsx: true, + }, + transform: + { + react: { runtime: "automatic" } } } }, diff --git a/run-serve.tsx b/run-serve.tsx index 78bbb24..74e81a5 100644 --- a/run-serve.tsx +++ b/run-serve.tsx @@ -5,7 +5,6 @@ import CustomServe from ">able/api.tsx"; export const Root = new URL(`file://${Deno.cwd().replaceAll("\\", "/")}`).toString(); - type DenoConfig = {imports:Record}; const ImportMap:DenoConfig = {imports:{}}; let ImportMapProxies:Record = {}; @@ -248,9 +247,9 @@ export default async()=> if(running){return}; running = true; - await ImportMapReload(); try { + await ImportMapReload(); await SWCW.default(); } catch(e) @@ -258,7 +257,6 @@ export default async()=> console.log("swc init error:", e); } - const server = Deno.serve({port:parseInt(Deno.env.get("port")||"8000")}, async(req: Request)=> { const url:URL = new URL(req.url); -- 2.34.1