├── .gitignore ├── .vscode ├── extensions.json └── settings.json ├── README.md ├── browser ├── cache_buster.ts ├── cache_buster_test.ts ├── swdev-client.ts └── swdev-worker.ts ├── bundler.ts ├── deploy └── deno_deploy_provider.ts ├── deps.ts ├── examples ├── playground │ ├── .gitignore │ ├── App.svelte │ ├── index.html │ ├── main.tsx │ └── nested │ │ └── index.html ├── react │ ├── index.html │ └── main.tsx ├── self-edit │ ├── index.html │ └── main.tsx └── svelte │ ├── App.svelte │ ├── index.html │ └── main.tsx ├── file_watcher.ts ├── plugins.ts ├── prebuilt.ts ├── release.sh ├── rpc ├── README.md ├── shared.ts ├── test.ts ├── websocket_adapter.ts └── websocket_server_adapter.ts ├── serve.ts ├── server_api_impl.ts ├── static_server.ts ├── sw ├── env.ts ├── handleInternal.ts ├── handleStatic.ts └── handleWithTransform.ts ├── swc_wasm ├── Cargo.lock ├── Cargo.toml ├── README.md ├── build.js ├── lib.rs ├── mod.ts ├── types.ts └── wasm.js ├── swdev-dev.ts ├── swdev.ts ├── template ├── .gitignore.raw ├── App.svelte ├── README.md ├── index.html └── main.tsx ├── tsconfig.json ├── types.ts ├── utils.ts └── version.ts /.gitignore: -------------------------------------------------------------------------------- 1 | ### https://raw.github.com/github/gitignore/55df35ee63aef4a6f859559af980c9fb87bee1a1/Node.gitignore 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | lerna-debug.log* 10 | 11 | # Diagnostic reports (https://nodejs.org/api/report.html) 12 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | *.pid.lock 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | *.lcov 26 | 27 | # nyc test coverage 28 | .nyc_output 29 | 30 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 31 | .grunt 32 | 33 | # Bower dependency directory (https://bower.io/) 34 | bower_components 35 | 36 | # node-waf configuration 37 | .lock-wscript 38 | 39 | # Compiled binary addons (https://nodejs.org/api/addons.html) 40 | build/Release 41 | 42 | # Dependency directories 43 | node_modules/ 44 | jspm_packages/ 45 | 46 | # TypeScript v1 declaration files 47 | typings/ 48 | 49 | # TypeScript cache 50 | *.tsbuildinfo 51 | 52 | # Optional npm cache directory 53 | .npm 54 | 55 | # Optional eslint cache 56 | .eslintcache 57 | 58 | # Microbundle cache 59 | .rpt2_cache/ 60 | .rts2_cache_cjs/ 61 | .rts2_cache_es/ 62 | .rts2_cache_umd/ 63 | 64 | # Optional REPL history 65 | .node_repl_history 66 | 67 | # Output of 'npm pack' 68 | *.tgz 69 | 70 | # Yarn Integrity file 71 | .yarn-integrity 72 | 73 | # dotenv environment variables file 74 | .env 75 | .env.test 76 | 77 | # parcel-bundler cache (https://parceljs.org/) 78 | .cache 79 | 80 | # Next.js build output 81 | .next 82 | 83 | # Nuxt.js build / generate output 84 | .nuxt 85 | dist 86 | 87 | # Gatsby files 88 | .cache/ 89 | # Comment in the public line in if your project uses Gatsby and not Next.js 90 | # https://nextjs.org/blog/next-9-1#public-directory-support 91 | # public 92 | 93 | # vuepress build output 94 | .vuepress/dist 95 | 96 | # Serverless directories 97 | .serverless/ 98 | 99 | # FuseBox cache 100 | .fusebox/ 101 | 102 | # DynamoDB Local files 103 | .dynamodb/ 104 | 105 | # TernJS port file 106 | .tern-port 107 | 108 | # Stores VSCode versions used for testing VSCode extensions 109 | .vscode-test 110 | 111 | *.bundle.js 112 | tmp 113 | swc_wasm/target -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["svelte.svelte-vscode"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { "deno.enable": true } 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SWDEV 2 | 3 | Runtime transfome by Service Worker and Deno(PoC). 4 | 5 | ## How to use 6 | 7 | ```bash 8 | # install 9 | $ deno install -qAf --unstable https://deno.land/x/swdev/swdev.ts 10 | 11 | $ swdev init myapp 12 | $ cd myapp 13 | $ swdev serve 14 | ``` 15 | 16 | open http://localhost:7777 17 | 18 | _CAUTION_: port:7777 register service-worker. Unregister service-worker after develop. 19 | 20 | ## How to develop 21 | 22 | ```bash 23 | $ deno run -A --unstable swdev-dev.ts prebuild --client --worker # build __swdev-client and __swdev-server 24 | $ deno run -A --unstable serve.ts examples/react --local # run 25 | ``` 26 | 27 | ## Concepts 28 | 29 | - Transform and cache in service-worker (`typescript` and `svelte`) 30 | - Cache bursting by file change event 31 | - Safe file read / write by `deno` permissions 32 | - Use deno semantics in frontend 33 | - Edit itself in browser 34 | - Bundle for production 35 | 36 | ## Install 37 | 38 | ``` 39 | $ swdev init swdev-app 40 | $ cd swdev-app 41 | $ swdev serve 42 | ``` 43 | 44 | ## Experimental Read/Write via websocket` 45 | 46 | Run with `--allow-write` flag. 47 | 48 | `$ swdev serve --allow-write` 49 | 50 | ```ts 51 | // declare to touch 52 | declare const DenoProxy: { 53 | exec: any; 54 | }; 55 | 56 | // READ 57 | console.log(await DenoProxy.exec("readTextFile", "index.html")); 58 | // WRITE: need --allow-write 59 | await DenoProxy.exec("writeTextFile", "foo.ts", "export default 1;"); 60 | ``` 61 | 62 | These features are provided by `/__swdev_client.js` 63 | 64 | ## Experimental Command Run` 65 | 66 | Run with `--allow-run` flag. 67 | 68 | `$ swdev serve --allow-run` 69 | 70 | ```ts 71 | // declare to touch 72 | declare const DenoProxy: { 73 | exec: any; 74 | }; 75 | 76 | // RUN commands 77 | await DenoProxy.exec("run", ["ls", "-al"]); 78 | ``` 79 | 80 | ## Release build 81 | 82 | ```bash 83 | ## Build entry point 84 | $ swdev build #=> main.bundle.js 85 | 86 | ## Deploy assets 87 | # netlify deploy --prod -d . 88 | ``` 89 | 90 | ## LICENSE 91 | 92 | MIT 93 | -------------------------------------------------------------------------------- /browser/cache_buster.ts: -------------------------------------------------------------------------------- 1 | export function rewriteWithRandomHash(code: string) { 2 | const newCode = code 3 | .replace( 4 | /(import|export)\s+(.*)\s+from\s+['"](\..*)['"]/gi, 5 | `$1 $2 from "$3?${Math.random()}"` 6 | ) 7 | .replace( 8 | /import\s+['"](\..*)['"]/, 9 | // ts 10 | `import "$1?${Math.random()}"` 11 | ); 12 | return newCode; 13 | } 14 | -------------------------------------------------------------------------------- /browser/cache_buster_test.ts: -------------------------------------------------------------------------------- 1 | import { assertNotMatch } from "https://deno.land/std@0.82.0/testing/asserts.ts"; 2 | import { rewriteWithRandomHash } from "./cache_buster.ts"; 3 | 4 | const code = ` 5 | import "./direct"; 6 | import { a } from "./a.ts"; 7 | export { b } from "./b.ts"; 8 | `; 9 | 10 | Deno.test("doSomething", async () => { 11 | const x = rewriteWithRandomHash(code); 12 | assertNotMatch(x, /a\.ts\"/); 13 | assertNotMatch(x, /b\.ts\"/); 14 | assertNotMatch(x, /direct"/); 15 | console.log(x); 16 | // assertEquals(actual, expected); 17 | }); 18 | -------------------------------------------------------------------------------- /browser/swdev-client.ts: -------------------------------------------------------------------------------- 1 | import type { RevalidateCommand, Command } from "../types.ts"; 2 | import type { ServerApiImpl } from "../server_api_impl.ts"; 3 | import { wrap } from "../rpc/websocket_adapter.ts"; 4 | 5 | declare var navigator: any; 6 | 7 | const log = (...args: any) => console.info("[swdev-client]", ...args); 8 | 9 | async function setupServiceWorker() { 10 | if (navigator.serviceWorker == null) { 11 | throw new Error("Your browser can not use serviceWorker"); 12 | } 13 | let installed = !!navigator.serviceWorker.controller; 14 | navigator.serviceWorker.addEventListener("controllerchange", () => { 15 | if (installed) { 16 | console.warn("[swdev] service-worker updated. reload it."); 17 | } 18 | }); 19 | 20 | navigator.serviceWorker.addEventListener("message", (ev: any) => { 21 | log("message", ev); 22 | // TODO: reload 23 | }); 24 | 25 | const reg = await navigator.serviceWorker.register("/__swdev-worker.js"); 26 | await navigator.serviceWorker.ready; 27 | installed = true; 28 | setInterval(() => reg.update(), 60 * 1000); 29 | } 30 | 31 | export async function requestRevalidate(cmd: RevalidateCommand) { 32 | const newPaths = cmd.paths.map((u) => 33 | u.startsWith("/") ? `${location.protocol}//${location.host}${u}` : u 34 | ); 35 | 36 | const res = await fetch("/__swdev/revalidate", { 37 | method: "POST", 38 | body: JSON.stringify({ paths: newPaths }), 39 | headers: { "Content-Type": "application/json" }, 40 | }); 41 | if (!res.ok) { 42 | log("revalidate", newPaths); 43 | } else { 44 | log("revalidate-requested", newPaths); 45 | } 46 | return; 47 | } 48 | 49 | let dispose: any = null; 50 | 51 | async function run(url: string, opts: { nocache?: boolean }) { 52 | const runId = opts.nocache 53 | ? `nocache-${Math.random()}` 54 | : Math.random().toString(); 55 | log("run", runId); 56 | 57 | await dispose?.(); 58 | const mod = await import(url + "?" + runId); 59 | dispose = await mod?.default?.(); 60 | } 61 | 62 | // init DenoProxy 63 | function initDenoProxySocket() { 64 | const socket = new WebSocket(`ws://localhost:17777/`); 65 | const api = wrap(socket); 66 | // @ts-ignore 67 | globalThis.DenoProxy = api; 68 | 69 | // test getFiles 70 | // socket.onopen = async () => { 71 | // const result = await api.exec("run", ["ls"]); 72 | // log("init with", result); 73 | // }; 74 | return socket; 75 | } 76 | 77 | let started = false; 78 | 79 | const socket = initDenoProxySocket(); 80 | 81 | export async function start( 82 | url: string, 83 | opts: { nocache?: boolean; onFileChange?: () => void } = {} 84 | ) { 85 | if (started) return; 86 | started = true; 87 | log("start"); 88 | 89 | await setupServiceWorker(); 90 | 91 | const onFileChange = 92 | opts.onFileChange ?? (() => run(url, { nocache: opts.nocache })); 93 | 94 | try { 95 | socket.onmessage = async (message) => { 96 | try { 97 | const cmd = JSON.parse(message.data) as Command; 98 | if (cmd.type === "revalidate") { 99 | await requestRevalidate(cmd); 100 | log("revalidated", cmd.paths); 101 | onFileChange(); 102 | } 103 | // TODO: revalidate all 104 | if (cmd.type === "files") { 105 | console.log("current-files", cmd.files); 106 | } 107 | } catch (e) { 108 | console.error(e); 109 | } 110 | }; 111 | } catch (err) { 112 | // no socket 113 | console.error(err); 114 | } 115 | 116 | await run(url, { nocache: opts.nocache }); 117 | } 118 | -------------------------------------------------------------------------------- /browser/swdev-worker.ts: -------------------------------------------------------------------------------- 1 | import { createTransformHandler } from "../sw/handleWithTransform.ts"; 2 | import { FetchEvent, Env } from "../sw/env.ts"; 3 | import { createInternalHandler } from "../sw/handleInternal.ts"; 4 | 5 | declare var self: any; 6 | 7 | const getStore = () => self.caches.open("v1"); 8 | 9 | async function load(request: Request) { 10 | return fetch(request).then((res) => res.text()); 11 | } 12 | 13 | const env: Env = { getStore, load }; 14 | 15 | const handleInternal = createInternalHandler(env); 16 | const handleWithTransform = createTransformHandler(env); 17 | 18 | self.addEventListener("install", (ev: any) => ev.waitUntil(self.skipWaiting())); 19 | self.addEventListener("activate", (ev: any) => 20 | ev.waitUntil(self.clients.claim()) 21 | ); 22 | 23 | const TARGET_EXTENSIONS = [".ts", ".tsx", ".svelte"]; 24 | self.addEventListener("fetch", (event: FetchEvent) => { 25 | const [url, _hash] = event.request.url.split("?"); 26 | if (url.endsWith("/__swdev/revalidate")) { 27 | event.respondWith(handleInternal(event)); 28 | } else if (TARGET_EXTENSIONS.some((ext) => url.endsWith(ext))) { 29 | event.respondWith(handleWithTransform(event)); 30 | } 31 | }); 32 | -------------------------------------------------------------------------------- /bundler.ts: -------------------------------------------------------------------------------- 1 | import { rollup, httpResolve } from "./deps.ts"; 2 | import { denoLoader, svelte, compress } from "./plugins.ts"; 3 | 4 | export async function bundle(entryPath: string) { 5 | const sourceGen = await rollup({ 6 | input: entryPath, 7 | plugins: [ 8 | httpResolve({ 9 | resolveIdFallback(id: string, importer: any) { 10 | if (importer == null) { 11 | return; 12 | } 13 | if (id.startsWith(".")) { 14 | return; 15 | } 16 | if (id.startsWith("https://")) { 17 | return id; 18 | } 19 | if (id.includes("svelte")) { 20 | return `https://cdn.skypack.dev/${id}`; 21 | } 22 | return `https://cdn.esm.sh/${id}`; 23 | }, 24 | }), 25 | denoLoader(), 26 | svelte(), 27 | compress(), 28 | ], 29 | }).then((g: any) => g.generate({ format: "es" })); 30 | const outpath = entryPath.replace(/(.*)\.tsx?/, "$1.bundle.js"); 31 | await Deno.writeTextFile(outpath, sourceGen.output[0].code); 32 | } 33 | -------------------------------------------------------------------------------- /deploy/deno_deploy_provider.ts: -------------------------------------------------------------------------------- 1 | import { createTransformHandler } from "../sw/handleWithTransform.ts"; 2 | import { FetchEvent, Env, IStore } from "../sw/env.ts"; 3 | import { createInternalHandler } from "../sw/handleInternal.ts"; 4 | import { createHandleStatic } from "../sw/handleStatic.ts"; 5 | 6 | declare var self: any; 7 | 8 | async function load(_request: Request) { 9 | // TODO: implement it! 10 | return "export default 1"; 11 | } 12 | 13 | class DenoDeployStore implements IStore { 14 | private _data: { [k: string]: Response } = {}; 15 | async match(request: Request) { 16 | for (const [k, v] of Object.entries(this._data)) { 17 | if (k === request.url) { 18 | return v.clone(); 19 | } 20 | } 21 | } 22 | async put(k: string, request: Response) { 23 | this._data[k] = request.clone(); 24 | } 25 | async delete(k: string) { 26 | delete this._data[k]; 27 | } 28 | } 29 | 30 | let _store: any; 31 | async function getStore(): Promise { 32 | return (_store ??= new DenoDeployStore()); 33 | } 34 | 35 | const env: Env = { getStore, load }; 36 | const handleInternal = createInternalHandler(env); 37 | const handleWithTransform = createTransformHandler(env); 38 | const handleStatic = createHandleStatic(env); 39 | 40 | const TARGET_EXTENSIONS = [".ts", ".tsx", ".svelte"]; 41 | 42 | self.addEventListener("fetch", (event: FetchEvent) => { 43 | const [url, _hash] = event.request.url.split("?"); 44 | if (url.endsWith("/__swdev/revalidate")) { 45 | event.respondWith(handleInternal(event)); 46 | } else if (TARGET_EXTENSIONS.some((ext) => url.endsWith(ext))) { 47 | event.respondWith(handleWithTransform(event)); 48 | } else { 49 | event.respondWith(handleStatic(event)); 50 | } 51 | }); 52 | -------------------------------------------------------------------------------- /deps.ts: -------------------------------------------------------------------------------- 1 | export { parse } from "https://deno.land/std@0.90.0/flags/mod.ts"; 2 | export { 3 | join, 4 | posix, 5 | extname, 6 | dirname, 7 | } from "https://deno.land/std@0.91.0/path/mod.ts"; 8 | export { 9 | listenAndServe, 10 | listenAndServeTLS, 11 | } from "https://deno.land/std@0.90.0/http/server.ts"; 12 | export type { 13 | HTTPSOptions, 14 | ServerRequest, 15 | Response, 16 | } from "https://deno.land/std@0.90.0/http/server.ts"; 17 | export { assert } from "https://deno.land/std@0.90.0/_util/assert.ts"; 18 | export { ensureDir, exists } from "https://deno.land/std@0.91.0/fs/mod.ts"; 19 | export { expandGlob } from "https://deno.land/std@0.91.0/fs/mod.ts"; 20 | export { rollup } from "https://cdn.esm.sh/rollup"; 21 | export { httpResolve } from "https://cdn.esm.sh/rollup-plugin-http-resolve"; 22 | export type { Plugin as RollupPlugin } from "https://cdn.esm.sh/rollup"; 23 | export { minify } from "https://cdn.esm.sh/terser"; 24 | export type { WebSocketClient } from "https://deno.land/x/websocket@v0.1.0/mod.ts"; 25 | export { WebSocketServer } from "https://deno.land/x/websocket@v0.1.0/mod.ts"; 26 | export { virtualFs } from "https://cdn.esm.sh/rollup-plugin-virtual-fs"; 27 | export { default as ts } from "https://cdn.esm.sh/typescript"; 28 | -------------------------------------------------------------------------------- /examples/playground/.gitignore: -------------------------------------------------------------------------------- 1 | *__swdev-* 2 | *.bundle.js -------------------------------------------------------------------------------- /examples/playground/App.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 |
10 | Hello Svelte - {x} 11 |
12 | -------------------------------------------------------------------------------- /examples/playground/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SWDEV Playground 7 | 15 | 24 | 25 | 26 |
27 |
28 | 29 | -------------------------------------------------------------------------------- /examples/playground/main.tsx: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import SvelteApp from "./App.svelte"; 3 | import React from "https://cdn.esm.sh/react"; 4 | import ReactDOM from "https://cdn.esm.sh/react-dom"; 5 | 6 | function App() { 7 | return
Hello live reload !!!
; 8 | } 9 | 10 | export default () => { 11 | const target = document.querySelector(".svelte-root")!; 12 | let app: any; 13 | if (target.firstChild) { 14 | app = new SvelteApp({ target, hydrate: true }); 15 | } else { 16 | app = new SvelteApp({ target, hydrate: false }); 17 | } 18 | ReactDOM.render(, document.querySelector(".react-root")); 19 | return async () => { 20 | app?.$destroy?.(); 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /examples/playground/nested/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SWDEV Playground 7 | 15 | 24 | 25 | 26 |

Nested

27 |
28 |
29 | 30 | -------------------------------------------------------------------------------- /examples/react/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SWDEV Playground 7 | 16 | 17 | 18 |
19 | 20 | -------------------------------------------------------------------------------- /examples/react/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "https://cdn.esm.sh/react"; 2 | import ReactDOM from "https://cdn.esm.sh/react-dom"; 3 | 4 | function App() { 5 | return
Hello React on Swdev with swc 3
; 6 | } 7 | 8 | export default () => { 9 | ReactDOM.render(, document.querySelector(".root")); 10 | }; 11 | -------------------------------------------------------------------------------- /examples/self-edit/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SWDEV Playground 7 | 16 | 25 | 26 | 27 |
28 | 29 | -------------------------------------------------------------------------------- /examples/self-edit/main.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef, useState } from "https://cdn.esm.sh/react"; 2 | import ReactDOM from "https://cdn.esm.sh/react-dom"; 3 | import loader from "https://cdn.esm.sh/@monaco-editor/loader"; 4 | import type Monaco from "https://cdn.esm.sh/monaco-editor"; 5 | 6 | declare var document: any; 7 | declare type HTMLElement = any; 8 | 9 | declare const DenoProxy: {exec: any}; 10 | 11 | let monaco: Monaco = null as any; 12 | 13 | // @ts-ignore 14 | const vars = (globalThis.__s ??= {}); 15 | 16 | function useHotState(key: string, initialValue: T) { 17 | return useState(vars[key] ?? initialValue); 18 | } 19 | 20 | function App() { 21 | const ref = useRef(null); 22 | const [files, setFiles] = useHotState('files', null); 23 | const [selectedFile, setSelectedFile] = useHotState('selectedFiles', null); 24 | 25 | const [editor, setEditor] = useState(null) 26 | 27 | useEffect(() => { 28 | let disposer: any = null; 29 | (async () => { 30 | monaco = await loader.init(); 31 | if (ref.current) { 32 | const editor = monaco.editor.create(ref.current, { 33 | lineNumbers: "off", 34 | theme: "vs-dark", 35 | fontSize: 16, 36 | minimap: { 37 | enabled: false, 38 | }, 39 | }); 40 | setEditor(editor); 41 | editor.layout(); 42 | 43 | const currentFiles = await DenoProxy.exec("getFiles"); 44 | setFiles(currentFiles); 45 | 46 | if (currentFiles.length > 0 && selectedFile == null) { 47 | const f = currentFiles[0]; 48 | setSelectedFile(f); 49 | } 50 | 51 | disposer = () => { 52 | editor.dispose(); 53 | }; 54 | } 55 | })(); 56 | return () => { 57 | disposer?.(); 58 | }; 59 | }, []); 60 | 61 | useEffect(() => { 62 | if (editor == null ) return; 63 | (async () => { 64 | if (editor == null ) return; 65 | if (selectedFile == null ) return; 66 | const text: string = await DenoProxy.exec("readTextFile", selectedFile); 67 | let langType; 68 | if (selectedFile.endsWith('.ts') || selectedFile.endsWith(".tsx")) { 69 | langType = "typescript" 70 | } 71 | else if (selectedFile.endsWith('.html')) { 72 | langType = "html" 73 | } 74 | else if (selectedFile.endsWith('.css')) { 75 | langType = "css" 76 | } 77 | const model = monaco.editor.createModel(text, langType); 78 | editor.setModel(model); 79 | })(); 80 | 81 | const dispose = editor.addAction({ 82 | id: 'my-save', 83 | label: 'Save', 84 | keybindings: [ 85 | monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_S, 86 | ], 87 | precondition: null, 88 | keybindingContext: null, 89 | contextMenuGroupId: 'navigation', 90 | contextMenuOrder: 1.5, 91 | run: async (editor: any) => { 92 | const value = editor.getValue(); 93 | await DenoProxy.exec('writeTextFile', selectedFile, value); 94 | } 95 | }); 96 | return () => { 97 | // console.log("dispose", dispose); 98 | // dispose(); 99 | dispose.dispose(); 100 | } 101 | }, [editor, selectedFile]); 102 | 103 | const onClickSave = async (ev: any) => { 104 | if (editor) { 105 | const value = editor.getValue(); 106 | await DenoProxy.exec('writeTextFile', selectedFile, value) 107 | // setSelectedFile(target); 108 | } 109 | } 110 | 111 | const onChange = (ev: any) => { 112 | const target = ev.target.value; 113 | setSelectedFile(target); 114 | } 115 | 116 | return ( 117 | <> 118 |
126 | {editor == null && <>loading...} 127 | {files && 128 | 138 | } 139 | 140 |
141 |
142 |
143 | 144 |
145 | 146 | ); 147 | } 148 | 149 | export default async () => { 150 | ReactDOM.render(, document.querySelector(".root")); 151 | }; 152 | -------------------------------------------------------------------------------- /examples/svelte/App.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 |
10 | Hello Svelte - {x} 11 |
12 | -------------------------------------------------------------------------------- /examples/svelte/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SWDEV Playground 7 | 15 | 24 | 25 | 26 |
27 | 28 | -------------------------------------------------------------------------------- /examples/svelte/main.tsx: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import SvelteApp from "./App.svelte"; 3 | 4 | export default () => { 5 | const target = document.querySelector(".root")!; 6 | let app: any; 7 | if (target.firstChild) { 8 | app = new SvelteApp({ target, hydrate: true }); 9 | } else { 10 | app = new SvelteApp({ target, hydrate: false }); 11 | } 12 | return async () => { 13 | app?.$destroy?.(); 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /file_watcher.ts: -------------------------------------------------------------------------------- 1 | import { WebSocketClient, WebSocketServer, join, parse } from "./deps.ts"; 2 | import { expose } from "./rpc/websocket_server_adapter.ts"; 3 | import { createApi } from "./server_api_impl.ts"; 4 | import type { ServeArgs, RevalidateCommand } from "./types.ts"; 5 | 6 | const log = (...args: any) => console.log("[swdev:file_watcher]", ...args); 7 | 8 | export type ServerApiImpl = ReturnType; 9 | 10 | export function startFileWatcher( 11 | wss: WebSocketServer, 12 | opts: { cwd: string; target?: string } 13 | ) { 14 | const cwd = opts.cwd; 15 | const target = opts.target ?? "."; 16 | const watchRoot = join(cwd, target); 17 | 18 | wss.on("connection", async (socket: WebSocketClient) => { 19 | let timeoutId: number | null = null; 20 | let changedPaths = new Set(); 21 | 22 | log("connection created"); 23 | const watcher = Deno.watchFs(watchRoot); 24 | let closed = false; 25 | 26 | socket.on("close", () => { 27 | closed = true; 28 | log("connection closed"); 29 | }); 30 | 31 | expose(socket, createApi(watchRoot)); 32 | 33 | // start file watch 34 | for await (const event of watcher) { 35 | if (closed) break; 36 | debounceEmit(socket, event.paths); 37 | } 38 | function debounceEmit(socket: WebSocketClient, paths: string[]) { 39 | for (const path of paths) { 40 | changedPaths.add(path.replace(watchRoot, "")); 41 | } 42 | timeoutId && clearTimeout(timeoutId); 43 | timeoutId = setTimeout(() => { 44 | timeoutId = null; 45 | socket.send( 46 | JSON.stringify({ 47 | type: "revalidate", 48 | paths: Array.from(changedPaths), 49 | } as RevalidateCommand) 50 | ); 51 | changedPaths = new Set(); 52 | }, 300); 53 | } 54 | }); 55 | 56 | log("started"); 57 | } 58 | 59 | if (import.meta.main) { 60 | const wss = new WebSocketServer(17777); 61 | const serverArgs = parse(Deno.args) as ServeArgs; 62 | const target = serverArgs._[0] ?? "."; 63 | startFileWatcher(wss, { cwd: Deno.cwd(), target }); 64 | } 65 | -------------------------------------------------------------------------------- /plugins.ts: -------------------------------------------------------------------------------- 1 | import { 2 | preprocess, 3 | compile as svelteCompile, 4 | } from "https://cdn.esm.sh/svelte/compiler"; 5 | 6 | import { ts, RollupPlugin, exists, minify, join, dirname } from "./deps.ts"; 7 | 8 | // cache in tmp 9 | const TS_CODE_PATH = "/tmp/_tscode.js"; 10 | let tsCode: string | null = await Deno.readTextFile(TS_CODE_PATH).catch( 11 | (_e) => null 12 | ); 13 | 14 | export const loadTs = () => 15 | ({ 16 | name: "ts-in-rollup", 17 | resolveId(id: string) { 18 | if (id === "https://cdn.esm.sh/typescript") { 19 | return id; 20 | } 21 | }, 22 | async load(id: string) { 23 | if (id === "https://cdn.esm.sh/typescript") { 24 | if (tsCode != null) return tsCode; 25 | const code = await fetch( 26 | "https://cdn.jsdelivr.net/npm/typescript@4.2.3/lib/typescript.js" 27 | ).then((res) => res.text()); 28 | const rewrote = code 29 | .replace(/require\("perf_hooks"\)/, "{}") 30 | .replace(/require\("inspector"\)/, "{}"); 31 | tsCode = 32 | `globalThis.window = self;\n` + rewrote + `export default ts;\n`; 33 | await Deno.writeTextFile(TS_CODE_PATH, tsCode); 34 | return tsCode; 35 | } 36 | }, 37 | } as RollupPlugin); 38 | 39 | export const svelte = () => 40 | ({ 41 | name: "svelte", 42 | async transform(code: string, id: string) { 43 | if (id.endsWith(".svelte")) { 44 | const { code: preprocessed } = await preprocess( 45 | code, 46 | [tsPreprocess()], 47 | { 48 | filename: "$.tsx", 49 | } 50 | ); 51 | const compiled = svelteCompile(preprocessed, { 52 | css: false, 53 | }); 54 | return compiled.js.code; 55 | } 56 | return; 57 | }, 58 | } as RollupPlugin); 59 | 60 | const log = (...args: any) => console.log("[deno-loader]", ...args); 61 | 62 | export const tsPreprocess = () => { 63 | const script: any = async ({ content, filename }: any) => { 64 | const out = ts.transpile(content, { 65 | fileName: filename ?? "/$$.tsx", 66 | target: ts.ScriptTarget.ES2019, 67 | }); 68 | return { code: out }; 69 | }; 70 | return { 71 | script, 72 | }; 73 | }; 74 | 75 | export const transform = () => { 76 | return { 77 | name: "ts-transform", 78 | transform(code: string, id: string) { 79 | if (id.endsWith(".ts") || id.endsWith(".tsx")) { 80 | const out = ts.transpile(code, { 81 | target: ts.ScriptTarget.ES2019, 82 | }); 83 | return out; 84 | } 85 | return; 86 | }, 87 | } as RollupPlugin; 88 | }; 89 | 90 | export const compress = () => { 91 | return { 92 | name: "minify", 93 | async transform(code: string, id: string) { 94 | const out = await minify(code, { 95 | module: true, 96 | }); 97 | return out.code; 98 | }, 99 | } as RollupPlugin; 100 | }; 101 | 102 | export const denoLoader = () => 103 | ({ 104 | name: "deno-loader", 105 | async resolveId(id: string, importer: string | undefined) { 106 | const realpath = importer ? join(dirname(importer), id) : id; 107 | // console.log("[deno-loader:resolve]", realpath); 108 | // console.log("deno-loader:resolveId", id, importer); 109 | if (await exists(realpath)) { 110 | // console.log("deno-loader:resolveId]", realpath); 111 | return realpath; 112 | } 113 | return; 114 | }, 115 | async load(id: string) { 116 | if (await exists(id)) { 117 | const content = await Deno.readTextFile(id); 118 | // console.log("deno-loader:load", id, content.slice(0, 10), "..."); 119 | return content; 120 | } 121 | }, 122 | transform(code: string, id: string) { 123 | if (id.endsWith(".ts") || id.endsWith(".tsx")) { 124 | // console.log("deno-loader:transform", id); 125 | const out = ts.transpile(code, { 126 | filename: "$.tsx", 127 | target: ts.ScriptTarget.ES2019, 128 | jsx: ts.JsxEmit.React, 129 | }); 130 | return out; 131 | } 132 | return; 133 | }, 134 | } as RollupPlugin); 135 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | version=$(deno eval "import {version} from './version.ts'; console.log(version)") 4 | 5 | echo "Start release for $version" 6 | 7 | rm -rf tmp 8 | deno run -A --unstable swdev-dev.ts prebuild --client --worker 9 | git tag $version 10 | git push origin main --tags 11 | -------------------------------------------------------------------------------- /rpc/README.md: -------------------------------------------------------------------------------- 1 | ```ts 2 | import { WebSocketServer, WebSocketClient } from "../deps.ts"; 3 | export type { WorkerApi, RemoteCall } from "./shared.ts"; 4 | import * as serverRpc from "./websocket_server_adapter.ts"; 5 | import * as clientRpc from "./websocket_adapter.ts"; 6 | 7 | const wss = new WebSocketServer(17777); 8 | 9 | wss.on("connection", async (socket: WebSocketClient) => { 10 | serverRpc.expose(socket, { 11 | async foo(a: number) { 12 | return { a }; 13 | }, 14 | }); 15 | socket.send("yeah!"); 16 | }); 17 | 18 | const cli = new WebSocket("ws://localhost:17777/"); 19 | const api = clientRpc.wrap(cli); 20 | cli.onopen = async (ev) => { 21 | const ret = await api.exec("foo", 1); 22 | console.log("user result", ret); 23 | }; 24 | ``` 25 | -------------------------------------------------------------------------------- /rpc/shared.ts: -------------------------------------------------------------------------------- 1 | type RemoteImpl = Record Promise>; 2 | export type RemoteCall = { 3 | exec( 4 | func: T, 5 | ...args: Parameters 6 | ): ReturnType; 7 | terminate(): Promise; 8 | }; 9 | 10 | // https://developer.mozilla.org/ja/docs/Web/API/Transferable 11 | // https://nodejs.org/api/worker_threads.html#worker_threads_port_postmessage_value_transferlist 12 | type Transferrable = any; 13 | 14 | export type Expose = (impl: I) => RemoteCall; 15 | export type WorkerApi = RemoteCall; 16 | export type Cmd = string | [name: string, transferrable?: Transferrable[]]; 17 | 18 | const REQUEST_MARK = "m$s"; 19 | const RESPONSE_MARK = "m$r"; 20 | 21 | type Request = [ 22 | mark: typeof REQUEST_MARK, 23 | id: number, 24 | cmd: Cmd, 25 | ...args: Transferrable[] 26 | ]; 27 | type Response = [ 28 | mark: typeof RESPONSE_MARK, 29 | id: number, 30 | error: boolean, 31 | result: Transferrable 32 | ]; 33 | 34 | export type Adapter = [ 35 | emit: ( 36 | ctx: Ctx, 37 | data: Response | Request, 38 | transferrable?: Array 39 | ) => void, 40 | listen: (ctx: Ctx, fn: any) => void, 41 | terminate: (ctx: Ctx) => Promise 42 | ]; 43 | 44 | export const createExpose = ([emit, listen, terminate]: Adapter) => ( 45 | ctx: any, 46 | api: any 47 | ) => { 48 | listen(ctx, (ev: MessageEvent) => { 49 | if (ev.data?.[0] !== REQUEST_MARK) { 50 | return; 51 | } 52 | const [, id, cmd, ...args] = ev.data as Request; 53 | const [cmdName, transferrable] = typeof cmd === "string" ? [cmd, []] : cmd; 54 | const func = api[cmdName]; 55 | 56 | func(...args) 57 | .then((result: any) => { 58 | emit(ctx, [RESPONSE_MARK, id, false, result], transferrable); 59 | }) 60 | .catch((e: any) => 61 | emit(ctx, [RESPONSE_MARK, id, true, e?.stack ?? e?.toString()]) 62 | ); 63 | }); 64 | }; 65 | 66 | const _sentIdMap: Map< 67 | number, 68 | [resolve: (ret: any) => void, reject: (err: any) => void] 69 | > = new Map(); 70 | let _cnt = 0; 71 | const genId = () => _cnt++; 72 | export const createWrap = ([emit, listen, terminate]: Adapter) => < 73 | Impl extends RemoteImpl 74 | >( 75 | ctx: WebSocket 76 | ): WorkerApi => { 77 | listen(ctx, (ev: MessageEvent) => { 78 | if (ev.data?.[0] !== RESPONSE_MARK) { 79 | return; 80 | } 81 | const [, id, error, result] = ev.data as Response; 82 | const obj = _sentIdMap.get(id); 83 | if (obj == null) return; 84 | _sentIdMap.delete(id); 85 | obj[error ? 1 : 0](result); 86 | }); 87 | return { 88 | terminate: () => terminate(ctx), 89 | // @ts-ignore 90 | exec(cmd: Cmd, ...args: Transferrable) { 91 | const id = genId(); 92 | return new Promise((resolve, reject) => { 93 | _sentIdMap.set(id, [resolve, reject]); 94 | const [cmdName, transferrable] = 95 | typeof cmd === "string" ? [cmd, []] : cmd; 96 | const req = [REQUEST_MARK, id, cmdName, ...args] as Request; 97 | emit(ctx, req, transferrable); 98 | }); 99 | }, 100 | }; 101 | }; 102 | -------------------------------------------------------------------------------- /rpc/test.ts: -------------------------------------------------------------------------------- 1 | import { WebSocketServer, WebSocketClient } from "../deps.ts"; 2 | export type { WorkerApi, RemoteCall } from "./shared.ts"; 3 | import * as serverRpc from "./websocket_server_adapter.ts"; 4 | import * as clientRpc from "./websocket_adapter.ts"; 5 | 6 | const wss = new WebSocketServer(17777); 7 | 8 | wss.on("connection", async (socket: WebSocketClient) => { 9 | console.log("server:connected"); 10 | serverRpc.expose(socket, { 11 | async foo(a: number) { 12 | return { a }; 13 | }, 14 | }); 15 | }); 16 | 17 | const cli = new WebSocket("ws://localhost:17777/"); 18 | const api = clientRpc.wrap(cli); 19 | cli.onopen = async (ev) => { 20 | const ret = await api.exec("foo", 1); 21 | console.log("user result", ret); 22 | }; 23 | -------------------------------------------------------------------------------- /rpc/websocket_adapter.ts: -------------------------------------------------------------------------------- 1 | import { createExpose, createWrap, Adapter } from "./shared.ts"; 2 | 3 | const adapter: Adapter = [ 4 | // emit 5 | (ctx, arg) => { 6 | ctx.send(JSON.stringify(arg)); 7 | }, 8 | // listen 9 | (ctx, handler) => { 10 | ctx.addEventListener("message", (ev) => { 11 | try { 12 | const parsed = JSON.parse(ev.data); 13 | handler(parsed); 14 | } catch (err) { 15 | console.error(err); 16 | } 17 | }); 18 | }, 19 | // terminate 20 | // @ts-ignore 21 | (ctx) => ctx.terminate(), 22 | ]; 23 | 24 | export type { WorkerApi, RemoteCall } from "./shared.ts"; 25 | export const expose = createExpose(adapter); 26 | export const wrap = createWrap(adapter); 27 | -------------------------------------------------------------------------------- /rpc/websocket_server_adapter.ts: -------------------------------------------------------------------------------- 1 | import { WebSocketClient } from "../deps.ts"; 2 | import { createExpose, createWrap, Adapter } from "./shared.ts"; 3 | export type { WorkerApi, RemoteCall } from "./shared.ts"; 4 | 5 | const adapter: Adapter = [ 6 | // emit 7 | (ctx, arg) => { 8 | ctx.send(JSON.stringify({ data: arg })); 9 | }, 10 | // listen 11 | (ctx, handler) => { 12 | ctx.on("message", (data) => { 13 | try { 14 | const parsed = JSON.parse(data); 15 | handler({ 16 | data: parsed, 17 | }); 18 | } catch (err) { 19 | console.error("server:parse-error", err); 20 | } 21 | }); 22 | }, 23 | // terminate 24 | async (ctx) => ctx.close(0), 25 | ]; 26 | 27 | export const expose = createExpose(adapter); 28 | export const wrap = createWrap(adapter); 29 | -------------------------------------------------------------------------------- /serve.ts: -------------------------------------------------------------------------------- 1 | import type { ServeArgs } from "./types.ts"; 2 | import { WebSocketServer, parse } from "./deps.ts"; 3 | import { startStaticServer } from "./static_server.ts"; 4 | import { startFileWatcher } from "./file_watcher.ts"; 5 | 6 | export async function serve(args: ServeArgs, target: string) { 7 | const wss = new WebSocketServer(17777); 8 | await Promise.all([ 9 | startFileWatcher(wss, { cwd: Deno.cwd(), target }), 10 | startStaticServer(args, target), 11 | ]); 12 | } 13 | 14 | if (import.meta.main) { 15 | const args = parse(Deno.args) as ServeArgs; 16 | const target = args._[0]; 17 | serve(args, target); 18 | } 19 | -------------------------------------------------------------------------------- /server_api_impl.ts: -------------------------------------------------------------------------------- 1 | import { expandGlob, join } from "./deps.ts"; 2 | 3 | export function createApi(watchRoot: string) { 4 | return { 5 | async getFiles() { 6 | const files: string[] = []; 7 | for await (const file of expandGlob(watchRoot + "/**/*")) { 8 | if (file.isFile && !file.path.startsWith("__swdev")) { 9 | files.push(file.path.replace(watchRoot, "")); 10 | } 11 | } 12 | return files; 13 | }, 14 | async readTextFile(filepath: string) { 15 | const fpath = join(watchRoot, filepath); 16 | return Deno.readTextFile(fpath); 17 | }, 18 | // need allow-write 19 | async writeTextFile(filepath: string, content: string) { 20 | const fpath = join(watchRoot, filepath); 21 | return Deno.writeTextFile(fpath, content); 22 | }, 23 | // need --allow-run 24 | async run(cmd: string[]) { 25 | const p = Deno.run({ 26 | cwd: watchRoot, 27 | cmd, 28 | stdin: "piped", 29 | stdout: "piped", 30 | }); 31 | return new TextDecoder().decode(await p.output()); 32 | }, 33 | }; 34 | } 35 | 36 | export type ServerApiImpl = ReturnType; 37 | -------------------------------------------------------------------------------- /static_server.ts: -------------------------------------------------------------------------------- 1 | import type { ServeArgs } from "./types.ts"; 2 | import prebuiltData from "./prebuilt.ts"; 3 | import { 4 | extname, 5 | posix, 6 | HTTPSOptions, 7 | listenAndServe, 8 | listenAndServeTLS, 9 | Response, 10 | ServerRequest, 11 | assert, 12 | parse, 13 | } from "./deps.ts"; 14 | 15 | interface EntryInfo { 16 | mode: string; 17 | size: string; 18 | url: string; 19 | name: string; 20 | } 21 | 22 | const encoder = new TextEncoder(); 23 | 24 | const MEDIA_TYPES: Record = { 25 | ".md": "text/markdown", 26 | ".html": "text/html", 27 | ".htm": "text/html", 28 | ".json": "application/json", 29 | ".map": "application/json", 30 | ".txt": "text/plain", 31 | ".ts": "text/typescript", 32 | ".tsx": "text/tsx", 33 | ".js": "application/javascript", 34 | ".jsx": "text/jsx", 35 | ".gz": "application/gzip", 36 | ".css": "text/css", 37 | ".wasm": "application/wasm", 38 | ".mjs": "application/javascript", 39 | ".svg": "image/svg+xml", 40 | }; 41 | 42 | /** Returns the content-type based on the extension of a path. */ 43 | function contentType(path: string): string | undefined { 44 | return MEDIA_TYPES[extname(path)]; 45 | } 46 | 47 | function modeToString(isDir: boolean, maybeMode: number | null): string { 48 | const modeMap = ["---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"]; 49 | 50 | if (maybeMode === null) { 51 | return "(unknown mode)"; 52 | } 53 | const mode = maybeMode.toString(8); 54 | if (mode.length < 3) { 55 | return "(unknown mode)"; 56 | } 57 | let output = ""; 58 | mode 59 | .split("") 60 | .reverse() 61 | .slice(0, 3) 62 | .forEach((v): void => { 63 | output = modeMap[+v] + output; 64 | }); 65 | output = `(${isDir ? "d" : "-"}${output})`; 66 | return output; 67 | } 68 | 69 | function fileLenToString(len: number): string { 70 | const multiplier = 1024; 71 | let base = 1; 72 | const suffix = ["B", "K", "M", "G", "T"]; 73 | let suffixIndex = 0; 74 | 75 | while (base * multiplier < len) { 76 | if (suffixIndex >= suffix.length - 1) { 77 | break; 78 | } 79 | base *= multiplier; 80 | suffixIndex++; 81 | } 82 | 83 | return `${(len / base).toFixed(2)}${suffix[suffixIndex]}`; 84 | } 85 | 86 | /** 87 | * Returns an HTTP Response with the requested file as the body 88 | * @param req The server request context used to cleanup the file handle 89 | * @param filePath Path of the file to serve 90 | */ 91 | export async function serveFile( 92 | req: ServerRequest, 93 | filePath: string 94 | ): Promise { 95 | const [file, fileInfo] = await Promise.all([ 96 | Deno.open(filePath), 97 | Deno.stat(filePath), 98 | ]); 99 | const headers = new Headers(); 100 | headers.set("content-length", fileInfo.size.toString()); 101 | const contentTypeValue = contentType(filePath); 102 | if (contentTypeValue) { 103 | headers.set("content-type", contentTypeValue); 104 | } 105 | req.done.then(() => { 106 | file.close(); 107 | }); 108 | return { 109 | status: 200, 110 | body: file, 111 | headers, 112 | }; 113 | } 114 | 115 | /** 116 | * Returns an HTTP Response with the requested instance 117 | * @param req The server request context used to cleanup the file handle 118 | * @param content Instance on memory 119 | */ 120 | export async function serveInstance( 121 | _req: ServerRequest, 122 | content: string 123 | ): Promise { 124 | const headers = new Headers(); 125 | // headers.set("content-length", content.length.toString()); 126 | headers.set("content-type", "text/javascript"); 127 | return { 128 | status: 200, 129 | body: content, 130 | headers, 131 | }; 132 | } 133 | 134 | // TODO(bartlomieju): simplify this after deno.stat and deno.readDir are fixed 135 | async function serveDir( 136 | req: ServerRequest, 137 | dirPath: string, 138 | target: string 139 | ): Promise { 140 | const showDotfiles = true; 141 | const dirUrl = `/${posix.relative(target, dirPath)}`; 142 | const listEntry: EntryInfo[] = []; 143 | 144 | // if ".." makes sense 145 | if (dirUrl !== "/") { 146 | const prevPath = posix.join(dirPath, ".."); 147 | const fileInfo = await Deno.stat(prevPath); 148 | listEntry.push({ 149 | mode: modeToString(true, fileInfo.mode), 150 | size: "", 151 | name: "../", 152 | url: posix.join(dirUrl, ".."), 153 | }); 154 | } 155 | 156 | for await (const entry of Deno.readDir(dirPath)) { 157 | if (!showDotfiles && entry.name[0] === ".") { 158 | continue; 159 | } 160 | const filePath = posix.join(dirPath, entry.name); 161 | const fileUrl = posix.join(dirUrl, entry.name); 162 | if (entry.name === "index.html" && entry.isFile) { 163 | // in case index.html as dir... 164 | return serveFile(req, filePath); 165 | } 166 | const fileInfo = await Deno.stat(filePath); 167 | listEntry.push({ 168 | mode: modeToString(entry.isDirectory, fileInfo.mode), 169 | size: entry.isFile ? fileLenToString(fileInfo.size ?? 0) : "", 170 | name: `${entry.name}${entry.isDirectory ? "/" : ""}`, 171 | url: fileUrl, 172 | }); 173 | } 174 | listEntry.sort((a, b) => 175 | a.name.toLowerCase() > b.name.toLowerCase() ? 1 : -1 176 | ); 177 | const formattedDirUrl = `${dirUrl.replace(/\/$/, "")}/`; 178 | const page = encoder.encode(dirViewerTemplate(formattedDirUrl, listEntry)); 179 | 180 | const headers = new Headers(); 181 | headers.set("content-type", "text/html"); 182 | 183 | const res = { 184 | status: 200, 185 | body: page, 186 | headers, 187 | }; 188 | return res; 189 | } 190 | 191 | function serveFallback(_req: ServerRequest, e: Error): Promise { 192 | if (e instanceof URIError) { 193 | return Promise.resolve({ 194 | status: 400, 195 | body: encoder.encode("Bad Request"), 196 | }); 197 | } else if (e instanceof Deno.errors.NotFound) { 198 | return Promise.resolve({ 199 | status: 404, 200 | body: encoder.encode("Not Found"), 201 | }); 202 | } else { 203 | return Promise.resolve({ 204 | status: 500, 205 | body: encoder.encode("Internal server error"), 206 | }); 207 | } 208 | } 209 | 210 | function serverLog(req: ServerRequest, res: Response): void { 211 | const d = new Date().toISOString(); 212 | const dateFmt = `[${d.slice(0, 10)} ${d.slice(11, 19)}]`; 213 | const s = `${dateFmt} "${req.method} ${req.url} ${req.proto}" ${res.status}`; 214 | console.log(s); 215 | } 216 | 217 | function setCORS(res: Response): void { 218 | if (!res.headers) { 219 | res.headers = new Headers(); 220 | } 221 | res.headers.append("access-control-allow-origin", "*"); 222 | res.headers.append( 223 | "access-control-allow-headers", 224 | "Origin, X-Requested-With, Content-Type, Accept, Range" 225 | ); 226 | } 227 | 228 | function dirViewerTemplate(dirname: string, entries: EntryInfo[]): string { 229 | return html` 230 | 231 | 232 | 233 | 234 | 235 | 236 | Deno File Server 237 | 285 | 286 | 287 |
288 |

Index of ${dirname}

289 | 290 | 291 | 292 | 293 | 294 | 295 | ${entries.map( 296 | (entry) => 297 | html` 298 | 299 | 300 | 301 | 304 | 305 | ` 306 | )} 307 |
ModeSizeName
${entry.mode}${entry.size} 302 | ${entry.name} 303 |
308 |
309 | 310 | 311 | `; 312 | } 313 | 314 | function html(strings: TemplateStringsArray, ...values: unknown[]): string { 315 | const l = strings.length - 1; 316 | let html = ""; 317 | 318 | for (let i = 0; i < l; i++) { 319 | let v = values[i]; 320 | if (v instanceof Array) { 321 | v = v.join(""); 322 | } 323 | const s = strings[i] + v; 324 | html += s; 325 | } 326 | html += strings[l]; 327 | return html; 328 | } 329 | 330 | function normalizeURL(url: string): string { 331 | let normalizedUrl = url; 332 | try { 333 | normalizedUrl = decodeURI(normalizedUrl); 334 | } catch (e) { 335 | if (!(e instanceof URIError)) { 336 | throw e; 337 | } 338 | } 339 | 340 | try { 341 | //allowed per https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html 342 | const absoluteURI = new URL(normalizedUrl); 343 | normalizedUrl = absoluteURI.pathname; 344 | } catch (e) { 345 | //wasn't an absoluteURI 346 | if (!(e instanceof TypeError)) { 347 | throw e; 348 | } 349 | } 350 | 351 | if (normalizedUrl[0] !== "/") { 352 | throw new URIError("The request URI is malformed."); 353 | } 354 | 355 | normalizedUrl = posix.normalize(normalizedUrl); 356 | const startOfParams = normalizedUrl.indexOf("?"); 357 | return startOfParams > -1 358 | ? normalizedUrl.slice(0, startOfParams) 359 | : normalizedUrl; 360 | } 361 | 362 | export async function startStaticServer(serverArgs: ServeArgs, target: string) { 363 | const CORSEnabled = serverArgs.cors ? true : false; 364 | const port = serverArgs.port ?? serverArgs.p ?? 4507; 365 | const host = serverArgs.host ?? "0.0.0.0"; 366 | const addr = `${host}:${port}`; 367 | const tlsOpts = {} as HTTPSOptions; 368 | tlsOpts.certFile = serverArgs.cert ?? serverArgs.c ?? ""; 369 | tlsOpts.keyFile = serverArgs.key ?? serverArgs.k ?? ""; 370 | const dirListingEnabled = true; 371 | 372 | if (tlsOpts.keyFile || tlsOpts.certFile) { 373 | if (tlsOpts.keyFile === "" || tlsOpts.certFile === "") { 374 | console.log("--key and --cert are required for TLS"); 375 | serverArgs.h = true; 376 | } 377 | } 378 | 379 | if (serverArgs.h ?? serverArgs.help) { 380 | console.log(`Deno File Server 381 | Serves a local directory in HTTP. 382 | 383 | INSTALL: 384 | deno install --allow-net --allow-read https://deno.land/std/http/file_server.ts 385 | 386 | USAGE: 387 | file_server [path] [options] 388 | 389 | OPTIONS: 390 | -h, --help Prints help information 391 | -p, --port Set port 392 | --cors Enable CORS via the "Access-Control-Allow-Origin" header 393 | --host Hostname (default is 0.0.0.0) 394 | -c, --cert TLS certificate file (enables TLS) 395 | -k, --key TLS key file (enables TLS) 396 | --no-dir-listing Disable directory listing 397 | --no-dotfiles Do not show dotfiles 398 | 399 | All TLS options are required when one is provided.`); 400 | Deno.exit(); 401 | } 402 | 403 | const handler = async (req: ServerRequest): Promise => { 404 | let response: Response | undefined; 405 | try { 406 | const normalizedUrl = normalizeURL(req.url); 407 | let fsPath = posix.join(target, normalizedUrl); 408 | if (req.url.startsWith("/__swdev-")) { 409 | const existFile = Deno.stat(fsPath) 410 | .then(() => true) 411 | .catch(() => false); 412 | if (await existFile) { 413 | response = await serveFile(req, fsPath); 414 | } else { 415 | const t = req.url.substr(1) as keyof typeof prebuiltData; 416 | if (prebuiltData[t]) { 417 | response = await serveInstance(req, prebuiltData[t]); 418 | } else { 419 | throw new Error(`Not Found for ${t}`); 420 | } 421 | } 422 | } else { 423 | const fileInfo = await Deno.stat(fsPath); 424 | if (fileInfo.isDirectory) { 425 | if (dirListingEnabled) { 426 | response = await serveDir(req, fsPath, target); 427 | } else { 428 | throw new Deno.errors.NotFound(); 429 | } 430 | } else { 431 | response = await serveFile(req, fsPath); 432 | } 433 | } 434 | } catch (e) { 435 | console.error(e.message); 436 | response = await serveFallback(req, e); 437 | } finally { 438 | if (CORSEnabled) { 439 | assert(response); 440 | setCORS(response); 441 | } 442 | serverLog(req, response!); 443 | try { 444 | await req.respond(response!); 445 | } catch (e) { 446 | console.error(e.message); 447 | } 448 | } 449 | }; 450 | 451 | let proto = "http"; 452 | if (tlsOpts.keyFile || tlsOpts.certFile) { 453 | proto += "s"; 454 | tlsOpts.hostname = host; 455 | tlsOpts.port = port; 456 | listenAndServeTLS(tlsOpts, handler); 457 | } else { 458 | listenAndServe(addr, handler); 459 | } 460 | console.log(`${proto.toUpperCase()} server listening on ${proto}://${addr}/`); 461 | } 462 | 463 | if (import.meta.main) { 464 | const serverArgs = parse(Deno.args) as ServeArgs; 465 | const target = serverArgs._[0] ?? "."; 466 | console.log(serverArgs, target); 467 | await startStaticServer(serverArgs, target); 468 | } 469 | -------------------------------------------------------------------------------- /sw/env.ts: -------------------------------------------------------------------------------- 1 | export type IStore = { 2 | put(key: string, resp: Response): Promise; 3 | delete(k: string): Promise; 4 | match(req: Request): Promise; 5 | }; 6 | 7 | export type Env = { 8 | getStore: () => Promise; 9 | load(request: Request): Promise; 10 | }; 11 | 12 | // mocks 13 | export type FetchEvent = { 14 | request: Request; 15 | respondWith(promise: Promise): void; 16 | }; 17 | 18 | export const log = (...args: any) => console.info("[swdev-worker]", ...args); 19 | -------------------------------------------------------------------------------- /sw/handleInternal.ts: -------------------------------------------------------------------------------- 1 | import { RevalidateCommand } from "../types.ts"; 2 | import { FetchEvent, Env, log } from "./env.ts"; 3 | 4 | export function createInternalHandler(env: Env) { 5 | return async (event: FetchEvent): Promise => { 6 | const cmd: RevalidateCommand = await event.request.json(); 7 | await Promise.all( 8 | cmd.paths.map(async (path: string) => { 9 | try { 10 | const store = await env.getStore(); 11 | await store.delete(path); 12 | log("revalidated", path); 13 | } catch (err) { 14 | log(err); 15 | } 16 | }) 17 | ); 18 | return new Response(event.request.url, { 19 | // @ts-ignore 20 | mode: "no-cors", 21 | status: 200, 22 | }); 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /sw/handleStatic.ts: -------------------------------------------------------------------------------- 1 | import { FetchEvent, Env } from "./env.ts"; 2 | 3 | export function createHandleStatic(_env: Env) { 4 | return async (_event: FetchEvent): Promise => { 5 | const { pathname } = new URL(_event.request.url); 6 | if (["/"].includes(pathname)) { 7 | return new Response(html, { 8 | status: 200, 9 | headers: { 10 | "Content-Type": "text/html", 11 | }, 12 | }); 13 | } 14 | throw new Error(`[handle-static] not found`); 15 | }; 16 | } 17 | 18 | const html = ` 19 | 20 | 21 | 22 | 23 | 24 | SWDEV Playground 25 | 36 | 37 | 38 |
39 | 40 | 41 | `; 42 | -------------------------------------------------------------------------------- /sw/handleWithTransform.ts: -------------------------------------------------------------------------------- 1 | import { transpileDefault } from "../swc_wasm/mod.ts"; 2 | import { rewriteWithRandomHash } from "../browser/cache_buster.ts"; 3 | import { 4 | compile as svelteCompile, 5 | preprocess, 6 | } from "https://cdn.skypack.dev/svelte/compiler"; 7 | import hash from "https://cdn.esm.sh/string-hash"; 8 | import { Env } from "./env.ts"; 9 | 10 | type FetchEvent = { 11 | request: Request; 12 | respondWith(promise: Promise): void; 13 | }; 14 | 15 | export function createTransformHandler(env: Env) { 16 | return async (event: FetchEvent): Promise => { 17 | const [url, hash] = event.request.url.split("?"); 18 | const useCache = !hash?.startsWith("nocache"); 19 | if (useCache) { 20 | const store = await env.getStore(); 21 | const matched = await store.match(new Request(url)); 22 | if (matched) { 23 | const text = await matched.text(); 24 | const newCode = rewriteWithRandomHash(text); 25 | return new Response(newCode, { 26 | // @ts-ignore 27 | mode: "no-cors", 28 | status: 200, 29 | headers: { 30 | "Content-Type": "text/javascript", 31 | }, 32 | }); 33 | } 34 | } 35 | const raw = await env.load(event.request); 36 | return await createNewResponseWithCache(env, url, raw, useCache); 37 | }; 38 | } 39 | 40 | async function transform(url: string, code: string): Promise { 41 | const newHash = hash(code); 42 | const header = `/* SWDEV-HASH:${newHash} */\n`; 43 | if (url.endsWith(".ts") || url.endsWith(".tsx")) { 44 | const result = await transpileDefault(code); 45 | return header + result.code; 46 | } else if (url.endsWith(".svelte")) { 47 | const { code: preprocessed } = await preprocess(code, [tsPreprocess()], { 48 | filename: "$.tsx", 49 | }); 50 | const compiled = svelteCompile(preprocessed, { 51 | css: false, 52 | hydratable: true, 53 | }); 54 | return header + compiled.js.code; 55 | } else { 56 | throw new Error(`unknown extension: ${url}`); 57 | } 58 | } 59 | 60 | async function createNewResponseWithCache( 61 | env: Env, 62 | url: string, 63 | newCode: string, 64 | saveCache: boolean = true 65 | ) { 66 | let output = await transform(url, newCode); 67 | if (!saveCache) { 68 | output = rewriteWithRandomHash(output); 69 | } 70 | const modifiedResponse = new Response(output, { 71 | // @ts-ignore 72 | // mode: "no-cors", 73 | headers: { 74 | "Content-Type": "text/javascript", 75 | }, 76 | }); 77 | if (saveCache) { 78 | const store = await env.getStore(); 79 | await store.put(url, modifiedResponse.clone()); 80 | } 81 | return modifiedResponse; 82 | } 83 | 84 | const tsPreprocess = () => { 85 | const script: any = async ({ content, filename }: any) => { 86 | const out = await transpileDefault(content); 87 | return { code: out.code }; 88 | }; 89 | return { 90 | script, 91 | }; 92 | }; 93 | -------------------------------------------------------------------------------- /swc_wasm/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "Inflector" 7 | version = "0.11.4" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" 10 | dependencies = [ 11 | "lazy_static", 12 | "regex", 13 | ] 14 | 15 | [[package]] 16 | name = "ahash" 17 | version = "0.3.8" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217" 20 | dependencies = [ 21 | "const-random", 22 | ] 23 | 24 | [[package]] 25 | name = "aho-corasick" 26 | version = "0.7.15" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" 29 | dependencies = [ 30 | "memchr", 31 | ] 32 | 33 | [[package]] 34 | name = "anyhow" 35 | version = "1.0.40" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" 38 | 39 | [[package]] 40 | name = "arrayvec" 41 | version = "0.5.2" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" 44 | 45 | [[package]] 46 | name = "ast_node" 47 | version = "0.7.2" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "7c84c445d38f7f29c82ed56c2cfae4885e5e6d9fb81b956ab31430757ddad5d7" 50 | dependencies = [ 51 | "darling", 52 | "pmutil", 53 | "proc-macro2", 54 | "quote", 55 | "swc_macros_common", 56 | "syn", 57 | ] 58 | 59 | [[package]] 60 | name = "autocfg" 61 | version = "0.1.7" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" 64 | 65 | [[package]] 66 | name = "autocfg" 67 | version = "1.0.1" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 70 | 71 | [[package]] 72 | name = "base64" 73 | version = "0.11.0" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" 76 | 77 | [[package]] 78 | name = "base64" 79 | version = "0.12.3" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" 82 | 83 | [[package]] 84 | name = "bitflags" 85 | version = "1.2.1" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 88 | 89 | [[package]] 90 | name = "bumpalo" 91 | version = "3.6.1" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" 94 | 95 | [[package]] 96 | name = "byteorder" 97 | version = "1.4.3" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 100 | 101 | [[package]] 102 | name = "cfg-if" 103 | version = "0.1.10" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 106 | 107 | [[package]] 108 | name = "cfg-if" 109 | version = "1.0.0" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 112 | 113 | [[package]] 114 | name = "cloudabi" 115 | version = "0.0.3" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 118 | dependencies = [ 119 | "bitflags", 120 | ] 121 | 122 | [[package]] 123 | name = "console_error_panic_hook" 124 | version = "0.1.6" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211" 127 | dependencies = [ 128 | "cfg-if 0.1.10", 129 | "wasm-bindgen", 130 | ] 131 | 132 | [[package]] 133 | name = "const-random" 134 | version = "0.1.13" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "f590d95d011aa80b063ffe3253422ed5aa462af4e9867d43ce8337562bac77c4" 137 | dependencies = [ 138 | "const-random-macro", 139 | "proc-macro-hack", 140 | ] 141 | 142 | [[package]] 143 | name = "const-random-macro" 144 | version = "0.1.13" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "615f6e27d000a2bffbc7f2f6a8669179378fa27ee4d0a509e985dfc0a7defb40" 147 | dependencies = [ 148 | "getrandom 0.2.2", 149 | "lazy_static", 150 | "proc-macro-hack", 151 | "tiny-keccak", 152 | ] 153 | 154 | [[package]] 155 | name = "crunchy" 156 | version = "0.2.2" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" 159 | 160 | [[package]] 161 | name = "darling" 162 | version = "0.10.2" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" 165 | dependencies = [ 166 | "darling_core", 167 | "darling_macro", 168 | ] 169 | 170 | [[package]] 171 | name = "darling_core" 172 | version = "0.10.2" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" 175 | dependencies = [ 176 | "fnv", 177 | "ident_case", 178 | "proc-macro2", 179 | "quote", 180 | "strsim", 181 | "syn", 182 | ] 183 | 184 | [[package]] 185 | name = "darling_macro" 186 | version = "0.10.2" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" 189 | dependencies = [ 190 | "darling_core", 191 | "quote", 192 | "syn", 193 | ] 194 | 195 | [[package]] 196 | name = "dashmap" 197 | version = "3.11.10" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "0f260e2fc850179ef410018660006951c1b55b79e8087e87111a2c388994b9b5" 200 | dependencies = [ 201 | "ahash", 202 | "cfg-if 0.1.10", 203 | "num_cpus", 204 | ] 205 | 206 | [[package]] 207 | name = "dashmap" 208 | version = "4.0.2" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" 211 | dependencies = [ 212 | "cfg-if 1.0.0", 213 | "num_cpus", 214 | ] 215 | 216 | [[package]] 217 | name = "deno_swc" 218 | version = "0.0.1" 219 | dependencies = [ 220 | "anyhow", 221 | "console_error_panic_hook", 222 | "fxhash", 223 | "js-sys", 224 | "once_cell", 225 | "serde", 226 | "serde_json", 227 | "sourcemap", 228 | "swc", 229 | "swc_common", 230 | "swc_ecma_ast", 231 | "wasm-bindgen", 232 | "wee_alloc", 233 | ] 234 | 235 | [[package]] 236 | name = "either" 237 | version = "1.6.1" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 240 | 241 | [[package]] 242 | name = "enum_kind" 243 | version = "0.2.1" 244 | source = "registry+https://github.com/rust-lang/crates.io-index" 245 | checksum = "78b940da354ae81ef0926c5eaa428207b8f4f091d3956c891dfbd124162bed99" 246 | dependencies = [ 247 | "pmutil", 248 | "proc-macro2", 249 | "swc_macros_common", 250 | "syn", 251 | ] 252 | 253 | [[package]] 254 | name = "fnv" 255 | version = "1.0.7" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 258 | 259 | [[package]] 260 | name = "form_urlencoded" 261 | version = "1.0.1" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 264 | dependencies = [ 265 | "matches", 266 | "percent-encoding", 267 | ] 268 | 269 | [[package]] 270 | name = "from_variant" 271 | version = "0.1.3" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "0951635027ca477be98f8774abd6f0345233439d63f307e47101acb40c7cc63d" 274 | dependencies = [ 275 | "pmutil", 276 | "proc-macro2", 277 | "swc_macros_common", 278 | "syn", 279 | ] 280 | 281 | [[package]] 282 | name = "fuchsia-cprng" 283 | version = "0.1.1" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" 286 | 287 | [[package]] 288 | name = "fxhash" 289 | version = "0.2.1" 290 | source = "registry+https://github.com/rust-lang/crates.io-index" 291 | checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" 292 | dependencies = [ 293 | "byteorder", 294 | ] 295 | 296 | [[package]] 297 | name = "getrandom" 298 | version = "0.1.16" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" 301 | dependencies = [ 302 | "cfg-if 1.0.0", 303 | "libc", 304 | "wasi 0.9.0+wasi-snapshot-preview1", 305 | ] 306 | 307 | [[package]] 308 | name = "getrandom" 309 | version = "0.2.2" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" 312 | dependencies = [ 313 | "cfg-if 1.0.0", 314 | "libc", 315 | "wasi 0.10.2+wasi-snapshot-preview1", 316 | ] 317 | 318 | [[package]] 319 | name = "hashbrown" 320 | version = "0.9.1" 321 | source = "registry+https://github.com/rust-lang/crates.io-index" 322 | checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" 323 | 324 | [[package]] 325 | name = "hermit-abi" 326 | version = "0.1.18" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" 329 | dependencies = [ 330 | "libc", 331 | ] 332 | 333 | [[package]] 334 | name = "ident_case" 335 | version = "1.0.1" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 338 | 339 | [[package]] 340 | name = "idna" 341 | version = "0.2.2" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "89829a5d69c23d348314a7ac337fe39173b61149a9864deabd260983aed48c21" 344 | dependencies = [ 345 | "matches", 346 | "unicode-bidi", 347 | "unicode-normalization", 348 | ] 349 | 350 | [[package]] 351 | name = "if_chain" 352 | version = "1.0.1" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "1f7280c75fb2e2fc47080ec80ccc481376923acb04501957fc38f935c3de5088" 355 | 356 | [[package]] 357 | name = "indexmap" 358 | version = "1.6.2" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" 361 | dependencies = [ 362 | "autocfg 1.0.1", 363 | "hashbrown", 364 | ] 365 | 366 | [[package]] 367 | name = "is-macro" 368 | version = "0.1.9" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "a322dd16d960e322c3d92f541b4c1a4f0a2e81e1fdeee430d8cecc8b72e8015f" 371 | dependencies = [ 372 | "Inflector", 373 | "pmutil", 374 | "proc-macro2", 375 | "quote", 376 | "syn", 377 | ] 378 | 379 | [[package]] 380 | name = "itoa" 381 | version = "0.4.7" 382 | source = "registry+https://github.com/rust-lang/crates.io-index" 383 | checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" 384 | 385 | [[package]] 386 | name = "js-sys" 387 | version = "0.3.49" 388 | source = "registry+https://github.com/rust-lang/crates.io-index" 389 | checksum = "dc15e39392125075f60c95ba416f5381ff6c3a948ff02ab12464715adf56c821" 390 | dependencies = [ 391 | "wasm-bindgen", 392 | ] 393 | 394 | [[package]] 395 | name = "lazy_static" 396 | version = "1.4.0" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 399 | 400 | [[package]] 401 | name = "libc" 402 | version = "0.2.92" 403 | source = "registry+https://github.com/rust-lang/crates.io-index" 404 | checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" 405 | 406 | [[package]] 407 | name = "lock_api" 408 | version = "0.1.5" 409 | source = "registry+https://github.com/rust-lang/crates.io-index" 410 | checksum = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" 411 | dependencies = [ 412 | "owning_ref", 413 | "scopeguard", 414 | ] 415 | 416 | [[package]] 417 | name = "log" 418 | version = "0.4.14" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 421 | dependencies = [ 422 | "cfg-if 1.0.0", 423 | ] 424 | 425 | [[package]] 426 | name = "matches" 427 | version = "0.1.8" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 430 | 431 | [[package]] 432 | name = "maybe-uninit" 433 | version = "2.0.0" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" 436 | 437 | [[package]] 438 | name = "memchr" 439 | version = "2.3.4" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" 442 | 443 | [[package]] 444 | name = "memory_units" 445 | version = "0.4.0" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" 448 | 449 | [[package]] 450 | name = "new_debug_unreachable" 451 | version = "1.0.4" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" 454 | 455 | [[package]] 456 | name = "num-bigint" 457 | version = "0.2.6" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" 460 | dependencies = [ 461 | "autocfg 1.0.1", 462 | "num-integer", 463 | "num-traits", 464 | "serde", 465 | ] 466 | 467 | [[package]] 468 | name = "num-integer" 469 | version = "0.1.44" 470 | source = "registry+https://github.com/rust-lang/crates.io-index" 471 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 472 | dependencies = [ 473 | "autocfg 1.0.1", 474 | "num-traits", 475 | ] 476 | 477 | [[package]] 478 | name = "num-traits" 479 | version = "0.2.14" 480 | source = "registry+https://github.com/rust-lang/crates.io-index" 481 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 482 | dependencies = [ 483 | "autocfg 1.0.1", 484 | ] 485 | 486 | [[package]] 487 | name = "num_cpus" 488 | version = "1.13.0" 489 | source = "registry+https://github.com/rust-lang/crates.io-index" 490 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 491 | dependencies = [ 492 | "hermit-abi", 493 | "libc", 494 | ] 495 | 496 | [[package]] 497 | name = "once_cell" 498 | version = "1.7.2" 499 | source = "registry+https://github.com/rust-lang/crates.io-index" 500 | checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" 501 | 502 | [[package]] 503 | name = "ordered-float" 504 | version = "2.1.1" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "766f840da25490628d8e63e529cd21c014f6600c6b8517add12a6fa6167a6218" 507 | dependencies = [ 508 | "num-traits", 509 | ] 510 | 511 | [[package]] 512 | name = "owning_ref" 513 | version = "0.4.1" 514 | source = "registry+https://github.com/rust-lang/crates.io-index" 515 | checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" 516 | dependencies = [ 517 | "stable_deref_trait", 518 | ] 519 | 520 | [[package]] 521 | name = "parking_lot" 522 | version = "0.7.1" 523 | source = "registry+https://github.com/rust-lang/crates.io-index" 524 | checksum = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" 525 | dependencies = [ 526 | "lock_api", 527 | "parking_lot_core", 528 | ] 529 | 530 | [[package]] 531 | name = "parking_lot_core" 532 | version = "0.4.0" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" 535 | dependencies = [ 536 | "libc", 537 | "rand 0.6.5", 538 | "rustc_version", 539 | "smallvec 0.6.14", 540 | "winapi", 541 | ] 542 | 543 | [[package]] 544 | name = "percent-encoding" 545 | version = "2.1.0" 546 | source = "registry+https://github.com/rust-lang/crates.io-index" 547 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 548 | 549 | [[package]] 550 | name = "phf" 551 | version = "0.8.0" 552 | source = "registry+https://github.com/rust-lang/crates.io-index" 553 | checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" 554 | dependencies = [ 555 | "phf_macros", 556 | "phf_shared", 557 | "proc-macro-hack", 558 | ] 559 | 560 | [[package]] 561 | name = "phf_generator" 562 | version = "0.8.0" 563 | source = "registry+https://github.com/rust-lang/crates.io-index" 564 | checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" 565 | dependencies = [ 566 | "phf_shared", 567 | "rand 0.7.3", 568 | ] 569 | 570 | [[package]] 571 | name = "phf_macros" 572 | version = "0.8.0" 573 | source = "registry+https://github.com/rust-lang/crates.io-index" 574 | checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" 575 | dependencies = [ 576 | "phf_generator", 577 | "phf_shared", 578 | "proc-macro-hack", 579 | "proc-macro2", 580 | "quote", 581 | "syn", 582 | ] 583 | 584 | [[package]] 585 | name = "phf_shared" 586 | version = "0.8.0" 587 | source = "registry+https://github.com/rust-lang/crates.io-index" 588 | checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" 589 | dependencies = [ 590 | "siphasher", 591 | ] 592 | 593 | [[package]] 594 | name = "pmutil" 595 | version = "0.5.3" 596 | source = "registry+https://github.com/rust-lang/crates.io-index" 597 | checksum = "3894e5d549cccbe44afecf72922f277f603cd4bb0219c8342631ef18fffbe004" 598 | dependencies = [ 599 | "proc-macro2", 600 | "quote", 601 | "syn", 602 | ] 603 | 604 | [[package]] 605 | name = "ppv-lite86" 606 | version = "0.2.10" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" 609 | 610 | [[package]] 611 | name = "precomputed-hash" 612 | version = "0.1.1" 613 | source = "registry+https://github.com/rust-lang/crates.io-index" 614 | checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" 615 | 616 | [[package]] 617 | name = "proc-macro-hack" 618 | version = "0.5.19" 619 | source = "registry+https://github.com/rust-lang/crates.io-index" 620 | checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" 621 | 622 | [[package]] 623 | name = "proc-macro2" 624 | version = "1.0.26" 625 | source = "registry+https://github.com/rust-lang/crates.io-index" 626 | checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" 627 | dependencies = [ 628 | "unicode-xid", 629 | ] 630 | 631 | [[package]] 632 | name = "quote" 633 | version = "1.0.9" 634 | source = "registry+https://github.com/rust-lang/crates.io-index" 635 | checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" 636 | dependencies = [ 637 | "proc-macro2", 638 | ] 639 | 640 | [[package]] 641 | name = "rand" 642 | version = "0.6.5" 643 | source = "registry+https://github.com/rust-lang/crates.io-index" 644 | checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" 645 | dependencies = [ 646 | "autocfg 0.1.7", 647 | "libc", 648 | "rand_chacha 0.1.1", 649 | "rand_core 0.4.2", 650 | "rand_hc 0.1.0", 651 | "rand_isaac", 652 | "rand_jitter", 653 | "rand_os", 654 | "rand_pcg 0.1.2", 655 | "rand_xorshift", 656 | "winapi", 657 | ] 658 | 659 | [[package]] 660 | name = "rand" 661 | version = "0.7.3" 662 | source = "registry+https://github.com/rust-lang/crates.io-index" 663 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 664 | dependencies = [ 665 | "getrandom 0.1.16", 666 | "libc", 667 | "rand_chacha 0.2.2", 668 | "rand_core 0.5.1", 669 | "rand_hc 0.2.0", 670 | "rand_pcg 0.2.1", 671 | ] 672 | 673 | [[package]] 674 | name = "rand_chacha" 675 | version = "0.1.1" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" 678 | dependencies = [ 679 | "autocfg 0.1.7", 680 | "rand_core 0.3.1", 681 | ] 682 | 683 | [[package]] 684 | name = "rand_chacha" 685 | version = "0.2.2" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" 688 | dependencies = [ 689 | "ppv-lite86", 690 | "rand_core 0.5.1", 691 | ] 692 | 693 | [[package]] 694 | name = "rand_core" 695 | version = "0.3.1" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 698 | dependencies = [ 699 | "rand_core 0.4.2", 700 | ] 701 | 702 | [[package]] 703 | name = "rand_core" 704 | version = "0.4.2" 705 | source = "registry+https://github.com/rust-lang/crates.io-index" 706 | checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" 707 | 708 | [[package]] 709 | name = "rand_core" 710 | version = "0.5.1" 711 | source = "registry+https://github.com/rust-lang/crates.io-index" 712 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 713 | dependencies = [ 714 | "getrandom 0.1.16", 715 | ] 716 | 717 | [[package]] 718 | name = "rand_hc" 719 | version = "0.1.0" 720 | source = "registry+https://github.com/rust-lang/crates.io-index" 721 | checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" 722 | dependencies = [ 723 | "rand_core 0.3.1", 724 | ] 725 | 726 | [[package]] 727 | name = "rand_hc" 728 | version = "0.2.0" 729 | source = "registry+https://github.com/rust-lang/crates.io-index" 730 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 731 | dependencies = [ 732 | "rand_core 0.5.1", 733 | ] 734 | 735 | [[package]] 736 | name = "rand_isaac" 737 | version = "0.1.1" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" 740 | dependencies = [ 741 | "rand_core 0.3.1", 742 | ] 743 | 744 | [[package]] 745 | name = "rand_jitter" 746 | version = "0.1.4" 747 | source = "registry+https://github.com/rust-lang/crates.io-index" 748 | checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" 749 | dependencies = [ 750 | "libc", 751 | "rand_core 0.4.2", 752 | "winapi", 753 | ] 754 | 755 | [[package]] 756 | name = "rand_os" 757 | version = "0.1.3" 758 | source = "registry+https://github.com/rust-lang/crates.io-index" 759 | checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" 760 | dependencies = [ 761 | "cloudabi", 762 | "fuchsia-cprng", 763 | "libc", 764 | "rand_core 0.4.2", 765 | "rdrand", 766 | "winapi", 767 | ] 768 | 769 | [[package]] 770 | name = "rand_pcg" 771 | version = "0.1.2" 772 | source = "registry+https://github.com/rust-lang/crates.io-index" 773 | checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" 774 | dependencies = [ 775 | "autocfg 0.1.7", 776 | "rand_core 0.4.2", 777 | ] 778 | 779 | [[package]] 780 | name = "rand_pcg" 781 | version = "0.2.1" 782 | source = "registry+https://github.com/rust-lang/crates.io-index" 783 | checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" 784 | dependencies = [ 785 | "rand_core 0.5.1", 786 | ] 787 | 788 | [[package]] 789 | name = "rand_xorshift" 790 | version = "0.1.1" 791 | source = "registry+https://github.com/rust-lang/crates.io-index" 792 | checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" 793 | dependencies = [ 794 | "rand_core 0.3.1", 795 | ] 796 | 797 | [[package]] 798 | name = "rdrand" 799 | version = "0.4.0" 800 | source = "registry+https://github.com/rust-lang/crates.io-index" 801 | checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" 802 | dependencies = [ 803 | "rand_core 0.3.1", 804 | ] 805 | 806 | [[package]] 807 | name = "regex" 808 | version = "1.4.5" 809 | source = "registry+https://github.com/rust-lang/crates.io-index" 810 | checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" 811 | dependencies = [ 812 | "aho-corasick", 813 | "memchr", 814 | "regex-syntax", 815 | ] 816 | 817 | [[package]] 818 | name = "regex-syntax" 819 | version = "0.6.23" 820 | source = "registry+https://github.com/rust-lang/crates.io-index" 821 | checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" 822 | 823 | [[package]] 824 | name = "retain_mut" 825 | version = "0.1.2" 826 | source = "registry+https://github.com/rust-lang/crates.io-index" 827 | checksum = "53552c6c49e1e13f1a203ef0080ab3bbef0beb570a528993e83df057a9d9bba1" 828 | 829 | [[package]] 830 | name = "rustc_version" 831 | version = "0.2.3" 832 | source = "registry+https://github.com/rust-lang/crates.io-index" 833 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 834 | dependencies = [ 835 | "semver", 836 | ] 837 | 838 | [[package]] 839 | name = "ryu" 840 | version = "1.0.5" 841 | source = "registry+https://github.com/rust-lang/crates.io-index" 842 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 843 | 844 | [[package]] 845 | name = "same-file" 846 | version = "1.0.6" 847 | source = "registry+https://github.com/rust-lang/crates.io-index" 848 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 849 | dependencies = [ 850 | "winapi-util", 851 | ] 852 | 853 | [[package]] 854 | name = "scoped-tls" 855 | version = "1.0.0" 856 | source = "registry+https://github.com/rust-lang/crates.io-index" 857 | checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" 858 | 859 | [[package]] 860 | name = "scopeguard" 861 | version = "0.3.3" 862 | source = "registry+https://github.com/rust-lang/crates.io-index" 863 | checksum = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" 864 | 865 | [[package]] 866 | name = "semver" 867 | version = "0.9.0" 868 | source = "registry+https://github.com/rust-lang/crates.io-index" 869 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 870 | dependencies = [ 871 | "semver-parser", 872 | "serde", 873 | ] 874 | 875 | [[package]] 876 | name = "semver-parser" 877 | version = "0.7.0" 878 | source = "registry+https://github.com/rust-lang/crates.io-index" 879 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 880 | 881 | [[package]] 882 | name = "serde" 883 | version = "1.0.125" 884 | source = "registry+https://github.com/rust-lang/crates.io-index" 885 | checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" 886 | dependencies = [ 887 | "serde_derive", 888 | ] 889 | 890 | [[package]] 891 | name = "serde_derive" 892 | version = "1.0.125" 893 | source = "registry+https://github.com/rust-lang/crates.io-index" 894 | checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" 895 | dependencies = [ 896 | "proc-macro2", 897 | "quote", 898 | "syn", 899 | ] 900 | 901 | [[package]] 902 | name = "serde_json" 903 | version = "1.0.64" 904 | source = "registry+https://github.com/rust-lang/crates.io-index" 905 | checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" 906 | dependencies = [ 907 | "itoa", 908 | "ryu", 909 | "serde", 910 | ] 911 | 912 | [[package]] 913 | name = "siphasher" 914 | version = "0.3.5" 915 | source = "registry+https://github.com/rust-lang/crates.io-index" 916 | checksum = "cbce6d4507c7e4a3962091436e56e95290cb71fa302d0d270e32130b75fbff27" 917 | 918 | [[package]] 919 | name = "smallvec" 920 | version = "0.6.14" 921 | source = "registry+https://github.com/rust-lang/crates.io-index" 922 | checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" 923 | dependencies = [ 924 | "maybe-uninit", 925 | ] 926 | 927 | [[package]] 928 | name = "smallvec" 929 | version = "1.6.1" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" 932 | 933 | [[package]] 934 | name = "sourcemap" 935 | version = "6.0.1" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "6e031f2463ecbdd5f34c950f89f5c1e1032f22c0f8e3dc4bdb2e8b6658cf61eb" 938 | dependencies = [ 939 | "base64 0.11.0", 940 | "if_chain", 941 | "lazy_static", 942 | "regex", 943 | "rustc_version", 944 | "serde", 945 | "serde_json", 946 | "url", 947 | ] 948 | 949 | [[package]] 950 | name = "st-map" 951 | version = "0.1.4" 952 | source = "registry+https://github.com/rust-lang/crates.io-index" 953 | checksum = "3caeb13a58f859600a7b75fffe66322e1fca0122ca02cfc7262344a7e30502d1" 954 | dependencies = [ 955 | "arrayvec", 956 | "static-map-macro", 957 | ] 958 | 959 | [[package]] 960 | name = "stable_deref_trait" 961 | version = "1.2.0" 962 | source = "registry+https://github.com/rust-lang/crates.io-index" 963 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 964 | 965 | [[package]] 966 | name = "static-map-macro" 967 | version = "0.2.1" 968 | source = "registry+https://github.com/rust-lang/crates.io-index" 969 | checksum = "d5503e07f148238811bbfd578684a0457c7284bab41b60d76def35431a1295fd" 970 | dependencies = [ 971 | "pmutil", 972 | "proc-macro2", 973 | "quote", 974 | "syn", 975 | ] 976 | 977 | [[package]] 978 | name = "string_cache" 979 | version = "0.8.1" 980 | source = "registry+https://github.com/rust-lang/crates.io-index" 981 | checksum = "8ddb1139b5353f96e429e1a5e19fbaf663bddedaa06d1dbd49f82e352601209a" 982 | dependencies = [ 983 | "lazy_static", 984 | "new_debug_unreachable", 985 | "phf_shared", 986 | "precomputed-hash", 987 | "serde", 988 | ] 989 | 990 | [[package]] 991 | name = "string_cache_codegen" 992 | version = "0.5.1" 993 | source = "registry+https://github.com/rust-lang/crates.io-index" 994 | checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97" 995 | dependencies = [ 996 | "phf_generator", 997 | "phf_shared", 998 | "proc-macro2", 999 | "quote", 1000 | ] 1001 | 1002 | [[package]] 1003 | name = "string_enum" 1004 | version = "0.3.1" 1005 | source = "registry+https://github.com/rust-lang/crates.io-index" 1006 | checksum = "f584cc881e9e5f1fd6bf827b0444aa94c30d8fe6378cf241071b5f5700b2871f" 1007 | dependencies = [ 1008 | "pmutil", 1009 | "proc-macro2", 1010 | "quote", 1011 | "swc_macros_common", 1012 | "syn", 1013 | ] 1014 | 1015 | [[package]] 1016 | name = "strsim" 1017 | version = "0.9.3" 1018 | source = "registry+https://github.com/rust-lang/crates.io-index" 1019 | checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" 1020 | 1021 | [[package]] 1022 | name = "swc" 1023 | version = "0.13.0" 1024 | source = "registry+https://github.com/rust-lang/crates.io-index" 1025 | checksum = "e4e459be5383dda785b98e942aaad1ce2655a4291f0080274bc611596cd6fcc7" 1026 | dependencies = [ 1027 | "anyhow", 1028 | "base64 0.12.3", 1029 | "dashmap 3.11.10", 1030 | "either", 1031 | "log", 1032 | "once_cell", 1033 | "regex", 1034 | "serde", 1035 | "serde_json", 1036 | "sourcemap", 1037 | "swc_atoms", 1038 | "swc_common", 1039 | "swc_ecma_ast", 1040 | "swc_ecma_codegen", 1041 | "swc_ecma_ext_transforms", 1042 | "swc_ecma_parser", 1043 | "swc_ecma_preset_env", 1044 | "swc_ecma_transforms", 1045 | "swc_ecma_utils", 1046 | "swc_ecma_visit", 1047 | "swc_visit", 1048 | ] 1049 | 1050 | [[package]] 1051 | name = "swc_atoms" 1052 | version = "0.2.5" 1053 | source = "registry+https://github.com/rust-lang/crates.io-index" 1054 | checksum = "762f5c66bf70e6f96db67808b5ad783c33a72cc3e0022cd04b41349231cdbe6c" 1055 | dependencies = [ 1056 | "string_cache", 1057 | "string_cache_codegen", 1058 | ] 1059 | 1060 | [[package]] 1061 | name = "swc_common" 1062 | version = "0.10.13" 1063 | source = "registry+https://github.com/rust-lang/crates.io-index" 1064 | checksum = "1c46e9d1414d5a361a4eb548e3f76bee3e2d9f8f4333907881fe681a59a829aa" 1065 | dependencies = [ 1066 | "ast_node", 1067 | "cfg-if 0.1.10", 1068 | "either", 1069 | "from_variant", 1070 | "fxhash", 1071 | "log", 1072 | "num-bigint", 1073 | "once_cell", 1074 | "owning_ref", 1075 | "parking_lot", 1076 | "scoped-tls", 1077 | "serde", 1078 | "sourcemap", 1079 | "string_cache", 1080 | "swc_eq_ignore_macros", 1081 | "swc_visit", 1082 | "unicode-width", 1083 | ] 1084 | 1085 | [[package]] 1086 | name = "swc_ecma_ast" 1087 | version = "0.42.0" 1088 | source = "registry+https://github.com/rust-lang/crates.io-index" 1089 | checksum = "83eb6a73820660a5af3c24ae1d436e84e4d4c13822021140011361e678df247b" 1090 | dependencies = [ 1091 | "is-macro", 1092 | "num-bigint", 1093 | "serde", 1094 | "string_enum", 1095 | "swc_atoms", 1096 | "swc_common", 1097 | ] 1098 | 1099 | [[package]] 1100 | name = "swc_ecma_codegen" 1101 | version = "0.50.3" 1102 | source = "registry+https://github.com/rust-lang/crates.io-index" 1103 | checksum = "a33c3d4fac9f40837861d53e8f86950e3bdf98f11d099aa9816830d5485fd2c7" 1104 | dependencies = [ 1105 | "bitflags", 1106 | "num-bigint", 1107 | "sourcemap", 1108 | "swc_atoms", 1109 | "swc_common", 1110 | "swc_ecma_ast", 1111 | "swc_ecma_codegen_macros", 1112 | "swc_ecma_parser", 1113 | ] 1114 | 1115 | [[package]] 1116 | name = "swc_ecma_codegen_macros" 1117 | version = "0.5.2" 1118 | source = "registry+https://github.com/rust-lang/crates.io-index" 1119 | checksum = "51af418026cb4ea588e2b15fa206c44e09a3184b718e12a0919729c7c3ad20d3" 1120 | dependencies = [ 1121 | "pmutil", 1122 | "proc-macro2", 1123 | "quote", 1124 | "swc_macros_common", 1125 | "syn", 1126 | ] 1127 | 1128 | [[package]] 1129 | name = "swc_ecma_ext_transforms" 1130 | version = "0.10.0" 1131 | source = "registry+https://github.com/rust-lang/crates.io-index" 1132 | checksum = "f5147fef1017adc904a444c466674dfbbb7361e22e2f98262e7077621eacb07f" 1133 | dependencies = [ 1134 | "phf", 1135 | "swc_atoms", 1136 | "swc_common", 1137 | "swc_ecma_ast", 1138 | "swc_ecma_parser", 1139 | "swc_ecma_utils", 1140 | "swc_ecma_visit", 1141 | ] 1142 | 1143 | [[package]] 1144 | name = "swc_ecma_parser" 1145 | version = "0.52.2" 1146 | source = "registry+https://github.com/rust-lang/crates.io-index" 1147 | checksum = "c03250697857164f16fa98f8e1726f566652d13e52ea3f0c3ecea9deb63ee327" 1148 | dependencies = [ 1149 | "either", 1150 | "enum_kind", 1151 | "fxhash", 1152 | "log", 1153 | "num-bigint", 1154 | "serde", 1155 | "smallvec 1.6.1", 1156 | "swc_atoms", 1157 | "swc_common", 1158 | "swc_ecma_ast", 1159 | "swc_ecma_visit", 1160 | "unicode-xid", 1161 | ] 1162 | 1163 | [[package]] 1164 | name = "swc_ecma_preset_env" 1165 | version = "0.13.0" 1166 | source = "registry+https://github.com/rust-lang/crates.io-index" 1167 | checksum = "f2eff07cfb57c582449aba98f05b9fc1644be80cd3a525089c22689dfa9e2782" 1168 | dependencies = [ 1169 | "dashmap 3.11.10", 1170 | "fxhash", 1171 | "once_cell", 1172 | "semver", 1173 | "serde", 1174 | "serde_json", 1175 | "st-map", 1176 | "string_enum", 1177 | "swc_atoms", 1178 | "swc_common", 1179 | "swc_ecma_ast", 1180 | "swc_ecma_transforms", 1181 | "swc_ecma_utils", 1182 | "swc_ecma_visit", 1183 | "walkdir", 1184 | ] 1185 | 1186 | [[package]] 1187 | name = "swc_ecma_transforms" 1188 | version = "0.43.0" 1189 | source = "registry+https://github.com/rust-lang/crates.io-index" 1190 | checksum = "fb55368ba3185781373a120060e6cbc4f058c947e29a03c9f82fa492d76f2082" 1191 | dependencies = [ 1192 | "swc_atoms", 1193 | "swc_common", 1194 | "swc_ecma_ast", 1195 | "swc_ecma_parser", 1196 | "swc_ecma_transforms_base", 1197 | "swc_ecma_transforms_compat", 1198 | "swc_ecma_transforms_module", 1199 | "swc_ecma_transforms_optimization", 1200 | "swc_ecma_transforms_proposal", 1201 | "swc_ecma_transforms_react", 1202 | "swc_ecma_transforms_typescript", 1203 | "swc_ecma_utils", 1204 | "swc_ecma_visit", 1205 | "unicode-xid", 1206 | ] 1207 | 1208 | [[package]] 1209 | name = "swc_ecma_transforms_base" 1210 | version = "0.10.1" 1211 | source = "registry+https://github.com/rust-lang/crates.io-index" 1212 | checksum = "9e255452f3ce0a34bc8e31e098c4d74fb53fa5fa01127d7c1dc01a4e6d299e05" 1213 | dependencies = [ 1214 | "fxhash", 1215 | "once_cell", 1216 | "phf", 1217 | "scoped-tls", 1218 | "smallvec 1.6.1", 1219 | "swc_atoms", 1220 | "swc_common", 1221 | "swc_ecma_ast", 1222 | "swc_ecma_parser", 1223 | "swc_ecma_utils", 1224 | "swc_ecma_visit", 1225 | ] 1226 | 1227 | [[package]] 1228 | name = "swc_ecma_transforms_compat" 1229 | version = "0.11.0" 1230 | source = "registry+https://github.com/rust-lang/crates.io-index" 1231 | checksum = "d9720c4de8f17b18a085887c1b8d39946afa93f43d5e9ec1a0a3428a986a2e0d" 1232 | dependencies = [ 1233 | "arrayvec", 1234 | "fxhash", 1235 | "indexmap", 1236 | "is-macro", 1237 | "num-bigint", 1238 | "ordered-float", 1239 | "serde", 1240 | "smallvec 1.6.1", 1241 | "swc_atoms", 1242 | "swc_common", 1243 | "swc_ecma_ast", 1244 | "swc_ecma_transforms_base", 1245 | "swc_ecma_transforms_macros", 1246 | "swc_ecma_utils", 1247 | "swc_ecma_visit", 1248 | ] 1249 | 1250 | [[package]] 1251 | name = "swc_ecma_transforms_macros" 1252 | version = "0.2.1" 1253 | source = "registry+https://github.com/rust-lang/crates.io-index" 1254 | checksum = "f7680ada61fa22c2164c3f32864efba31566710b503c30631ccc3b6f0fa800bc" 1255 | dependencies = [ 1256 | "pmutil", 1257 | "proc-macro2", 1258 | "quote", 1259 | "swc_macros_common", 1260 | "syn", 1261 | ] 1262 | 1263 | [[package]] 1264 | name = "swc_ecma_transforms_module" 1265 | version = "0.11.0" 1266 | source = "registry+https://github.com/rust-lang/crates.io-index" 1267 | checksum = "51fe647940ddb284dd5f3dbb6b2359371b3a76351b1205b99dfbbdaa5beb9fa2" 1268 | dependencies = [ 1269 | "Inflector", 1270 | "fxhash", 1271 | "indexmap", 1272 | "serde", 1273 | "swc_atoms", 1274 | "swc_common", 1275 | "swc_ecma_ast", 1276 | "swc_ecma_parser", 1277 | "swc_ecma_transforms_base", 1278 | "swc_ecma_utils", 1279 | "swc_ecma_visit", 1280 | ] 1281 | 1282 | [[package]] 1283 | name = "swc_ecma_transforms_optimization" 1284 | version = "0.13.0" 1285 | source = "registry+https://github.com/rust-lang/crates.io-index" 1286 | checksum = "a5fbeda6a80f0e9c54c6b1c541a7abdbb424bd38a53e4706de55323240ff199d" 1287 | dependencies = [ 1288 | "dashmap 4.0.2", 1289 | "fxhash", 1290 | "indexmap", 1291 | "log", 1292 | "once_cell", 1293 | "retain_mut", 1294 | "serde_json", 1295 | "swc_atoms", 1296 | "swc_common", 1297 | "swc_ecma_ast", 1298 | "swc_ecma_parser", 1299 | "swc_ecma_transforms_base", 1300 | "swc_ecma_utils", 1301 | "swc_ecma_visit", 1302 | ] 1303 | 1304 | [[package]] 1305 | name = "swc_ecma_transforms_proposal" 1306 | version = "0.11.0" 1307 | source = "registry+https://github.com/rust-lang/crates.io-index" 1308 | checksum = "783ec607c28af31fac1d721f5e704e37d0f4d3bd28d0cfe194ebcb81fe07f3bb" 1309 | dependencies = [ 1310 | "either", 1311 | "fxhash", 1312 | "serde", 1313 | "smallvec 1.6.1", 1314 | "swc_atoms", 1315 | "swc_common", 1316 | "swc_ecma_ast", 1317 | "swc_ecma_parser", 1318 | "swc_ecma_transforms_base", 1319 | "swc_ecma_utils", 1320 | "swc_ecma_visit", 1321 | ] 1322 | 1323 | [[package]] 1324 | name = "swc_ecma_transforms_react" 1325 | version = "0.12.0" 1326 | source = "registry+https://github.com/rust-lang/crates.io-index" 1327 | checksum = "e7460753477921dafe398700c9d77ee607ceb71c24354aab60d55b7a1e185d28" 1328 | dependencies = [ 1329 | "dashmap 4.0.2", 1330 | "once_cell", 1331 | "regex", 1332 | "serde", 1333 | "string_enum", 1334 | "swc_atoms", 1335 | "swc_common", 1336 | "swc_ecma_ast", 1337 | "swc_ecma_parser", 1338 | "swc_ecma_transforms_base", 1339 | "swc_ecma_utils", 1340 | "swc_ecma_visit", 1341 | ] 1342 | 1343 | [[package]] 1344 | name = "swc_ecma_transforms_typescript" 1345 | version = "0.12.1" 1346 | source = "registry+https://github.com/rust-lang/crates.io-index" 1347 | checksum = "f4da4c18eccaa5c6852396a0eafd345d24ab468592c468131e53664a3234da33" 1348 | dependencies = [ 1349 | "fxhash", 1350 | "serde", 1351 | "swc_atoms", 1352 | "swc_common", 1353 | "swc_ecma_ast", 1354 | "swc_ecma_parser", 1355 | "swc_ecma_transforms_base", 1356 | "swc_ecma_utils", 1357 | "swc_ecma_visit", 1358 | ] 1359 | 1360 | [[package]] 1361 | name = "swc_ecma_utils" 1362 | version = "0.33.0" 1363 | source = "registry+https://github.com/rust-lang/crates.io-index" 1364 | checksum = "c0178053286bfdde5cfc53f68fb76c3741e2a2a848d5f47327559dff01beb34a" 1365 | dependencies = [ 1366 | "once_cell", 1367 | "scoped-tls", 1368 | "swc_atoms", 1369 | "swc_common", 1370 | "swc_ecma_ast", 1371 | "swc_ecma_visit", 1372 | "unicode-xid", 1373 | ] 1374 | 1375 | [[package]] 1376 | name = "swc_ecma_visit" 1377 | version = "0.28.0" 1378 | source = "registry+https://github.com/rust-lang/crates.io-index" 1379 | checksum = "fd3d60b9dc97ae4f181d4d60f43142d8ac9669953db410bcedefb29a14627e19" 1380 | dependencies = [ 1381 | "num-bigint", 1382 | "swc_atoms", 1383 | "swc_common", 1384 | "swc_ecma_ast", 1385 | "swc_visit", 1386 | ] 1387 | 1388 | [[package]] 1389 | name = "swc_eq_ignore_macros" 1390 | version = "0.1.0" 1391 | source = "registry+https://github.com/rust-lang/crates.io-index" 1392 | checksum = "8c8f200a2eaed938e7c1a685faaa66e6d42fa9e17da5f62572d3cbc335898f5e" 1393 | dependencies = [ 1394 | "pmutil", 1395 | "proc-macro2", 1396 | "quote", 1397 | "syn", 1398 | ] 1399 | 1400 | [[package]] 1401 | name = "swc_macros_common" 1402 | version = "0.3.3" 1403 | source = "registry+https://github.com/rust-lang/crates.io-index" 1404 | checksum = "08ed2e930f5a1a4071fe62c90fd3a296f6030e5d94bfe13993244423caf59a78" 1405 | dependencies = [ 1406 | "pmutil", 1407 | "proc-macro2", 1408 | "quote", 1409 | "syn", 1410 | ] 1411 | 1412 | [[package]] 1413 | name = "swc_visit" 1414 | version = "0.2.4" 1415 | source = "registry+https://github.com/rust-lang/crates.io-index" 1416 | checksum = "583cfe83f6002e1118559308b88181f34b5936b403b72548cd0259bfcf0ca39e" 1417 | dependencies = [ 1418 | "either", 1419 | "swc_visit_macros", 1420 | ] 1421 | 1422 | [[package]] 1423 | name = "swc_visit_macros" 1424 | version = "0.2.3" 1425 | source = "registry+https://github.com/rust-lang/crates.io-index" 1426 | checksum = "e3b2825fee79f10d0166e8e650e79c7a862fb991db275743083f07555d7641f0" 1427 | dependencies = [ 1428 | "Inflector", 1429 | "pmutil", 1430 | "proc-macro2", 1431 | "quote", 1432 | "swc_macros_common", 1433 | "syn", 1434 | ] 1435 | 1436 | [[package]] 1437 | name = "syn" 1438 | version = "1.0.65" 1439 | source = "registry+https://github.com/rust-lang/crates.io-index" 1440 | checksum = "f3a1d708c221c5a612956ef9f75b37e454e88d1f7b899fbd3a18d4252012d663" 1441 | dependencies = [ 1442 | "proc-macro2", 1443 | "quote", 1444 | "unicode-xid", 1445 | ] 1446 | 1447 | [[package]] 1448 | name = "tiny-keccak" 1449 | version = "2.0.2" 1450 | source = "registry+https://github.com/rust-lang/crates.io-index" 1451 | checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" 1452 | dependencies = [ 1453 | "crunchy", 1454 | ] 1455 | 1456 | [[package]] 1457 | name = "tinyvec" 1458 | version = "1.1.1" 1459 | source = "registry+https://github.com/rust-lang/crates.io-index" 1460 | checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023" 1461 | dependencies = [ 1462 | "tinyvec_macros", 1463 | ] 1464 | 1465 | [[package]] 1466 | name = "tinyvec_macros" 1467 | version = "0.1.0" 1468 | source = "registry+https://github.com/rust-lang/crates.io-index" 1469 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 1470 | 1471 | [[package]] 1472 | name = "unicode-bidi" 1473 | version = "0.3.4" 1474 | source = "registry+https://github.com/rust-lang/crates.io-index" 1475 | checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" 1476 | dependencies = [ 1477 | "matches", 1478 | ] 1479 | 1480 | [[package]] 1481 | name = "unicode-normalization" 1482 | version = "0.1.17" 1483 | source = "registry+https://github.com/rust-lang/crates.io-index" 1484 | checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" 1485 | dependencies = [ 1486 | "tinyvec", 1487 | ] 1488 | 1489 | [[package]] 1490 | name = "unicode-width" 1491 | version = "0.1.8" 1492 | source = "registry+https://github.com/rust-lang/crates.io-index" 1493 | checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" 1494 | 1495 | [[package]] 1496 | name = "unicode-xid" 1497 | version = "0.2.1" 1498 | source = "registry+https://github.com/rust-lang/crates.io-index" 1499 | checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" 1500 | 1501 | [[package]] 1502 | name = "url" 1503 | version = "2.2.1" 1504 | source = "registry+https://github.com/rust-lang/crates.io-index" 1505 | checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" 1506 | dependencies = [ 1507 | "form_urlencoded", 1508 | "idna", 1509 | "matches", 1510 | "percent-encoding", 1511 | ] 1512 | 1513 | [[package]] 1514 | name = "walkdir" 1515 | version = "2.3.2" 1516 | source = "registry+https://github.com/rust-lang/crates.io-index" 1517 | checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" 1518 | dependencies = [ 1519 | "same-file", 1520 | "winapi", 1521 | "winapi-util", 1522 | ] 1523 | 1524 | [[package]] 1525 | name = "wasi" 1526 | version = "0.9.0+wasi-snapshot-preview1" 1527 | source = "registry+https://github.com/rust-lang/crates.io-index" 1528 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 1529 | 1530 | [[package]] 1531 | name = "wasi" 1532 | version = "0.10.2+wasi-snapshot-preview1" 1533 | source = "registry+https://github.com/rust-lang/crates.io-index" 1534 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 1535 | 1536 | [[package]] 1537 | name = "wasm-bindgen" 1538 | version = "0.2.72" 1539 | source = "registry+https://github.com/rust-lang/crates.io-index" 1540 | checksum = "8fe8f61dba8e5d645a4d8132dc7a0a66861ed5e1045d2c0ed940fab33bac0fbe" 1541 | dependencies = [ 1542 | "cfg-if 1.0.0", 1543 | "serde", 1544 | "serde_json", 1545 | "wasm-bindgen-macro", 1546 | ] 1547 | 1548 | [[package]] 1549 | name = "wasm-bindgen-backend" 1550 | version = "0.2.72" 1551 | source = "registry+https://github.com/rust-lang/crates.io-index" 1552 | checksum = "046ceba58ff062da072c7cb4ba5b22a37f00a302483f7e2a6cdc18fedbdc1fd3" 1553 | dependencies = [ 1554 | "bumpalo", 1555 | "lazy_static", 1556 | "log", 1557 | "proc-macro2", 1558 | "quote", 1559 | "syn", 1560 | "wasm-bindgen-shared", 1561 | ] 1562 | 1563 | [[package]] 1564 | name = "wasm-bindgen-macro" 1565 | version = "0.2.72" 1566 | source = "registry+https://github.com/rust-lang/crates.io-index" 1567 | checksum = "0ef9aa01d36cda046f797c57959ff5f3c615c9cc63997a8d545831ec7976819b" 1568 | dependencies = [ 1569 | "quote", 1570 | "wasm-bindgen-macro-support", 1571 | ] 1572 | 1573 | [[package]] 1574 | name = "wasm-bindgen-macro-support" 1575 | version = "0.2.72" 1576 | source = "registry+https://github.com/rust-lang/crates.io-index" 1577 | checksum = "96eb45c1b2ee33545a813a92dbb53856418bf7eb54ab34f7f7ff1448a5b3735d" 1578 | dependencies = [ 1579 | "proc-macro2", 1580 | "quote", 1581 | "syn", 1582 | "wasm-bindgen-backend", 1583 | "wasm-bindgen-shared", 1584 | ] 1585 | 1586 | [[package]] 1587 | name = "wasm-bindgen-shared" 1588 | version = "0.2.72" 1589 | source = "registry+https://github.com/rust-lang/crates.io-index" 1590 | checksum = "b7148f4696fb4960a346eaa60bbfb42a1ac4ebba21f750f75fc1375b098d5ffa" 1591 | 1592 | [[package]] 1593 | name = "wee_alloc" 1594 | version = "0.4.5" 1595 | source = "registry+https://github.com/rust-lang/crates.io-index" 1596 | checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" 1597 | dependencies = [ 1598 | "cfg-if 0.1.10", 1599 | "libc", 1600 | "memory_units", 1601 | "winapi", 1602 | ] 1603 | 1604 | [[package]] 1605 | name = "winapi" 1606 | version = "0.3.9" 1607 | source = "registry+https://github.com/rust-lang/crates.io-index" 1608 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1609 | dependencies = [ 1610 | "winapi-i686-pc-windows-gnu", 1611 | "winapi-x86_64-pc-windows-gnu", 1612 | ] 1613 | 1614 | [[package]] 1615 | name = "winapi-i686-pc-windows-gnu" 1616 | version = "0.4.0" 1617 | source = "registry+https://github.com/rust-lang/crates.io-index" 1618 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1619 | 1620 | [[package]] 1621 | name = "winapi-util" 1622 | version = "0.1.5" 1623 | source = "registry+https://github.com/rust-lang/crates.io-index" 1624 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1625 | dependencies = [ 1626 | "winapi", 1627 | ] 1628 | 1629 | [[package]] 1630 | name = "winapi-x86_64-pc-windows-gnu" 1631 | version = "0.4.0" 1632 | source = "registry+https://github.com/rust-lang/crates.io-index" 1633 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1634 | -------------------------------------------------------------------------------- /swc_wasm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "deno_swc" 3 | version = "0.0.1" 4 | authors = ["Divy Srivastava "] 5 | edition = "2018" 6 | publish = false 7 | 8 | [lib] 9 | crate-type = ["cdylib"] 10 | path = "lib.rs" 11 | 12 | [dependencies] 13 | swc = "0.13.0" 14 | swc_ecma_ast = "0.42.0" 15 | swc_common = "0.10.13" 16 | anyhow = "1.0.31" 17 | serde = { version = "1.0", features = ["derive"] } 18 | serde_json = "1.0" 19 | fxhash = "0.2" 20 | wasm-bindgen = { version = "0.2.64", features = ["serde-serialize"] } 21 | wee_alloc = { version = "0.4.5", optional = true } 22 | js-sys = "0.3.44" 23 | console_error_panic_hook = "0.1.6" 24 | sourcemap = "6.0.1" 25 | once_cell = "1.3.1" 26 | 27 | [profile.release] 28 | lto = true 29 | opt-level = "z" 30 | 31 | [features] 32 | default = ["wee_alloc"] 33 | -------------------------------------------------------------------------------- /swc_wasm/README.md: -------------------------------------------------------------------------------- 1 | Fork of [nestdotland/deno_swc: The SWC compiler for Deno.](https://github.com/nestdotland/deno_swc) 2 | -------------------------------------------------------------------------------- /swc_wasm/build.js: -------------------------------------------------------------------------------- 1 | import { encode } from "https://deno.land/std@0.61.0/encoding/base64.ts"; 2 | import Terser from "https://esm.sh/terser@4.8.0"; 3 | 4 | const name = "deno_swc"; 5 | 6 | const encoder = new TextEncoder(); 7 | 8 | async function requires(...executables) { 9 | const where = Deno.build.os === "windows" ? "where" : "which"; 10 | 11 | for (const executable of executables) { 12 | const process = Deno.run({ 13 | cmd: [where, executable], 14 | stderr: "null", 15 | stdin: "null", 16 | stdout: "null", 17 | }); 18 | 19 | if (!(await process.status()).success) { 20 | err(`Could not find required build tool ${executable}`); 21 | } 22 | } 23 | } 24 | 25 | async function run(msg, cmd) { 26 | log(msg); 27 | 28 | const process = Deno.run({ cmd }); 29 | 30 | if (!(await process.status()).success) { 31 | err(`${msg} failed`); 32 | } 33 | } 34 | 35 | function log(text) { 36 | console.log(`[log] ${text}`); 37 | } 38 | 39 | function err(text) { 40 | console.log(`[err] ${text}`); 41 | return Deno.exit(1); 42 | } 43 | 44 | await requires("rustup", "rustc", "cargo", "wasm-pack"); 45 | 46 | if (!(await Deno.stat("Cargo.toml")).isFile) { 47 | err(`the build script should be executed in the "${name}" root`); 48 | } 49 | 50 | await run( 51 | "building using wasm-pack", 52 | ["wasm-pack", "build", "--target", "web", "--release"], 53 | ); 54 | 55 | const wasm = await Deno.readFile(`pkg/${name}_bg.wasm`); 56 | const encoded = encode(wasm); 57 | log( 58 | `encoded wasm using base64, size increase: ${encoded.length - 59 | wasm.length} bytes`, 60 | ); 61 | 62 | log("inlining wasm in js"); 63 | const source = 64 | `export const source = Uint8Array.from(atob("${encoded}"), c => c.charCodeAt(0));`; 65 | 66 | const init = await Deno.readTextFile(`pkg/${name}.js`); 67 | 68 | log("minifying js"); 69 | const output = Terser.minify(`${source}\n${init}`, { 70 | mangle: { module: true }, 71 | output: { 72 | preamble: "//deno-fmt-ignore-file", 73 | }, 74 | }); 75 | 76 | if (output.error) { 77 | err(`encountered error when minifying: ${output.error}`); 78 | } 79 | 80 | const reduction = new Blob([(`${source}\n${init}`)]).size - 81 | new Blob([output.code]).size; 82 | log(`minified js, size reduction: ${reduction} bytes`); 83 | 84 | log(`writing output to file ("wasm.js")`); 85 | await Deno.writeFile("wasm.js", encoder.encode(output.code)); 86 | 87 | const outputFile = await Deno.stat("wasm.js"); 88 | log( 89 | `output file ("wasm.js"), final size is: ${outputFile.size} bytes`, 90 | ); 91 | -------------------------------------------------------------------------------- /swc_wasm/lib.rs: -------------------------------------------------------------------------------- 1 | use once_cell::sync::Lazy; 2 | use std::{ 3 | fmt::{self, Display, Formatter}, 4 | io::{self, Write}, 5 | sync::{Arc, RwLock}, 6 | }; 7 | use swc::{config::Options, Compiler}; 8 | use swc_common::{ 9 | errors::{DiagnosticBuilder, Emitter, Handler, SourceMapperDyn}, 10 | FileName, FilePathMapping, SourceMap, 11 | }; 12 | 13 | use wasm_bindgen::prelude::*; 14 | 15 | #[wasm_bindgen(js_name = "transformSync")] 16 | pub fn transform_sync(s: &str, opts: JsValue) -> Result { 17 | console_error_panic_hook::set_once(); 18 | 19 | let opts: Options = opts 20 | .into_serde() 21 | .map_err(|err| format!("failed to parse options: {}", err))?; 22 | 23 | let (c, errors) = compiler(); 24 | 25 | let fm = c.cm.new_source_file(FileName::Anon, s.into()); 26 | let out = c 27 | .process_js_file(fm, &opts) 28 | .map_err(|err| format!("failed to process code: {}\n{}", err, errors))?; 29 | 30 | Ok(JsValue::from_serde(&out).unwrap()) 31 | } 32 | 33 | fn compiler() -> (Compiler, BufferedError) { 34 | let cm = codemap(); 35 | 36 | let (handler, errors) = new_handler(cm.clone()); 37 | 38 | let c = Compiler::new(cm.clone(), handler); 39 | 40 | (c, errors) 41 | } 42 | 43 | /// Get global sourcemap 44 | fn codemap() -> Arc { 45 | static CM: Lazy> = 46 | Lazy::new(|| Arc::new(SourceMap::new(FilePathMapping::empty()))); 47 | 48 | CM.clone() 49 | } 50 | 51 | /// Creates a new handler which emits to returned buffer. 52 | fn new_handler(_cm: Arc) -> (Arc, BufferedError) { 53 | let e = BufferedError::default(); 54 | 55 | let handler = Handler::with_emitter(true, false, Box::new(MyEmiter::default())); 56 | 57 | (Arc::new(handler), e) 58 | } 59 | 60 | #[derive(Clone, Default)] 61 | struct MyEmiter(BufferedError); 62 | 63 | impl Emitter for MyEmiter { 64 | fn emit(&mut self, db: &DiagnosticBuilder<'_>) { 65 | let z = &(self.0).0; 66 | for msg in &db.message { 67 | z.write().unwrap().push_str(&msg.0); 68 | } 69 | } 70 | } 71 | 72 | #[derive(Clone, Default)] 73 | pub(crate) struct BufferedError(Arc>); 74 | 75 | impl Write for BufferedError { 76 | fn write(&mut self, d: &[u8]) -> io::Result { 77 | self.0 78 | .write() 79 | .unwrap() 80 | .push_str(&String::from_utf8_lossy(d)); 81 | 82 | Ok(d.len()) 83 | } 84 | fn flush(&mut self) -> io::Result<()> { 85 | Ok(()) 86 | } 87 | } 88 | 89 | impl Display for BufferedError { 90 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 91 | Display::fmt(&self.0.read().unwrap(), f) 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /swc_wasm/mod.ts: -------------------------------------------------------------------------------- 1 | import init, { source, transformSync } from "./wasm.js"; 2 | import { TransformConfig, ParserConfig } from "./types.ts"; 3 | 4 | let __initialized = false; 5 | async function _init() { 6 | if (__initialized) return; 7 | __initialized = true; 8 | await init(source); 9 | } 10 | 11 | export async function transform( 12 | code: string, 13 | opts: { 14 | jsc: { parser: ParserConfig; transform: TransformConfig; tsc: string }; 15 | } 16 | ): Promise<{ code: string }> { 17 | await _init(); 18 | return transformSync(code, opts); 19 | } 20 | 21 | export async function transpileDefault(code: string) { 22 | return await transform(code, { 23 | jsc: { 24 | // @ts-ignore 25 | target: "es2019", 26 | parser: { 27 | syntax: "typescript", 28 | tsx: true, 29 | }, 30 | transform: { 31 | react: { 32 | pragma: "React.createElement", 33 | pragmaFrag: "React.Fragment", 34 | development: false, 35 | useBuiltins: true, 36 | throwIfNamespace: true, 37 | }, 38 | }, 39 | }, 40 | }); 41 | } 42 | 43 | // const code = `import React from "https://cdn.esm.sh/react"; 44 | // import ReactDOM from "https://cdn.esm.sh/react-dom"; 45 | 46 | // function App() { 47 | // return
Hello React on Swdev
; 48 | // } 49 | 50 | // export default () => { 51 | // ReactDOM.render(, document.querySelector(".root")); 52 | // }; 53 | // `; 54 | 55 | // const out = await transpile(code); 56 | // console.log(out); 57 | -------------------------------------------------------------------------------- /swc_wasm/types.ts: -------------------------------------------------------------------------------- 1 | export interface Plugin { 2 | (module: Program): Program; 3 | } 4 | 5 | export type ParseOptions = ParserConfig & { 6 | comments?: boolean; 7 | script?: boolean; 8 | /** 9 | * Defaults to es3. 10 | */ 11 | target?: JscTarget; 12 | }; 13 | 14 | /** 15 | * Programmatic options. 16 | */ 17 | export interface Options extends Config { 18 | /** 19 | * If true, a file is parsed as a script instead of module. 20 | */ 21 | script?: boolean; 22 | 23 | /** 24 | * The working directory that all paths in the programmatic 25 | * options will be resolved relative to. 26 | * 27 | * Defaults to `process.cwd()`. 28 | */ 29 | cwd?: string; 30 | caller?: CallerOptions; 31 | /** The filename associated with the code currently being compiled, 32 | * if there is one. The filename is optional, but not all of Swc's 33 | * functionality is available when the filename is unknown, because a 34 | * subset of options rely on the filename for their functionality. 35 | * 36 | * The three primary cases users could run into are: 37 | * 38 | * - The filename is exposed to plugins. Some plugins may require the 39 | * presence of the filename. 40 | * - Options like "test", "exclude", and "ignore" require the filename 41 | * for string/RegExp matching. 42 | * - .swcrc files are loaded relative to the file being compiled. 43 | * If this option is omitted, Swc will behave as if swcrc: false has been set. 44 | */ 45 | filename?: string; 46 | 47 | /** 48 | * The initial path that will be processed based on the "rootMode" to 49 | * determine the conceptual root folder for the current Swc project. 50 | * This is used in two primary cases: 51 | * 52 | * - The base directory when checking for the default "configFile" value 53 | * - The default value for "swcrcRoots". 54 | * 55 | * Defaults to `opts.cwd` 56 | */ 57 | root?: string; 58 | 59 | /** 60 | * This option, combined with the "root" value, defines how Swc chooses 61 | * its project root. The different modes define different ways that Swc 62 | * can process the "root" value to get the final project root. 63 | * 64 | * "root" - Passes the "root" value through as unchanged. 65 | * "upward" - Walks upward from the "root" directory, looking for a directory 66 | * containinga swc.config.js file, and throws an error if a swc.config.js 67 | * is not found. 68 | * "upward-optional" - Walk upward from the "root" directory, looking for 69 | * a directory containing a swc.config.js file, and falls back to "root" 70 | * if a swc.config.js is not found. 71 | * 72 | * 73 | * "root" is the default mode because it avoids the risk that Swc 74 | * will accidentally load a swc.config.js that is entirely outside 75 | * of the current project folder. If you use "upward-optional", 76 | * be aware that it will walk up the directory structure all the 77 | * way to the filesystem root, and it is always possible that someone 78 | * will have a forgotten swc.config.js in their home directory, 79 | * which could cause unexpected errors in your builds. 80 | * 81 | * 82 | * Users with monorepo project structures that run builds/tests on a 83 | * per-package basis may well want to use "upward" since monorepos 84 | * often have a swc.config.js in the project root. Running Swc 85 | * in a monorepo subdirectory without "upward", will cause Swc 86 | * to skip loading any swc.config.js files in the project root, 87 | * which can lead to unexpected errors and compilation failure. 88 | */ 89 | rootMode?: "root" | "upward" | "upward-optional"; 90 | 91 | /** 92 | * The current active environment used during configuration loading. 93 | * This value is used as the key when resolving "env" configs, 94 | * and is also available inside configuration functions, plugins, 95 | * and presets, via the api.env() function. 96 | * 97 | * Defaults to `process.env.SWC_ENV || process.env.NODE_ENV || "development"` 98 | */ 99 | envName?: string; 100 | 101 | /** 102 | * Defaults to searching for a default `.swcrc` file, but can 103 | * be passed the path of any JS or JSON5 config file. 104 | * 105 | * 106 | * NOTE: This option does not affect loading of .swcrc files, 107 | * so while it may be tempting to do configFile: "./foo/.swcrc", 108 | * it is not recommended. If the given .swcrc is loaded via the 109 | * standard file-relative logic, you'll end up loading the same 110 | * config file twice, merging it with itself. If you are linking 111 | * a specific config file, it is recommended to stick with a 112 | * naming scheme that is independent of the "swcrc" name. 113 | * 114 | * Defaults to `path.resolve(opts.root, ".swcrc")` 115 | */ 116 | configFile?: string | boolean; 117 | 118 | /** 119 | * true will enable searching for configuration files relative to the "filename" provided to Swc. 120 | * 121 | * A swcrc value passed in the programmatic options will override one set within a configuration file. 122 | * 123 | * Note: .swcrc files are only loaded if the current "filename" is inside of 124 | * a package that matches one of the "swcrcRoots" packages. 125 | * 126 | * 127 | * Defaults to true as long as the filename option has been specificed 128 | */ 129 | swcrc?: boolean; 130 | 131 | /** 132 | * By default, Babel will only search for .babelrc files within the "root" package 133 | * because otherwise Babel cannot know if a given .babelrc is meant to be loaded, 134 | * or if it's "plugins" and "presets" have even been installed, since the file 135 | * being compiled could be inside node_modules, or have been symlinked into the project. 136 | * 137 | * 138 | * This option allows users to provide a list of other packages that should be 139 | * considered "root" packages when considering whether to load .babelrc files. 140 | * 141 | * 142 | * For example, a monorepo setup that wishes to allow individual packages 143 | * to have their own configs might want to do 144 | * 145 | * 146 | * 147 | * Defaults to `opts.root` 148 | */ 149 | swcrcRoots?: boolean | MatchPattern | MatchPattern[]; 150 | 151 | /** 152 | * `true` will attempt to load an input sourcemap from the file itself, if it 153 | * contains a //# sourceMappingURL=... comment. If no map is found, or the 154 | * map fails to load and parse, it will be silently discarded. 155 | * 156 | * If an object is provided, it will be treated as the source map object itself. 157 | * 158 | * Defaults to `true`. 159 | */ 160 | inputSourceMap?: boolean | string; 161 | 162 | /** 163 | * - true to generate a sourcemap for the code and include it in the result object. 164 | * - "inline" to generate a sourcemap and append it as a data URL to the end of the code, but not include it in the result object. 165 | * - "both" is the same as inline, but will include the map in the result object. 166 | * 167 | * `swc-cli` overloads some of these to also affect how maps are written to disk: 168 | * 169 | * - true will write the map to a .map file on disk 170 | * - "inline" will write the file directly, so it will have a data: containing the map 171 | * - "both" will write the file with a data: URL and also a .map. 172 | * - Note: These options are bit weird, so it may make the most sense to just use true 173 | * and handle the rest in your own code, depending on your use case. 174 | */ 175 | sourceMaps?: boolean | "inline" | "both"; 176 | 177 | /** 178 | * The name to use for the file inside the source map object. 179 | * 180 | * Defaults to `path.basename(opts.filenameRelative)` when available, or `"unknown"`. 181 | */ 182 | sourceFileName?: string; 183 | 184 | /** 185 | * The sourceRoot fields to set in the generated source map, if one is desired. 186 | */ 187 | sourceRoot?: string; 188 | 189 | plugin?: Plugin; 190 | 191 | isModule?: boolean; 192 | } 193 | 194 | export interface CallerOptions { 195 | name: string; 196 | [key: string]: any; 197 | } 198 | 199 | export type Swcrc = Config | Config[]; 200 | 201 | /** 202 | * .swcrc 203 | */ 204 | export interface Config { 205 | env?: EnvConfig; 206 | jsc?: JscConfig; 207 | module?: ModuleConfig; 208 | minify?: boolean; 209 | } 210 | 211 | /** 212 | * Configuration ported from babel-preset-env 213 | */ 214 | export interface EnvConfig { 215 | mode?: "usage" | "entry"; 216 | debug?: boolean; 217 | dynamicImport?: boolean; 218 | 219 | loose?: boolean; 220 | 221 | /// Skipped es features. 222 | /// 223 | /// e.g.) 224 | /// - `core-js/modules/foo` 225 | skip?: string[]; 226 | 227 | include?: string[]; 228 | 229 | exclude?: string[]; 230 | 231 | /** 232 | * The version of the used core js. 233 | * 234 | */ 235 | coreJs?: string; 236 | 237 | targets?: any; 238 | 239 | shippedProposals?: boolean; 240 | 241 | /** 242 | * Enable all trnasforms 243 | */ 244 | forceAllTransforms?: boolean; 245 | } 246 | 247 | export interface JscConfig { 248 | loose?: boolean; 249 | 250 | /** 251 | * Defaults to EsParserConfig 252 | */ 253 | parser?: ParserConfig; 254 | transform?: TransformConfig; 255 | /** 256 | * Use `@swc/helpers` instead of inline helpers. 257 | */ 258 | externalHelpers?: boolean; 259 | 260 | /** 261 | * Defaults to `es3` (which enableds **all** pass). 262 | */ 263 | target?: JscTarget; 264 | } 265 | 266 | export type JscTarget = 267 | | "es3" 268 | | "es5" 269 | | "es2015" 270 | | "es2016" 271 | | "es2017" 272 | | "es2018" 273 | | "es2019"; 274 | 275 | export type ParserConfig = TsParserConfig | EsParserConfig; 276 | export interface TsParserConfig { 277 | syntax: "typescript"; 278 | /** 279 | * Defaults to `false`. 280 | */ 281 | tsx?: boolean; 282 | /** 283 | * Defaults to `false`. 284 | */ 285 | decorators?: boolean; 286 | /** 287 | * Defaults to `false` 288 | */ 289 | dynamicImport?: boolean; 290 | } 291 | 292 | export interface EsParserConfig { 293 | syntax: "ecmascript"; 294 | /** 295 | * Defaults to false. 296 | */ 297 | jsc?: boolean; 298 | /** 299 | * Defaults to `false`. This is not implemented yet. 300 | */ 301 | numericSeparator?: boolean; 302 | /** 303 | * Defaults to `false` 304 | */ 305 | classPrivateProperty?: boolean; 306 | /** 307 | * Defaults to `false` 308 | */ 309 | privateMethod?: boolean; 310 | /** 311 | * Defaults to `false` 312 | */ 313 | classProperty?: boolean; 314 | /** 315 | * Defaults to `false` 316 | */ 317 | functionBind?: boolean; 318 | /** 319 | * Defaults to `false` 320 | */ 321 | decorators?: boolean; 322 | /** 323 | * Defaults to `false` 324 | */ 325 | decoratorsBeforeExport?: boolean; 326 | /** 327 | * Defaults to `false` 328 | */ 329 | dynamicImport?: boolean; 330 | /** 331 | * Defaults to `false` 332 | */ 333 | nullishCoalescing?: boolean; 334 | } 335 | 336 | /** 337 | * Options for trasnform. 338 | */ 339 | export interface TransformConfig { 340 | /** 341 | * Effective only if `syntax` supports ƒ. 342 | */ 343 | react?: ReactConfig; 344 | constModules?: ConstModulesConfig; 345 | 346 | /** 347 | * Defaults to null, which skips optimizer pass. 348 | */ 349 | optimizer?: OptimizerConfig; 350 | } 351 | 352 | export interface ReactConfig { 353 | /** 354 | * Replace the function used when compiling JSX expressions. 355 | * 356 | * Defaults to `React.createElement`. 357 | */ 358 | pragma: String; 359 | /** 360 | * Replace the component used when compiling JSX fragments. 361 | * 362 | * Defaults to `React.Fragment` 363 | */ 364 | pragmaFrag: String; 365 | /** 366 | * Toggles whether or not to throw an error if a XML namespaced tag name is used. For example: 367 | * `` 368 | * 369 | * Though the JSX spec allows this, it is disabled by default since React's 370 | * JSX does not currently have support for it. 371 | * 372 | */ 373 | throwIfNamespace: boolean; 374 | /** 375 | * Toggles plugins that aid in development, such as @swc/plugin-transform-react-jsx-self 376 | * and @swc/plugin-transform-react-jsx-source. 377 | * 378 | * Defaults to `false`, 379 | * 380 | */ 381 | development: boolean; 382 | /** 383 | * Use `Object.assign()` instead of `_extends`. Defaults to false. 384 | */ 385 | useBuiltins: boolean; 386 | } 387 | /** 388 | * - `import { DEBUG } from '@ember/env-flags';` 389 | * - `import { FEATURE_A, FEATURE_B } from '@ember/features';` 390 | * 391 | * See: https://github.com/swc-project/swc/issues/18#issuecomment-466272558 392 | */ 393 | export interface ConstModulesConfig { 394 | globals?: { 395 | [module: string]: { 396 | [name: string]: string; 397 | }; 398 | }; 399 | } 400 | 401 | export interface OptimizerConfig { 402 | globals?: GlobalPassOption; 403 | } 404 | 405 | /** 406 | * Options for inline-global pass. 407 | */ 408 | export interface GlobalPassOption { 409 | /** 410 | * Global variables. 411 | * 412 | * e.g. `{ __DEBUG__: true }` 413 | */ 414 | vars?: { [key: string]: string }; 415 | 416 | /** 417 | * Name of environment variables to inline. 418 | * 419 | * Defaults to `["NODE_ENV", "SWC_ENV"]` 420 | */ 421 | envs?: string[]; 422 | } 423 | 424 | export type ModuleConfig = CommonJsConfig | UmdConfig | AmdConfig; 425 | 426 | export interface BaseModuleConfig { 427 | /** 428 | * By default, when using exports with babel a non-enumerable `__esModule` 429 | * property is exported. In some cases this property is used to determine 430 | * if the import is the default export or if it contains the default export. 431 | * 432 | * In order to prevent the __esModule property from being exported, you 433 | * can set the strict option to true. 434 | * 435 | * Defaults to `false`. 436 | */ 437 | strict?: boolean; 438 | 439 | /** 440 | * Emits 'use strict' directive. 441 | * 442 | * Defaults to `true`. 443 | */ 444 | strict_mode?: boolean; 445 | 446 | /** 447 | * Changes Babel's compiled import statements to be lazily evaluated when their imported bindings are used for the first time. 448 | * 449 | * This can improve initial load time of your module because evaluating dependencies up 450 | * front is sometimes entirely un-necessary. This is especially the case when implementing 451 | * a library module. 452 | * 453 | * 454 | * The value of `lazy` has a few possible effects: 455 | * 456 | * - `false` - No lazy initialization of any imported module. 457 | * - `true` - Do not lazy-initialize local `./foo` imports, but lazy-init `foo` dependencies. 458 | * 459 | * Local paths are much more likely to have circular dependencies, which may break if loaded lazily, 460 | * so they are not lazy by default, whereas dependencies between independent modules are rarely cyclical. 461 | * 462 | * - `Array` - Lazy-initialize all imports with source matching one of the given strings. 463 | * 464 | * ----- 465 | * 466 | * The two cases where imports can never be lazy are: 467 | * 468 | * - `import "foo";` 469 | * 470 | * Side-effect imports are automatically non-lazy since their very existence means 471 | * that there is no binding to later kick off initialization. 472 | * 473 | * - `export * from "foo"` 474 | * 475 | * Re-exporting all names requires up-front execution because otherwise there is no 476 | * way to know what names need to be exported. 477 | * 478 | * Defaults to `false`. 479 | */ 480 | lazy?: boolean | string[]; 481 | /** 482 | * By default, when using exports with swc a non-enumerable __esModule property is exported. 483 | * This property is then used to determine if the import is the default export or if 484 | * it contains the default export. 485 | * 486 | * In cases where the auto-unwrapping of default is not needed, you can set the noInterop option 487 | * to true to avoid the usage of the interopRequireDefault helper (shown in inline form above). 488 | * 489 | * Defaults to `false`. 490 | */ 491 | noInterop?: boolean; 492 | } 493 | 494 | export interface CommonJsConfig extends BaseModuleConfig { 495 | type: "commonjs"; 496 | } 497 | 498 | export interface UmdConfig extends BaseModuleConfig { 499 | type: "umd"; 500 | globals?: { [key: string]: string }; 501 | } 502 | 503 | export interface AmdConfig extends BaseModuleConfig { 504 | type: "amd"; 505 | moduleId: string; 506 | } 507 | 508 | export interface Output { 509 | /** 510 | * Transformed code 511 | */ 512 | code: string; 513 | /** 514 | * Sourcemap (**not** base64 encoded) 515 | */ 516 | map?: string; 517 | } 518 | 519 | export interface MatchPattern {} 520 | 521 | // ------------------------------- 522 | // ---------- Ast nodes ---------- 523 | // ------------------------------- 524 | 525 | export interface Span { 526 | start: number; 527 | end: number; 528 | ctxt: number; 529 | } 530 | 531 | export interface Node { 532 | type: string; 533 | } 534 | 535 | export interface HasSpan { 536 | span: Span; 537 | } 538 | 539 | export interface HasDecorator { 540 | decorators?: Decorator[]; 541 | } 542 | 543 | export interface Class extends HasSpan, HasDecorator { 544 | body: ClassMember[]; 545 | 546 | superClass?: Expression; 547 | 548 | is_abstract: boolean; 549 | 550 | typeParams: TsTypeParameterDeclaration; 551 | 552 | superTypeParams?: TsTypeParameterInstantiation; 553 | 554 | implements: TsExpressionWithTypeArguments[]; 555 | } 556 | 557 | export type ClassMember = 558 | | Constructor 559 | | ClassMethod 560 | | PrivateMethod 561 | | ClassProperty 562 | | PrivateProperty 563 | | TsIndexSignature; 564 | 565 | export interface ClassPropertyBase extends Node, HasSpan, HasDecorator { 566 | value?: Expression; 567 | 568 | typeAnnotation?: TsTypeAnnotation; 569 | 570 | is_static: boolean; 571 | 572 | computed: boolean; 573 | 574 | accessibility?: Accessibility; 575 | 576 | /// Typescript extension. 577 | is_abstract: boolean; 578 | 579 | is_optional: boolean; 580 | 581 | readonly: boolean; 582 | 583 | definite: boolean; 584 | } 585 | 586 | export interface ClassProperty extends ClassPropertyBase { 587 | type: "ClassProperty"; 588 | 589 | key: Expression; 590 | } 591 | 592 | export interface PrivateProperty extends ClassPropertyBase { 593 | type: "PrivateProperty"; 594 | 595 | key: PrivateName; 596 | } 597 | 598 | export interface Param extends Node, HasSpan, HasDecorator { 599 | type: "Parameter"; 600 | pat: Pattern; 601 | } 602 | 603 | export interface Constructor extends Node, HasSpan { 604 | type: "Constructor"; 605 | 606 | key: PropertyName; 607 | 608 | params: (Param | TsParameterProperty)[]; 609 | 610 | body: BlockStatement; 611 | 612 | accessibility?: Accessibility; 613 | 614 | is_optional: boolean; 615 | } 616 | 617 | export interface ClassMethodBase extends Node, HasSpan { 618 | function: Fn; 619 | 620 | kind: MethodKind; 621 | 622 | is_static: boolean; 623 | 624 | accessibility?: Accessibility; 625 | 626 | is_abstract: boolean; 627 | 628 | is_optional: boolean; 629 | } 630 | 631 | export interface ClassMethod extends ClassMethodBase { 632 | type: "ClassMethod"; 633 | 634 | key: PropertyName; 635 | } 636 | 637 | export interface PrivateMethod extends ClassMethodBase { 638 | type: "PrivateMethod"; 639 | 640 | key: PrivateName; 641 | } 642 | 643 | export interface Decorator extends Node, HasSpan { 644 | type: "Decorator"; 645 | 646 | expression: Expression; 647 | } 648 | 649 | export type MethodKind = "method" | "setter" | "getter"; 650 | 651 | export type Declaration = 652 | | ClassDeclaration 653 | | FunctionDeclaration 654 | | VariableDeclaration 655 | | TsInterfaceDeclaration 656 | | TsTypeAliasDeclaration 657 | | TsEnumDeclaration 658 | | TsModuleDeclaration; 659 | 660 | export interface FunctionDeclaration extends Fn { 661 | type: "FunctionDeclaration"; 662 | 663 | ident: Identifier; 664 | 665 | declare: boolean; 666 | } 667 | 668 | export interface ClassDeclaration extends Class, Node { 669 | type: "ClassDeclaration"; 670 | 671 | identifier: Identifier; 672 | 673 | declare: boolean; 674 | } 675 | 676 | export interface VariableDeclaration extends Node, HasSpan { 677 | type: "VariableDeclaration"; 678 | 679 | kind: VariableDeclarationKind; 680 | 681 | declare: boolean; 682 | 683 | declarations: VariableDeclarator[]; 684 | } 685 | 686 | export type VariableDeclarationKind = "get" | "let" | "const"; 687 | 688 | export interface VariableDeclarator extends Node, HasSpan { 689 | type: "VariableDeclarator"; 690 | 691 | id: Pattern; 692 | 693 | /// Initialization expresion. 694 | init?: Expression; 695 | 696 | /// Typescript only 697 | definite: boolean; 698 | } 699 | 700 | export type Expression = 701 | | ThisExpression 702 | | ArrayExpression 703 | | ObjectExpression 704 | | FunctionExpression 705 | | UnaryExpression 706 | | UpdateExpression 707 | | BinaryExpression 708 | | AssignmentExpression 709 | | MemberExpression 710 | | ConditionalExpression 711 | | CallExpression 712 | | NewExpression 713 | | SequenceExpression 714 | | Identifier 715 | | Literal 716 | | TemplateLiteral 717 | | TaggedTemplateExpression 718 | | ArrowFunctionExpression 719 | | ClassExpression 720 | | YieldExpression 721 | | MetaProperty 722 | | AwaitExpression 723 | | ParenthesisExpression 724 | | JSXMemberExpression 725 | | JSXNamespacedName 726 | | JSXEmptyExpression 727 | | JSXElement 728 | | JSXFragment 729 | | TsTypeAssertion 730 | | TsNonNullExpression 731 | | TsTypeCastExpression 732 | | TsAsExpression 733 | | PrivateName 734 | | OptionalChainingExpression 735 | | Invalid; 736 | 737 | interface ExpressionBase extends Node, HasSpan {} 738 | 739 | export interface OptionalChainingExpression extends ExpressionBase { 740 | type: "OptionalChainingExpression"; 741 | /** 742 | * Call expression or member expression. 743 | */ 744 | expr: Expression; 745 | } 746 | 747 | export interface ThisExpression extends ExpressionBase { 748 | type: "ThisExpression"; 749 | } 750 | 751 | export interface ArrayExpression extends ExpressionBase { 752 | type: "ArrayExpression"; 753 | 754 | elements: (Expression | SpreadElement | undefined)[]; 755 | } 756 | 757 | export interface ObjectExpression extends ExpressionBase { 758 | type: "ObjectExpression"; 759 | 760 | properties: (Property | SpreadElement)[]; 761 | } 762 | 763 | export interface Argument { 764 | spread: Span; 765 | expression: Expression; 766 | } 767 | 768 | export type PropertOrSpread = Property | SpreadElement; 769 | 770 | export interface SpreadElement extends Node { 771 | type: "SpreadElement"; 772 | 773 | spread: Span; 774 | 775 | arguments: Expression; 776 | } 777 | 778 | export interface UnaryExpression extends ExpressionBase { 779 | type: "UnaryExpression"; 780 | 781 | operator: UnaryOperator; 782 | 783 | argument: Expression; 784 | } 785 | 786 | export interface UpdateExpression extends ExpressionBase { 787 | type: "UpdateExpression"; 788 | 789 | operator: UpdateOperator; 790 | 791 | prefix: boolean; 792 | 793 | argument: Expression; 794 | } 795 | 796 | export interface BinaryExpression extends ExpressionBase { 797 | type: "BinaryExpression"; 798 | 799 | operator: BinaryOperator; 800 | 801 | left: Expression; 802 | 803 | right: Expression; 804 | } 805 | 806 | export interface FunctionExpression extends Fn, ExpressionBase { 807 | type: "FunctionExpression"; 808 | 809 | identifier: Identifier; 810 | } 811 | 812 | export interface ClassExpression extends Class, ExpressionBase { 813 | type: "ClassExpression"; 814 | 815 | identifier: Identifier; 816 | } 817 | 818 | export interface AssignmentExpression extends ExpressionBase { 819 | type: "AssignmentExpression"; 820 | 821 | operator: AssignmentOperator; 822 | 823 | left: Pattern | Expression; 824 | 825 | right: Expression; 826 | } 827 | 828 | export interface MemberExpression extends ExpressionBase { 829 | type: "MemberExpression"; 830 | 831 | object: Expression | Super; 832 | 833 | property: Expression; 834 | 835 | computed: boolean; 836 | } 837 | 838 | export interface ConditionalExpression extends ExpressionBase { 839 | type: "ConditionalExpression"; 840 | 841 | test: Expression; 842 | 843 | consequent: Expression; 844 | 845 | alternate: Expression; 846 | } 847 | 848 | export interface Super extends Node, HasSpan { 849 | type: "Super"; 850 | } 851 | 852 | export interface CallExpression extends ExpressionBase { 853 | type: "CallExpression"; 854 | 855 | callee: Expression | Super; 856 | 857 | arguments: Argument[]; 858 | 859 | typeArguments?: TsTypeParameterInstantiation; 860 | } 861 | 862 | export interface NewExpression extends ExpressionBase { 863 | type: "NewExpression"; 864 | 865 | callee: Expression; 866 | 867 | arguments: Argument[]; 868 | 869 | typeArguments?: TsTypeParameterInstantiation; 870 | } 871 | 872 | export interface SequenceExpression extends ExpressionBase { 873 | type: "SequenceExpression"; 874 | 875 | expressions: Expression[]; 876 | } 877 | 878 | export interface ArrowFunctionExpression extends ExpressionBase { 879 | type: "ArrowFunctionExpression"; 880 | 881 | params: Pattern[]; 882 | 883 | body: BlockStatement | Expression; 884 | 885 | async: boolean; 886 | 887 | generator: boolean; 888 | 889 | typeParameters?: TsTypeParameterDeclaration; 890 | 891 | returnType?: TsTypeAnnotation; 892 | } 893 | 894 | export interface YieldExpression extends ExpressionBase { 895 | type: "YieldExpression"; 896 | 897 | argument?: Expression; 898 | 899 | delegate: boolean; 900 | } 901 | 902 | export interface MetaProperty extends Node { 903 | type: "MetaProperty"; 904 | 905 | meta: Identifier; 906 | 907 | property: Identifier; 908 | } 909 | 910 | export interface AwaitExpression extends ExpressionBase { 911 | type: "AwaitExpression"; 912 | 913 | argument: Expression; 914 | } 915 | 916 | export interface TplBase { 917 | expressions: Expression[]; 918 | 919 | quasis: TemplateElement[]; 920 | } 921 | 922 | export interface TemplateLiteral extends ExpressionBase, TplBase { 923 | type: "TemplateLiteral"; 924 | } 925 | 926 | export interface TaggedTemplateExpression extends ExpressionBase, TplBase { 927 | type: "TaggedTemplateExpression"; 928 | 929 | tag: Expression; 930 | 931 | typeParameters: TsTypeParameterInstantiation; 932 | } 933 | 934 | export interface TemplateElement extends ExpressionBase { 935 | type: "TemplateElement"; 936 | 937 | tail: boolean; 938 | cooked: StringLiteral; 939 | raw: StringLiteral; 940 | } 941 | 942 | export interface ParenthesisExpression extends ExpressionBase { 943 | type: "ParenthesisExpression"; 944 | 945 | expression: Expression; 946 | } 947 | 948 | export interface Fn extends HasSpan, HasDecorator { 949 | params: Param[]; 950 | 951 | body: BlockStatement; 952 | 953 | generator: boolean; 954 | 955 | async: boolean; 956 | 957 | typeParameters?: TsTypeParameterDeclaration; 958 | 959 | returnType?: TsTypeAnnotation; 960 | } 961 | 962 | interface PatternBase { 963 | typeAnnotation?: TsTypeAnnotation; 964 | } 965 | 966 | export interface Identifier extends HasSpan, PatternBase { 967 | type: "Identifier"; 968 | 969 | value: string; 970 | 971 | /// TypeScript only. Used in case of an optional parameter. 972 | optional: boolean; 973 | } 974 | 975 | export interface PrivateName extends ExpressionBase { 976 | type: "PrivateName"; 977 | 978 | id: Identifier; 979 | } 980 | 981 | export type JSXObject = JSXMemberExpression | Identifier; 982 | 983 | export interface JSXMemberExpression extends Node { 984 | type: "JSXMemberExpression"; 985 | 986 | object: JSXObject; 987 | property: Identifier; 988 | } 989 | 990 | /** 991 | * XML-based namespace syntax: 992 | */ 993 | export interface JSXNamespacedName extends Node { 994 | type: "JSXNamespacedName"; 995 | 996 | namespace: Identifier; 997 | name: Identifier; 998 | } 999 | 1000 | export interface JSXEmptyExpression extends Node, HasSpan { 1001 | type: "JSXEmptyExpression"; 1002 | } 1003 | 1004 | export interface JSXExpressionContainer extends Node { 1005 | type: "JSXExpressionContainer"; 1006 | 1007 | expression: JSXExpression; 1008 | } 1009 | 1010 | export type JSXExpression = JSXEmptyExpression | Expression; 1011 | 1012 | export interface JSXSpreadChild extends Node { 1013 | type: "JSXSpreadChild"; 1014 | 1015 | expression: Expression; 1016 | } 1017 | 1018 | export type JSXElementName = 1019 | | Identifier 1020 | | JSXMemberExpression 1021 | | JSXNamespacedName; 1022 | 1023 | export interface JSXOpeningElement extends Node, HasSpan { 1024 | type: "JSXOpeningElement"; 1025 | 1026 | name: JSXElementName; 1027 | 1028 | attrs?: JSXAttributeOrSpread[]; 1029 | 1030 | selfClosing: boolean; 1031 | 1032 | typeArguments?: TsTypeParameterInstantiation; 1033 | } 1034 | 1035 | export type JSXAttributeOrSpread = JSXAttribute | SpreadElement; 1036 | 1037 | export interface JSXClosingElement extends Node, HasSpan { 1038 | type: "JSXClosingElement"; 1039 | 1040 | name: JSXElementName; 1041 | } 1042 | 1043 | export interface JSXAttribute extends Node, HasSpan { 1044 | type: "JSXAttribute"; 1045 | 1046 | name: JSXAttributeName; 1047 | 1048 | value?: JSXAttrValue; 1049 | } 1050 | 1051 | export type JSXAttributeName = Identifier | JSXNamespacedName; 1052 | 1053 | export type JSXAttrValue = 1054 | | Literal 1055 | | JSXExpressionContainer 1056 | | JSXElement 1057 | | JSXFragment; 1058 | 1059 | export interface JSXText extends Node, HasSpan { 1060 | type: "JSXText"; 1061 | 1062 | value: string; 1063 | raw: string; 1064 | } 1065 | 1066 | export interface JSXElement extends Node, HasSpan { 1067 | type: "JSXElement"; 1068 | 1069 | opening: JSXOpeningElement; 1070 | children: JSXElementChild[]; 1071 | closing?: JSXClosingElement; 1072 | } 1073 | 1074 | export type JSXElementChild = 1075 | | JSXText 1076 | | JSXExpressionContainer 1077 | | JSXSpreadChild 1078 | | JSXElement 1079 | | JSXFragment; 1080 | 1081 | export interface JSXFragment extends Node, HasSpan { 1082 | type: "JSXFragment"; 1083 | 1084 | opening: JSXOpeningFragment; 1085 | 1086 | children: JSXElementChild[]; 1087 | 1088 | closing: JSXClosingFragment; 1089 | } 1090 | 1091 | export interface JSXOpeningFragment extends Node, HasSpan { 1092 | type: "JSXOpeningFragment"; 1093 | } 1094 | 1095 | export interface JSXClosingFragment extends Node, HasSpan { 1096 | type: "JSXClosingFragment"; 1097 | } 1098 | 1099 | export type Literal = 1100 | | StringLiteral 1101 | | BooleanLiteral 1102 | | NullLiteral 1103 | | NumericLiteral 1104 | | RegExpLiteral 1105 | | JSXText; 1106 | 1107 | export interface StringLiteral extends Node, HasSpan { 1108 | type: "StringLiteral"; 1109 | 1110 | value: string; 1111 | has_escape: boolean; 1112 | } 1113 | 1114 | export interface BooleanLiteral extends Node, HasSpan { 1115 | type: "BooleanLiteral"; 1116 | 1117 | value: boolean; 1118 | } 1119 | 1120 | export interface NullLiteral extends Node, HasSpan { 1121 | type: "NullLiteral"; 1122 | } 1123 | 1124 | export interface RegExpLiteral extends Node, HasSpan { 1125 | type: "RegExpLiteral"; 1126 | 1127 | pattern: string; 1128 | flags: string; 1129 | } 1130 | 1131 | export interface NumericLiteral extends Node, HasSpan { 1132 | type: "NumericLiteral"; 1133 | 1134 | value: number; 1135 | } 1136 | 1137 | export type ModuleDeclaration = 1138 | | ImportDeclaration 1139 | | ExportDeclaration 1140 | | ExportNamedDeclaration 1141 | | ExportDefaultDeclaration 1142 | | ExportDefaultExpression 1143 | | ExportAllDeclaration 1144 | | TsImportEqualsDeclaration 1145 | | TsExportAssignment 1146 | | TsNamespaceExportDeclaration; 1147 | 1148 | export interface ExportDefaultExpression extends Node, HasSpan { 1149 | type: "ExportDefaultExpression"; 1150 | 1151 | expression: Expression; 1152 | } 1153 | 1154 | export interface ExportDeclaration extends Node, HasSpan { 1155 | type: "ExportDeclaration"; 1156 | 1157 | declaration: Declaration; 1158 | } 1159 | 1160 | export interface ImportDeclaration extends Node, HasSpan { 1161 | type: "ImportDeclaration"; 1162 | 1163 | specifiers: ImporSpecifier[]; 1164 | 1165 | source: StringLiteral; 1166 | } 1167 | 1168 | export type ImporSpecifier = 1169 | | ImportDefaultSpecifier 1170 | | NamedImportSpecifier 1171 | | ImportNamespaceSpecifier; 1172 | 1173 | export interface ExportAllDeclaration extends Node, HasSpan { 1174 | type: "ExportAllDeclaration"; 1175 | 1176 | source: StringLiteral; 1177 | } 1178 | 1179 | /** 1180 | * - `export { foo } from 'mod'` 1181 | * - `export { foo as bar } from 'mod'` 1182 | */ 1183 | export interface ExportNamedDeclaration extends Node, HasSpan { 1184 | type: "ExportNamedDeclaration"; 1185 | 1186 | specifiers: ExportSpecifier[]; 1187 | 1188 | source?: StringLiteral; 1189 | } 1190 | 1191 | export interface ExportDefaultDeclaration extends Node, HasSpan { 1192 | type: "ExportDefaultDeclaration"; 1193 | 1194 | decl: DefaultDecl; 1195 | } 1196 | 1197 | export type DefaultDecl = 1198 | | ClassExpression 1199 | | FunctionExpression 1200 | | TsInterfaceDeclaration; 1201 | 1202 | export type ImportSpecifier = 1203 | | NamedImportSpecifier 1204 | | ImportDefaultSpecifier 1205 | | ImportNamespaceSpecifier; 1206 | 1207 | /** 1208 | * e.g. `import foo from 'mod.js'` 1209 | */ 1210 | export interface ImportDefaultSpecifier extends Node, HasSpan { 1211 | type: "ImportDefaultSpecifier"; 1212 | local: Identifier; 1213 | } 1214 | 1215 | /** 1216 | * e.g. `import * as foo from 'mod.js'`. 1217 | */ 1218 | export interface ImportNamespaceSpecifier extends Node, HasSpan { 1219 | type: "ImportNamespaceSpecifier"; 1220 | 1221 | local: Identifier; 1222 | } 1223 | 1224 | /** 1225 | * e.g. - `import { foo } from 'mod.js'` 1226 | * 1227 | * local = foo, imported = None 1228 | * 1229 | * e.g. `import { foo as bar } from 'mod.js'` 1230 | * 1231 | * local = bar, imported = Some(foo) for 1232 | */ 1233 | export interface NamedImportSpecifier extends Node, HasSpan { 1234 | type: "ImportSpecifier"; 1235 | local: Identifier; 1236 | imported: Identifier; 1237 | } 1238 | 1239 | export type ExportSpecifier = 1240 | | ExportNamespaceSpecifer 1241 | | ExportDefaultSpecifier 1242 | | NamedExportSpecifier; 1243 | 1244 | /** 1245 | * `export * as foo from 'src';` 1246 | */ 1247 | export interface ExportNamespaceSpecifer extends Node, HasSpan { 1248 | type: "ExportNamespaceSpecifer"; 1249 | 1250 | name: Identifier; 1251 | } 1252 | 1253 | export interface ExportDefaultSpecifier extends Node, HasSpan { 1254 | type: "ExportDefaultSpecifier"; 1255 | 1256 | exported: Identifier; 1257 | } 1258 | 1259 | export interface NamedExportSpecifier extends Node, HasSpan { 1260 | type: "ExportSpecifier"; 1261 | 1262 | orig: Identifier; 1263 | /** 1264 | * `Some(bar)` in `export { foo as bar }` 1265 | */ 1266 | exported: Identifier; 1267 | } 1268 | 1269 | interface HasInterpreter { 1270 | /** 1271 | * e.g. `/usr/bin/node` for `#!/usr/bin/node` 1272 | */ 1273 | interpreter: string; 1274 | } 1275 | 1276 | export type Program = Module | Script; 1277 | 1278 | export interface Module extends Node, HasSpan, HasInterpreter { 1279 | type: "Module"; 1280 | 1281 | body: ModuleItem[]; 1282 | } 1283 | 1284 | export interface Script extends Node, HasSpan, HasInterpreter { 1285 | type: "Script"; 1286 | 1287 | body: Statement[]; 1288 | } 1289 | 1290 | export type ModuleItem = ModuleDeclaration | Statement; 1291 | 1292 | export type BinaryOperator = 1293 | | "==" 1294 | | "!=" 1295 | | "===" 1296 | | "!==" 1297 | | "<" 1298 | | "<=" 1299 | | ">" 1300 | | ">=" 1301 | | "<<" 1302 | | ">>" 1303 | | ">>>" 1304 | | "+" 1305 | | "-" 1306 | | "*" 1307 | | "/" 1308 | | "%" 1309 | | "**" 1310 | | "|" 1311 | | "^" 1312 | | "&" 1313 | | "||" 1314 | | "&&" 1315 | | "in" 1316 | | "instanceof" 1317 | | "??"; 1318 | 1319 | export type AssignmentOperator = 1320 | | "=" 1321 | | "+=" 1322 | | "-=" 1323 | | "*=" 1324 | | "/=" 1325 | | "%=" 1326 | | "**=" 1327 | | "<<=" 1328 | | ">>=" 1329 | | ">>>=" 1330 | | "|=" 1331 | | "^=" 1332 | | "&="; 1333 | 1334 | export type UpdateOperator = "++" | "--"; 1335 | 1336 | export type UnaryOperator = 1337 | | "-" 1338 | | "+" 1339 | | "!" 1340 | | "~" 1341 | | "typeof" 1342 | | "void" 1343 | | "delete"; 1344 | 1345 | export type Pattern = 1346 | | Identifier 1347 | | ArrayPattern 1348 | | RestElement 1349 | | ObjectPattern 1350 | | AssignmentPattern 1351 | | Invalid 1352 | | Expression; 1353 | 1354 | export interface ArrayPattern extends Node, HasSpan, PatternBase { 1355 | type: "ArrayPattern"; 1356 | 1357 | elements: (Pattern | undefined)[]; 1358 | } 1359 | 1360 | export interface ObjectPattern extends Node, HasSpan, PatternBase { 1361 | type: "ObjectPattern"; 1362 | 1363 | props: ObjectPatternProperty[]; 1364 | } 1365 | 1366 | export interface AssignmentPattern extends Node, HasSpan, PatternBase { 1367 | type: "AssignmentPattern"; 1368 | 1369 | left: Pattern; 1370 | right: Expression; 1371 | } 1372 | 1373 | export interface RestElement extends Node, HasSpan, PatternBase { 1374 | type: "RestElement"; 1375 | 1376 | rest: Span; 1377 | 1378 | argument: Pattern; 1379 | } 1380 | 1381 | export type ObjectPatternProperty = 1382 | | KeyValuePatternProperty 1383 | | AssignmentPatternProperty 1384 | | RestElement; 1385 | 1386 | /** 1387 | * `{key: value}` 1388 | */ 1389 | export interface KeyValuePatternProperty extends Node { 1390 | type: "KeyValuePatternProperty"; 1391 | 1392 | key: PropertyName; 1393 | value: Pattern; 1394 | } 1395 | 1396 | /** 1397 | * `{key}` or `{key = value}` 1398 | */ 1399 | export interface AssignmentPatternProperty extends Node, HasSpan { 1400 | type: "AssignmentPatternProperty"; 1401 | 1402 | key: Identifier; 1403 | value?: Expression; 1404 | } 1405 | 1406 | /** Identifier is `a` in `{ a, }` */ 1407 | export type Property = 1408 | | Identifier 1409 | | KeyValueProperty 1410 | | AssignmentProperty 1411 | | GetterProperty 1412 | | SetterProperty 1413 | | MethodProperty; 1414 | 1415 | interface PropBase extends Node { 1416 | key: PropertyName; 1417 | } 1418 | 1419 | export interface KeyValueProperty extends PropBase { 1420 | type: "KeyValueProperty"; 1421 | 1422 | value: Expression; 1423 | } 1424 | 1425 | export interface AssignmentProperty extends Node { 1426 | type: "AssignmentProperty"; 1427 | 1428 | key: Identifier; 1429 | value: Expression; 1430 | } 1431 | 1432 | export interface GetterProperty extends PropBase, HasSpan { 1433 | type: "GetterProperty"; 1434 | 1435 | typeAnnotation?: TsTypeAnnotation; 1436 | 1437 | body: BlockStatement; 1438 | } 1439 | 1440 | export interface SetterProperty extends PropBase, HasSpan { 1441 | type: "SetterProperty"; 1442 | 1443 | param: Pattern; 1444 | body: BlockStatement; 1445 | } 1446 | 1447 | export interface MethodProperty extends PropBase, Fn { 1448 | type: "MethodProperty"; 1449 | } 1450 | 1451 | export type PropertyName = 1452 | | Identifier 1453 | | StringLiteral 1454 | | NumericLiteral 1455 | | ComputedPropName; 1456 | 1457 | export interface ComputedPropName extends Node, HasSpan { 1458 | type: "Computed"; 1459 | expression: Expression; 1460 | } 1461 | 1462 | export interface BlockStatement extends Node, HasSpan { 1463 | type: "BlockStatement"; 1464 | 1465 | stmts: Statement[]; 1466 | } 1467 | 1468 | export interface ExpressionStatement extends Node, HasSpan { 1469 | type: "ExpressionStatement"; 1470 | expression: Expression; 1471 | } 1472 | 1473 | export type Statement = 1474 | | ExpressionStatement 1475 | | BlockStatement 1476 | | EmptyStatement 1477 | | DebuggerStatement 1478 | | WithStatement 1479 | | ReturnStatement 1480 | | LabeledStatement 1481 | | BreakStatement 1482 | | ContinueStatement 1483 | | IfStatement 1484 | | SwitchStatement 1485 | | ThrowStatement 1486 | | TryStatement 1487 | | WhileStatement 1488 | | DoWhileStatement 1489 | | ForStatement 1490 | | ForInStatement 1491 | | ForOfStatement 1492 | | Declaration; 1493 | 1494 | export interface EmptyStatement extends Node, HasSpan { 1495 | type: "EmptyStatement"; 1496 | } 1497 | 1498 | export interface DebuggerStatement extends Node, HasSpan { 1499 | type: "DebuggerStatement"; 1500 | } 1501 | 1502 | export interface WithStatement extends Node, HasSpan { 1503 | type: "WithStatement"; 1504 | 1505 | object: Expression; 1506 | body: Statement; 1507 | } 1508 | 1509 | export interface ReturnStatement extends Node, HasSpan { 1510 | type: "ReturnStatement"; 1511 | 1512 | argument: Expression; 1513 | } 1514 | 1515 | export interface LabeledStatement extends Node, HasSpan { 1516 | type: "LabeledStatement"; 1517 | 1518 | label: Identifier; 1519 | body: Statement; 1520 | } 1521 | 1522 | export interface BreakStatement extends Node, HasSpan { 1523 | type: "BreakStatement"; 1524 | 1525 | label: Identifier; 1526 | } 1527 | 1528 | export interface ContinueStatement extends Node, HasSpan { 1529 | type: "ContinueStatement"; 1530 | 1531 | label: Identifier; 1532 | } 1533 | 1534 | export interface IfStatement extends Node, HasSpan { 1535 | type: "IfStatement"; 1536 | 1537 | test: Expression; 1538 | consequent: Statement; 1539 | alternate?: Statement; 1540 | } 1541 | 1542 | export interface SwitchStatement extends Node, HasSpan { 1543 | type: "SwitchStatement"; 1544 | 1545 | discriminant: Expression; 1546 | cases: SwitchCase[]; 1547 | } 1548 | 1549 | export interface ThrowStatement extends Node, HasSpan { 1550 | type: "ThrowStatement"; 1551 | 1552 | argument: Expression; 1553 | } 1554 | 1555 | export interface TryStatement extends Node, HasSpan { 1556 | type: "TryStatement"; 1557 | 1558 | block: BlockStatement; 1559 | handler?: CatchClause; 1560 | finalizer: BlockStatement; 1561 | } 1562 | 1563 | export interface WhileStatement extends Node, HasSpan { 1564 | type: "WhileStatement"; 1565 | 1566 | test: Expression; 1567 | body: Statement; 1568 | } 1569 | 1570 | export interface DoWhileStatement extends Node, HasSpan { 1571 | type: "DoWhileStatement"; 1572 | 1573 | test: Expression; 1574 | body: Statement; 1575 | } 1576 | 1577 | export interface ForStatement extends Node, HasSpan { 1578 | type: "ForStatement"; 1579 | 1580 | init?: VariableDeclaration | Expression; 1581 | test?: Expression; 1582 | update?: Expression; 1583 | body: Statement; 1584 | } 1585 | 1586 | export interface ForInStatement extends Node, HasSpan { 1587 | type: "ForInStatement"; 1588 | 1589 | left: VariableDeclaration | Pattern; 1590 | right: Expression; 1591 | body: Statement; 1592 | } 1593 | 1594 | export interface ForOfStatement extends Node, HasSpan { 1595 | type: "ForOfStatement"; 1596 | 1597 | /** 1598 | * Span of the await token. 1599 | * 1600 | * es2018 for-await-of statements, e.g., `for await (const x of xs) {` 1601 | */ 1602 | await: Span; 1603 | left: VariableDeclaration | Pattern; 1604 | right: Expression; 1605 | body: Statement; 1606 | } 1607 | 1608 | export interface SwitchCase extends Node, HasSpan { 1609 | type: "SwitchCase"; 1610 | 1611 | /** 1612 | * Undefined for default case 1613 | */ 1614 | test?: Expression; 1615 | consequent: Statement[]; 1616 | } 1617 | 1618 | export interface CatchClause extends Node, HasSpan { 1619 | type: "CatchClause"; 1620 | 1621 | /** 1622 | * The param is `undefined` if the catch binding is omitted. E.g., `try { foo() } catch {}` 1623 | */ 1624 | param: Pattern; 1625 | body: BlockStatement; 1626 | } 1627 | 1628 | export interface TsTypeAnnotation extends Node, HasSpan { 1629 | type: "TsTypeAnnotation"; 1630 | 1631 | typeAnnotation: TsType; 1632 | } 1633 | 1634 | export interface TsTypeParameterDeclaration extends Node, HasSpan { 1635 | type: "TsTypeParameterDeclaration"; 1636 | 1637 | parameters: TsTypeParameter[]; 1638 | } 1639 | 1640 | export interface TsTypeParameter extends Node, HasSpan { 1641 | type: "TsTypeParameter"; 1642 | 1643 | name: Identifier; 1644 | constraint: TsType; 1645 | default: TsType; 1646 | } 1647 | 1648 | export interface TsTypeParameterInstantiation extends Node, HasSpan { 1649 | type: "TsTypeParameterInstantiation"; 1650 | 1651 | params: TsType[]; 1652 | } 1653 | 1654 | export interface TsTypeCastExpression extends Node, HasSpan { 1655 | type: "TsTypeCastExpression"; 1656 | 1657 | expression: Expression; 1658 | typeAnnotation: TsTypeAnnotation; 1659 | } 1660 | 1661 | export interface TsParameterProperty extends Node, HasSpan, HasDecorator { 1662 | type: "TsParameterProperty"; 1663 | 1664 | accessibility?: Accessibility; 1665 | readonly: boolean; 1666 | param: TsParameterPropertyParameter; 1667 | } 1668 | 1669 | export type TsParameterPropertyParameter = Identifier | AssignmentPattern; 1670 | 1671 | export interface TsQualifiedName extends Node { 1672 | type: "TsQualifiedName"; 1673 | 1674 | left: TsEntityName; 1675 | right: Identifier; 1676 | } 1677 | 1678 | export type TsEntityName = TsQualifiedName | Identifier; 1679 | 1680 | export type TsSignatureDeclaration = 1681 | | TsCallSignatureDeclaration 1682 | | TsConstructSignatureDeclaration 1683 | | TsMethodSignature 1684 | | TsFunctionType 1685 | | TsConstructorType; 1686 | 1687 | export type TsTypeElement = 1688 | | TsCallSignatureDeclaration 1689 | | TsConstructSignatureDeclaration 1690 | | TsPropertySignature 1691 | | TsMethodSignature 1692 | | TsIndexSignature; 1693 | 1694 | export interface TsCallSignatureDeclaration extends Node, HasSpan { 1695 | type: "TsCallSignatureDeclaration"; 1696 | 1697 | params: TsFnParameter[]; 1698 | typeAnnotation: TsTypeAnnotation; 1699 | typeParams: TsTypeParameterDeclaration; 1700 | } 1701 | 1702 | export interface TsConstructSignatureDeclaration extends Node, HasSpan { 1703 | type: "TsConstructSignatureDeclaration"; 1704 | 1705 | params: TsFnParameter[]; 1706 | typeAnnotation: TsTypeAnnotation; 1707 | typeParams: TsTypeParameterDeclaration; 1708 | } 1709 | 1710 | export interface TsPropertySignature extends Node, HasSpan { 1711 | type: "TsPropertySignature"; 1712 | 1713 | readonly: boolean; 1714 | key: Expression; 1715 | computed: boolean; 1716 | optional: boolean; 1717 | 1718 | init: Expression; 1719 | params: TsFnParameter[]; 1720 | 1721 | typeAnnotation?: TsTypeAnnotation; 1722 | typeParams: TsTypeParameterDeclaration; 1723 | } 1724 | 1725 | export interface TsMethodSignature extends Node, HasSpan { 1726 | type: "TsMethodSignature"; 1727 | 1728 | readonly: boolean; 1729 | key: Expression; 1730 | computed: boolean; 1731 | optional: boolean; 1732 | params: TsFnParameter[]; 1733 | 1734 | typeAnnotation: TsTypeAnnotation; 1735 | typeParams: TsTypeParameterDeclaration; 1736 | } 1737 | 1738 | export interface TsIndexSignature extends Node, HasSpan { 1739 | type: "TsIndexSignature"; 1740 | 1741 | readonly: boolean; 1742 | params: TsFnParameter[]; 1743 | 1744 | typeAnnotation?: TsTypeAnnotation; 1745 | } 1746 | 1747 | export type TsType = 1748 | | TsKeywordType 1749 | | TsThisType 1750 | | TsFnOrConstructorType 1751 | | TsTypeReference 1752 | | TsTypeQuery 1753 | | TsTypeLiteral 1754 | | TsArrayType 1755 | | TsTupleType 1756 | | TsOptionalType 1757 | | TsRestType 1758 | | TsUnionOrIntersectionType 1759 | | TsConditionalType 1760 | | TsInferType 1761 | | TsParenthesizedType 1762 | | TsTypeOperator 1763 | | TsIndexedAccessType 1764 | | TsMappedType 1765 | | TsLiteralType 1766 | | TsImportType 1767 | | TsTypePredicate; 1768 | 1769 | export type TsFnOrConstructorType = TsFunctionType | TsConstructorType; 1770 | 1771 | export interface TsKeywordType extends Node, HasSpan { 1772 | type: "TsKeywordType"; 1773 | 1774 | kind: TsKeywordTypeKind; 1775 | } 1776 | 1777 | export type TsKeywordTypeKind = 1778 | | "any" 1779 | | "unknown" 1780 | | "number" 1781 | | "object" 1782 | | "boolean" 1783 | | "bigint" 1784 | | "string" 1785 | | "symbol" 1786 | | "void" 1787 | | "undefined" 1788 | | "null" 1789 | | "never"; 1790 | 1791 | export interface TsThisType extends Node, HasSpan { 1792 | type: "TsThisType"; 1793 | } 1794 | 1795 | export type TsFnParameter = Identifier | RestElement | ObjectPattern; 1796 | 1797 | export interface TsFunctionType extends Node, HasSpan { 1798 | type: "TsFunctionType"; 1799 | 1800 | typeParams: TsTypeParameterDeclaration; 1801 | typeAnnotation: TsTypeAnnotation; 1802 | } 1803 | 1804 | export interface TsConstructorType extends Node, HasSpan { 1805 | type: "TsConstructorType"; 1806 | 1807 | params: TsFnParameter[]; 1808 | 1809 | typeParams: TsTypeParameterDeclaration; 1810 | typeAnnotation: TsTypeAnnotation; 1811 | } 1812 | 1813 | export interface TsTypeReference extends Node, HasSpan { 1814 | type: "TsTypeReference"; 1815 | 1816 | typeName: TsEntityName; 1817 | typeParams: TsTypeParameterInstantiation; 1818 | } 1819 | 1820 | export interface TsTypePredicate extends Node, HasSpan { 1821 | type: "TsTypePredicate"; 1822 | 1823 | asserts: boolean; 1824 | 1825 | paramName: TsThisTypeOrIdent; 1826 | typeAnnotation: TsTypeAnnotation; 1827 | } 1828 | 1829 | export type TsThisTypeOrIdent = TsThisType | Identifier; 1830 | 1831 | export interface TsImportType extends Node, HasSpan { 1832 | argument: StringLiteral; 1833 | qualifier?: TsEntityName; 1834 | typeArguments?: TsTypeParameterInstantiation; 1835 | } 1836 | 1837 | /** 1838 | * `typeof` operator 1839 | */ 1840 | export interface TsTypeQuery extends Node, HasSpan { 1841 | type: "TsTypeQuery"; 1842 | 1843 | exprName: TsTypeQueryExpr; 1844 | } 1845 | 1846 | export type TsTypeQueryExpr = TsEntityName | TsImportType; 1847 | 1848 | export interface TsTypeLiteral extends Node, HasSpan { 1849 | type: "TsTypeLiteral"; 1850 | 1851 | members: TsTypeElement[]; 1852 | } 1853 | 1854 | export interface TsArrayType extends Node, HasSpan { 1855 | type: "TsArrayType"; 1856 | 1857 | elemType: TsType; 1858 | } 1859 | 1860 | export interface TsTupleType extends Node, HasSpan { 1861 | type: "TsTupleType"; 1862 | 1863 | elemTypes: TsType[]; 1864 | } 1865 | 1866 | export interface TsOptionalType extends Node, HasSpan { 1867 | type: "TsOptionalType"; 1868 | 1869 | typeAnnotation: TsType; 1870 | } 1871 | 1872 | export interface TsRestType extends Node, HasSpan { 1873 | type: "TsRestType"; 1874 | 1875 | typeAnnotation: TsType; 1876 | } 1877 | 1878 | export type TsUnionOrIntersectionType = TsUnionType | TsIntersectionType; 1879 | 1880 | export interface TsUnionType extends Node, HasSpan { 1881 | type: "TsUnionType"; 1882 | 1883 | types: TsType[]; 1884 | } 1885 | 1886 | export interface TsIntersectionType extends Node, HasSpan { 1887 | type: "TsIntersectionType"; 1888 | 1889 | types: TsType[]; 1890 | } 1891 | 1892 | export interface TsConditionalType extends Node, HasSpan { 1893 | type: "TsConditionalType"; 1894 | 1895 | checkType: TsType; 1896 | extendsType: TsType; 1897 | trueType: TsType; 1898 | falseType: TsType; 1899 | } 1900 | 1901 | export interface TsInferType extends Node, HasSpan { 1902 | type: "TsInferType"; 1903 | 1904 | typeParam: TsTypeParameter; 1905 | } 1906 | 1907 | export interface TsParenthesizedType extends Node, HasSpan { 1908 | type: "TsParenthesizedType"; 1909 | 1910 | typeAnnotation: TsType; 1911 | } 1912 | 1913 | export interface TsTypeOperator extends Node, HasSpan { 1914 | type: "TsTypeOperator"; 1915 | 1916 | op: TsTypeOperatorOp; 1917 | typeAnnotation: TsType; 1918 | } 1919 | 1920 | export type TsTypeOperatorOp = "keyof" | "unique"; 1921 | 1922 | export interface TsIndexedAccessType extends Node, HasSpan { 1923 | type: "TsIndexedAccessType"; 1924 | 1925 | objectType: TsType; 1926 | indexType: TsType; 1927 | } 1928 | 1929 | export type TruePlusMinus = true | "+" | "-"; 1930 | 1931 | export interface TsMappedType extends Node, HasSpan { 1932 | type: "TsMappedType"; 1933 | 1934 | readonly: TruePlusMinus; 1935 | typeParam: TsTypeParameter; 1936 | optional: TruePlusMinus; 1937 | typeAnnotation: TsType; 1938 | } 1939 | 1940 | export interface TsLiteralType extends Node, HasSpan { 1941 | type: "TsLiteralType"; 1942 | 1943 | literal: TsLiteral; 1944 | } 1945 | 1946 | export type TsLiteral = 1947 | | NumericLiteral 1948 | | StringLiteral 1949 | | BooleanLiteral 1950 | | TemplateLiteral; 1951 | 1952 | // // ================ 1953 | // // TypeScript declarations 1954 | // // ================ 1955 | 1956 | export interface TsInterfaceDeclaration extends Node, HasSpan { 1957 | type: "TsInterfaceDeclaration"; 1958 | 1959 | id: Identifier; 1960 | declare: boolean; 1961 | typeParams?: TsTypeParameterDeclaration; 1962 | extends: TsExpressionWithTypeArguments[]; 1963 | body: TsInterfaceBody; 1964 | } 1965 | 1966 | export interface TsInterfaceBody extends Node, HasSpan { 1967 | type: "TsInterfaceBody"; 1968 | 1969 | body: TsTypeElement[]; 1970 | } 1971 | 1972 | export interface TsExpressionWithTypeArguments extends Node, HasSpan { 1973 | type: "TsExpressionWithTypeArguments"; 1974 | 1975 | expression: TsEntityName; 1976 | typeArguments?: TsTypeParameterInstantiation; 1977 | } 1978 | 1979 | export interface TsTypeAliasDeclaration extends Node, HasSpan { 1980 | type: "TsTypeAliasDeclaration"; 1981 | 1982 | declare: boolean; 1983 | id: Identifier; 1984 | typeParams?: TsTypeParameterDeclaration; 1985 | typeAnnotation: TsType; 1986 | } 1987 | 1988 | export interface TsEnumDeclaration extends Node, HasSpan { 1989 | type: "TsEnumDeclaration"; 1990 | 1991 | declare: boolean; 1992 | is_const: boolean; 1993 | id: Identifier; 1994 | member: TsEnumMember[]; 1995 | } 1996 | 1997 | export interface TsEnumMember extends Node, HasSpan { 1998 | type: "TsEnumMember"; 1999 | 2000 | id: TsEnumMemberId; 2001 | init?: Expression; 2002 | } 2003 | 2004 | export type TsEnumMemberId = Identifier | StringLiteral; 2005 | 2006 | export interface TsModuleDeclaration extends Node, HasSpan { 2007 | type: "TsModuleDeclaration"; 2008 | 2009 | declare: boolean; 2010 | global: boolean; 2011 | id: TsModuleName; 2012 | body?: TsNamespaceBody; 2013 | } 2014 | 2015 | /** 2016 | * `namespace A.B { }` is a namespace named `A` with another TsNamespaceDecl as its body. 2017 | */ 2018 | export type TsNamespaceBody = TsModuleBlock | TsNamespaceDeclaration; 2019 | 2020 | export interface TsModuleBlock extends Node, HasSpan { 2021 | type: "TsModuleBlock"; 2022 | 2023 | body: ModuleItem[]; 2024 | } 2025 | 2026 | export interface TsNamespaceDeclaration extends Node, HasSpan { 2027 | type: "TsNamespaceDeclaration"; 2028 | 2029 | declare: boolean; 2030 | global: boolean; 2031 | id: Identifier; 2032 | body: TsNamespaceBody; 2033 | } 2034 | 2035 | export type TsModuleName = Identifier | StringLiteral; 2036 | 2037 | export interface TsImportEqualsDeclaration extends Node, HasSpan { 2038 | type: "TsImportEqualsDeclaration"; 2039 | 2040 | declare: boolean; 2041 | is_export: boolean; 2042 | id: Identifier; 2043 | moduleRef: TsModuleReference; 2044 | } 2045 | 2046 | export type TsModuleReference = TsEntityName | TsExternalModuleReference; 2047 | 2048 | export interface TsExternalModuleReference extends Node, HasSpan { 2049 | type: "TsExternalModuleReference"; 2050 | 2051 | expression: Expression; 2052 | } 2053 | 2054 | export interface TsExportAssignment extends Node, HasSpan { 2055 | type: "TsExportAssignment"; 2056 | 2057 | expression: Expression; 2058 | } 2059 | 2060 | export interface TsNamespaceExportDeclaration extends Node, HasSpan { 2061 | type: "TsNamespaceExportDeclaration"; 2062 | 2063 | id: Identifier; 2064 | } 2065 | 2066 | export interface TsAsExpression extends ExpressionBase { 2067 | type: "TsAsExpression"; 2068 | 2069 | expression: Expression; 2070 | typeAnnotation: TsType; 2071 | } 2072 | 2073 | export interface TsTypeAssertion extends ExpressionBase { 2074 | type: "TsTypeAssertion"; 2075 | 2076 | expression: Expression; 2077 | typeAnnotation: TsType; 2078 | } 2079 | 2080 | export interface TsNonNullExpression extends ExpressionBase { 2081 | type: "TsNonNullExpression"; 2082 | 2083 | expression: Expression; 2084 | } 2085 | 2086 | export type Accessibility = "public" | "protected" | "private"; 2087 | 2088 | export interface Invalid extends Node, HasSpan { 2089 | type: "Invalid"; 2090 | } 2091 | -------------------------------------------------------------------------------- /swdev-dev.ts: -------------------------------------------------------------------------------- 1 | import { parse, expandGlob, minify, ensureDir } from "./deps.ts"; 2 | import { version } from "./version.ts"; 3 | 4 | const args = parse(Deno.args); 5 | const [task] = args._ as string[]; 6 | const log = (...args: any) => console.log("[swdev-dev]", ...args); 7 | 8 | async function buildClientAssets(opts: { client: boolean; worker: boolean }) { 9 | await ensureDir("tmp"); 10 | let workerCode: string; 11 | if (opts.worker) { 12 | await Deno.run({ 13 | cmd: [ 14 | "deno", 15 | "bundle", 16 | "--unstable", 17 | "--no-check", 18 | "browser/swdev-worker.ts", 19 | "tmp/swdev-worker.js", 20 | ], 21 | }).status(); 22 | workerCode = await Deno.readTextFile("tmp/swdev-worker.js"); 23 | console.log("[dev]", "gen tmp/swdev-worker.js"); 24 | } else { 25 | console.log("[dev]", "use cache tmp/swdev-worker.js"); 26 | workerCode = await Deno.readTextFile("tmp/swdev-worker.js"); 27 | } 28 | 29 | let clientCode: string; 30 | if (opts.client) { 31 | await Deno.run({ 32 | cmd: [ 33 | "deno", 34 | "bundle", 35 | "--unstable", 36 | "--no-check", 37 | "browser/swdev-client.ts", 38 | "tmp/swdev-client.js", 39 | ], 40 | }).status(); 41 | 42 | clientCode = await Deno.readTextFile("tmp/swdev-client.js"); 43 | await Deno.writeTextFile("tmp/swdev-client.js", clientCode); 44 | console.log("[dev]", "gen tmp/swdev-client.js"); 45 | } else { 46 | console.log("[dev]", "use cache tmp/swdev-client.js"); 47 | clientCode = await Deno.readTextFile("tmp/swdev-client.js"); 48 | } 49 | 50 | return { 51 | "__swdev-worker.js": (await minify(workerCode, { module: true })) 52 | .code as string, 53 | "__swdev-client.js": (await minify(clientCode, { module: true })) 54 | .code as string, 55 | }; 56 | } 57 | 58 | switch (task) { 59 | case "prebuild": { 60 | // initialize 61 | const prebuiltData: { [k: string]: string } = await buildClientAssets({ 62 | client: args.client ?? false, 63 | worker: args.worker ?? false, 64 | }); 65 | 66 | // Add template to prebulitData 67 | for await (const file of expandGlob("template/*")) { 68 | if (file.isFile) { 69 | prebuiltData[file.name] = await Deno.readTextFile(file.path); 70 | } 71 | } 72 | await Deno.writeTextFile( 73 | "prebuilt.ts", 74 | `export default ${JSON.stringify(prebuiltData)}` 75 | ); 76 | log("generate prebuilt.ts", Object.keys(prebuiltData)); 77 | break; 78 | } 79 | case "install": { 80 | const process = Deno.run({ 81 | cmd: [ 82 | "deno", 83 | "install", 84 | "-qAf", 85 | "--unstable", 86 | `https://deno.land/x/swdev@${version}/swdev.ts`, 87 | ], 88 | stdout: "piped", 89 | stderr: "piped", 90 | }); 91 | const { code } = await process.status(); 92 | if (code === 0) { 93 | const rawOutput = await process.output(); 94 | await Deno.stdout.write(rawOutput); 95 | } else { 96 | const rawError = await process.stderrOutput(); 97 | const errorString = new TextDecoder().decode(rawError); 98 | console.log(errorString); 99 | } 100 | Deno.exit(code); 101 | } 102 | default: { 103 | console.warn("Unkown command", task); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /swdev.ts: -------------------------------------------------------------------------------- 1 | import { parse, ensureDir, join } from "./deps.ts"; 2 | import { version } from "./version.ts"; 3 | 4 | const args = parse(Deno.args); 5 | const [task, second] = args._ as [string, string | undefined]; 6 | 7 | switch (task) { 8 | case "init": { 9 | const prebuilt = await import("./prebuilt.ts"); 10 | const targetDir = join(second ?? "."); 11 | await ensureDir(targetDir); 12 | for (const [fpath, content] of Object.entries(prebuilt.default)) { 13 | if (!fpath.startsWith("__swdev-")) { 14 | const outpath = join(targetDir, fpath).replace(/\.raw$/, ""); 15 | await Deno.writeTextFile(outpath, content); 16 | } 17 | } 18 | break; 19 | } 20 | 21 | case "build": { 22 | const { bundle } = await import("./bundler.ts"); 23 | bundle(second ?? "main.tsx"); 24 | break; 25 | } 26 | 27 | case "serve": { 28 | const port = 7777; 29 | const runner = args.local 30 | ? "serve.ts" 31 | : `https://deno.land/x/swdev@${version}/serve.ts`; 32 | console.log("[swdev] run", runner); 33 | // const target = join(Deno.cwd(), second ?? "."); 34 | const target = second ?? "."; 35 | const process = Deno.run({ 36 | cmd: [ 37 | "deno", 38 | "run", 39 | ...(args["allow-run"] ? [`--allow-run`] : []), 40 | "--allow-net", 41 | ...(args["allow-write"] ? [`--allow-write=${target}`] : []), 42 | `--allow-read=${Deno.cwd()}`, 43 | "--unstable", 44 | runner, 45 | second ?? ".", 46 | "-p", 47 | port.toString(), 48 | ], 49 | stdout: "piped", 50 | stderr: "piped", 51 | }); 52 | 53 | const endpoint = "ws://localhost:17777"; 54 | console.log(`[swdev:asset-server] http://localhost:${port}`); 55 | console.log(`[swdev:ws] ${endpoint}`); 56 | const { code } = await process.status(); 57 | if (code === 0) { 58 | const rawOutput = await process.output(); 59 | await Deno.stdout.write(rawOutput); 60 | } else { 61 | const rawError = await process.stderrOutput(); 62 | const errorString = new TextDecoder().decode(rawError); 63 | console.log(errorString); 64 | } 65 | Deno.exit(code); 66 | break; 67 | } 68 | default: { 69 | console.warn("[swdev] Unknown command", task); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /template/.gitignore.raw: -------------------------------------------------------------------------------- 1 | *__swdev-* 2 | *.bundle.js -------------------------------------------------------------------------------- /template/App.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 |
10 | Edit me 11 | {x} 12 |
13 | -------------------------------------------------------------------------------- /template/README.md: -------------------------------------------------------------------------------- 1 | # Swdev Project 2 | 3 | created by https://deno.land/x/swdev 4 | 5 | ## develop 6 | 7 | ``` 8 | $ swdev serve 9 | ``` 10 | 11 | ## build and release 12 | 13 | ```bash 14 | $ swdev build 15 | 16 | ## release 17 | # npm install -g netlify-cli 18 | # netlify deploy --prod -d . 19 | ``` 20 | 21 | ## LICENSE 22 | 23 | MIT 24 | -------------------------------------------------------------------------------- /template/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SWDEV Playground 7 | 15 | 16 | 17 |
18 |
19 | 20 | 29 | 30 | -------------------------------------------------------------------------------- /template/main.tsx: -------------------------------------------------------------------------------- 1 | import App from "./App.svelte"; 2 | import React from "https://cdn.esm.sh/react"; 3 | import ReactDOM from "https://cdn.esm.sh/react-dom"; 4 | 5 | export default async () => { 6 | // on start 7 | const app = new App({ target: document.querySelector(".svelte-root") }); 8 | ReactDOM.render( 9 |
React component
, 10 | document.querySelector(".react-root") 11 | ); 12 | return async () => { 13 | // on dispose 14 | console.log("destroy"); 15 | app.$destroy(); 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": ["examples", "*.svelte", "tmp"], 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "esModuleInterop": true, 6 | "experimentalDecorators": true, 7 | "inlineSourceMap": true, 8 | "isolatedModules": true, 9 | "jsx": "react", 10 | "lib": ["deno.window", "WebWorker", "DOM"], 11 | "module": "esnext", 12 | "strict": true, 13 | "target": "esnext", 14 | "useDefineForClassFields": true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /types.ts: -------------------------------------------------------------------------------- 1 | export type GetFilesCommand = { 2 | type: "files"; 3 | files: string[]; 4 | }; 5 | 6 | export type ReadFileCommand = { 7 | type: "read-file"; 8 | filepath: string; 9 | }; 10 | 11 | export type WriteFileCommand = { 12 | type: "write-file"; 13 | filepath: string; 14 | content: string; 15 | }; 16 | 17 | export type RevalidateCommand = { 18 | type: "revalidate"; 19 | paths: string[]; 20 | }; 21 | 22 | export type Command = RevalidateCommand | GetFilesCommand; 23 | 24 | export interface ServeArgs { 25 | _: string[]; 26 | // -p --port 27 | p?: number; 28 | port?: number; 29 | // --cors 30 | cors?: boolean; 31 | dotfiles?: boolean; 32 | // --host 33 | host?: string; 34 | // -c --cert 35 | c?: string; 36 | cert?: string; 37 | // -k --key 38 | k?: string; 39 | key?: string; 40 | // -h --help 41 | h?: boolean; 42 | help?: boolean; 43 | } 44 | -------------------------------------------------------------------------------- /utils.ts: -------------------------------------------------------------------------------- 1 | // import * as path from "https://deno.land/std@0.91.0/path/mod.ts"; 2 | 3 | // export async function getAsset(filepath: string, host?: string | undefined) { 4 | // if (host) { 5 | // const dest = path.join(host, filepath); 6 | // return await fetch(dest).then((res) => res.text()); 7 | // } else { 8 | // // DEVELOPMENT 9 | // return await Deno.readTextFile(filepath); 10 | // } 11 | // } 12 | -------------------------------------------------------------------------------- /version.ts: -------------------------------------------------------------------------------- 1 | export const version = "0.5.2"; 2 | --------------------------------------------------------------------------------