reset-framework-cli 1.1.2 → 1.1.5
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/LICENSE +20 -20
- package/README.md +47 -47
- package/package.json +4 -4
- package/src/commands/build.js +114 -113
- package/src/commands/dev.js +148 -144
- package/src/commands/doctor.js +89 -89
- package/src/commands/init.js +838 -903
- package/src/commands/package.js +49 -44
- package/src/index.js +213 -213
- package/src/lib/context.js +66 -66
- package/src/lib/framework.js +150 -28
- package/src/lib/logger.js +11 -11
- package/src/lib/output.js +214 -106
- package/src/lib/process.js +253 -156
- package/src/lib/project.js +559 -475
- package/src/lib/toolchain.js +62 -62
- package/src/lib/ui.js +244 -244
- package/templates/basic/README.md +15 -15
- package/templates/basic/frontend/README.md +73 -73
- package/templates/basic/frontend/eslint.config.js +23 -23
- package/templates/basic/frontend/index.html +13 -13
- package/templates/basic/frontend/package.json +31 -31
- package/templates/basic/frontend/public/icons.svg +24 -24
- package/templates/basic/frontend/src/App.css +216 -138
- package/templates/basic/frontend/src/App.tsx +77 -76
- package/templates/basic/frontend/src/assets/vite.svg +1 -1
- package/templates/basic/frontend/src/index.css +111 -111
- package/templates/basic/frontend/src/lib/reset.ts +1 -1
- package/templates/basic/frontend/src/main.tsx +10 -10
- package/templates/basic/frontend/tsconfig.app.json +28 -28
- package/templates/basic/frontend/tsconfig.json +7 -7
- package/templates/basic/frontend/tsconfig.node.json +26 -26
- package/templates/basic/frontend/vite.config.ts +16 -16
- package/templates/basic/reset.config.json +58 -58
package/src/lib/process.js
CHANGED
|
@@ -1,206 +1,303 @@
|
|
|
1
|
-
import { spawn } from "node:child_process"
|
|
2
|
-
|
|
3
|
-
import { logger } from "./logger.js"
|
|
4
|
-
|
|
5
|
-
function sleep(ms) {
|
|
6
|
-
return new Promise((resolve) => {
|
|
7
|
-
setTimeout(resolve, ms)
|
|
8
|
-
})
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function resolveNpmCommand() {
|
|
12
|
-
return process.platform === "win32" ? "npm.cmd" : "npm"
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function resolvePackageManagerCommand(packageManager = "npm") {
|
|
16
|
-
if (packageManager === "npm") {
|
|
17
|
-
return resolveNpmCommand()
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (packageManager === "yarn") {
|
|
21
|
-
return process.platform === "win32" ? "yarn.cmd" : "yarn"
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (packageManager === "pnpm") {
|
|
25
|
-
return process.platform === "win32" ? "pnpm.cmd" : "pnpm"
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (packageManager === "bun") {
|
|
29
|
-
return process.platform === "win32" ? "bun.exe" : "bun"
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
throw new Error(`Unsupported package manager: ${packageManager}`)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function getInstallCommandArgs(packageManager = "npm") {
|
|
36
|
-
if (packageManager === "npm") {
|
|
37
|
-
return ["install", "--include=optional"]
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (packageManager === "yarn") {
|
|
41
|
-
return ["install"]
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return ["install"]
|
|
45
|
-
}
|
|
46
|
-
|
|
1
|
+
import { spawn, spawnSync } from "node:child_process"
|
|
2
|
+
|
|
3
|
+
import { logger } from "./logger.js"
|
|
4
|
+
|
|
5
|
+
function sleep(ms) {
|
|
6
|
+
return new Promise((resolve) => {
|
|
7
|
+
setTimeout(resolve, ms)
|
|
8
|
+
})
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function resolveNpmCommand() {
|
|
12
|
+
return process.platform === "win32" ? "npm.cmd" : "npm"
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function resolvePackageManagerCommand(packageManager = "npm") {
|
|
16
|
+
if (packageManager === "npm") {
|
|
17
|
+
return resolveNpmCommand()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (packageManager === "yarn") {
|
|
21
|
+
return process.platform === "win32" ? "yarn.cmd" : "yarn"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (packageManager === "pnpm") {
|
|
25
|
+
return process.platform === "win32" ? "pnpm.cmd" : "pnpm"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (packageManager === "bun") {
|
|
29
|
+
return process.platform === "win32" ? "bun.exe" : "bun"
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
throw new Error(`Unsupported package manager: ${packageManager}`)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function getInstallCommandArgs(packageManager = "npm") {
|
|
36
|
+
if (packageManager === "npm") {
|
|
37
|
+
return ["install", "--include=optional"]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (packageManager === "yarn") {
|
|
41
|
+
return ["install"]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return ["install"]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
47
|
export function formatCommand(command, args = []) {
|
|
48
48
|
return [command, ...args].join(" ")
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
function shouldUseShell(command) {
|
|
52
|
+
return process.platform === "win32" && typeof command === "string" && /\.(cmd|bat)$/i.test(command)
|
|
53
|
+
}
|
|
54
|
+
|
|
51
55
|
export async function runCommand(command, args = [], options = {}) {
|
|
52
56
|
const { cwd, dryRun = false, env } = options
|
|
53
57
|
|
|
54
58
|
logger.info(`$ ${formatCommand(command, args)}`)
|
|
55
|
-
|
|
56
|
-
if (dryRun) {
|
|
57
|
-
return
|
|
58
|
-
}
|
|
59
|
-
|
|
59
|
+
|
|
60
|
+
if (dryRun) {
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
60
64
|
await new Promise((resolve, reject) => {
|
|
61
65
|
const child = spawn(command, args, {
|
|
62
66
|
cwd,
|
|
63
67
|
env: env ? { ...process.env, ...env } : process.env,
|
|
64
|
-
stdio: "inherit"
|
|
68
|
+
stdio: "inherit",
|
|
69
|
+
shell: shouldUseShell(command)
|
|
65
70
|
})
|
|
66
71
|
|
|
67
72
|
child.once("error", reject)
|
|
68
|
-
child.once("exit", (code, signal) => {
|
|
69
|
-
if (code === 0) {
|
|
70
|
-
resolve(undefined)
|
|
71
|
-
return
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
reject(
|
|
75
|
-
new Error(
|
|
76
|
-
signal
|
|
77
|
-
? `Command terminated by signal: ${signal}`
|
|
78
|
-
: `Command exited with code ${code}`
|
|
79
|
-
)
|
|
80
|
-
)
|
|
81
|
-
})
|
|
82
|
-
})
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export async function captureCommandOutput(command, args = [], options = {}) {
|
|
86
|
-
const { cwd, env } = options
|
|
87
|
-
|
|
88
|
-
await Promise.resolve()
|
|
89
|
-
|
|
73
|
+
child.once("exit", (code, signal) => {
|
|
74
|
+
if (code === 0) {
|
|
75
|
+
resolve(undefined)
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
reject(
|
|
80
|
+
new Error(
|
|
81
|
+
signal
|
|
82
|
+
? `Command terminated by signal: ${signal}`
|
|
83
|
+
: `Command exited with code ${code}`
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
})
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export async function captureCommandOutput(command, args = [], options = {}) {
|
|
91
|
+
const { cwd, env } = options
|
|
92
|
+
|
|
93
|
+
await Promise.resolve()
|
|
94
|
+
|
|
90
95
|
return await new Promise((resolve, reject) => {
|
|
91
96
|
const child = spawn(command, args, {
|
|
92
97
|
cwd,
|
|
93
98
|
env: env ? { ...process.env, ...env } : process.env,
|
|
94
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
let stdout = ""
|
|
98
|
-
let stderr = ""
|
|
99
|
-
|
|
100
|
-
child.stdout?.on("data", (chunk) => {
|
|
101
|
-
stdout += String(chunk)
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
child.stderr?.on("data", (chunk) => {
|
|
105
|
-
stderr += String(chunk)
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
child.once("error", reject)
|
|
109
|
-
child.once("exit", (code, signal) => {
|
|
110
|
-
if (code === 0) {
|
|
111
|
-
resolve(stdout.trim())
|
|
112
|
-
return
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
reject(
|
|
116
|
-
new Error(
|
|
117
|
-
signal
|
|
118
|
-
? `Command terminated by signal: ${signal}`
|
|
119
|
-
: (stderr.trim() || stdout.trim() || `Command exited with code ${code}`)
|
|
120
|
-
)
|
|
121
|
-
)
|
|
99
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
100
|
+
shell: shouldUseShell(command)
|
|
122
101
|
})
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
102
|
+
|
|
103
|
+
let stdout = ""
|
|
104
|
+
let stderr = ""
|
|
105
|
+
|
|
106
|
+
child.stdout?.on("data", (chunk) => {
|
|
107
|
+
stdout += String(chunk)
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
child.stderr?.on("data", (chunk) => {
|
|
111
|
+
stderr += String(chunk)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
child.once("error", reject)
|
|
115
|
+
child.once("exit", (code, signal) => {
|
|
116
|
+
if (code === 0) {
|
|
117
|
+
resolve(stdout.trim())
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
reject(
|
|
122
|
+
new Error(
|
|
123
|
+
signal
|
|
124
|
+
? `Command terminated by signal: ${signal}`
|
|
125
|
+
: (stderr.trim() || stdout.trim() || `Command exited with code ${code}`)
|
|
126
|
+
)
|
|
127
|
+
)
|
|
128
|
+
})
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
|
|
126
132
|
export function spawnCommand(command, args = [], options = {}) {
|
|
127
133
|
const { cwd, dryRun = false, env } = options
|
|
128
134
|
|
|
129
135
|
logger.info(`$ ${formatCommand(command, args)}`)
|
|
130
|
-
|
|
131
|
-
if (dryRun) {
|
|
132
|
-
return null
|
|
133
|
-
}
|
|
134
|
-
|
|
136
|
+
|
|
137
|
+
if (dryRun) {
|
|
138
|
+
return null
|
|
139
|
+
}
|
|
140
|
+
|
|
135
141
|
return spawn(command, args, {
|
|
136
142
|
cwd,
|
|
137
143
|
env: env ? { ...process.env, ...env } : process.env,
|
|
138
|
-
|
|
144
|
+
detached: process.platform !== "win32",
|
|
145
|
+
stdio: "inherit",
|
|
146
|
+
shell: shouldUseShell(command)
|
|
139
147
|
})
|
|
140
148
|
}
|
|
149
|
+
|
|
150
|
+
export function waitForProcessExit(child, label) {
|
|
151
|
+
return new Promise((resolve, reject) => {
|
|
152
|
+
child.once("error", reject)
|
|
153
|
+
child.once("exit", (code, signal) => {
|
|
154
|
+
if (code === 0 || signal === "SIGINT" || signal === "SIGTERM") {
|
|
155
|
+
resolve(undefined)
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
reject(
|
|
160
|
+
new Error(
|
|
161
|
+
signal
|
|
162
|
+
? `${label} terminated by signal: ${signal}`
|
|
163
|
+
: `${label} exited with code ${code}`
|
|
164
|
+
)
|
|
165
|
+
)
|
|
166
|
+
})
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function registerChildCleanup(children) {
|
|
171
|
+
const activeChildren = children.filter(Boolean)
|
|
172
|
+
let cleanupPromise = null
|
|
141
173
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (code === 0 || signal === "SIGINT" || signal === "SIGTERM") {
|
|
147
|
-
resolve(undefined)
|
|
174
|
+
const waitForChildExit = (child, timeoutMs = 3000) =>
|
|
175
|
+
new Promise((resolve) => {
|
|
176
|
+
if (!child || child.exitCode !== null || child.signalCode !== null) {
|
|
177
|
+
resolve(true)
|
|
148
178
|
return
|
|
149
179
|
}
|
|
150
180
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
)
|
|
181
|
+
const handleExit = () => {
|
|
182
|
+
clearTimeout(timeout)
|
|
183
|
+
child.off("error", handleError)
|
|
184
|
+
resolve(true)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const handleError = () => {
|
|
188
|
+
clearTimeout(timeout)
|
|
189
|
+
child.off("exit", handleExit)
|
|
190
|
+
resolve(true)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const timeout = setTimeout(() => {
|
|
194
|
+
child.off("exit", handleExit)
|
|
195
|
+
child.off("error", handleError)
|
|
196
|
+
resolve(false)
|
|
197
|
+
}, timeoutMs)
|
|
198
|
+
|
|
199
|
+
child.once("exit", handleExit)
|
|
200
|
+
child.once("error", handleError)
|
|
158
201
|
})
|
|
159
|
-
})
|
|
160
|
-
}
|
|
161
202
|
|
|
162
|
-
|
|
163
|
-
|
|
203
|
+
const terminateChild = async (child) => {
|
|
204
|
+
if (!child || child.pid == null || child.exitCode !== null || child.signalCode !== null) {
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (process.platform === "win32") {
|
|
209
|
+
const result = spawnSync("taskkill.exe", ["/pid", String(child.pid), "/t", "/f"], {
|
|
210
|
+
stdio: "ignore",
|
|
211
|
+
windowsHide: true
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
if (result.status !== 0 && child.exitCode === null && child.signalCode === null) {
|
|
215
|
+
try {
|
|
216
|
+
child.kill("SIGTERM")
|
|
217
|
+
} catch {
|
|
218
|
+
// Ignore late shutdown races.
|
|
219
|
+
}
|
|
220
|
+
}
|
|
164
221
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
222
|
+
await waitForChildExit(child, 2000)
|
|
223
|
+
return
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
try {
|
|
227
|
+
process.kill(-child.pid, "SIGTERM")
|
|
228
|
+
} catch (error) {
|
|
229
|
+
if (error?.code !== "ESRCH") {
|
|
230
|
+
try {
|
|
231
|
+
child.kill("SIGTERM")
|
|
232
|
+
} catch {
|
|
233
|
+
// Ignore late shutdown races.
|
|
234
|
+
}
|
|
169
235
|
}
|
|
170
236
|
}
|
|
237
|
+
|
|
238
|
+
if (await waitForChildExit(child, 3000)) {
|
|
239
|
+
return
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
try {
|
|
243
|
+
process.kill(-child.pid, "SIGKILL")
|
|
244
|
+
} catch (error) {
|
|
245
|
+
if (error?.code !== "ESRCH") {
|
|
246
|
+
try {
|
|
247
|
+
child.kill("SIGKILL")
|
|
248
|
+
} catch {
|
|
249
|
+
// Ignore late shutdown races.
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
await waitForChildExit(child, 1000)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const cleanup = async () => {
|
|
258
|
+
if (cleanupPromise) {
|
|
259
|
+
return cleanupPromise
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
cleanupPromise = (async () => {
|
|
263
|
+
await Promise.all(activeChildren.map((child) => terminateChild(child)))
|
|
264
|
+
})()
|
|
265
|
+
|
|
266
|
+
return cleanupPromise
|
|
171
267
|
}
|
|
172
268
|
|
|
173
269
|
const handleSignal = () => {
|
|
174
|
-
cleanup()
|
|
175
|
-
|
|
270
|
+
void cleanup().finally(() => {
|
|
271
|
+
process.exit(0)
|
|
272
|
+
})
|
|
176
273
|
}
|
|
177
274
|
|
|
178
275
|
process.on("SIGINT", handleSignal)
|
|
179
276
|
process.on("SIGTERM", handleSignal)
|
|
180
277
|
|
|
181
|
-
return () => {
|
|
278
|
+
return async () => {
|
|
182
279
|
process.off("SIGINT", handleSignal)
|
|
183
280
|
process.off("SIGTERM", handleSignal)
|
|
184
|
-
cleanup()
|
|
281
|
+
await cleanup()
|
|
185
282
|
}
|
|
186
283
|
}
|
|
187
|
-
|
|
188
|
-
export async function waitForUrl(url, options = {}) {
|
|
189
|
-
const { intervalMs = 250, timeoutMs = 15000 } = options
|
|
190
|
-
const deadline = Date.now() + timeoutMs
|
|
191
|
-
|
|
192
|
-
while (Date.now() < deadline) {
|
|
193
|
-
try {
|
|
194
|
-
const response = await fetch(url)
|
|
195
|
-
if (response.status < 500) {
|
|
196
|
-
return
|
|
197
|
-
}
|
|
198
|
-
} catch {
|
|
199
|
-
// Retry until timeout.
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
await sleep(intervalMs)
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
throw new Error(`Timed out waiting for ${url}`)
|
|
206
|
-
}
|
|
284
|
+
|
|
285
|
+
export async function waitForUrl(url, options = {}) {
|
|
286
|
+
const { intervalMs = 250, timeoutMs = 15000 } = options
|
|
287
|
+
const deadline = Date.now() + timeoutMs
|
|
288
|
+
|
|
289
|
+
while (Date.now() < deadline) {
|
|
290
|
+
try {
|
|
291
|
+
const response = await fetch(url)
|
|
292
|
+
if (response.status < 500) {
|
|
293
|
+
return
|
|
294
|
+
}
|
|
295
|
+
} catch {
|
|
296
|
+
// Retry until timeout.
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
await sleep(intervalMs)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
throw new Error(`Timed out waiting for ${url}`)
|
|
303
|
+
}
|