toiljs 0.0.15 → 0.0.16
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/.babelrc +13 -13
- package/.gitattributes +2 -2
- package/.github/ISSUE_TEMPLATE/bug_report.md +38 -38
- package/.github/ISSUE_TEMPLATE/bug_report.yml +90 -90
- package/.github/ISSUE_TEMPLATE/config.yml +8 -8
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -20
- package/.github/PULL_REQUEST_TEMPLATE.md +43 -43
- package/.github/changelog-config.json +45 -45
- package/.github/dependabot.yml +27 -27
- package/.github/workflows/ci.yml +191 -191
- package/.prettierrc.json +11 -11
- package/.vscode/settings.json +9 -9
- package/CHANGELOG.md +5 -5
- package/LICENSE +187 -187
- package/README.md +339 -315
- package/as-pect.asconfig.json +34 -34
- package/as-pect.config.js +65 -65
- package/assets/logo.svg +36 -36
- package/build/backend/.tsbuildinfo +1 -1
- package/build/cli/.tsbuildinfo +1 -1
- package/build/cli/index.js +0 -0
- package/build/client/.tsbuildinfo +1 -1
- package/build/client/dev/devtools.d.ts +6 -0
- package/build/client/dev/devtools.js +442 -0
- package/build/client/dev/error-overlay.d.ts +9 -0
- package/build/client/dev/error-overlay.js +19 -4
- package/build/client/navigation/prefetch.d.ts +1 -0
- package/build/client/navigation/prefetch.js +35 -0
- package/build/client/routing/Router.js +1 -1
- package/build/client/routing/hooks.js +6 -2
- package/build/client/routing/loader.d.ts +23 -0
- package/build/client/routing/loader.js +53 -7
- package/build/client/routing/mount.js +4 -3
- package/build/compiler/.tsbuildinfo +1 -1
- package/build/compiler/config.d.ts +16 -0
- package/build/compiler/config.js +7 -0
- package/build/compiler/docs.js +16 -16
- package/build/compiler/index.d.ts +2 -2
- package/build/compiler/index.js +1 -1
- package/build/compiler/plugin.js +156 -0
- package/build/compiler/prerender.d.ts +1 -0
- package/build/compiler/prerender.js +1 -1
- package/build/compiler/seo.d.ts +1 -1
- package/build/compiler/seo.js +5 -4
- package/build/compiler/ssg.js +32 -1
- package/build/io/.tsbuildinfo +1 -1
- package/build/logger/.tsbuildinfo +1 -1
- package/build/shared/.tsbuildinfo +1 -1
- package/eslint.config.js +48 -48
- package/examples/basic/client/404.tsx +11 -11
- package/examples/basic/client/components/.gitkeep +1 -1
- package/examples/basic/client/global-error.tsx +13 -13
- package/examples/basic/client/layout.tsx +25 -25
- package/examples/basic/client/public/images/.gitkeep +1 -1
- package/examples/basic/client/public/images/logo.svg +36 -36
- package/examples/basic/client/public/robots.txt +2 -2
- package/examples/basic/client/routes/docs/[...slug].tsx +12 -12
- package/examples/basic/client/routes/features/error/error.tsx +16 -16
- package/examples/basic/client/routes/features/template/b.tsx +14 -14
- package/examples/basic/client/routes/files/[[...slug]].tsx +21 -21
- package/examples/basic/client/routes/gallery/layout.tsx +13 -13
- package/examples/basic/client/routes/io.tsx +24 -24
- package/examples/basic/client/routes/loader-demo/loading.tsx +13 -13
- package/examples/basic/client/routes/search.tsx +61 -61
- package/examples/basic/client/toil.tsx +5 -5
- package/package.json +155 -148
- package/presets/eslint.js +88 -88
- package/presets/no-uint8array-tostring.js +200 -200
- package/presets/prettier.json +18 -18
- package/presets/tsconfig.json +37 -37
- package/src/backend/index.ts +160 -160
- package/src/cli/proc.ts +50 -50
- package/src/cli/updates.ts +69 -69
- package/src/cli/validate.ts +31 -31
- package/src/client/channel/channel.ts +146 -146
- package/src/client/components/Form.tsx +65 -65
- package/src/client/components/Script.tsx +113 -113
- package/src/client/components/Slot.tsx +21 -21
- package/src/client/dev/devtools.tsx +973 -0
- package/src/client/dev/error-overlay.tsx +30 -4
- package/src/client/head/head.ts +167 -167
- package/src/client/head/metadata.ts +112 -112
- package/src/client/index.ts +89 -89
- package/src/client/navigation/NavLink.tsx +86 -86
- package/src/client/navigation/navigation.ts +235 -235
- package/src/client/navigation/prefetch.ts +169 -130
- package/src/client/navigation/scroll.ts +53 -53
- package/src/client/routing/Router.tsx +8 -2
- package/src/client/routing/action.ts +122 -122
- package/src/client/routing/error-boundary.tsx +43 -43
- package/src/client/routing/hooks.ts +21 -6
- package/src/client/routing/loader.ts +325 -235
- package/src/client/routing/match.ts +47 -47
- package/src/client/routing/mount.tsx +54 -52
- package/src/client/routing/params-context.ts +10 -10
- package/src/client/routing/slot-context.ts +7 -7
- package/src/client/search/search.ts +189 -189
- package/src/client/search/use-page-search.ts +73 -73
- package/src/client/types.ts +73 -73
- package/src/compiler/config.ts +219 -182
- package/src/compiler/docs.ts +228 -228
- package/src/compiler/generate.ts +394 -394
- package/src/compiler/index.ts +64 -57
- package/src/compiler/pages.ts +70 -70
- package/src/compiler/plugin.ts +170 -2
- package/src/compiler/prerender.ts +156 -156
- package/src/compiler/seo.ts +397 -390
- package/src/compiler/ssg.ts +162 -126
- package/src/io/BinaryReader.ts +340 -340
- package/src/io/BinaryWriter.ts +385 -385
- package/src/io/FastMap.ts +127 -127
- package/src/io/index.ts +11 -11
- package/src/io/lengths.ts +14 -14
- package/src/io/types.ts +18 -18
- package/src/logger/index.ts +22 -22
- package/src/server/index.ts +10 -10
- package/src/server/main.ts +13 -13
- package/src/server/tsconfig.json +4 -4
- package/src/shared/index.ts +10 -10
- package/std/client/index.d.ts +15 -15
- package/std/client/package.json +3 -3
- package/test/assembly/example.spec.ts +7 -7
- package/test/channel.test.ts +21 -21
- package/test/dom/Link.test.tsx +47 -47
- package/test/dom/NavLink.test.tsx +37 -37
- package/test/dom/error-overlay.test.tsx +44 -44
- package/test/dom/loader.test.tsx +121 -121
- package/test/dom/navigation.test.ts +59 -59
- package/test/dom/revalidate.test.tsx +38 -38
- package/test/dom/route-head.test.tsx +78 -78
- package/test/dom/router-loading.test.tsx +44 -44
- package/test/dom/scroll.test.ts +56 -56
- package/test/dom/use-metadata.test.tsx +58 -58
- package/test/io.test.ts +93 -93
- package/test/navlink.test.ts +28 -28
- package/test/placeholder.test.ts +9 -9
- package/test/routes.test.ts +76 -76
- package/test/seo.test.ts +175 -164
- package/test/slot-layouts.test.ts +69 -69
- package/test/ssg.test.ts +36 -36
- package/test/update.test.ts +44 -44
- package/test/validate.test.ts +42 -42
- package/toil-routes.d.ts +7 -0
- package/toilconfig.json +30 -30
- package/tsconfig.backend.json +13 -13
- package/tsconfig.base.json +35 -35
- package/tsconfig.cli.json +13 -13
- package/tsconfig.client.json +14 -14
- package/tsconfig.compiler.json +13 -13
- package/tsconfig.io.json +12 -12
- package/tsconfig.json +22 -22
- package/tsconfig.logger.json +12 -12
- package/tsconfig.server.json +10 -10
- package/tsconfig.shared.json +12 -12
- package/vitest.config.ts +26 -26
- package/.idea/codeStyles/Project.xml +0 -54
- package/.idea/codeStyles/codeStyleConfig.xml +0 -5
- package/.idea/inspectionProfiles/Project_Default.xml +0 -6
- package/.idea/modules.xml +0 -8
- package/.idea/prettier.xml +0 -7
- package/.idea/toiljs.iml +0 -8
- package/.idea/vcs.xml +0 -6
- package/.toil/entry.tsx +0 -9
- package/.toil/index.html +0 -12
- package/.toil/routes.ts +0 -9
- package/build/cli/configure.d.ts +0 -16
- package/build/cli/configure.js +0 -272
- package/build/cli/create.d.ts +0 -16
- package/build/cli/create.js +0 -420
- package/build/cli/diagnostics.d.ts +0 -55
- package/build/cli/diagnostics.js +0 -333
- package/build/cli/doctor.d.ts +0 -6
- package/build/cli/doctor.js +0 -249
- package/build/cli/features.d.ts +0 -25
- package/build/cli/features.js +0 -107
- package/build/cli/index.d.ts +0 -2
- package/build/cli/proc.d.ts +0 -6
- package/build/cli/proc.js +0 -31
- package/build/cli/ui.d.ts +0 -9
- package/build/cli/ui.js +0 -75
- package/build/cli/update.d.ts +0 -7
- package/build/cli/update.js +0 -117
- package/build/cli/updates.d.ts +0 -10
- package/build/cli/updates.js +0 -45
- package/build/cli/validate.d.ts +0 -4
- package/build/cli/validate.js +0 -19
- package/build/client/Link.d.ts +0 -8
- package/build/client/Link.js +0 -44
- package/build/client/NavLink.d.ts +0 -14
- package/build/client/NavLink.js +0 -37
- package/build/client/Router.d.ts +0 -7
- package/build/client/Router.js +0 -55
- package/build/client/channel.d.ts +0 -23
- package/build/client/channel.js +0 -94
- package/build/client/error-boundary.d.ts +0 -16
- package/build/client/error-boundary.js +0 -19
- package/build/client/head.d.ts +0 -26
- package/build/client/head.js +0 -87
- package/build/client/hooks.d.ts +0 -17
- package/build/client/hooks.js +0 -48
- package/build/client/lazy.d.ts +0 -16
- package/build/client/lazy.js +0 -53
- package/build/client/match.d.ts +0 -2
- package/build/client/match.js +0 -32
- package/build/client/mount.d.ts +0 -2
- package/build/client/mount.js +0 -13
- package/build/client/navigation.d.ts +0 -13
- package/build/client/navigation.js +0 -97
- package/build/client/params-context.d.ts +0 -2
- package/build/client/params-context.js +0 -2
- package/build/client/prefetch.d.ts +0 -11
- package/build/client/prefetch.js +0 -100
- package/build/client/runtime.d.ts +0 -31
- package/build/client/runtime.js +0 -112
- package/build/client/scroll.d.ts +0 -8
- package/build/client/scroll.js +0 -36
- package/toil-env.d.ts +0 -16
package/src/compiler/docs.ts
CHANGED
|
@@ -1,228 +1,228 @@
|
|
|
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
|
-
/** A doc file's contents from an array of lines (single-quoted, so backticks/`${}` stay literal). */
|
|
72
|
-
function doc(lines: string[]): string {
|
|
73
|
-
return lines.join('\n') + '\n';
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export const TOIL_DOCS: Record<string, string> = {
|
|
77
|
-
'index.md': doc([
|
|
78
|
-
'# toiljs',
|
|
79
|
-
'',
|
|
80
|
-
'A full-stack React framework: a Vite-bundled client SPA with file-based routing, plus a',
|
|
81
|
-
'toilscript-to-WebAssembly server target.',
|
|
82
|
-
'',
|
|
83
|
-
'## Project layout',
|
|
84
|
-
'',
|
|
85
|
-
'- `client/`, the app: `routes/` (file-based), `layout.tsx`, `components/`, `styles/`,',
|
|
86
|
-
' `public/`, and `toil.tsx` (the entry that calls `Toil.mount`).',
|
|
87
|
-
'- `server/`, the toilscript → WASM target (`@main` entry), compiled by `toilscript`.',
|
|
88
|
-
'- `toil.config.ts`, configuration via `defineConfig` (`toiljs.config.ts` also works).',
|
|
89
|
-
'- Generated, gitignored, do not edit: `.toil/` (working dir), `toil-env.d.ts` (ambient',
|
|
90
|
-
' globals), `toil-routes.d.ts` (typed routes).',
|
|
91
|
-
'',
|
|
92
|
-
'## Key ideas',
|
|
93
|
-
'',
|
|
94
|
-
'- `Toil` is a native global (no import): `Toil.Link`, `Toil.useRouter`, `Toil.useLoaderData`,',
|
|
95
|
-
' etc. The IO classes (`BinaryWriter`, `BinaryReader`, `FastMap`, `FastSet`) are globals too.',
|
|
96
|
-
'- Scripts: `npm run dev` (HMR), `npm run build` (→ `build/client` + `build/server`),',
|
|
97
|
-
' `npm start` (self-host the build).',
|
|
98
|
-
'',
|
|
99
|
-
'See `routing.md`, `client.md`, `styling.md`, `server.md`, `cli.md`.',
|
|
100
|
-
]),
|
|
101
|
-
'routing.md': doc([
|
|
102
|
-
'# Routing',
|
|
103
|
-
'',
|
|
104
|
-
'File-based, under `client/routes/`. A file path maps to a URL.',
|
|
105
|
-
'',
|
|
106
|
-
'## Route files',
|
|
107
|
-
'',
|
|
108
|
-
'- `index.tsx` → `/`, `about.tsx` → `/about`, `blog/index.tsx` → `/blog`',
|
|
109
|
-
'- `[id].tsx` → dynamic `/:id`, read with `Toil.useParams<{ id: string }>()`',
|
|
110
|
-
'- `[...slug].tsx` → catch-all (1+ segments); `[[...slug]].tsx` → optional catch-all (0+)',
|
|
111
|
-
'- `(group)/` → route group: groups files / scopes a layout, adds no URL segment',
|
|
112
|
-
'',
|
|
113
|
-
'## Special files',
|
|
114
|
-
'',
|
|
115
|
-
'- `layout.tsx`, wraps the routes beneath it. Root `client/layout.tsx` wraps everything;',
|
|
116
|
-
' nested `routes/**/layout.tsx` compose inside it.',
|
|
117
|
-
'- `loading.tsx`, Suspense fallback shown while a route (chunk + loader) loads',
|
|
118
|
-
'- `error.tsx`, error boundary; receives `{ error, reset }` (`Toil.RouteErrorProps`)',
|
|
119
|
-
'- `client/404.tsx`, shown when no route matches',
|
|
120
|
-
'',
|
|
121
|
-
'## Data loaders',
|
|
122
|
-
'',
|
|
123
|
-
'Export `loader` from a route; it runs on navigation, in parallel with the chunk, and the',
|
|
124
|
-
'page suspends until it resolves (so `loading.tsx` shows). Read it with `useLoaderData`:',
|
|
125
|
-
'',
|
|
126
|
-
' export const loader = async ({ params, searchParams }: Toil.LoaderArgs) => {',
|
|
127
|
-
' return fetch(`/api/post/${params.id}`).then((r) => r.json());',
|
|
128
|
-
' };',
|
|
129
|
-
' export default function Post() {',
|
|
130
|
-
' const post = Toil.useLoaderData<{ title: string }>();',
|
|
131
|
-
' return <h1>{post.title}</h1>;',
|
|
132
|
-
' }',
|
|
133
|
-
'',
|
|
134
|
-
'`Toil.useRouter().refresh()` re-runs loaders.',
|
|
135
|
-
'',
|
|
136
|
-
'## Navigation',
|
|
137
|
-
'',
|
|
138
|
-
'- `Toil.Link` / `Toil.NavLink` (adds an active class) / `Toil.useRouter()`',
|
|
139
|
-
' (push / replace / back / forward / refresh / prefetch)',
|
|
140
|
-
'- `Toil.useParams`, `usePathname`, `useSearchParams`, `useNavigationPending`',
|
|
141
|
-
'- Hrefs are type-checked against your routes, a typo is a compile error.',
|
|
142
|
-
]),
|
|
143
|
-
'client.md': doc([
|
|
144
|
-
'# Client runtime',
|
|
145
|
-
'',
|
|
146
|
-
'Everything is on the `Toil` global, no imports needed in route files.',
|
|
147
|
-
'',
|
|
148
|
-
'## Entry',
|
|
149
|
-
'',
|
|
150
|
-
'`client/toil.tsx` imports the route table + global styles and mounts the app:',
|
|
151
|
-
'',
|
|
152
|
-
' import { routes, layout, notFound } from "toiljs/routes";',
|
|
153
|
-
' import "./styles/main.css";',
|
|
154
|
-
' Toil.mount(routes, layout, notFound);',
|
|
155
|
-
'',
|
|
156
|
-
'## API (on `Toil`)',
|
|
157
|
-
'',
|
|
158
|
-
'- Components: `Link`, `NavLink`, `Head`',
|
|
159
|
-
'- Navigation: `navigate`, `useRouter`, `useNavigate`',
|
|
160
|
-
'- Location: `usePathname`, `useSearchParams`, `useParams`, `useNavigationPending`',
|
|
161
|
-
'- Data: `useLoaderData` (see `routing.md`)',
|
|
162
|
-
'- Head: `useHead`, `useTitle`, `<Head>`, set the `<title>` / meta per route',
|
|
163
|
-
'- Realtime: `useChannel`, `connectChannel` (WebSocket to the backend at `/_toil`)',
|
|
164
|
-
'- IO globals (no `Toil.` prefix): `BinaryWriter`, `BinaryReader`, `FastMap`, `FastSet`',
|
|
165
|
-
'',
|
|
166
|
-
'## Head example',
|
|
167
|
-
'',
|
|
168
|
-
' Toil.useHead({',
|
|
169
|
-
' title: "Blog",',
|
|
170
|
-
' titleTemplate: "%s · MyApp",',
|
|
171
|
-
' meta: [{ name: "description", content: "..." }],',
|
|
172
|
-
' });',
|
|
173
|
-
]),
|
|
174
|
-
'styling.md': doc([
|
|
175
|
-
'# Styling',
|
|
176
|
-
'',
|
|
177
|
-
'The app imports one stylesheet from `client/toil.tsx` (e.g. `./styles/main.css`).',
|
|
178
|
-
'',
|
|
179
|
-
'## Preprocessors & Tailwind',
|
|
180
|
-
'',
|
|
181
|
-
'Pick a CSS preprocessor (none / Sass / Less / Stylus) and optionally Tailwind at',
|
|
182
|
-
'`toiljs create`, or change it later on an existing project:',
|
|
183
|
-
'',
|
|
184
|
-
' toiljs configure # interactive',
|
|
185
|
-
' toiljs configure --tailwind # add Tailwind',
|
|
186
|
-
' toiljs configure --style sass # switch preprocessor',
|
|
187
|
-
'',
|
|
188
|
-
'`configure` installs/removes the right packages and rewrites the imports. Tailwind lives',
|
|
189
|
-
'in its own `styles/tailwind.css` (`@import "tailwindcss";`).',
|
|
190
|
-
'',
|
|
191
|
-
'## Imports',
|
|
192
|
-
'',
|
|
193
|
-
'`.css` / `.scss` / `.sass` / `.less` / `.styl` and image imports (`.svg`, `.png`, …) are',
|
|
194
|
-
'typed via `toil-env.d.ts`.',
|
|
195
|
-
]),
|
|
196
|
-
'server.md': doc([
|
|
197
|
-
'# Server (toilscript → WebAssembly)',
|
|
198
|
-
'',
|
|
199
|
-
'`server/` is the toilscript source, compiled to WebAssembly by `toilscript`.',
|
|
200
|
-
'',
|
|
201
|
-
'- `server/main.ts`, the `@main` entry, exported as the WASM `main`.',
|
|
202
|
-
'- `server/index.ts`, your functions.',
|
|
203
|
-
'- `server/tsconfig.json`, extends `toilscript/std/assembly.json` (AssemblyScript/toilscript',
|
|
204
|
-
' globals like `i32`, not the DOM), so editors resolve server types correctly.',
|
|
205
|
-
'- `npm run build:server` (or `npm run build`) emits `build/server/release.wasm`.',
|
|
206
|
-
'',
|
|
207
|
-
'Note: the client↔server bridge (calling WASM exports from the client) is not wired yet.',
|
|
208
|
-
]),
|
|
209
|
-
'cli.md': doc([
|
|
210
|
-
'# CLI',
|
|
211
|
-
'',
|
|
212
|
-
'- `toiljs create [name]`, scaffold a project. Flags: `--template app|minimal`,',
|
|
213
|
-
' `--style css|sass|less|stylus`, `--tailwind`, `--no-ai`, `-y`/`--yes`.',
|
|
214
|
-
'- `toiljs dev`, dev server with HMR (`--port`, `--root`).',
|
|
215
|
-
'- `toiljs build`, production build → `build/client` (chain `toilscript` for the server).',
|
|
216
|
-
'- `toiljs start`, self-host the built app (hyper-express) with a `/_toil` WebSocket channel.',
|
|
217
|
-
'- `toiljs configure`, toggle styling features on an existing project (see `styling.md`).',
|
|
218
|
-
]),
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
/** Writes the framework docs into `<toilDir>/docs/`. Called by `generate` each dev/build. */
|
|
222
|
-
export function writeDocs(toilDir: string): void {
|
|
223
|
-
const dir = path.join(toilDir, 'docs');
|
|
224
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
225
|
-
for (const [name, content] of Object.entries(TOIL_DOCS)) {
|
|
226
|
-
fs.writeFileSync(path.join(dir, name), content);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
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
|
+
/** A doc file's contents from an array of lines (single-quoted, so backticks/`${}` stay literal). */
|
|
72
|
+
function doc(lines: string[]): string {
|
|
73
|
+
return lines.join('\n') + '\n';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export const TOIL_DOCS: Record<string, string> = {
|
|
77
|
+
'index.md': doc([
|
|
78
|
+
'# toiljs',
|
|
79
|
+
'',
|
|
80
|
+
'A full-stack React framework: a Vite-bundled client SPA with file-based routing, plus a',
|
|
81
|
+
'toilscript-to-WebAssembly server target.',
|
|
82
|
+
'',
|
|
83
|
+
'## Project layout',
|
|
84
|
+
'',
|
|
85
|
+
'- `client/`, the app: `routes/` (file-based), `layout.tsx`, `components/`, `styles/`,',
|
|
86
|
+
' `public/`, and `toil.tsx` (the entry that calls `Toil.mount`).',
|
|
87
|
+
'- `server/`, the toilscript → WASM target (`@main` entry), compiled by `toilscript`.',
|
|
88
|
+
'- `toil.config.ts`, configuration via `defineConfig` (`toiljs.config.ts` also works).',
|
|
89
|
+
'- Generated, gitignored, do not edit: `.toil/` (working dir), `toil-env.d.ts` (ambient',
|
|
90
|
+
' globals), `toil-routes.d.ts` (typed routes).',
|
|
91
|
+
'',
|
|
92
|
+
'## Key ideas',
|
|
93
|
+
'',
|
|
94
|
+
'- `Toil` is a native global (no import): `Toil.Link`, `Toil.useRouter`, `Toil.useLoaderData`,',
|
|
95
|
+
' etc. The IO classes (`BinaryWriter`, `BinaryReader`, `FastMap`, `FastSet`) are globals too.',
|
|
96
|
+
'- Scripts: `npm run dev` (HMR), `npm run build` (→ `build/client` + `build/server`),',
|
|
97
|
+
' `npm start` (self-host the build).',
|
|
98
|
+
'',
|
|
99
|
+
'See `routing.md`, `client.md`, `styling.md`, `server.md`, `cli.md`.',
|
|
100
|
+
]),
|
|
101
|
+
'routing.md': doc([
|
|
102
|
+
'# Routing',
|
|
103
|
+
'',
|
|
104
|
+
'File-based, under `client/routes/`. A file path maps to a URL.',
|
|
105
|
+
'',
|
|
106
|
+
'## Route files',
|
|
107
|
+
'',
|
|
108
|
+
'- `index.tsx` → `/`, `about.tsx` → `/about`, `blog/index.tsx` → `/blog`',
|
|
109
|
+
'- `[id].tsx` → dynamic `/:id`, read with `Toil.useParams<{ id: string }>()`',
|
|
110
|
+
'- `[...slug].tsx` → catch-all (1+ segments); `[[...slug]].tsx` → optional catch-all (0+)',
|
|
111
|
+
'- `(group)/` → route group: groups files / scopes a layout, adds no URL segment',
|
|
112
|
+
'',
|
|
113
|
+
'## Special files',
|
|
114
|
+
'',
|
|
115
|
+
'- `layout.tsx`, wraps the routes beneath it. Root `client/layout.tsx` wraps everything;',
|
|
116
|
+
' nested `routes/**/layout.tsx` compose inside it.',
|
|
117
|
+
'- `loading.tsx`, Suspense fallback shown while a route (chunk + loader) loads',
|
|
118
|
+
'- `error.tsx`, error boundary; receives `{ error, reset }` (`Toil.RouteErrorProps`)',
|
|
119
|
+
'- `client/404.tsx`, shown when no route matches',
|
|
120
|
+
'',
|
|
121
|
+
'## Data loaders',
|
|
122
|
+
'',
|
|
123
|
+
'Export `loader` from a route; it runs on navigation, in parallel with the chunk, and the',
|
|
124
|
+
'page suspends until it resolves (so `loading.tsx` shows). Read it with `useLoaderData`:',
|
|
125
|
+
'',
|
|
126
|
+
' export const loader = async ({ params, searchParams }: Toil.LoaderArgs) => {',
|
|
127
|
+
' return fetch(`/api/post/${params.id}`).then((r) => r.json());',
|
|
128
|
+
' };',
|
|
129
|
+
' export default function Post() {',
|
|
130
|
+
' const post = Toil.useLoaderData<{ title: string }>();',
|
|
131
|
+
' return <h1>{post.title}</h1>;',
|
|
132
|
+
' }',
|
|
133
|
+
'',
|
|
134
|
+
'`Toil.useRouter().refresh()` re-runs loaders.',
|
|
135
|
+
'',
|
|
136
|
+
'## Navigation',
|
|
137
|
+
'',
|
|
138
|
+
'- `Toil.Link` / `Toil.NavLink` (adds an active class) / `Toil.useRouter()`',
|
|
139
|
+
' (push / replace / back / forward / refresh / prefetch)',
|
|
140
|
+
'- `Toil.useParams`, `usePathname`, `useSearchParams`, `useNavigationPending`',
|
|
141
|
+
'- Hrefs are type-checked against your routes, a typo is a compile error.',
|
|
142
|
+
]),
|
|
143
|
+
'client.md': doc([
|
|
144
|
+
'# Client runtime',
|
|
145
|
+
'',
|
|
146
|
+
'Everything is on the `Toil` global, no imports needed in route files.',
|
|
147
|
+
'',
|
|
148
|
+
'## Entry',
|
|
149
|
+
'',
|
|
150
|
+
'`client/toil.tsx` imports the route table + global styles and mounts the app:',
|
|
151
|
+
'',
|
|
152
|
+
' import { routes, layout, notFound } from "toiljs/routes";',
|
|
153
|
+
' import "./styles/main.css";',
|
|
154
|
+
' Toil.mount(routes, layout, notFound);',
|
|
155
|
+
'',
|
|
156
|
+
'## API (on `Toil`)',
|
|
157
|
+
'',
|
|
158
|
+
'- Components: `Link`, `NavLink`, `Head`',
|
|
159
|
+
'- Navigation: `navigate`, `useRouter`, `useNavigate`',
|
|
160
|
+
'- Location: `usePathname`, `useSearchParams`, `useParams`, `useNavigationPending`',
|
|
161
|
+
'- Data: `useLoaderData` (see `routing.md`)',
|
|
162
|
+
'- Head: `useHead`, `useTitle`, `<Head>`, set the `<title>` / meta per route',
|
|
163
|
+
'- Realtime: `useChannel`, `connectChannel` (WebSocket to the backend at `/_toil`)',
|
|
164
|
+
'- IO globals (no `Toil.` prefix): `BinaryWriter`, `BinaryReader`, `FastMap`, `FastSet`',
|
|
165
|
+
'',
|
|
166
|
+
'## Head example',
|
|
167
|
+
'',
|
|
168
|
+
' Toil.useHead({',
|
|
169
|
+
' title: "Blog",',
|
|
170
|
+
' titleTemplate: "%s · MyApp",',
|
|
171
|
+
' meta: [{ name: "description", content: "..." }],',
|
|
172
|
+
' });',
|
|
173
|
+
]),
|
|
174
|
+
'styling.md': doc([
|
|
175
|
+
'# Styling',
|
|
176
|
+
'',
|
|
177
|
+
'The app imports one stylesheet from `client/toil.tsx` (e.g. `./styles/main.css`).',
|
|
178
|
+
'',
|
|
179
|
+
'## Preprocessors & Tailwind',
|
|
180
|
+
'',
|
|
181
|
+
'Pick a CSS preprocessor (none / Sass / Less / Stylus) and optionally Tailwind at',
|
|
182
|
+
'`toiljs create`, or change it later on an existing project:',
|
|
183
|
+
'',
|
|
184
|
+
' toiljs configure # interactive',
|
|
185
|
+
' toiljs configure --tailwind # add Tailwind',
|
|
186
|
+
' toiljs configure --style sass # switch preprocessor',
|
|
187
|
+
'',
|
|
188
|
+
'`configure` installs/removes the right packages and rewrites the imports. Tailwind lives',
|
|
189
|
+
'in its own `styles/tailwind.css` (`@import "tailwindcss";`).',
|
|
190
|
+
'',
|
|
191
|
+
'## Imports',
|
|
192
|
+
'',
|
|
193
|
+
'`.css` / `.scss` / `.sass` / `.less` / `.styl` and image imports (`.svg`, `.png`, …) are',
|
|
194
|
+
'typed via `toil-env.d.ts`.',
|
|
195
|
+
]),
|
|
196
|
+
'server.md': doc([
|
|
197
|
+
'# Server (toilscript → WebAssembly)',
|
|
198
|
+
'',
|
|
199
|
+
'`server/` is the toilscript source, compiled to WebAssembly by `toilscript`.',
|
|
200
|
+
'',
|
|
201
|
+
'- `server/main.ts`, the `@main` entry, exported as the WASM `main`.',
|
|
202
|
+
'- `server/index.ts`, your functions.',
|
|
203
|
+
'- `server/tsconfig.json`, extends `toilscript/std/assembly.json` (AssemblyScript/toilscript',
|
|
204
|
+
' globals like `i32`, not the DOM), so editors resolve server types correctly.',
|
|
205
|
+
'- `npm run build:server` (or `npm run build`) emits `build/server/release.wasm`.',
|
|
206
|
+
'',
|
|
207
|
+
'Note: the client↔server bridge (calling WASM exports from the client) is not wired yet.',
|
|
208
|
+
]),
|
|
209
|
+
'cli.md': doc([
|
|
210
|
+
'# CLI',
|
|
211
|
+
'',
|
|
212
|
+
'- `toiljs create [name]`, scaffold a project. Flags: `--template app|minimal`,',
|
|
213
|
+
' `--style css|sass|less|stylus`, `--tailwind`, `--no-ai`, `-y`/`--yes`.',
|
|
214
|
+
'- `toiljs dev`, dev server with HMR (`--port`, `--root`).',
|
|
215
|
+
'- `toiljs build`, production build → `build/client` (chain `toilscript` for the server).',
|
|
216
|
+
'- `toiljs start`, self-host the built app (hyper-express) with a `/_toil` WebSocket channel.',
|
|
217
|
+
'- `toiljs configure`, toggle styling features on an existing project (see `styling.md`).',
|
|
218
|
+
]),
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
/** Writes the framework docs into `<toilDir>/docs/`. Called by `generate` each dev/build. */
|
|
222
|
+
export function writeDocs(toilDir: string): void {
|
|
223
|
+
const dir = path.join(toilDir, 'docs');
|
|
224
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
225
|
+
for (const [name, content] of Object.entries(TOIL_DOCS)) {
|
|
226
|
+
fs.writeFileSync(path.join(dir, name), content);
|
|
227
|
+
}
|
|
228
|
+
}
|