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/build/cli/create.js
DELETED
|
@@ -1,420 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
import { cancel, confirm, intro, isCancel, multiselect, note, outro, select, spinner, text, } from '@clack/prompts';
|
|
5
|
-
import { AI_HELPER_IDS, AI_HELPERS, aiHelperFiles, TOIL_DOCS, TOIL_ENV_DTS } from 'toiljs/compiler';
|
|
6
|
-
import pc from 'picocolors';
|
|
7
|
-
import { PKG_VERSION, PREPROCESSORS, requiredPackages, setStyleImports, styleEntry, styleImportLines, TAILWIND_CSS, TAILWIND_ENTRY, } from './features.js';
|
|
8
|
-
import { run } from './proc.js';
|
|
9
|
-
import { accent, dim, version } from './ui.js';
|
|
10
|
-
import { isPackageManager, isValidName, resolveProjectDir } from './validate.js';
|
|
11
|
-
const PREPROCESSOR_LABEL = {
|
|
12
|
-
css: 'Plain CSS',
|
|
13
|
-
sass: 'Sass (SCSS)',
|
|
14
|
-
less: 'Less',
|
|
15
|
-
stylus: 'Stylus',
|
|
16
|
-
};
|
|
17
|
-
const DEFAULT_STYLE_CONTENT = ':root {\n color-scheme: dark;\n}\n\n' +
|
|
18
|
-
'body {\n margin: 0;\n background: #080d11;\n color: #f5f6fa;\n' +
|
|
19
|
-
' font-family: system-ui, -apple-system, sans-serif;\n line-height: 1.6;\n}\n\n' +
|
|
20
|
-
'a {\n color: #2563ff;\n text-decoration: none;\n}\n\n' +
|
|
21
|
-
'a:hover {\n color: #22e3ab;\n}\n\n' +
|
|
22
|
-
'code {\n background: #11161f;\n color: #22e3ab;\n padding: 0.1rem 0.4rem;\n' +
|
|
23
|
-
' border-radius: 4px;\n font-size: 0.9em;\n}\n\n' +
|
|
24
|
-
'h1 {\n background: linear-gradient(90deg, #2563ff, #7c3aed, #22e3ab);\n' +
|
|
25
|
-
' -webkit-background-clip: text;\n background-clip: text;\n color: transparent;\n}\n';
|
|
26
|
-
function bail(value) {
|
|
27
|
-
if (isCancel(value)) {
|
|
28
|
-
cancel('Scaffolding cancelled.');
|
|
29
|
-
process.exit(0);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
async function isEmptyDir(dir) {
|
|
33
|
-
try {
|
|
34
|
-
const entries = await fs.readdir(dir);
|
|
35
|
-
return entries.length === 0;
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
return true;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
function scaffold(name, template, features, aiTools, images) {
|
|
42
|
-
const toilVersion = version();
|
|
43
|
-
const devDependencies = {
|
|
44
|
-
'@types/react': '^19.2.15',
|
|
45
|
-
'@types/react-dom': '^19.2.3',
|
|
46
|
-
eslint: '^10.2.0',
|
|
47
|
-
prettier: '^3.8.1',
|
|
48
|
-
toilscript: '^0.1.2',
|
|
49
|
-
typescript: '^6.0.3',
|
|
50
|
-
};
|
|
51
|
-
for (const dep of requiredPackages(features).sort()) {
|
|
52
|
-
devDependencies[dep] = PKG_VERSION[dep] ?? 'latest';
|
|
53
|
-
}
|
|
54
|
-
const pkg = {
|
|
55
|
-
name: path.basename(name),
|
|
56
|
-
private: true,
|
|
57
|
-
type: 'module',
|
|
58
|
-
scripts: {
|
|
59
|
-
dev: 'toiljs dev',
|
|
60
|
-
build: 'toiljs build && toilscript --target release',
|
|
61
|
-
'build:client': 'toiljs build',
|
|
62
|
-
'build:server': 'toilscript --target release',
|
|
63
|
-
lint: 'eslint client',
|
|
64
|
-
typecheck: 'tsc --noEmit',
|
|
65
|
-
format: 'prettier --write "client/**/*.{ts,tsx,css,scss,less}" "client/public/**/*.html"',
|
|
66
|
-
},
|
|
67
|
-
dependencies: {
|
|
68
|
-
toiljs: `^${toilVersion}`,
|
|
69
|
-
react: '^19.2.6',
|
|
70
|
-
'react-dom': '^19.2.6',
|
|
71
|
-
},
|
|
72
|
-
devDependencies,
|
|
73
|
-
};
|
|
74
|
-
const files = {
|
|
75
|
-
'package.json': JSON.stringify(pkg, null, 4) + '\n',
|
|
76
|
-
'toil.config.ts': "import { defineConfig } from 'toiljs/compiler';\n\n" +
|
|
77
|
-
'export default defineConfig({\n' +
|
|
78
|
-
' client: {\n' +
|
|
79
|
-
' // Optimize images at build time (resize/compress imported images).\n' +
|
|
80
|
-
` images: ${String(images)},\n` +
|
|
81
|
-
' },\n' +
|
|
82
|
-
'});\n',
|
|
83
|
-
'tsconfig.json': '{\n "extends": "toiljs/tsconfig",\n "include": ["client", "toil-env.d.ts", "toil-routes.d.ts"]\n}\n',
|
|
84
|
-
'eslint.config.js': "import toiljs from 'toiljs/eslint';\n\nexport default toiljs;\n",
|
|
85
|
-
'.prettierrc': '"toiljs/prettier"\n',
|
|
86
|
-
'.gitignore': 'node_modules\nbuild\n.toil\ntoil-env.d.ts\ntoil-routes.d.ts\n',
|
|
87
|
-
'.vscode/settings.json': JSON.stringify({ 'typescript.tsdk': 'node_modules/typescript/lib' }, null, 4) + '\n',
|
|
88
|
-
'toil-env.d.ts': TOIL_ENV_DTS,
|
|
89
|
-
'toil-routes.d.ts': '// AUTO-GENERATED by toil, do not edit.\nexport {};\n',
|
|
90
|
-
'toilconfig.json': JSON.stringify({
|
|
91
|
-
entries: ['server/main.ts'],
|
|
92
|
-
targets: {
|
|
93
|
-
release: {
|
|
94
|
-
outFile: 'build/server/release.wasm',
|
|
95
|
-
textFile: 'build/server/release.wat',
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
options: {
|
|
99
|
-
sourceMap: false,
|
|
100
|
-
optimizeLevel: 3,
|
|
101
|
-
shrinkLevel: 1,
|
|
102
|
-
converge: true,
|
|
103
|
-
noAssert: false,
|
|
104
|
-
enable: [
|
|
105
|
-
'sign-extension',
|
|
106
|
-
'mutable-globals',
|
|
107
|
-
'nontrapping-f2i',
|
|
108
|
-
'bulk-memory',
|
|
109
|
-
'simd',
|
|
110
|
-
'reference-types',
|
|
111
|
-
'multi-value',
|
|
112
|
-
],
|
|
113
|
-
runtime: 'stub',
|
|
114
|
-
memoryBase: 0,
|
|
115
|
-
initialMemory: 1,
|
|
116
|
-
debug: false,
|
|
117
|
-
trapMode: 'allow',
|
|
118
|
-
},
|
|
119
|
-
}, null, 4) + '\n',
|
|
120
|
-
'server/tsconfig.json': JSON.stringify({
|
|
121
|
-
extends: 'toilscript/std/assembly.json',
|
|
122
|
-
include: ['./**/*.ts'],
|
|
123
|
-
}, null, 4) + '\n',
|
|
124
|
-
'server/index.ts': 'export function add(a: i32, b: i32): i32 {\n return a + b;\n}\n',
|
|
125
|
-
'server/main.ts': "import { add } from './index';\n\n" +
|
|
126
|
-
'@main\nfunction run(): i32 {\n return add(40, 2);\n}\n',
|
|
127
|
-
'README.md': [
|
|
128
|
-
'# ' + path.basename(name),
|
|
129
|
-
'',
|
|
130
|
-
'A [toiljs](https://toil.org) app.',
|
|
131
|
-
'',
|
|
132
|
-
'## Develop',
|
|
133
|
-
'',
|
|
134
|
-
' npm install',
|
|
135
|
-
' npm run dev',
|
|
136
|
-
'',
|
|
137
|
-
'## Build',
|
|
138
|
-
'',
|
|
139
|
-
' npm run build',
|
|
140
|
-
'',
|
|
141
|
-
].join('\n'),
|
|
142
|
-
};
|
|
143
|
-
if (template === 'minimal')
|
|
144
|
-
Object.assign(files, minimalClient(name, features));
|
|
145
|
-
Object.assign(files, aiHelperFiles(aiTools));
|
|
146
|
-
for (const [docName, content] of Object.entries(TOIL_DOCS)) {
|
|
147
|
-
files[`.toil/docs/${docName}`] = content;
|
|
148
|
-
}
|
|
149
|
-
return files;
|
|
150
|
-
}
|
|
151
|
-
function minimalClient(name, features) {
|
|
152
|
-
const files = {
|
|
153
|
-
'client/public/index.html': '<!doctype html>\n<html lang="en">\n <head>\n' +
|
|
154
|
-
' <meta charset="utf-8" />\n' +
|
|
155
|
-
' <meta name="viewport" content="width=device-width, initial-scale=1" />\n' +
|
|
156
|
-
' <meta name="theme-color" content="#080D11" />\n' +
|
|
157
|
-
' <meta name="description" content="" />\n' +
|
|
158
|
-
' <link rel="icon" type="image/svg+xml" href="/favicon.svg" />\n' +
|
|
159
|
-
' <link rel="manifest" href="/manifest.webmanifest" />\n' +
|
|
160
|
-
` <title>${path.basename(name)}</title>\n` +
|
|
161
|
-
' </head>\n <body>\n <div id="root"></div>\n </body>\n</html>\n',
|
|
162
|
-
'client/public/favicon.svg': '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">\n' +
|
|
163
|
-
' <defs>\n' +
|
|
164
|
-
' <linearGradient id="g" x1="0" y1="0" x2="1" y2="1">\n' +
|
|
165
|
-
' <stop offset="0" stop-color="#2563FF" />\n' +
|
|
166
|
-
' <stop offset="0.5" stop-color="#7C3AED" />\n' +
|
|
167
|
-
' <stop offset="1" stop-color="#22E3AB" />\n' +
|
|
168
|
-
' </linearGradient>\n' +
|
|
169
|
-
' </defs>\n' +
|
|
170
|
-
' <rect width="32" height="32" rx="7" fill="#080D11" />\n' +
|
|
171
|
-
' <path d="M9 10h14v3.2h-5.4V24h-3.2V13.2H9z" fill="url(#g)" />\n' +
|
|
172
|
-
'</svg>\n',
|
|
173
|
-
'client/public/robots.txt': 'User-agent: *\nAllow: /\n',
|
|
174
|
-
'client/public/manifest.webmanifest': JSON.stringify({
|
|
175
|
-
name: path.basename(name),
|
|
176
|
-
short_name: path.basename(name),
|
|
177
|
-
start_url: '/',
|
|
178
|
-
display: 'standalone',
|
|
179
|
-
background_color: '#080D11',
|
|
180
|
-
theme_color: '#080D11',
|
|
181
|
-
icons: [{ src: '/favicon.svg', type: 'image/svg+xml', sizes: 'any' }],
|
|
182
|
-
}, null, 4) + '\n',
|
|
183
|
-
'client/public/images/.gitkeep': '# Place images and other static assets here; served at /images/*.\n',
|
|
184
|
-
'client/toil.tsx': "import { routes, layout, notFound, globalError, slots } from 'toiljs/routes';\n\n" +
|
|
185
|
-
styleImportLines(features).join('\n') +
|
|
186
|
-
'\n\n' +
|
|
187
|
-
'Toil.mount(routes, layout, notFound, globalError, slots);\n',
|
|
188
|
-
[`client/${styleEntry(features.preprocessor)}`]: DEFAULT_STYLE_CONTENT,
|
|
189
|
-
'client/components/.gitkeep': '# Place shared React components here.\n',
|
|
190
|
-
'client/layout.tsx': `import { type ReactNode } from 'react';
|
|
191
|
-
|
|
192
|
-
export default function Layout({ children }: { children?: ReactNode }) {
|
|
193
|
-
return (
|
|
194
|
-
<div style={{ maxWidth: 680, margin: '0 auto', padding: '3rem 1.5rem' }}>
|
|
195
|
-
<header
|
|
196
|
-
style={{
|
|
197
|
-
display: 'flex',
|
|
198
|
-
gap: '1rem',
|
|
199
|
-
alignItems: 'baseline',
|
|
200
|
-
borderBottom: '1px solid #1b2330',
|
|
201
|
-
paddingBottom: '0.75rem',
|
|
202
|
-
marginBottom: '1.5rem',
|
|
203
|
-
}}>
|
|
204
|
-
<strong style={{ color: '#2563FF', fontSize: '1.1rem' }}>${path.basename(name)}</strong>
|
|
205
|
-
<nav style={{ display: 'flex', gap: '1rem' }}>
|
|
206
|
-
<Toil.Link href="/">home</Toil.Link>
|
|
207
|
-
</nav>
|
|
208
|
-
</header>
|
|
209
|
-
{children}
|
|
210
|
-
</div>
|
|
211
|
-
);
|
|
212
|
-
}
|
|
213
|
-
`,
|
|
214
|
-
'client/routes/index.tsx': 'export default function Home() {\n' +
|
|
215
|
-
' return (\n <main>\n' +
|
|
216
|
-
' <h1>Welcome to toiljs</h1>\n' +
|
|
217
|
-
' <p>File-based routing, bundled by Vite, zero config.</p>\n' +
|
|
218
|
-
' </main>\n );\n}\n',
|
|
219
|
-
};
|
|
220
|
-
if (features.tailwind)
|
|
221
|
-
files[`client/${TAILWIND_ENTRY}`] = TAILWIND_CSS;
|
|
222
|
-
return files;
|
|
223
|
-
}
|
|
224
|
-
function appClientDir() {
|
|
225
|
-
return path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', 'examples', 'basic', 'client');
|
|
226
|
-
}
|
|
227
|
-
async function applyStyling(clientDir, features) {
|
|
228
|
-
if (features.preprocessor === 'css' && !features.tailwind)
|
|
229
|
-
return;
|
|
230
|
-
const entry = styleEntry(features.preprocessor);
|
|
231
|
-
if (entry !== 'styles/main.css') {
|
|
232
|
-
await fs.rename(path.join(clientDir, 'styles', 'main.css'), path.join(clientDir, entry));
|
|
233
|
-
}
|
|
234
|
-
if (features.tailwind) {
|
|
235
|
-
await fs.writeFile(path.join(clientDir, TAILWIND_ENTRY), TAILWIND_CSS, 'utf8');
|
|
236
|
-
}
|
|
237
|
-
const toilPath = path.join(clientDir, 'toil.tsx');
|
|
238
|
-
await fs.writeFile(toilPath, setStyleImports(await fs.readFile(toilPath, 'utf8'), features), 'utf8');
|
|
239
|
-
}
|
|
240
|
-
async function writeFiles(dir, files) {
|
|
241
|
-
for (const [rel, contents] of Object.entries(files)) {
|
|
242
|
-
const full = path.join(dir, rel);
|
|
243
|
-
await fs.mkdir(path.dirname(full), { recursive: true });
|
|
244
|
-
await fs.writeFile(full, contents, 'utf8');
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
export async function runCreate(opts) {
|
|
248
|
-
intro(accent(' toiljs create '));
|
|
249
|
-
let name = opts.name;
|
|
250
|
-
if (!name) {
|
|
251
|
-
if (opts.yes) {
|
|
252
|
-
name = 'my-toil-app';
|
|
253
|
-
}
|
|
254
|
-
else {
|
|
255
|
-
const answer = await text({
|
|
256
|
-
message: 'Project name',
|
|
257
|
-
placeholder: 'my-toil-app',
|
|
258
|
-
defaultValue: 'my-toil-app',
|
|
259
|
-
validate: (v) => {
|
|
260
|
-
const result = isValidName(v || 'my-toil-app');
|
|
261
|
-
return result === true ? undefined : result;
|
|
262
|
-
},
|
|
263
|
-
});
|
|
264
|
-
bail(answer);
|
|
265
|
-
name = answer.trim() || 'my-toil-app';
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
const valid = isValidName(name);
|
|
269
|
-
if (valid !== true) {
|
|
270
|
-
cancel(valid);
|
|
271
|
-
process.exit(1);
|
|
272
|
-
}
|
|
273
|
-
const targetDir = resolveProjectDir(opts.cwd, name);
|
|
274
|
-
if (targetDir === null) {
|
|
275
|
-
cancel('Project name must stay inside the current directory (no "..", no absolute paths).');
|
|
276
|
-
process.exit(1);
|
|
277
|
-
}
|
|
278
|
-
const rel = path.relative(opts.cwd, targetDir) || '.';
|
|
279
|
-
if (!(await isEmptyDir(targetDir))) {
|
|
280
|
-
if (opts.yes) {
|
|
281
|
-
cancel(`Directory ${pc.cyan(rel)} is not empty.`);
|
|
282
|
-
process.exit(1);
|
|
283
|
-
}
|
|
284
|
-
const proceed = await confirm({
|
|
285
|
-
message: `Directory ${pc.cyan(rel)} is not empty. Scaffold into it anyway?`,
|
|
286
|
-
initialValue: false,
|
|
287
|
-
});
|
|
288
|
-
bail(proceed);
|
|
289
|
-
if (!proceed) {
|
|
290
|
-
cancel('Scaffolding cancelled.');
|
|
291
|
-
process.exit(0);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
let template = opts.template ?? 'app';
|
|
295
|
-
if (!opts.template && !opts.yes) {
|
|
296
|
-
const templateOptions = [
|
|
297
|
-
{
|
|
298
|
-
value: 'app',
|
|
299
|
-
label: 'App',
|
|
300
|
-
hint: 'the full ToilJS starter, landing page, layout, styles, demo routes',
|
|
301
|
-
},
|
|
302
|
-
{ value: 'minimal', label: 'Minimal', hint: 'just a layout and a home route' },
|
|
303
|
-
];
|
|
304
|
-
const choice = await select({
|
|
305
|
-
message: 'Which template?',
|
|
306
|
-
options: templateOptions,
|
|
307
|
-
initialValue: 'app',
|
|
308
|
-
});
|
|
309
|
-
bail(choice);
|
|
310
|
-
template = choice === 'minimal' ? 'minimal' : 'app';
|
|
311
|
-
}
|
|
312
|
-
let preprocessor = opts.preprocessor ?? 'css';
|
|
313
|
-
let tailwind = opts.tailwind ?? false;
|
|
314
|
-
if (!opts.yes) {
|
|
315
|
-
if (opts.preprocessor === undefined) {
|
|
316
|
-
const choice = await select({
|
|
317
|
-
message: 'Styling',
|
|
318
|
-
options: PREPROCESSORS.map((value) => ({
|
|
319
|
-
value,
|
|
320
|
-
label: PREPROCESSOR_LABEL[value],
|
|
321
|
-
})),
|
|
322
|
-
initialValue: 'css',
|
|
323
|
-
});
|
|
324
|
-
bail(choice);
|
|
325
|
-
preprocessor = choice;
|
|
326
|
-
}
|
|
327
|
-
if (opts.tailwind === undefined) {
|
|
328
|
-
const tw = await confirm({ message: 'Add Tailwind CSS?', initialValue: false });
|
|
329
|
-
bail(tw);
|
|
330
|
-
tailwind = tw;
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
const features = { preprocessor, tailwind };
|
|
334
|
-
let aiTools = opts.ai === false ? [] : [...AI_HELPER_IDS];
|
|
335
|
-
if (opts.ai === undefined && !opts.yes) {
|
|
336
|
-
const picked = await multiselect({
|
|
337
|
-
message: 'AI assistant files (read by Claude, Cursor, Codex, Copilot)',
|
|
338
|
-
options: [
|
|
339
|
-
...AI_HELPERS.map((h) => ({ value: h.id, label: h.label })),
|
|
340
|
-
{ value: 'none', label: 'None' },
|
|
341
|
-
],
|
|
342
|
-
initialValues: [...AI_HELPER_IDS],
|
|
343
|
-
required: false,
|
|
344
|
-
});
|
|
345
|
-
bail(picked);
|
|
346
|
-
aiTools = picked.includes('none') ? [] : picked;
|
|
347
|
-
}
|
|
348
|
-
let images = opts.images ?? true;
|
|
349
|
-
if (opts.images === undefined && !opts.yes) {
|
|
350
|
-
const im = await confirm({ message: 'Optimize images at build time?', initialValue: true });
|
|
351
|
-
bail(im);
|
|
352
|
-
images = im;
|
|
353
|
-
}
|
|
354
|
-
let initGit = opts.git ?? false;
|
|
355
|
-
let install = opts.install ?? false;
|
|
356
|
-
const pm = opts.pm ?? 'npm';
|
|
357
|
-
if (!isPackageManager(pm)) {
|
|
358
|
-
cancel(`Unsupported package manager: ${pm} (use npm, pnpm, yarn, or bun).`);
|
|
359
|
-
process.exit(1);
|
|
360
|
-
}
|
|
361
|
-
if (!opts.yes) {
|
|
362
|
-
if (opts.git === undefined) {
|
|
363
|
-
const g = await confirm({
|
|
364
|
-
message: 'Initialize a git repository?',
|
|
365
|
-
initialValue: true,
|
|
366
|
-
});
|
|
367
|
-
bail(g);
|
|
368
|
-
initGit = g;
|
|
369
|
-
}
|
|
370
|
-
if (opts.install === undefined) {
|
|
371
|
-
const i = await confirm({ message: 'Install dependencies now?', initialValue: false });
|
|
372
|
-
bail(i);
|
|
373
|
-
install = i;
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
const s = spinner();
|
|
377
|
-
s.start('Scaffolding project');
|
|
378
|
-
await writeFiles(targetDir, scaffold(name, template, features, aiTools, images));
|
|
379
|
-
if (template === 'app') {
|
|
380
|
-
await fs.cp(appClientDir(), path.join(targetDir, 'client'), { recursive: true });
|
|
381
|
-
const indexHtml = path.join(targetDir, 'client', 'public', 'index.html');
|
|
382
|
-
const html = await fs.readFile(indexHtml, 'utf8');
|
|
383
|
-
await fs.writeFile(indexHtml, html.replace(/<title>[^<]*<\/title>/, `<title>${path.basename(name)}</title>`));
|
|
384
|
-
await applyStyling(path.join(targetDir, 'client'), features);
|
|
385
|
-
}
|
|
386
|
-
s.stop(`Scaffolded ${pc.cyan(rel)}`);
|
|
387
|
-
if (initGit) {
|
|
388
|
-
const g = spinner();
|
|
389
|
-
g.start('Initializing git repository');
|
|
390
|
-
try {
|
|
391
|
-
await run('git', ['init', '-q'], targetDir);
|
|
392
|
-
await run('git', ['add', '-A'], targetDir);
|
|
393
|
-
g.stop('Initialized git repository');
|
|
394
|
-
}
|
|
395
|
-
catch {
|
|
396
|
-
g.stop(pc.yellow('Skipped git init (git not available)'));
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
if (install) {
|
|
400
|
-
const i = spinner();
|
|
401
|
-
i.start(`Installing dependencies with ${pm}`);
|
|
402
|
-
try {
|
|
403
|
-
await run(pm, ['install'], targetDir);
|
|
404
|
-
i.stop('Installed dependencies');
|
|
405
|
-
}
|
|
406
|
-
catch {
|
|
407
|
-
i.stop(pc.yellow(`Could not install with ${pm}, run it yourself later`));
|
|
408
|
-
install = false;
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
const steps = [];
|
|
412
|
-
if (rel !== '.')
|
|
413
|
-
steps.push(`cd ${rel}`);
|
|
414
|
-
if (!install)
|
|
415
|
-
steps.push('npm install');
|
|
416
|
-
steps.push(`${accent('npm run dev')} ${dim('start the dev server')}`);
|
|
417
|
-
steps.push(`${accent('npm run build')} ${dim('build for production')}`);
|
|
418
|
-
note(steps.map((l) => dim(' ') + l).join('\n'), 'Next steps');
|
|
419
|
-
outro(`Created ${accent(path.basename(name))}, happy building! ${dim('· v' + version())}`);
|
|
420
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { type Preprocessor } from './features.js';
|
|
2
|
-
export type CheckStatus = 'pass' | 'warn' | 'fail';
|
|
3
|
-
export interface Check {
|
|
4
|
-
readonly id: string;
|
|
5
|
-
readonly label: string;
|
|
6
|
-
readonly status: CheckStatus;
|
|
7
|
-
readonly detail?: string;
|
|
8
|
-
readonly fix?: string;
|
|
9
|
-
}
|
|
10
|
-
export interface CheckGroup {
|
|
11
|
-
readonly title: string;
|
|
12
|
-
readonly checks: Check[];
|
|
13
|
-
}
|
|
14
|
-
export interface DoctorSummary {
|
|
15
|
-
readonly pass: number;
|
|
16
|
-
readonly warn: number;
|
|
17
|
-
readonly fail: number;
|
|
18
|
-
}
|
|
19
|
-
export declare function satisfiesMin(version: string, range: string): boolean;
|
|
20
|
-
export declare function checkNode(current: string, requiredRange: string): Check;
|
|
21
|
-
export declare function checkPeer(name: string, installed: string | null, range: string): Check;
|
|
22
|
-
export declare function checkPackageManager(lockfiles: readonly string[]): Check;
|
|
23
|
-
export declare function checkToiljsInstalled(version: string | null): Check;
|
|
24
|
-
export declare function checkDir(id: string, label: string, exists: boolean, fix: string): Check;
|
|
25
|
-
export declare function checkMountSlots(entrySource: string | null): Check;
|
|
26
|
-
export declare function checkRootElement(indexHtml: string | null): Check;
|
|
27
|
-
export declare function checkRoutesPresent(routeCount: number): Check;
|
|
28
|
-
export declare function checkDuplicatePatterns(patterns: readonly string[]): Check;
|
|
29
|
-
export interface SourceFile {
|
|
30
|
-
readonly path: string;
|
|
31
|
-
readonly source: string;
|
|
32
|
-
}
|
|
33
|
-
export interface AssetIssue {
|
|
34
|
-
readonly file: string;
|
|
35
|
-
readonly line: number;
|
|
36
|
-
readonly value: string;
|
|
37
|
-
}
|
|
38
|
-
export declare function findRelativeAssets(files: readonly SourceFile[]): AssetIssue[];
|
|
39
|
-
export declare function checkRelativeAssets(issues: readonly AssetIssue[]): Check;
|
|
40
|
-
export declare function checkConfigLoads(loaded: boolean, error?: string): Check;
|
|
41
|
-
export declare function checkBasePath(base: string): Check;
|
|
42
|
-
export declare function checkSeoUrl(seoConfigured: boolean, hasUrl: boolean): Check;
|
|
43
|
-
export interface StylingFacts {
|
|
44
|
-
readonly preprocessorImported: Preprocessor | null;
|
|
45
|
-
readonly preprocessorInstalled: boolean;
|
|
46
|
-
readonly tailwindImported: boolean;
|
|
47
|
-
readonly tailwindInstalled: boolean;
|
|
48
|
-
}
|
|
49
|
-
export declare function checkStyling(f: StylingFacts): Check;
|
|
50
|
-
export declare function checkToilconfig(present: boolean): Check;
|
|
51
|
-
export declare function checkServerEntry(missing: readonly string[]): Check;
|
|
52
|
-
export declare function checkToilscriptInstalled(installed: boolean): Check;
|
|
53
|
-
export declare function checkWasmBuilt(exists: boolean): Check;
|
|
54
|
-
export declare function summarize(groups: readonly CheckGroup[]): DoctorSummary;
|
|
55
|
-
export declare function hasFailures(summary: DoctorSummary): boolean;
|