toiljs 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.idea/prettier.xml +1 -0
- package/as-pect.config.js +1 -1
- package/build/backend/.tsbuildinfo +1 -1
- package/build/backend/index.js +1 -2
- package/build/cli/.tsbuildinfo +1 -1
- package/build/cli/configure.d.ts +15 -0
- package/build/cli/configure.js +201 -0
- package/build/cli/create.d.ts +4 -0
- package/build/cli/create.js +193 -68
- package/build/cli/features.d.ts +23 -0
- package/build/cli/features.js +85 -0
- package/build/cli/index.js +42 -2
- package/build/cli/proc.d.ts +1 -0
- package/build/cli/proc.js +11 -0
- package/build/cli/ui.js +1 -2
- package/build/cli/validate.d.ts +4 -0
- package/build/cli/validate.js +19 -0
- package/build/client/.tsbuildinfo +1 -1
- package/build/client/Link.d.ts +8 -0
- package/build/client/Link.js +44 -0
- package/build/client/NavLink.d.ts +14 -0
- package/build/client/NavLink.js +37 -0
- package/build/client/Router.d.ts +7 -0
- package/build/client/Router.js +55 -0
- package/build/client/channel/channel.d.ts +23 -0
- package/build/client/channel/channel.js +94 -0
- package/build/client/error-boundary.d.ts +16 -0
- package/build/client/error-boundary.js +19 -0
- package/build/client/head/head.d.ts +26 -0
- package/build/client/head/head.js +87 -0
- package/build/client/head.d.ts +26 -0
- package/build/client/head.js +87 -0
- package/build/client/hooks.d.ts +17 -0
- package/build/client/hooks.js +48 -0
- package/build/client/index.d.ts +18 -6
- package/build/client/index.js +10 -3
- package/build/client/lazy.d.ts +16 -0
- package/build/client/lazy.js +53 -0
- package/build/client/match.js +7 -0
- package/build/client/mount.d.ts +2 -0
- package/build/client/mount.js +13 -0
- package/build/client/navigation/Link.d.ts +8 -0
- package/build/client/navigation/Link.js +44 -0
- package/build/client/navigation/NavLink.d.ts +14 -0
- package/build/client/navigation/NavLink.js +37 -0
- package/build/client/navigation/navigation.d.ts +13 -0
- package/build/client/navigation/navigation.js +97 -0
- package/build/client/navigation/prefetch.d.ts +11 -0
- package/build/client/navigation/prefetch.js +100 -0
- package/build/client/navigation/scroll.d.ts +8 -0
- package/build/client/navigation/scroll.js +36 -0
- package/build/client/navigation.d.ts +13 -0
- package/build/client/navigation.js +97 -0
- package/build/client/params-context.d.ts +2 -0
- package/build/client/params-context.js +2 -0
- package/build/client/prefetch.d.ts +11 -0
- package/build/client/prefetch.js +100 -0
- package/build/client/routing/Router.d.ts +7 -0
- package/build/client/routing/Router.js +55 -0
- package/build/client/routing/error-boundary.d.ts +16 -0
- package/build/client/routing/error-boundary.js +19 -0
- package/build/client/routing/hooks.d.ts +17 -0
- package/build/client/routing/hooks.js +48 -0
- package/build/client/routing/lazy.d.ts +16 -0
- package/build/client/routing/lazy.js +53 -0
- package/build/client/routing/match.d.ts +2 -0
- package/build/client/routing/match.js +32 -0
- package/build/client/routing/mount.d.ts +2 -0
- package/build/client/routing/mount.js +13 -0
- package/build/client/routing/params-context.d.ts +2 -0
- package/build/client/routing/params-context.js +2 -0
- package/build/client/scroll.d.ts +8 -0
- package/build/client/scroll.js +36 -0
- package/build/client/types.d.ts +27 -0
- package/build/client/types.js +1 -0
- package/build/compiler/.tsbuildinfo +1 -1
- package/build/compiler/config.d.ts +2 -0
- package/build/compiler/config.js +14 -2
- package/build/compiler/docs.d.ts +10 -0
- package/build/compiler/docs.js +59 -0
- package/build/compiler/generate.js +144 -16
- package/build/compiler/index.d.ts +4 -2
- package/build/compiler/index.js +4 -3
- package/build/compiler/plugin.js +16 -1
- package/build/compiler/routes.js +5 -1
- package/build/compiler/vite.d.ts +1 -1
- package/build/compiler/vite.js +17 -1
- package/build/io/.tsbuildinfo +1 -1
- package/build/io/BinaryWriter.js +2 -2
- package/eslint.config.js +1 -1
- package/examples/basic/.toil/docs/cli.md +3 -0
- package/examples/basic/.toil/docs/client.md +3 -0
- package/examples/basic/.toil/docs/index.md +3 -0
- package/examples/basic/.toil/docs/routing.md +3 -0
- package/examples/basic/.toil/docs/server.md +3 -0
- package/examples/basic/.toil/docs/styling.md +3 -0
- package/examples/basic/.toil/entry.tsx +3 -8
- package/examples/basic/.toil/globals.ts +6 -0
- package/examples/basic/.toil/index.html +16 -12
- package/examples/basic/.toil/public/images/.gitkeep +1 -0
- package/examples/basic/.toil/public/images/logo.svg +37 -0
- package/examples/basic/.toil/public/robots.txt +2 -0
- package/examples/basic/.toil/routes.ts +9 -7
- package/examples/basic/build/client/assets/404-Bq0jNTUo.js +1 -0
- package/examples/basic/build/client/assets/_...slug_-CXKf6qnB.js +1 -0
- package/examples/basic/build/client/assets/_id_-BadAyQnb.js +1 -0
- package/examples/basic/build/client/assets/about-BOhoEcEO.js +1 -0
- package/examples/basic/build/client/assets/get-started-BIXpcjkT.js +9 -0
- package/examples/basic/build/client/assets/index-BmqcTaBB.js +1 -0
- package/examples/basic/build/client/assets/io-DEVjjaJj.js +1 -0
- package/examples/basic/build/client/assets/layout-DJegirdz.js +1 -0
- package/examples/basic/build/client/assets/react-DEQrz1q7.js +9 -0
- package/examples/basic/build/client/assets/rolldown-runtime-KL5VtC6j.js +1 -0
- package/examples/basic/build/client/assets/routes-BYWn6TxK.js +1 -0
- package/examples/basic/build/client/css/style.css +2 -0
- package/examples/basic/build/client/images/.gitkeep +1 -0
- package/examples/basic/build/client/images/logo.svg +37 -0
- package/examples/basic/build/client/index.html +17 -0
- package/examples/basic/build/client/robots.txt +2 -0
- package/examples/basic/client/404.tsx +2 -5
- package/examples/basic/client/components/.gitkeep +1 -0
- package/examples/basic/client/components/Footer.tsx +8 -0
- package/examples/basic/client/components/HoneycombBackground.tsx +162 -0
- package/examples/basic/client/layout.tsx +43 -26
- package/examples/basic/client/public/favicon.ico +0 -0
- package/examples/basic/client/public/images/.gitkeep +1 -0
- package/examples/basic/client/public/images/logo.svg +37 -0
- package/examples/basic/client/public/index.html +16 -0
- package/examples/basic/client/public/robots.txt +2 -0
- package/examples/basic/client/routes/about.tsx +1 -3
- package/examples/basic/client/routes/blog/[id].tsx +2 -4
- package/examples/basic/client/routes/docs/[...slug].tsx +3 -6
- package/examples/basic/client/routes/get-started.tsx +84 -0
- package/examples/basic/client/routes/index.tsx +74 -7
- package/examples/basic/client/routes/io.tsx +3 -7
- package/examples/basic/client/styles/main.css +461 -0
- package/examples/basic/client/toil.tsx +7 -0
- package/examples/basic/node_modules/.bin/toilinit +16 -0
- package/examples/basic/node_modules/.bin/toilinit.cmd +17 -0
- package/examples/basic/node_modules/.bin/toilinit.ps1 +28 -0
- package/examples/basic/node_modules/.bin/toilscript +16 -0
- package/examples/basic/node_modules/.bin/toilscript.cmd +17 -0
- package/examples/basic/node_modules/.bin/toilscript.ps1 +28 -0
- package/examples/basic/node_modules/.bin/wasm-as +16 -0
- package/examples/basic/node_modules/.bin/wasm-as.cmd +17 -0
- package/examples/basic/node_modules/.bin/wasm-as.ps1 +28 -0
- package/examples/basic/node_modules/.bin/wasm-ctor-eval +16 -0
- package/examples/basic/node_modules/.bin/wasm-ctor-eval.cmd +17 -0
- package/examples/basic/node_modules/.bin/wasm-ctor-eval.ps1 +28 -0
- package/examples/basic/node_modules/.bin/wasm-dis +16 -0
- package/examples/basic/node_modules/.bin/wasm-dis.cmd +17 -0
- package/examples/basic/node_modules/.bin/wasm-dis.ps1 +28 -0
- package/examples/basic/node_modules/.bin/wasm-merge +16 -0
- package/examples/basic/node_modules/.bin/wasm-merge.cmd +17 -0
- package/examples/basic/node_modules/.bin/wasm-merge.ps1 +28 -0
- package/examples/basic/node_modules/.bin/wasm-metadce +16 -0
- package/examples/basic/node_modules/.bin/wasm-metadce.cmd +17 -0
- package/examples/basic/node_modules/.bin/wasm-metadce.ps1 +28 -0
- package/examples/basic/node_modules/.bin/wasm-opt +16 -0
- package/examples/basic/node_modules/.bin/wasm-opt.cmd +17 -0
- package/examples/basic/node_modules/.bin/wasm-opt.ps1 +28 -0
- package/examples/basic/node_modules/.bin/wasm-reduce +16 -0
- package/examples/basic/node_modules/.bin/wasm-reduce.cmd +17 -0
- package/examples/basic/node_modules/.bin/wasm-reduce.ps1 +28 -0
- package/examples/basic/node_modules/.bin/wasm-shell +16 -0
- package/examples/basic/node_modules/.bin/wasm-shell.cmd +17 -0
- package/examples/basic/node_modules/.bin/wasm-shell.ps1 +28 -0
- package/examples/basic/node_modules/.bin/wasm2js +16 -0
- package/examples/basic/node_modules/.bin/wasm2js.cmd +17 -0
- package/examples/basic/node_modules/.bin/wasm2js.ps1 +28 -0
- package/examples/basic/node_modules/.package-lock.json +49 -1
- package/examples/basic/node_modules/.vite/deps/_metadata.json +9 -9
- package/examples/basic/node_modules/binaryen/LICENSE +201 -0
- package/examples/basic/node_modules/binaryen/README.md +1362 -0
- package/examples/basic/node_modules/binaryen/bin/package.json +3 -0
- package/examples/basic/node_modules/binaryen/bin/wasm-as +0 -0
- package/examples/basic/node_modules/binaryen/bin/wasm-ctor-eval +0 -0
- package/examples/basic/node_modules/binaryen/bin/wasm-dis +0 -0
- package/examples/basic/node_modules/binaryen/bin/wasm-merge +0 -0
- package/examples/basic/node_modules/binaryen/bin/wasm-metadce +0 -0
- package/examples/basic/node_modules/binaryen/bin/wasm-opt +0 -0
- package/examples/basic/node_modules/binaryen/bin/wasm-reduce +0 -0
- package/examples/basic/node_modules/binaryen/bin/wasm-shell +0 -0
- package/examples/basic/node_modules/binaryen/bin/wasm2js +0 -0
- package/examples/basic/node_modules/binaryen/index.d.ts +2371 -0
- package/examples/basic/node_modules/binaryen/index.js +30552 -0
- package/examples/basic/node_modules/binaryen/package.json +50 -0
- package/examples/basic/node_modules/long/LICENSE +202 -0
- package/examples/basic/node_modules/long/README.md +286 -0
- package/examples/basic/node_modules/long/index.d.ts +2 -0
- package/examples/basic/node_modules/long/index.js +1581 -0
- package/examples/basic/node_modules/long/package.json +58 -0
- package/examples/basic/node_modules/long/types.d.ts +474 -0
- package/examples/basic/node_modules/long/umd/index.d.ts +3 -0
- package/examples/basic/node_modules/long/umd/index.js +1622 -0
- package/examples/basic/node_modules/long/umd/package.json +3 -0
- package/examples/basic/node_modules/long/umd/types.d.ts +474 -0
- package/examples/basic/node_modules/toilscript/LICENSE +201 -0
- package/examples/basic/node_modules/toilscript/NOTICE +94 -0
- package/examples/basic/node_modules/toilscript/README.md +66 -0
- package/examples/basic/node_modules/toilscript/bin/toilinit.js +468 -0
- package/examples/basic/node_modules/toilscript/bin/toilscript.js +35 -0
- package/examples/basic/node_modules/toilscript/dist/cli.d.ts +4 -0
- package/examples/basic/node_modules/toilscript/dist/cli.generated.d.ts +10027 -0
- package/examples/basic/node_modules/toilscript/dist/cli.js +24474 -0
- package/examples/basic/node_modules/toilscript/dist/cli.js.map +7 -0
- package/examples/basic/node_modules/toilscript/dist/importmap.json +9 -0
- package/examples/basic/node_modules/toilscript/dist/toilscript.d.ts +4 -0
- package/examples/basic/node_modules/toilscript/dist/toilscript.generated.d.ts +11242 -0
- package/examples/basic/node_modules/toilscript/dist/toilscript.js +337 -0
- package/examples/basic/node_modules/toilscript/dist/toilscript.js.map +7 -0
- package/examples/basic/node_modules/toilscript/dist/transform.cjs +1 -0
- package/examples/basic/node_modules/toilscript/dist/transform.d.ts +1 -0
- package/examples/basic/node_modules/toilscript/dist/transform.js +1 -0
- package/examples/basic/node_modules/toilscript/dist/web.js +22 -0
- package/examples/basic/node_modules/toilscript/lib/binaryen.d.ts +2 -0
- package/examples/basic/node_modules/toilscript/lib/binaryen.js +2 -0
- package/examples/basic/node_modules/toilscript/package.json +115 -0
- package/examples/basic/node_modules/toilscript/std/README.md +6 -0
- package/examples/basic/node_modules/toilscript/std/assembly/array.ts +550 -0
- package/examples/basic/node_modules/toilscript/std/assembly/arraybuffer.ts +77 -0
- package/examples/basic/node_modules/toilscript/std/assembly/atomics.ts +127 -0
- package/examples/basic/node_modules/toilscript/std/assembly/bindings/asyncify.ts +16 -0
- package/examples/basic/node_modules/toilscript/std/assembly/bindings/dom.ts +291 -0
- package/examples/basic/node_modules/toilscript/std/assembly/bindings/node.ts +6 -0
- package/examples/basic/node_modules/toilscript/std/assembly/bitflags.ts +53 -0
- package/examples/basic/node_modules/toilscript/std/assembly/builtins.ts +2650 -0
- package/examples/basic/node_modules/toilscript/std/assembly/byteslice.ts +177 -0
- package/examples/basic/node_modules/toilscript/std/assembly/compat.ts +2 -0
- package/examples/basic/node_modules/toilscript/std/assembly/console.ts +42 -0
- package/examples/basic/node_modules/toilscript/std/assembly/crypto.ts +9 -0
- package/examples/basic/node_modules/toilscript/std/assembly/dataview.ts +181 -0
- package/examples/basic/node_modules/toilscript/std/assembly/date.ts +375 -0
- package/examples/basic/node_modules/toilscript/std/assembly/diagnostics.ts +11 -0
- package/examples/basic/node_modules/toilscript/std/assembly/encoding.ts +151 -0
- package/examples/basic/node_modules/toilscript/std/assembly/endian.ts +45 -0
- package/examples/basic/node_modules/toilscript/std/assembly/error.ts +44 -0
- package/examples/basic/node_modules/toilscript/std/assembly/fixedarray.ts +173 -0
- package/examples/basic/node_modules/toilscript/std/assembly/fixedmap.ts +326 -0
- package/examples/basic/node_modules/toilscript/std/assembly/fixedset.ts +275 -0
- package/examples/basic/node_modules/toilscript/std/assembly/function.ts +42 -0
- package/examples/basic/node_modules/toilscript/std/assembly/index.d.ts +2892 -0
- package/examples/basic/node_modules/toilscript/std/assembly/iterator.ts +35 -0
- package/examples/basic/node_modules/toilscript/std/assembly/map.ts +269 -0
- package/examples/basic/node_modules/toilscript/std/assembly/math.ts +3289 -0
- package/examples/basic/node_modules/toilscript/std/assembly/memory.ts +123 -0
- package/examples/basic/node_modules/toilscript/std/assembly/number.ts +388 -0
- package/examples/basic/node_modules/toilscript/std/assembly/object.ts +36 -0
- package/examples/basic/node_modules/toilscript/std/assembly/performance.ts +9 -0
- package/examples/basic/node_modules/toilscript/std/assembly/pointer.ts +80 -0
- package/examples/basic/node_modules/toilscript/std/assembly/polyfills.ts +27 -0
- package/examples/basic/node_modules/toilscript/std/assembly/process.ts +50 -0
- package/examples/basic/node_modules/toilscript/std/assembly/reference.ts +48 -0
- package/examples/basic/node_modules/toilscript/std/assembly/regexp.ts +12 -0
- package/examples/basic/node_modules/toilscript/std/assembly/rt/README.md +83 -0
- package/examples/basic/node_modules/toilscript/std/assembly/rt/common.ts +81 -0
- package/examples/basic/node_modules/toilscript/std/assembly/rt/index-incremental.ts +2 -0
- package/examples/basic/node_modules/toilscript/std/assembly/rt/index-memory.ts +1 -0
- package/examples/basic/node_modules/toilscript/std/assembly/rt/index-minimal.ts +2 -0
- package/examples/basic/node_modules/toilscript/std/assembly/rt/index-stub.ts +1 -0
- package/examples/basic/node_modules/toilscript/std/assembly/rt/index.d.ts +37 -0
- package/examples/basic/node_modules/toilscript/std/assembly/rt/itcms.ts +419 -0
- package/examples/basic/node_modules/toilscript/std/assembly/rt/memory-runtime.ts +94 -0
- package/examples/basic/node_modules/toilscript/std/assembly/rt/rtrace.ts +15 -0
- package/examples/basic/node_modules/toilscript/std/assembly/rt/stub.ts +133 -0
- package/examples/basic/node_modules/toilscript/std/assembly/rt/tcms.ts +254 -0
- package/examples/basic/node_modules/toilscript/std/assembly/rt/tlsf.ts +592 -0
- package/examples/basic/node_modules/toilscript/std/assembly/rt.ts +90 -0
- package/examples/basic/node_modules/toilscript/std/assembly/set.ts +225 -0
- package/examples/basic/node_modules/toilscript/std/assembly/shared/feature.ts +68 -0
- package/examples/basic/node_modules/toilscript/std/assembly/shared/runtime.ts +13 -0
- package/examples/basic/node_modules/toilscript/std/assembly/shared/target.ts +11 -0
- package/examples/basic/node_modules/toilscript/std/assembly/shared/tsconfig.json +11 -0
- package/examples/basic/node_modules/toilscript/std/assembly/shared/typeinfo.ts +72 -0
- package/examples/basic/node_modules/toilscript/std/assembly/staticarray.ts +423 -0
- package/examples/basic/node_modules/toilscript/std/assembly/string.ts +850 -0
- package/examples/basic/node_modules/toilscript/std/assembly/symbol.ts +114 -0
- package/examples/basic/node_modules/toilscript/std/assembly/table.ts +16 -0
- package/examples/basic/node_modules/toilscript/std/assembly/toilscript.ts +16 -0
- package/examples/basic/node_modules/toilscript/std/assembly/tsconfig.json +6 -0
- package/examples/basic/node_modules/toilscript/std/assembly/typedarray.ts +1954 -0
- package/examples/basic/node_modules/toilscript/std/assembly/uri.ts +17 -0
- package/examples/basic/node_modules/toilscript/std/assembly/util/bytes.ts +107 -0
- package/examples/basic/node_modules/toilscript/std/assembly/util/casemap.ts +497 -0
- package/examples/basic/node_modules/toilscript/std/assembly/util/error.ts +58 -0
- package/examples/basic/node_modules/toilscript/std/assembly/util/hash.ts +117 -0
- package/examples/basic/node_modules/toilscript/std/assembly/util/math.ts +1922 -0
- package/examples/basic/node_modules/toilscript/std/assembly/util/memory.ts +290 -0
- package/examples/basic/node_modules/toilscript/std/assembly/util/number.ts +873 -0
- package/examples/basic/node_modules/toilscript/std/assembly/util/sort.ts +313 -0
- package/examples/basic/node_modules/toilscript/std/assembly/util/string.ts +1202 -0
- package/examples/basic/node_modules/toilscript/std/assembly/util/uri.ts +275 -0
- package/examples/basic/node_modules/toilscript/std/assembly/vector.ts +4 -0
- package/examples/basic/node_modules/toilscript/std/assembly.json +16 -0
- package/examples/basic/node_modules/toilscript/std/portable/index.d.ts +461 -0
- package/examples/basic/node_modules/toilscript/std/portable/index.js +416 -0
- package/examples/basic/node_modules/toilscript/std/portable.json +11 -0
- package/examples/basic/node_modules/toilscript/std/types/assembly/index.d.ts +1 -0
- package/examples/basic/node_modules/toilscript/std/types/assembly/package.json +3 -0
- package/examples/basic/node_modules/toilscript/std/types/portable/index.d.ts +1 -0
- package/examples/basic/node_modules/toilscript/std/types/portable/package.json +3 -0
- package/examples/basic/node_modules/toilscript/tsconfig-base.json +13 -0
- package/examples/basic/node_modules/toilscript/util/README.md +23 -0
- package/examples/basic/node_modules/toilscript/util/browser/fs.js +1 -0
- package/examples/basic/node_modules/toilscript/util/browser/module.js +5 -0
- package/examples/basic/node_modules/toilscript/util/browser/path.js +520 -0
- package/examples/basic/node_modules/toilscript/util/browser/process.js +59 -0
- package/examples/basic/node_modules/toilscript/util/browser/url.js +23 -0
- package/examples/basic/node_modules/toilscript/util/cpu.d.ts +9 -0
- package/examples/basic/node_modules/toilscript/util/cpu.js +42 -0
- package/examples/basic/node_modules/toilscript/util/find.d.ts +6 -0
- package/examples/basic/node_modules/toilscript/util/find.js +20 -0
- package/examples/basic/node_modules/toilscript/util/node.d.ts +21 -0
- package/examples/basic/node_modules/toilscript/util/node.js +34 -0
- package/examples/basic/node_modules/toilscript/util/options.d.ts +70 -0
- package/examples/basic/node_modules/toilscript/util/options.js +262 -0
- package/examples/basic/node_modules/toilscript/util/terminal.d.ts +52 -0
- package/examples/basic/node_modules/toilscript/util/terminal.js +35 -0
- package/examples/basic/node_modules/toilscript/util/text.d.ts +26 -0
- package/examples/basic/node_modules/toilscript/util/text.js +114 -0
- package/examples/basic/node_modules/toilscript/util/tsconfig.json +9 -0
- package/examples/basic/node_modules/toilscript/util/web.d.ts +11 -0
- package/examples/basic/node_modules/toilscript/util/web.js +33 -0
- package/examples/basic/package-lock.json +50 -1
- package/examples/basic/package.json +5 -2
- package/examples/basic/server/index.ts +3 -0
- package/examples/basic/server/main.ts +6 -0
- package/examples/basic/server/tsconfig.json +7 -0
- package/examples/basic/toil-env.d.ts +20 -1
- package/examples/basic/toil.config.ts +2 -5
- package/examples/basic/toilconfig.json +30 -0
- package/package.json +2 -2
- package/presets/eslint.js +2 -7
- package/presets/no-uint8array-tostring.js +4 -5
- package/presets/prettier.json +8 -1
- package/src/backend/index.ts +11 -18
- package/src/cli/configure.ts +272 -0
- package/src/cli/create.ts +267 -82
- package/src/cli/features.ts +128 -0
- package/src/cli/index.ts +44 -3
- package/src/cli/proc.ts +20 -0
- package/src/cli/ui.ts +4 -6
- package/src/cli/validate.ts +31 -0
- package/src/client/head/head.ts +140 -0
- package/src/client/index.ts +39 -9
- package/src/client/navigation/Link.tsx +99 -0
- package/src/client/navigation/NavLink.tsx +86 -0
- package/src/client/navigation/navigation.ts +142 -0
- package/src/client/navigation/prefetch.ts +130 -0
- package/src/client/navigation/scroll.ts +53 -0
- package/src/client/routing/Router.tsx +95 -0
- package/src/client/routing/error-boundary.tsx +43 -0
- package/src/client/routing/hooks.ts +115 -0
- package/src/client/routing/lazy.ts +93 -0
- package/src/client/{match.ts → routing/match.ts} +11 -3
- package/src/client/routing/mount.tsx +28 -0
- package/src/client/routing/params-context.ts +10 -0
- package/src/client/types.ts +36 -0
- package/src/compiler/config.ts +26 -10
- package/src/compiler/docs.ts +87 -0
- package/src/compiler/generate.ts +180 -23
- package/src/compiler/index.ts +6 -4
- package/src/compiler/plugin.ts +22 -1
- package/src/compiler/routes.ts +13 -7
- package/src/compiler/vite.ts +28 -5
- package/src/io/BinaryReader.ts +1 -5
- package/src/io/BinaryWriter.ts +3 -3
- package/src/server/index.ts +3 -4
- package/src/server/tsconfig.json +4 -0
- package/templates/app/client/404.tsx +11 -0
- package/templates/app/client/components/.gitkeep +1 -0
- package/templates/app/client/components/Footer.tsx +8 -0
- package/templates/app/client/components/HoneycombBackground.tsx +162 -0
- package/templates/app/client/layout.tsx +53 -0
- package/templates/app/client/public/favicon.ico +0 -0
- package/templates/app/client/public/images/.gitkeep +1 -0
- package/templates/app/client/public/images/logo.svg +37 -0
- package/templates/app/client/public/index.html +16 -0
- package/templates/app/client/public/robots.txt +2 -0
- package/templates/app/client/routes/about.tsx +11 -0
- package/templates/app/client/routes/blog/[id].tsx +12 -0
- package/templates/app/client/routes/docs/[...slug].tsx +12 -0
- package/templates/app/client/routes/get-started.tsx +84 -0
- package/templates/app/client/routes/index.tsx +80 -0
- package/templates/app/client/routes/io.tsx +24 -0
- package/templates/app/client/styles/main.css +461 -0
- package/templates/app/client/toil.tsx +7 -0
- package/test/channel.test.ts +1 -1
- package/test/configure.test.ts +90 -0
- package/test/features.test.ts +111 -0
- package/test/head.test.ts +35 -0
- package/test/io.test.ts +8 -0
- package/test/navlink.test.ts +28 -0
- package/test/routes.test.ts +16 -1
- package/test/validate.test.ts +42 -0
- package/vitest.config.ts +1 -1
- package/examples/basic/dist/assets/404-D1bS2aH_.js +0 -1
- package/examples/basic/dist/assets/_...slug_-wR3shlWn.js +0 -1
- package/examples/basic/dist/assets/_id_-EWYvHfi2.js +0 -1
- package/examples/basic/dist/assets/about-Ddvj1tjF.js +0 -1
- package/examples/basic/dist/assets/index-CdG0me90.js +0 -1
- package/examples/basic/dist/assets/io-CODNJU57.js +0 -1
- package/examples/basic/dist/assets/layout-C15ZTPYI.js +0 -1
- package/examples/basic/dist/assets/react-JbAfoxYe.js +0 -9
- package/examples/basic/dist/assets/rolldown-runtime-1VNLd2iN.js +0 -1
- package/examples/basic/dist/assets/routes-GoydenoY.js +0 -1
- package/examples/basic/dist/index.html +0 -12
- package/src/client/runtime.tsx +0 -190
- /package/src/client/{channel.ts → channel/channel.ts} +0 -0
|
@@ -6,7 +6,8 @@ export type RouteParams = Record<string, string>;
|
|
|
6
6
|
* Pure and runtime-agnostic (used by the router and unit-tested directly).
|
|
7
7
|
* matchRoute('/', '/') -> {}
|
|
8
8
|
* matchRoute('/blog/:id', '/blog/42') -> { id: '42' }
|
|
9
|
-
* matchRoute('/docs/*slug', '/docs/a/b') -> { slug: 'a/b' } (catch-all)
|
|
9
|
+
* matchRoute('/docs/*slug', '/docs/a/b') -> { slug: 'a/b' } (catch-all, 1+ segments)
|
|
10
|
+
* matchRoute('/docs/**slug', '/docs') -> { slug: '' } (optional catch-all, 0+ segments)
|
|
10
11
|
* matchRoute('/about', '/x') -> null
|
|
11
12
|
*/
|
|
12
13
|
export function matchRoute(pattern: string, pathname: string): RouteParams | null {
|
|
@@ -17,7 +18,15 @@ export function matchRoute(pattern: string, pathname: string): RouteParams | nul
|
|
|
17
18
|
for (let i = 0; i < patternSegs.length; i++) {
|
|
18
19
|
const p = patternSegs[i];
|
|
19
20
|
|
|
20
|
-
//
|
|
21
|
+
// Optional catch-all (`**slug`): captures the rest of the path, matching zero or more segments.
|
|
22
|
+
if (p.startsWith('**')) {
|
|
23
|
+
params[p.slice(2)] = pathSegs
|
|
24
|
+
.slice(i)
|
|
25
|
+
.map((s) => decodeURIComponent(s))
|
|
26
|
+
.join('/');
|
|
27
|
+
return params;
|
|
28
|
+
}
|
|
29
|
+
|
|
21
30
|
if (p.startsWith('*')) {
|
|
22
31
|
const rest = pathSegs.slice(i);
|
|
23
32
|
if (rest.length === 0) return null;
|
|
@@ -34,6 +43,5 @@ export function matchRoute(pattern: string, pathname: string): RouteParams | nul
|
|
|
34
43
|
}
|
|
35
44
|
}
|
|
36
45
|
|
|
37
|
-
// No catch-all consumed the tail: lengths must match exactly.
|
|
38
46
|
return patternSegs.length === pathSegs.length ? params : null;
|
|
39
47
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createRoot } from 'react-dom/client';
|
|
2
|
+
|
|
3
|
+
import { initNavigation } from '../navigation/navigation.js';
|
|
4
|
+
import { startPrefetcher } from '../navigation/prefetch.js';
|
|
5
|
+
import { Router } from './Router.js';
|
|
6
|
+
import type { LayoutLoader, NotFoundLoader, RouteDef } from '../types.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Mounts the toil client app into `#root` and starts idle link prefetching. Called by the
|
|
10
|
+
* compiler-generated `.toil/entry.tsx`.
|
|
11
|
+
*/
|
|
12
|
+
export function mount(
|
|
13
|
+
routes: RouteDef[],
|
|
14
|
+
layout: LayoutLoader = null,
|
|
15
|
+
notFound: NotFoundLoader = null,
|
|
16
|
+
): void {
|
|
17
|
+
const el = document.getElementById('root');
|
|
18
|
+
if (!el) throw new Error('toil: #root element not found');
|
|
19
|
+
initNavigation();
|
|
20
|
+
createRoot(el).render(
|
|
21
|
+
<Router
|
|
22
|
+
routes={routes}
|
|
23
|
+
layout={layout}
|
|
24
|
+
notFound={notFound}
|
|
25
|
+
/>,
|
|
26
|
+
);
|
|
27
|
+
startPrefetcher(routes);
|
|
28
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React context carrying the current route's dynamic params. The provider is set by {@link Router};
|
|
3
|
+
* read it with the {@link useParams} hook rather than consuming the context directly.
|
|
4
|
+
*/
|
|
5
|
+
import { createContext } from 'react';
|
|
6
|
+
|
|
7
|
+
import type { RouteParams } from './match.js';
|
|
8
|
+
|
|
9
|
+
/** Holds the params extracted from the active route (e.g. `{ id }` for `/blog/:id`). */
|
|
10
|
+
export const ParamsContext = createContext<RouteParams>({});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public router types shared across the client runtime. Kept dependency-free (type-only React
|
|
3
|
+
* imports) so any module can import them without pulling in component or DOM code.
|
|
4
|
+
*/
|
|
5
|
+
import type { ComponentType, ReactNode } from 'react';
|
|
6
|
+
|
|
7
|
+
/** Lazy loader for a layout component (wraps children). */
|
|
8
|
+
export type LayoutComponentLoader = () => Promise<{
|
|
9
|
+
default: ComponentType<{ children?: ReactNode }>;
|
|
10
|
+
}>;
|
|
11
|
+
|
|
12
|
+
/** Props passed to an `error.tsx` component: the thrown error and a function to retry rendering. */
|
|
13
|
+
export interface RouteErrorProps {
|
|
14
|
+
readonly error: Error;
|
|
15
|
+
readonly reset: () => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A route entry produced by the compiler: a URL pattern, a lazy loader for its page component, and
|
|
20
|
+
* the chain of nested layout loaders (shallowest → deepest, from nested `layout.tsx` files) that wrap it.
|
|
21
|
+
*/
|
|
22
|
+
export interface RouteDef {
|
|
23
|
+
readonly pattern: string;
|
|
24
|
+
readonly load: () => Promise<{ default: ComponentType }>;
|
|
25
|
+
readonly layouts?: readonly LayoutComponentLoader[];
|
|
26
|
+
/** Nearest `loading.tsx` — shown as the Suspense fallback while this route loads. */
|
|
27
|
+
readonly loading?: () => Promise<{ default: ComponentType }>;
|
|
28
|
+
/** Nearest `error.tsx` — rendered by an error boundary around this route. */
|
|
29
|
+
readonly errorComponent?: () => Promise<{ default: ComponentType<RouteErrorProps> }>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Optional root layout loader (wraps every page). `null` when the project defines no layout. */
|
|
33
|
+
export type LayoutLoader = LayoutComponentLoader | null;
|
|
34
|
+
|
|
35
|
+
/** Optional custom not-found (404) page loader, rendered when no route matches. */
|
|
36
|
+
export type NotFoundLoader = (() => Promise<{ default: ComponentType }>) | null;
|
package/src/compiler/config.ts
CHANGED
|
@@ -12,7 +12,13 @@ export interface ClientConfig {
|
|
|
12
12
|
readonly srcDir?: string;
|
|
13
13
|
/** Routes directory, relative to `srcDir`. Default `routes`. */
|
|
14
14
|
readonly routesDir?: string;
|
|
15
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Static assets directory, relative to root. Default `<srcDir>/public` (e.g. `client/public`).
|
|
17
|
+
* Holds the `index.html` template (owned and edited by you) plus any files served as-is at the
|
|
18
|
+
* base path (favicons, images, …).
|
|
19
|
+
*/
|
|
20
|
+
readonly publicDir?: string;
|
|
21
|
+
/** Production output directory, relative to root. Default `build/client`. */
|
|
16
22
|
readonly outDir?: string;
|
|
17
23
|
/** Public base path. Default `/`. */
|
|
18
24
|
readonly base?: string;
|
|
@@ -27,7 +33,7 @@ export interface ClientConfig {
|
|
|
27
33
|
}
|
|
28
34
|
|
|
29
35
|
/**
|
|
30
|
-
* Server-side (
|
|
36
|
+
* Server-side (toilscript → WASM) configuration. Reserved: the compiler does not yet
|
|
31
37
|
* build the server target via `toil build`; today it is compiled by `toilscript` directly.
|
|
32
38
|
*/
|
|
33
39
|
export interface ServerConfig {
|
|
@@ -46,7 +52,7 @@ export interface ToilConfig {
|
|
|
46
52
|
readonly root?: string;
|
|
47
53
|
/** Client (TSX/React/Vite) configuration. */
|
|
48
54
|
readonly client?: ClientConfig;
|
|
49
|
-
/** Server (
|
|
55
|
+
/** Server (toilscript/WASM) configuration. */
|
|
50
56
|
readonly server?: ServerConfig;
|
|
51
57
|
}
|
|
52
58
|
|
|
@@ -56,6 +62,8 @@ export interface ResolvedToilConfig {
|
|
|
56
62
|
readonly srcDir: string;
|
|
57
63
|
readonly clientAbsDir: string;
|
|
58
64
|
readonly routesAbsDir: string;
|
|
65
|
+
/** Absolute path to the static-assets dir (holds the `index.html` template). */
|
|
66
|
+
readonly publicDir: string;
|
|
59
67
|
readonly toilDir: string;
|
|
60
68
|
readonly outDir: string;
|
|
61
69
|
readonly base: string;
|
|
@@ -70,14 +78,23 @@ export function defineConfig(config: ToilConfig): ToilConfig {
|
|
|
70
78
|
return config;
|
|
71
79
|
}
|
|
72
80
|
|
|
73
|
-
const CONFIG_NAMES = [
|
|
81
|
+
const CONFIG_NAMES = [
|
|
82
|
+
'toil.config.ts',
|
|
83
|
+
'toil.config.mts',
|
|
84
|
+
'toil.config.js',
|
|
85
|
+
'toil.config.mjs',
|
|
86
|
+
'toiljs.config.ts',
|
|
87
|
+
'toiljs.config.mts',
|
|
88
|
+
'toiljs.config.js',
|
|
89
|
+
'toiljs.config.mjs',
|
|
90
|
+
];
|
|
74
91
|
|
|
75
92
|
/** Path to the built client runtime (`build/client/index.js`), sibling to `build/compiler`. */
|
|
76
93
|
function resolveRuntimePath(): string {
|
|
77
94
|
return path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../client/index.js');
|
|
78
95
|
}
|
|
79
96
|
|
|
80
|
-
/** Finds and loads `toil.config.*` from `root
|
|
97
|
+
/** Finds and loads `toil.config.*` or `toiljs.config.*` from `root`, then resolves defaults. */
|
|
81
98
|
export async function loadConfig(
|
|
82
99
|
opts: { root?: string; port?: number } = {},
|
|
83
100
|
): Promise<ResolvedToilConfig> {
|
|
@@ -87,10 +104,6 @@ export async function loadConfig(
|
|
|
87
104
|
for (const name of CONFIG_NAMES) {
|
|
88
105
|
const candidate = path.join(root, name);
|
|
89
106
|
if (fs.existsSync(candidate)) {
|
|
90
|
-
// Native ESM import (Node strips types from .ts/.mts). This keeps config loading
|
|
91
|
-
// independent of the project's tsconfig — which may `extends` a not-yet-installed
|
|
92
|
-
// package and would otherwise throw TSCONFIG_ERROR — and a file URL imports absolute
|
|
93
|
-
// paths correctly on Windows.
|
|
94
107
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- dynamic import() is typed `any`
|
|
95
108
|
const loaded: { default?: ToilConfig } = await import(pathToFileURL(candidate).href);
|
|
96
109
|
if (loaded.default) user = loaded.default;
|
|
@@ -108,8 +121,11 @@ export async function loadConfig(
|
|
|
108
121
|
srcDir,
|
|
109
122
|
clientAbsDir,
|
|
110
123
|
routesAbsDir: path.join(clientAbsDir, routesDir),
|
|
124
|
+
publicDir: client.publicDir
|
|
125
|
+
? path.resolve(root, client.publicDir)
|
|
126
|
+
: path.join(clientAbsDir, 'public'),
|
|
111
127
|
toilDir: path.join(root, '.toil'),
|
|
112
|
-
outDir: client.outDir ?? '
|
|
128
|
+
outDir: client.outDir ?? 'build/client',
|
|
113
129
|
base: client.base ?? '/',
|
|
114
130
|
port: opts.port ?? client.port ?? 3000,
|
|
115
131
|
runtimePath: resolveRuntimePath(),
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI-assistant helper files. `toiljs create` writes a small pointer file for each tool at the
|
|
3
|
+
* project root (committed, yours to edit); the real documentation lives under `.toil/docs/`,
|
|
4
|
+
* regenerated on every `toiljs dev` / `toiljs build` so it stays in sync with the installed
|
|
5
|
+
* toiljs version. The pointer files just tell the agent to read `.toil/docs/`.
|
|
6
|
+
*/
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
|
|
10
|
+
/** Shared body for the per-tool pointer files. */
|
|
11
|
+
const POINTER_BODY = `# toiljs · AI assistant guide
|
|
12
|
+
|
|
13
|
+
This is a **toiljs** project — a full-stack React framework (React + Vite client, file-based
|
|
14
|
+
routing, and a toilscript→WebAssembly server).
|
|
15
|
+
|
|
16
|
+
**Before editing this project, read the generated documentation in \`.toil/docs/\`.** It describes
|
|
17
|
+
the conventions you must follow:
|
|
18
|
+
|
|
19
|
+
- \`.toil/docs/index.md\` — overview and project layout
|
|
20
|
+
- \`.toil/docs/routing.md\` — file-based routing, nested layouts, loading / error files
|
|
21
|
+
- \`.toil/docs/client.md\` — the \`Toil\` global, Link / NavLink, router hooks
|
|
22
|
+
- \`.toil/docs/styling.md\` — CSS / Sass / Less / Stylus / Tailwind (via \`toiljs configure\`)
|
|
23
|
+
- \`.toil/docs/server.md\` — the toilscript server target
|
|
24
|
+
- \`.toil/docs/cli.md\` — toiljs CLI commands
|
|
25
|
+
|
|
26
|
+
\`.toil/docs/\` is regenerated by toiljs; do not edit it by hand. This pointer file is yours to edit.
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
/** A selectable AI coding-tool helper: its id, label, and the root pointer file(s) it scaffolds. */
|
|
30
|
+
export interface AiHelper {
|
|
31
|
+
readonly id: string;
|
|
32
|
+
readonly label: string;
|
|
33
|
+
readonly files: Record<string, string>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Per-tool pointer files, individually selectable in `toiljs create`. Each tool reads its own
|
|
38
|
+
* conventional file: Claude Code → CLAUDE.md, Codex / others → AGENTS.md, Cursor → .cursor/rules,
|
|
39
|
+
* GitHub Copilot → .github/copilot-instructions.md. Written once by `create`; not regenerated.
|
|
40
|
+
*/
|
|
41
|
+
export const AI_HELPERS: readonly AiHelper[] = [
|
|
42
|
+
{ id: 'claude', label: 'Claude Code (CLAUDE.md)', files: { 'CLAUDE.md': POINTER_BODY } },
|
|
43
|
+
{ id: 'codex', label: 'Codex / AGENTS.md', files: { 'AGENTS.md': POINTER_BODY } },
|
|
44
|
+
{
|
|
45
|
+
id: 'cursor',
|
|
46
|
+
label: 'Cursor (.cursor/rules)',
|
|
47
|
+
files: {
|
|
48
|
+
'.cursor/rules/toiljs.mdc': `---\ndescription: toiljs project conventions\nalwaysApply: true\n---\n\n${POINTER_BODY}`,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: 'copilot',
|
|
53
|
+
label: 'GitHub Copilot (.github/copilot-instructions.md)',
|
|
54
|
+
files: { '.github/copilot-instructions.md': POINTER_BODY },
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
/** All AI helper ids (the default selection). */
|
|
59
|
+
export const AI_HELPER_IDS: readonly string[] = AI_HELPERS.map((h) => h.id);
|
|
60
|
+
|
|
61
|
+
/** Merges the pointer files for the given helper ids into one path → content map. */
|
|
62
|
+
export function aiHelperFiles(ids: readonly string[]): Record<string, string> {
|
|
63
|
+
const out: Record<string, string> = {};
|
|
64
|
+
for (const helper of AI_HELPERS) {
|
|
65
|
+
if (ids.includes(helper.id)) Object.assign(out, helper.files);
|
|
66
|
+
}
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** The framework docs written into `.toil/docs/` (placeholders for now), keyed by filename. */
|
|
71
|
+
export const TOIL_DOCS: Record<string, string> = {
|
|
72
|
+
'index.md': '# toiljs\n\n<!-- TODO: overview and project layout -->\n',
|
|
73
|
+
'routing.md': '# Routing\n\n<!-- TODO: file-based routing, nested layouts, loading / error -->\n',
|
|
74
|
+
'client.md': '# Client runtime\n\n<!-- TODO: Toil global, Link / NavLink, router hooks -->\n',
|
|
75
|
+
'styling.md': '# Styling\n\n<!-- TODO: CSS / preprocessors / Tailwind via `toiljs configure` -->\n',
|
|
76
|
+
'server.md': '# Server (toilscript → WebAssembly)\n\n<!-- TODO -->\n',
|
|
77
|
+
'cli.md': '# CLI\n\n<!-- TODO: create / dev / build / start / configure -->\n',
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/** Writes the framework docs into `<toilDir>/docs/`. Called by `generate` each dev/build. */
|
|
81
|
+
export function writeDocs(toilDir: string): void {
|
|
82
|
+
const dir = path.join(toilDir, 'docs');
|
|
83
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
84
|
+
for (const [name, content] of Object.entries(TOIL_DOCS)) {
|
|
85
|
+
fs.writeFileSync(path.join(dir, name), content);
|
|
86
|
+
}
|
|
87
|
+
}
|
package/src/compiler/generate.ts
CHANGED
|
@@ -2,6 +2,7 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
|
|
4
4
|
import { type ResolvedToilConfig } from './config.js';
|
|
5
|
+
import { writeDocs } from './docs.js';
|
|
5
6
|
import { scanRoutes, type ScannedRoute } from './routes.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -12,16 +13,52 @@ import { scanRoutes, type ScannedRoute } from './routes.js';
|
|
|
12
13
|
* Lives at the project root because TypeScript's `include` globs skip dot-directories.
|
|
13
14
|
* Exported so `toiljs create` can write it during scaffolding, before the first dev/build.
|
|
14
15
|
*/
|
|
16
|
+
/** Side-effect style imports (e.g. `import './styles/main.css'`). */
|
|
17
|
+
const STYLE_EXTENSIONS = ['css', 'scss', 'sass', 'less', 'styl', 'stylus', 'pcss', 'sss'];
|
|
18
|
+
/** Asset imports whose default export is the resolved URL string (e.g. `import logo from './logo.svg'`). */
|
|
19
|
+
const ASSET_EXTENSIONS = [
|
|
20
|
+
'svg',
|
|
21
|
+
'png',
|
|
22
|
+
'jpg',
|
|
23
|
+
'jpeg',
|
|
24
|
+
'gif',
|
|
25
|
+
'webp',
|
|
26
|
+
'avif',
|
|
27
|
+
'ico',
|
|
28
|
+
'bmp',
|
|
29
|
+
'apng',
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
const STYLE_MODULES = STYLE_EXTENSIONS.map((ext) => `declare module '*.${ext}' {}`).join('\n');
|
|
33
|
+
const ASSET_MODULES = ASSET_EXTENSIONS.map(
|
|
34
|
+
(ext) => `declare module '*.${ext}' {\n const src: string;\n export default src;\n}`,
|
|
35
|
+
).join('\n');
|
|
36
|
+
|
|
15
37
|
export const TOIL_ENV_DTS =
|
|
16
38
|
`// AUTO-GENERATED by toil — do not edit.\n` +
|
|
39
|
+
`declare const Toil: typeof import('toiljs/client');\n` +
|
|
17
40
|
`declare const BinaryWriter: typeof import('toiljs/io').BinaryWriter;\n` +
|
|
18
41
|
`declare const BinaryReader: typeof import('toiljs/io').BinaryReader;\n` +
|
|
19
42
|
`declare const FastMap: typeof import('toiljs/io').FastMap;\n` +
|
|
20
|
-
`declare const FastSet: typeof import('toiljs/io').FastSet;\n
|
|
43
|
+
`declare const FastSet: typeof import('toiljs/io').FastSet;\n` +
|
|
44
|
+
`\n` +
|
|
45
|
+
`${STYLE_MODULES}\n` +
|
|
46
|
+
`\n` +
|
|
47
|
+
`${ASSET_MODULES}\n` +
|
|
48
|
+
`\n` +
|
|
49
|
+
`declare module 'toiljs/routes' {\n` +
|
|
50
|
+
` export const routes: import('toiljs/client').RouteDef[];\n` +
|
|
51
|
+
` export const layout: import('toiljs/client').LayoutLoader;\n` +
|
|
52
|
+
` export const notFound: import('toiljs/client').NotFoundLoader;\n` +
|
|
53
|
+
`}\n`;
|
|
21
54
|
|
|
22
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* Returns a `./`-prefixed, **extensionless** POSIX module specifier from `.toil` to `abs`, for use
|
|
57
|
+
* in generated `import(...)` calls. Extensionless so TypeScript doesn't demand
|
|
58
|
+
* `allowImportingTsExtensions` (TS5097) when the generated files are checked; Vite still resolves it.
|
|
59
|
+
*/
|
|
23
60
|
function relFromToil(cfg: ResolvedToilConfig, abs: string): string {
|
|
24
|
-
let rel = path.relative(cfg.toilDir, abs).replace(/\\/g, '/');
|
|
61
|
+
let rel = path.relative(cfg.toilDir, abs).replace(/\\/g, '/').replace(/\.(tsx|jsx)$/, '');
|
|
25
62
|
if (!rel.startsWith('.')) rel = './' + rel;
|
|
26
63
|
return rel;
|
|
27
64
|
}
|
|
@@ -39,8 +76,57 @@ function findNotFound(cfg: ResolvedToilConfig): string | undefined {
|
|
|
39
76
|
.find((p) => fs.existsSync(p));
|
|
40
77
|
}
|
|
41
78
|
|
|
79
|
+
/** Finds the user-owned app entry at `client/toil.{tsx,jsx}` (where `mount` is called). */
|
|
80
|
+
function findEntry(cfg: ResolvedToilConfig): string | undefined {
|
|
81
|
+
return ['toil.tsx', 'toil.jsx']
|
|
82
|
+
.map((name) => path.join(cfg.clientAbsDir, name))
|
|
83
|
+
.find((p) => fs.existsSync(p));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** A `layout.{tsx,jsx}` in `dir`, or undefined. */
|
|
87
|
+
function layoutIn(dir: string): string | undefined {
|
|
88
|
+
return ['layout.tsx', 'layout.jsx']
|
|
89
|
+
.map((name) => path.join(dir, name))
|
|
90
|
+
.find((p) => fs.existsSync(p));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Nested layout chain for a route file: `layout.{tsx,jsx}` at the routes root and each ancestor
|
|
95
|
+
* directory down to the file's own, shallowest → deepest. (The project root `client/layout.tsx`
|
|
96
|
+
* is handled separately as the top-level layout.)
|
|
97
|
+
*/
|
|
98
|
+
function findLayoutChain(cfg: ResolvedToilConfig, routeFile: string): string[] {
|
|
99
|
+
const relDir = path.dirname(path.relative(cfg.routesAbsDir, routeFile));
|
|
100
|
+
const segments = relDir === '.' ? [] : relDir.split(path.sep);
|
|
101
|
+
const chain: string[] = [];
|
|
102
|
+
let dir = cfg.routesAbsDir;
|
|
103
|
+
for (let i = 0; i <= segments.length; i++) {
|
|
104
|
+
if (i > 0) dir = path.join(dir, segments[i - 1]);
|
|
105
|
+
const layout = layoutIn(dir);
|
|
106
|
+
if (layout) chain.push(layout);
|
|
107
|
+
}
|
|
108
|
+
return chain;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Nearest special file named `base` (e.g. `loading`/`error`) from the route's dir up to the routes root. */
|
|
112
|
+
function findNearest(cfg: ResolvedToilConfig, routeFile: string, base: string): string | undefined {
|
|
113
|
+
const root = path.resolve(cfg.routesAbsDir);
|
|
114
|
+
let dir = path.dirname(routeFile);
|
|
115
|
+
for (;;) {
|
|
116
|
+
const found = [`${base}.tsx`, `${base}.jsx`]
|
|
117
|
+
.map((name) => path.join(dir, name))
|
|
118
|
+
.find((p) => fs.existsSync(p));
|
|
119
|
+
if (found) return found;
|
|
120
|
+
if (path.resolve(dir) === root) return undefined;
|
|
121
|
+
const parent = path.dirname(dir);
|
|
122
|
+
if (parent === dir) return undefined;
|
|
123
|
+
dir = parent;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
42
127
|
/**
|
|
43
|
-
* Generates the `.toil/` working dir (routes table, mount entry, HTML
|
|
128
|
+
* Generates the `.toil/` working dir (routes table, mount entry, the HTML entry built from the
|
|
129
|
+
* project's `public/index.html` template, and mirrored `public/` assets) and returns the scanned
|
|
44
130
|
* routes. Called before every dev/build and on route add/remove during dev.
|
|
45
131
|
*/
|
|
46
132
|
export function generate(cfg: ResolvedToilConfig): ScannedRoute[] {
|
|
@@ -50,40 +136,111 @@ export function generate(cfg: ResolvedToilConfig): ScannedRoute[] {
|
|
|
50
136
|
const layoutFile = findLayout(cfg);
|
|
51
137
|
const notFoundFile = findNotFound(cfg);
|
|
52
138
|
const routesSrc =
|
|
139
|
+
`// @ts-nocheck\n` +
|
|
53
140
|
`// AUTO-GENERATED by toil — do not edit.\n` +
|
|
54
141
|
`import type { RouteDef, LayoutLoader, NotFoundLoader } from 'toiljs/client';\n\n` +
|
|
55
142
|
`export const routes: RouteDef[] = [\n` +
|
|
56
143
|
routes
|
|
57
|
-
.map(
|
|
58
|
-
(
|
|
59
|
-
|
|
60
|
-
|
|
144
|
+
.map((r) => {
|
|
145
|
+
const imp = (f: string): string => `() => import(${JSON.stringify(relFromToil(cfg, f))})`;
|
|
146
|
+
const layouts = findLayoutChain(cfg, r.file).map(imp).join(', ');
|
|
147
|
+
const parts = [
|
|
148
|
+
`pattern: ${JSON.stringify(r.pattern)}`,
|
|
149
|
+
`load: ${imp(r.file)}`,
|
|
150
|
+
`layouts: [${layouts}]`,
|
|
151
|
+
];
|
|
152
|
+
const loadingFile = findNearest(cfg, r.file, 'loading');
|
|
153
|
+
if (loadingFile) parts.push(`loading: ${imp(loadingFile)}`);
|
|
154
|
+
const errorFile = findNearest(cfg, r.file, 'error');
|
|
155
|
+
if (errorFile) parts.push(`errorComponent: ${imp(errorFile)}`);
|
|
156
|
+
return ` { ${parts.join(', ')} },`;
|
|
157
|
+
})
|
|
61
158
|
.join('\n') +
|
|
62
159
|
`\n];\n\n` +
|
|
63
160
|
`export const layout: LayoutLoader = ${layoutFile ? `() => import(${JSON.stringify(relFromToil(cfg, layoutFile))})` : 'null'};\n` +
|
|
64
161
|
`export const notFound: NotFoundLoader = ${notFoundFile ? `() => import(${JSON.stringify(relFromToil(cfg, notFoundFile))})` : 'null'};\n`;
|
|
65
162
|
fs.writeFileSync(path.join(cfg.toilDir, 'routes.ts'), routesSrc);
|
|
66
163
|
|
|
67
|
-
const
|
|
164
|
+
const globalsSrc =
|
|
165
|
+
`// @ts-nocheck\n` +
|
|
68
166
|
`// AUTO-GENERATED by toil — do not edit.\n` +
|
|
69
|
-
`import
|
|
70
|
-
`import { BinaryWriter, BinaryReader, FastMap, FastSet } from 'toiljs/io';\n` +
|
|
71
|
-
`
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
167
|
+
`import * as Toil from 'toiljs/client';\n` +
|
|
168
|
+
`import { BinaryWriter, BinaryReader, FastMap, FastSet } from 'toiljs/io';\n\n` +
|
|
169
|
+
`Object.assign(globalThis, { Toil, BinaryWriter, BinaryReader, FastMap, FastSet });\n`;
|
|
170
|
+
fs.writeFileSync(path.join(cfg.toilDir, 'globals.ts'), globalsSrc);
|
|
171
|
+
|
|
172
|
+
const entryFile = findEntry(cfg);
|
|
173
|
+
const entrySrc = entryFile
|
|
174
|
+
? `// @ts-nocheck\n` +
|
|
175
|
+
`// AUTO-GENERATED by toil — do not edit.\n` +
|
|
176
|
+
`import './globals';\n` +
|
|
177
|
+
`import ${JSON.stringify(relFromToil(cfg, entryFile))};\n`
|
|
178
|
+
: `// @ts-nocheck\n` +
|
|
179
|
+
`// AUTO-GENERATED by toil — do not edit.\n` +
|
|
180
|
+
`import './globals';\n` +
|
|
181
|
+
`import { mount } from 'toiljs/client';\n` +
|
|
182
|
+
`import { routes, layout, notFound } from './routes';\n\n` +
|
|
183
|
+
`mount(routes, layout, notFound);\n`;
|
|
75
184
|
fs.writeFileSync(path.join(cfg.toilDir, 'entry.tsx'), entrySrc);
|
|
76
185
|
|
|
77
|
-
// Ambient global types (see TOIL_ENV_DTS). Regenerated each dev/build; also written by
|
|
78
|
-
// `toiljs create` so a fresh project type-checks before its first build.
|
|
79
186
|
fs.writeFileSync(path.join(cfg.root, 'toil-env.d.ts'), TOIL_ENV_DTS);
|
|
80
187
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
` <title>Toil App</title>\n </head>\n <body>\n <div id="root"></div>\n` +
|
|
85
|
-
` <script type="module" src="./entry.tsx"></script>\n </body>\n</html>\n`;
|
|
86
|
-
fs.writeFileSync(path.join(cfg.toilDir, 'index.html'), htmlSrc);
|
|
188
|
+
fs.writeFileSync(path.join(cfg.toilDir, 'index.html'), buildHtml(cfg));
|
|
189
|
+
syncPublicAssets(cfg);
|
|
190
|
+
writeDocs(cfg.toilDir);
|
|
87
191
|
|
|
88
192
|
return routes;
|
|
89
193
|
}
|
|
194
|
+
|
|
195
|
+
/** Fallback HTML when the project has no `public/index.html` template. The entry script is added
|
|
196
|
+
* by {@link buildHtml}. */
|
|
197
|
+
const DEFAULT_HTML =
|
|
198
|
+
`<!doctype html>\n<html lang="en">\n <head>\n <meta charset="utf-8" />\n` +
|
|
199
|
+
` <meta name="viewport" content="width=device-width, initial-scale=1" />\n` +
|
|
200
|
+
` <meta name="description" content="" />\n` +
|
|
201
|
+
` <title>Toil App</title>\n </head>\n <body>\n <div id="root"></div>\n` +
|
|
202
|
+
` </body>\n</html>\n`;
|
|
203
|
+
|
|
204
|
+
/** The module entry that boots the app, injected into the HTML (resolved relative to `.toil`). */
|
|
205
|
+
const ENTRY_SCRIPT = `<script type="module" src="./entry.tsx"></script>`;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Produces the `.toil/index.html` Vite entry from the project's `public/index.html` template (or
|
|
209
|
+
* the built-in default if absent), ensuring the generated module entry script is present. Users
|
|
210
|
+
* own the template — toil only guarantees the entry is wired, so it stays the SPA root.
|
|
211
|
+
*/
|
|
212
|
+
function buildHtml(cfg: ResolvedToilConfig): string {
|
|
213
|
+
const templatePath = path.join(cfg.publicDir, 'index.html');
|
|
214
|
+
let html = fs.existsSync(templatePath)
|
|
215
|
+
? fs.readFileSync(templatePath, 'utf8')
|
|
216
|
+
: DEFAULT_HTML;
|
|
217
|
+
// Inject the entry only if the template doesn't already reference it as a module script
|
|
218
|
+
// (matching the literal filename anywhere in the file would be too eager).
|
|
219
|
+
if (!/src=["']\.\/entry\.tsx["']/.test(html)) {
|
|
220
|
+
html = html.includes('</body>')
|
|
221
|
+
? html.replace('</body>', ` ${ENTRY_SCRIPT}\n </body>`)
|
|
222
|
+
: `${html}\n${ENTRY_SCRIPT}\n`;
|
|
223
|
+
}
|
|
224
|
+
return html;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Mirrors the project's `public/` assets into `.toil/public/` (Vite's publicDir under the `.toil`
|
|
229
|
+
* root), excluding the `index.html` template — that is processed into the entry above, and copying
|
|
230
|
+
* it here would clobber the built, asset-hashed page. Cleared each run so deletions propagate.
|
|
231
|
+
*/
|
|
232
|
+
function syncPublicAssets(cfg: ResolvedToilConfig): void {
|
|
233
|
+
const dest = path.join(cfg.toilDir, 'public');
|
|
234
|
+
fs.rmSync(dest, { recursive: true, force: true });
|
|
235
|
+
if (!fs.existsSync(cfg.publicDir)) return;
|
|
236
|
+
|
|
237
|
+
let copied = 0;
|
|
238
|
+
for (const entry of fs.readdirSync(cfg.publicDir, { withFileTypes: true })) {
|
|
239
|
+
if (entry.name === 'index.html') continue;
|
|
240
|
+
fs.cpSync(path.join(cfg.publicDir, entry.name), path.join(dest, entry.name), {
|
|
241
|
+
recursive: true,
|
|
242
|
+
});
|
|
243
|
+
copied++;
|
|
244
|
+
}
|
|
245
|
+
if (copied === 0) fs.rmSync(dest, { recursive: true, force: true });
|
|
246
|
+
}
|
package/src/compiler/index.ts
CHANGED
|
@@ -17,7 +17,7 @@ export interface ToilCommandOptions {
|
|
|
17
17
|
export async function dev(opts: ToilCommandOptions = {}): Promise<ViteDevServer> {
|
|
18
18
|
const cfg = await loadConfig(opts);
|
|
19
19
|
generate(cfg);
|
|
20
|
-
const server = await createServer(createViteConfig(cfg));
|
|
20
|
+
const server = await createServer(await createViteConfig(cfg));
|
|
21
21
|
await server.listen();
|
|
22
22
|
server.printUrls();
|
|
23
23
|
return server;
|
|
@@ -27,7 +27,7 @@ export async function dev(opts: ToilCommandOptions = {}): Promise<ViteDevServer>
|
|
|
27
27
|
export async function build(opts: ToilCommandOptions = {}): Promise<void> {
|
|
28
28
|
const cfg = await loadConfig(opts);
|
|
29
29
|
generate(cfg);
|
|
30
|
-
await viteBuild(createViteConfig(cfg));
|
|
30
|
+
await viteBuild(await createViteConfig(cfg));
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/**
|
|
@@ -44,7 +44,9 @@ export async function start(opts: ToilCommandOptions = {}): Promise<RunningBacke
|
|
|
44
44
|
return startBackend({ root: outDir, port: cfg.port });
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
export { defineConfig } from './config.js';
|
|
47
|
+
export { defineConfig, loadConfig } from './config.js';
|
|
48
48
|
export { TOIL_ENV_DTS } from './generate.js';
|
|
49
|
-
export
|
|
49
|
+
export { AI_HELPERS, AI_HELPER_IDS, aiHelperFiles, TOIL_DOCS } from './docs.js';
|
|
50
|
+
export type { AiHelper } from './docs.js';
|
|
51
|
+
export type { ToilConfig, ResolvedToilConfig } from './config.js';
|
|
50
52
|
export type { RunningBackend, BackendOptions } from 'toiljs/backend';
|
package/src/compiler/plugin.ts
CHANGED
|
@@ -11,9 +11,30 @@ import { generate } from './generate.js';
|
|
|
11
11
|
export function toilPlugin(cfg: ResolvedToilConfig): Plugin {
|
|
12
12
|
return {
|
|
13
13
|
name: 'toil',
|
|
14
|
+
// Catch empty import specifiers in source and report the file — rolldown otherwise fails
|
|
15
|
+
// resolution with a cryptic "The specifiers must be a non-empty string. Received ''".
|
|
16
|
+
transform(code, id) {
|
|
17
|
+
const file = id.split('?')[0];
|
|
18
|
+
if (id.includes('\0') || file.includes('/node_modules/') || !/\.[mc]?[jt]sx?$/.test(file)) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const empty =
|
|
22
|
+
/^[ \t]*import\s+(['"])\1\s*;?[ \t]*$/m.test(code) ||
|
|
23
|
+
/^[ \t]*import\b[^'"\n]*\bfrom\s+(['"])\1/m.test(code) ||
|
|
24
|
+
/^[ \t]*export\b[^'"\n]*\bfrom\s+(['"])\1/m.test(code) ||
|
|
25
|
+
/\bimport\s*\(\s*(['"])\1\s*\)/.test(code);
|
|
26
|
+
if (empty) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
`toil: empty import specifier (e.g. \`import '';\`) in ${file} — remove or complete the import.`,
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
},
|
|
14
33
|
configureServer(server) {
|
|
34
|
+
// Trailing slash so a sibling like `routes-extra/` doesn't match the `routes/` prefix.
|
|
35
|
+
const routesPrefix = cfg.routesAbsDir.replace(/\\/g, '/').replace(/\/?$/, '/');
|
|
15
36
|
const onChange = (file: string): void => {
|
|
16
|
-
if (file.replace(/\\/g, '/').startsWith(
|
|
37
|
+
if (file.replace(/\\/g, '/').startsWith(routesPrefix)) {
|
|
17
38
|
generate(cfg);
|
|
18
39
|
server.ws.send({ type: 'full-reload' });
|
|
19
40
|
}
|
package/src/compiler/routes.ts
CHANGED
|
@@ -8,14 +8,18 @@ export interface ScannedRoute {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
const ROUTE_EXT = /\.(tsx|jsx)$/;
|
|
11
|
+
/** Special files that live alongside routes but are not themselves pages. */
|
|
12
|
+
const SPECIAL_FILE = /^(layout|loading|error|404|not-found)\.(tsx|jsx)$/;
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* Derives a route pattern from a route file path (relative to the routes dir).
|
|
14
16
|
* index.tsx -> /
|
|
15
17
|
* about.tsx -> /about
|
|
16
18
|
* blog/index.tsx -> /blog
|
|
17
|
-
* blog/[id].tsx
|
|
18
|
-
* docs/[...slug].tsx
|
|
19
|
+
* blog/[id].tsx -> /blog/:id
|
|
20
|
+
* docs/[...slug].tsx -> /docs/*slug (catch-all)
|
|
21
|
+
* docs/[[...slug]].tsx -> /docs/**slug (optional catch-all)
|
|
22
|
+
* (marketing)/about.tsx -> /about (route group: parens add no URL segment)
|
|
19
23
|
*/
|
|
20
24
|
export function filePathToRoute(relPath: string): string {
|
|
21
25
|
const withoutExt = relPath.replace(/\\/g, '/').replace(ROUTE_EXT, '');
|
|
@@ -23,11 +27,13 @@ export function filePathToRoute(relPath: string): string {
|
|
|
23
27
|
const out: string[] = [];
|
|
24
28
|
for (let i = 0; i < segments.length; i++) {
|
|
25
29
|
const segment = segments[i];
|
|
30
|
+
if (/^\(.+\)$/.test(segment)) continue;
|
|
26
31
|
if (segment === 'index' && i === segments.length - 1) continue;
|
|
27
32
|
out.push(
|
|
28
33
|
segment
|
|
29
|
-
.replace(/^\[\.\.\.(.+)\]$/, '
|
|
30
|
-
.replace(/^\[(.+)\]$/, '
|
|
34
|
+
.replace(/^\[\[\.\.\.(.+)\]\]$/, '**$1')
|
|
35
|
+
.replace(/^\[\.\.\.(.+)\]$/, '*$1')
|
|
36
|
+
.replace(/^\[(.+)\]$/, ':$1'),
|
|
31
37
|
);
|
|
32
38
|
}
|
|
33
39
|
return '/' + out.join('/');
|
|
@@ -41,8 +47,8 @@ function specificity(pattern: string): number {
|
|
|
41
47
|
const segments = pattern.split('/').filter(Boolean);
|
|
42
48
|
let score = segments.length * 10;
|
|
43
49
|
for (const segment of segments) {
|
|
44
|
-
if (segment.startsWith('*')) score -= 5;
|
|
45
|
-
else if (!segment.startsWith(':')) score += 5;
|
|
50
|
+
if (segment.startsWith('*')) score -= 5;
|
|
51
|
+
else if (!segment.startsWith(':')) score += 5;
|
|
46
52
|
}
|
|
47
53
|
return score;
|
|
48
54
|
}
|
|
@@ -56,7 +62,7 @@ export function scanRoutes(routesDir: string): ScannedRoute[] {
|
|
|
56
62
|
const full = path.join(dir, entry.name);
|
|
57
63
|
if (entry.isDirectory()) {
|
|
58
64
|
walk(full);
|
|
59
|
-
} else if (ROUTE_EXT.test(entry.name)) {
|
|
65
|
+
} else if (ROUTE_EXT.test(entry.name) && !SPECIAL_FILE.test(entry.name)) {
|
|
60
66
|
found.push({
|
|
61
67
|
file: full,
|
|
62
68
|
pattern: filePathToRoute(path.relative(routesDir, full)),
|