cli #6
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -1,4 +1,3 @@
|
||||
{
|
||||
"deno.enable": true,
|
||||
"deno.unstable": true
|
||||
"deno.enable": true
|
||||
}
|
126
checker.tsx
126
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<string, string>;
|
||||
const bake =async(obj:ConfigCheck)=> await Deno.writeTextFile(Deno.cwd()+"/"+obj.path, JSON.stringify(obj.json, null, "\t"));
|
||||
|
||||
if(!importMap["react"])
|
||||
{
|
||||
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/"])
|
||||
{
|
||||
console.log(`🛠️ Adding Able import specifier (">able/").`);
|
||||
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}`;
|
||||
await bake(imports);
|
||||
if(!importMap[">able/app.tsx"])
|
||||
{
|
||||
importMap[">able/app.tsx"] = `./app.tsx`;
|
||||
await Install("app.tsx");
|
||||
}
|
||||
if(!importMap[">able/api.tsx"])
|
||||
{
|
||||
if(confirm(`🤔 OPTIONAL: Add backend ">able/api.tsx"?`))
|
||||
{
|
||||
importMap[">able/api.tsx"] = "./api.tsx";
|
||||
await Install("api.tsx");
|
||||
}
|
||||
}
|
||||
|
||||
const tasks:Record<string, string> = {
|
||||
@ -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<string, string>;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const options =
|
||||
{
|
||||
@ -213,90 +201,16 @@ export async function Check()
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "react"
|
||||
}
|
||||
|
||||
const compOpts = config.json.compilerOptions as Record<string, string|string[]> || {};
|
||||
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(imports);
|
||||
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.");
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
|
15
cli.tsx
15
cli.tsx
@ -69,6 +69,8 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
10
deno.jsonc
10
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",
|
||||
|
@ -1,56 +0,0 @@
|
||||
import { Router, Switch, Case } from ">able/iso-elements.tsx";
|
||||
|
||||
import React from "react";
|
||||
|
||||
const CTXString = React.createContext("lol");
|
||||
|
||||
type StateBinding<T> = [get:T, set:React.StateUpdater<T>];
|
||||
const CTXState = React.createContext(null) as React.Context<StateBinding<number>|null>;
|
||||
const Outer =(props:{children:React.JSX.Element})=>
|
||||
{
|
||||
const binding = React.useState(11);
|
||||
return <CTXState.Provider value={binding}>
|
||||
{props.children}
|
||||
</CTXState.Provider>
|
||||
};
|
||||
const Inner =()=>
|
||||
{
|
||||
const [stateGet, stateSet] = React.useContext(CTXState) || ["default", ()=>{}];
|
||||
return <button onClick={e=>stateSet((old)=>old+1)}>count: {stateGet} :)</button>
|
||||
};
|
||||
|
||||
|
||||
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 <CTXString.Provider value="intradestink">
|
||||
<Router.Provider>
|
||||
<div class="my-4 font-sans">
|
||||
<h1 class="font-black text-xl text-red-500">Title</h1>
|
||||
<h2 class="font-black text-blue-500 p-4">subtitle</h2>
|
||||
<p>
|
||||
<button onClick={e=>Dispatch(1)}>{Store.name}|{Store.age}?</button>
|
||||
</p>
|
||||
</div>
|
||||
<Outer>
|
||||
<Inner/>
|
||||
</Outer>
|
||||
<Outer>
|
||||
<Inner/>
|
||||
</Outer>
|
||||
</Router.Provider>
|
||||
</CTXString.Provider>;
|
||||
}
|
@ -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"]
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
import { Router, Switch, Case } from ">able/iso-elements.tsx";
|
||||
|
||||
import React from "react";
|
||||
|
||||
const CTXString = React.createContext("lol");
|
||||
|
||||
type StateBinding<T> = [get:T, set:React.StateUpdater<T>];
|
||||
const CTXState = React.createContext(null) as React.Context<StateBinding<number>|null>;
|
||||
const Outer =(props:{children:React.JSX.Element})=>
|
||||
{
|
||||
const binding = React.useState(11);
|
||||
return <CTXState.Provider value={binding}>
|
||||
{props.children}
|
||||
</CTXState.Provider>
|
||||
};
|
||||
const Inner =()=>
|
||||
{
|
||||
const [stateGet, stateSet] = React.useContext(CTXState) || ["default", ()=>{}];
|
||||
return <button onClick={e=>stateSet((old)=>old+1)}>count: {stateGet} :)</button>
|
||||
};
|
||||
|
||||
|
||||
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 <CTXString.Provider value="intradestink">
|
||||
<Router.Provider>
|
||||
<div class="my-4 font-sans">
|
||||
<h1 class="font-black text-xl text-red-500">Title</h1>
|
||||
<h2 class="font-black text-blue-500 p-4">subtitle</h2>
|
||||
<p>
|
||||
<button onClick={e=>Dispatch(1)}>{Store.name}|{Store.age}?</button>
|
||||
</p>
|
||||
</div>
|
||||
<Outer>
|
||||
<Inner/>
|
||||
</Outer>
|
||||
<Outer>
|
||||
<Inner/>
|
||||
</Outer>
|
||||
</Router.Provider>
|
||||
</CTXString.Provider>;
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
import Configure from ">able/run.tsx";
|
||||
|
||||
Configure({
|
||||
Start:"/app.tsx",
|
||||
Serve()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
})
|
@ -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";
|
||||
...
|
||||
|
||||
*/
|
||||
}
|
@ -16,6 +16,10 @@ Configure({
|
||||
{
|
||||
syntax: "typescript",
|
||||
tsx: true,
|
||||
},
|
||||
transform:
|
||||
{
|
||||
react: { runtime: "automatic" }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -5,7 +5,6 @@ import CustomServe from ">able/api.tsx";
|
||||
|
||||
export const Root = new URL(`file://${Deno.cwd().replaceAll("\\", "/")}`).toString();
|
||||
|
||||
|
||||
type DenoConfig = {imports:Record<string, string>};
|
||||
const ImportMap:DenoConfig = {imports:{}};
|
||||
let ImportMapProxies:Record<string, string> = {};
|
||||
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user