toiljs 0.0.11 → 0.0.12
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/README.md +2 -0
- package/build/cli/.tsbuildinfo +1 -1
- package/build/cli/configure.js +10 -4
- package/build/cli/create.js +58 -30
- package/build/cli/diagnostics.d.ts +55 -0
- package/build/cli/diagnostics.js +333 -0
- package/build/cli/doctor.d.ts +6 -0
- package/build/cli/doctor.js +249 -0
- package/build/cli/index.js +26 -0
- package/build/cli/proc.d.ts +5 -0
- package/build/cli/proc.js +20 -0
- package/build/cli/ui.d.ts +1 -0
- package/build/cli/ui.js +1 -0
- package/build/cli/update.d.ts +7 -0
- package/build/cli/update.js +117 -0
- package/build/cli/updates.d.ts +10 -0
- package/build/cli/updates.js +45 -0
- package/build/client/.tsbuildinfo +1 -1
- package/build/client/dev/error-overlay.js +1 -1
- package/build/client/head/metadata.js +3 -1
- package/build/client/index.d.ts +5 -1
- package/build/client/index.js +2 -0
- package/build/client/navigation/navigation.js +1 -1
- package/build/client/routing/Router.js +2 -2
- package/build/client/search/search.d.ts +26 -0
- package/build/client/search/search.js +101 -0
- package/build/client/search/use-page-search.d.ts +8 -0
- package/build/client/search/use-page-search.js +21 -0
- package/build/compiler/.tsbuildinfo +1 -1
- package/build/compiler/generate.js +26 -23
- package/build/compiler/index.d.ts +2 -0
- package/build/compiler/index.js +1 -0
- package/build/compiler/pages.d.ts +8 -0
- package/build/compiler/pages.js +37 -0
- package/build/compiler/plugin.js +3 -1
- package/build/compiler/prerender.d.ts +1 -0
- package/build/compiler/prerender.js +11 -5
- package/build/compiler/seo.js +10 -3
- package/build/io/.tsbuildinfo +1 -1
- package/examples/basic/client/components/Header.tsx +43 -41
- package/examples/basic/client/components/HoneycombBackground.tsx +223 -230
- package/examples/basic/client/public/index.html +18 -16
- package/examples/basic/client/routes/(legal)/privacy.tsx +18 -19
- package/examples/basic/client/routes/(legal)/terms.tsx +15 -16
- package/examples/basic/client/routes/about.tsx +21 -22
- package/examples/basic/client/routes/blog/[id].tsx +26 -18
- package/examples/basic/client/routes/features/actions.tsx +67 -67
- package/examples/basic/client/routes/features/error/index.tsx +27 -27
- package/examples/basic/client/routes/features/head.tsx +38 -38
- package/examples/basic/client/routes/features/index.tsx +83 -75
- package/examples/basic/client/routes/features/realtime.tsx +34 -32
- package/examples/basic/client/routes/features/script.tsx +31 -31
- package/examples/basic/client/routes/features/seo.tsx +39 -39
- package/examples/basic/client/routes/features/template/index.tsx +20 -20
- package/examples/basic/client/routes/features/template/template.tsx +16 -18
- package/examples/basic/client/routes/gallery/@modal/(.)photo/[id].tsx +23 -23
- package/examples/basic/client/routes/gallery/index.tsx +42 -42
- package/examples/basic/client/routes/gallery/photo/[id].tsx +18 -18
- package/examples/basic/client/routes/get-started.tsx +157 -84
- package/examples/basic/client/routes/index.tsx +137 -96
- package/examples/basic/client/routes/loader-demo/index.tsx +59 -52
- package/examples/basic/client/routes/search.tsx +61 -0
- package/examples/basic/client/routes/test.tsx +7 -8
- package/examples/basic/client/styles/main.css +624 -552
- package/package.json +2 -2
- package/presets/eslint.js +10 -3
- package/src/cli/configure.ts +363 -353
- package/src/cli/create.ts +563 -530
- package/src/cli/diagnostics.ts +421 -0
- package/src/cli/doctor.ts +318 -0
- package/src/cli/features.ts +166 -160
- package/src/cli/index.ts +242 -211
- package/src/cli/proc.ts +30 -0
- package/src/cli/ui.ts +111 -103
- package/src/cli/update.ts +150 -0
- package/src/cli/updates.ts +69 -0
- package/src/client/components/Image.tsx +91 -89
- package/src/client/dev/error-overlay.tsx +193 -197
- package/src/client/head/metadata.ts +94 -92
- package/src/client/index.ts +79 -64
- package/src/client/navigation/Link.tsx +94 -100
- package/src/client/navigation/navigation.ts +215 -218
- package/src/client/routing/Router.tsx +210 -193
- package/src/client/routing/hooks.ts +110 -114
- package/src/client/routing/lazy.ts +77 -81
- package/src/client/search/search.ts +189 -0
- package/src/client/search/use-page-search.ts +73 -0
- package/src/compiler/config.ts +173 -171
- package/src/compiler/fonts.ts +89 -87
- package/src/compiler/generate.ts +378 -373
- package/src/compiler/image-report.ts +88 -85
- package/src/compiler/index.ts +2 -0
- package/src/compiler/pages.ts +70 -0
- package/src/compiler/plugin.ts +51 -47
- package/src/compiler/prerender.ts +152 -130
- package/src/compiler/routes.ts +132 -131
- package/src/compiler/seo.ts +381 -356
- package/src/compiler/vite.ts +155 -145
- package/src/io/FastSet.ts +99 -96
- package/test/configure.test.ts +94 -90
- package/test/doctor.test.ts +140 -0
- package/test/dom/Image.test.tsx +73 -46
- package/test/dom/Script.test.tsx +48 -45
- package/test/dom/action.test.tsx +146 -129
- package/test/dom/error-overlay.test.tsx +44 -44
- package/test/dom/loader.test.tsx +2 -2
- package/test/dom/revalidate.test.tsx +1 -1
- package/test/dom/route-head.test.tsx +1 -2
- package/test/dom/slot.test.tsx +131 -109
- package/test/dom/view-transitions.test.tsx +53 -51
- package/test/features.test.ts +149 -142
- package/test/fonts.test.ts +28 -26
- package/test/head.test.ts +45 -35
- package/test/metadata.test.ts +42 -41
- package/test/pages.test.ts +105 -0
- package/test/prerender.test.ts +54 -46
- package/test/search.test.ts +114 -0
- package/test/seo.test.ts +164 -142
- package/test/update.test.ts +44 -0
package/src/cli/index.ts
CHANGED
|
@@ -1,211 +1,242 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* toiljs CLI. Routes `create` / `dev` / `build` and wraps them in the toiljs brand banner.
|
|
4
|
-
* The compiler stays presentation-free (imported via the package's own `toiljs/compiler`
|
|
5
|
-
* export); the epic bits, banner, the Clack scaffolding wizard, live here.
|
|
6
|
-
*/
|
|
7
|
-
import { build, dev, start } from 'toiljs/compiler';
|
|
8
|
-
|
|
9
|
-
import { runConfigure } from './configure.js';
|
|
10
|
-
import { runCreate, type Template } from './create.js';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
break;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
flags.
|
|
50
|
-
break;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
break;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
cmd('
|
|
116
|
-
cmd('
|
|
117
|
-
cmd('
|
|
118
|
-
cmd('
|
|
119
|
-
cmd('
|
|
120
|
-
'',
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
images: flags.images,
|
|
160
|
-
install: flags.install,
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
process.stdout.write(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
);
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
case '
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* toiljs CLI. Routes `create` / `dev` / `build` and wraps them in the toiljs brand banner.
|
|
4
|
+
* The compiler stays presentation-free (imported via the package's own `toiljs/compiler`
|
|
5
|
+
* export); the epic bits, banner, the Clack scaffolding wizard, live here.
|
|
6
|
+
*/
|
|
7
|
+
import { build, dev, start } from 'toiljs/compiler';
|
|
8
|
+
|
|
9
|
+
import { runConfigure } from './configure.js';
|
|
10
|
+
import { runCreate, type Template } from './create.js';
|
|
11
|
+
import { runDoctor } from './doctor.js';
|
|
12
|
+
import { runUpdate } from './update.js';
|
|
13
|
+
import { type Preprocessor, PREPROCESSORS } from './features.js';
|
|
14
|
+
import { accent, banner, bold, danger, dim, success, version } from './ui.js';
|
|
15
|
+
|
|
16
|
+
interface Flags {
|
|
17
|
+
root?: string;
|
|
18
|
+
port?: number;
|
|
19
|
+
name?: string;
|
|
20
|
+
template?: Template;
|
|
21
|
+
preprocessor?: Preprocessor;
|
|
22
|
+
tailwind?: boolean;
|
|
23
|
+
ai?: boolean;
|
|
24
|
+
images?: boolean;
|
|
25
|
+
install?: boolean;
|
|
26
|
+
git?: boolean;
|
|
27
|
+
pm?: string;
|
|
28
|
+
yes?: boolean;
|
|
29
|
+
json?: boolean;
|
|
30
|
+
target?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function parseArgs(argv: string[]): Flags {
|
|
34
|
+
const flags: Flags = {};
|
|
35
|
+
for (let i = 0; i < argv.length; i++) {
|
|
36
|
+
const arg = argv[i];
|
|
37
|
+
switch (arg) {
|
|
38
|
+
case '--root':
|
|
39
|
+
flags.root = argv[++i];
|
|
40
|
+
break;
|
|
41
|
+
case '--port': {
|
|
42
|
+
const port = Number(argv[++i]);
|
|
43
|
+
if (!Number.isNaN(port)) flags.port = port;
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
case '--template':
|
|
47
|
+
case '-t': {
|
|
48
|
+
const t = argv[++i];
|
|
49
|
+
if (t === 'app' || t === 'minimal') flags.template = t;
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
case '--pm':
|
|
53
|
+
flags.pm = argv[++i];
|
|
54
|
+
break;
|
|
55
|
+
case '--style': {
|
|
56
|
+
const s = argv[++i];
|
|
57
|
+
if ((PREPROCESSORS as readonly string[]).includes(s))
|
|
58
|
+
flags.preprocessor = s as Preprocessor;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
case '--tailwind':
|
|
62
|
+
flags.tailwind = true;
|
|
63
|
+
break;
|
|
64
|
+
case '--no-tailwind':
|
|
65
|
+
flags.tailwind = false;
|
|
66
|
+
break;
|
|
67
|
+
case '--ai':
|
|
68
|
+
flags.ai = true;
|
|
69
|
+
break;
|
|
70
|
+
case '--no-ai':
|
|
71
|
+
flags.ai = false;
|
|
72
|
+
break;
|
|
73
|
+
case '--images':
|
|
74
|
+
flags.images = true;
|
|
75
|
+
break;
|
|
76
|
+
case '--no-images':
|
|
77
|
+
flags.images = false;
|
|
78
|
+
break;
|
|
79
|
+
case '--install':
|
|
80
|
+
flags.install = true;
|
|
81
|
+
break;
|
|
82
|
+
case '--no-install':
|
|
83
|
+
flags.install = false;
|
|
84
|
+
break;
|
|
85
|
+
case '--git':
|
|
86
|
+
flags.git = true;
|
|
87
|
+
break;
|
|
88
|
+
case '--no-git':
|
|
89
|
+
flags.git = false;
|
|
90
|
+
break;
|
|
91
|
+
case '-y':
|
|
92
|
+
case '--yes':
|
|
93
|
+
flags.yes = true;
|
|
94
|
+
break;
|
|
95
|
+
case '--json':
|
|
96
|
+
flags.json = true;
|
|
97
|
+
break;
|
|
98
|
+
case '--target':
|
|
99
|
+
flags.target = argv[++i];
|
|
100
|
+
break;
|
|
101
|
+
default:
|
|
102
|
+
if (!arg.startsWith('-') && flags.name === undefined) flags.name = arg;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return flags;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function printHelp(): void {
|
|
109
|
+
const cmd = (name: string, desc: string): string => ` ${accent(name.padEnd(15))}${dim(desc)}`;
|
|
110
|
+
process.stdout.write(
|
|
111
|
+
[
|
|
112
|
+
`${bold('Usage')} ${dim('toiljs')} <command> [options]`,
|
|
113
|
+
'',
|
|
114
|
+
bold('Commands'),
|
|
115
|
+
cmd('create [name]', 'scaffold a new toiljs app'),
|
|
116
|
+
cmd('configure', 'toggle styling features (Sass/Less/Stylus, Tailwind)'),
|
|
117
|
+
cmd('dev', 'start the dev server with HMR'),
|
|
118
|
+
cmd('build', 'build the optimized production bundle'),
|
|
119
|
+
cmd('start', 'self-host the built app (hyper-express / uWS)'),
|
|
120
|
+
cmd('doctor', 'diagnose project setup and dependencies'),
|
|
121
|
+
cmd('update', 'check for and apply dependency updates'),
|
|
122
|
+
'',
|
|
123
|
+
bold('Options'),
|
|
124
|
+
cmd('--root <dir>', 'project root (default: current directory)'),
|
|
125
|
+
cmd('--port <n>', 'dev server port'),
|
|
126
|
+
cmd('-t, --template', 'create: app | minimal'),
|
|
127
|
+
cmd('--style <name>', 'create/configure: css | sass | less | stylus'),
|
|
128
|
+
cmd('--tailwind', 'create/configure: enable Tailwind (--no-tailwind to remove)'),
|
|
129
|
+
cmd('--no-ai', 'create: skip AI assistant files (CLAUDE.md, etc.)'),
|
|
130
|
+
cmd('-y, --yes', 'create: accept defaults (non-interactive)'),
|
|
131
|
+
cmd('--no-install', "create: don't install dependencies"),
|
|
132
|
+
cmd('--json', 'doctor: machine-readable output'),
|
|
133
|
+
cmd('--target <t>', 'update: latest | minor | patch | newest | greatest'),
|
|
134
|
+
cmd('-v, --version', 'print the toiljs version'),
|
|
135
|
+
'',
|
|
136
|
+
].join('\n') + '\n',
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async function main(): Promise<void> {
|
|
141
|
+
const [command, ...rest] = process.argv.slice(2);
|
|
142
|
+
|
|
143
|
+
if (command === '--version' || command === '-v') {
|
|
144
|
+
process.stdout.write(version() + '\n');
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const flags = parseArgs(rest);
|
|
149
|
+
|
|
150
|
+
switch (command) {
|
|
151
|
+
case 'create':
|
|
152
|
+
banner();
|
|
153
|
+
await runCreate({
|
|
154
|
+
name: flags.name,
|
|
155
|
+
template: flags.template,
|
|
156
|
+
preprocessor: flags.preprocessor,
|
|
157
|
+
tailwind: flags.tailwind,
|
|
158
|
+
ai: flags.ai,
|
|
159
|
+
images: flags.images,
|
|
160
|
+
install: flags.install,
|
|
161
|
+
git: flags.git,
|
|
162
|
+
pm: flags.pm,
|
|
163
|
+
yes: flags.yes,
|
|
164
|
+
cwd: process.cwd(),
|
|
165
|
+
});
|
|
166
|
+
break;
|
|
167
|
+
|
|
168
|
+
case 'configure':
|
|
169
|
+
banner();
|
|
170
|
+
await runConfigure({
|
|
171
|
+
root: flags.root,
|
|
172
|
+
preprocessor: flags.preprocessor,
|
|
173
|
+
tailwind: flags.tailwind,
|
|
174
|
+
images: flags.images,
|
|
175
|
+
install: flags.install,
|
|
176
|
+
cwd: process.cwd(),
|
|
177
|
+
});
|
|
178
|
+
break;
|
|
179
|
+
|
|
180
|
+
case 'dev':
|
|
181
|
+
banner();
|
|
182
|
+
process.stdout.write(dim(' starting dev server…') + '\n\n');
|
|
183
|
+
await dev({ root: flags.root, port: flags.port });
|
|
184
|
+
break;
|
|
185
|
+
|
|
186
|
+
case 'build':
|
|
187
|
+
banner();
|
|
188
|
+
process.stdout.write(dim(' building for production…') + '\n\n');
|
|
189
|
+
await build({ root: flags.root });
|
|
190
|
+
process.stdout.write('\n' + success(' ✓ ') + bold('build complete') + '\n\n');
|
|
191
|
+
break;
|
|
192
|
+
|
|
193
|
+
case 'start': {
|
|
194
|
+
banner();
|
|
195
|
+
process.stdout.write(dim(' self-hosting the built app…') + '\n\n');
|
|
196
|
+
const server = await start({ root: flags.root, port: flags.port });
|
|
197
|
+
process.stdout.write(
|
|
198
|
+
accent(' ➜ ') +
|
|
199
|
+
bold(`http://localhost:${String(server.port)}`) +
|
|
200
|
+
dim(` ws channel: ${server.wsPath}`) +
|
|
201
|
+
'\n\n',
|
|
202
|
+
);
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
case 'doctor':
|
|
207
|
+
// Skip the banner for --json so stdout stays valid JSON.
|
|
208
|
+
if (!flags.json) banner();
|
|
209
|
+
await runDoctor({ root: flags.root, cwd: process.cwd(), json: flags.json });
|
|
210
|
+
break;
|
|
211
|
+
|
|
212
|
+
case 'update':
|
|
213
|
+
banner();
|
|
214
|
+
await runUpdate({
|
|
215
|
+
root: flags.root,
|
|
216
|
+
cwd: process.cwd(),
|
|
217
|
+
yes: flags.yes,
|
|
218
|
+
target: flags.target,
|
|
219
|
+
});
|
|
220
|
+
break;
|
|
221
|
+
|
|
222
|
+
case 'help':
|
|
223
|
+
case '--help':
|
|
224
|
+
case '-h':
|
|
225
|
+
case undefined:
|
|
226
|
+
banner();
|
|
227
|
+
printHelp();
|
|
228
|
+
break;
|
|
229
|
+
|
|
230
|
+
default:
|
|
231
|
+
banner();
|
|
232
|
+
process.stdout.write(dim(` unknown command: ${command}`) + '\n\n');
|
|
233
|
+
printHelp();
|
|
234
|
+
process.exitCode = 1;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
main().catch((err: unknown) => {
|
|
239
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
240
|
+
process.stderr.write('\n' + danger(' ✗ ') + message + '\n');
|
|
241
|
+
process.exitCode = 1;
|
|
242
|
+
});
|
package/src/cli/proc.ts
CHANGED
|
@@ -18,3 +18,33 @@ export function run(cmd: string, args: string[], cwd: string): Promise<void> {
|
|
|
18
18
|
);
|
|
19
19
|
});
|
|
20
20
|
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Like {@link run}, but captures stdout/stderr and resolves with them plus the exit code (it never
|
|
24
|
+
* rejects on a non-zero exit, the caller decides). Used to read JSON from tools like
|
|
25
|
+
* `npm-check-updates`. Same Windows shell handling as {@link run}; args are fixed/allowlisted.
|
|
26
|
+
*/
|
|
27
|
+
export function capture(
|
|
28
|
+
cmd: string,
|
|
29
|
+
args: string[],
|
|
30
|
+
cwd: string,
|
|
31
|
+
): Promise<{ stdout: string; stderr: string; code: number }> {
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
const onWindows = process.platform === 'win32';
|
|
34
|
+
const child = onWindows
|
|
35
|
+
? spawn([cmd, ...args].join(' '), { cwd, shell: true })
|
|
36
|
+
: spawn(cmd, args, { cwd });
|
|
37
|
+
let stdout = '';
|
|
38
|
+
let stderr = '';
|
|
39
|
+
child.stdout?.on('data', (d: Buffer) => {
|
|
40
|
+
stdout += d.toString();
|
|
41
|
+
});
|
|
42
|
+
child.stderr?.on('data', (d: Buffer) => {
|
|
43
|
+
stderr += d.toString();
|
|
44
|
+
});
|
|
45
|
+
child.on('error', reject);
|
|
46
|
+
child.on('close', (code) => {
|
|
47
|
+
resolve({ stdout, stderr, code: code ?? 1 });
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
}
|