reset-framework-cli 1.1.4 → 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/package.json +4 -4
- package/src/commands/dev.js +10 -10
- package/src/commands/init.js +44 -114
- package/src/lib/process.js +120 -30
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reset-framework-cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Command-line tooling for Reset Framework.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
"node": ">=20.19.0"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@reset-framework/native": "1.1.
|
|
15
|
-
"@reset-framework/schema": "1.1.
|
|
16
|
-
"@reset-framework/sdk": "1.1.
|
|
14
|
+
"@reset-framework/native": "1.1.5",
|
|
15
|
+
"@reset-framework/schema": "1.1.5",
|
|
16
|
+
"@reset-framework/sdk": "1.1.5"
|
|
17
17
|
},
|
|
18
18
|
"bin": {
|
|
19
19
|
"reset-framework-cli": "src/index.js"
|
package/src/commands/dev.js
CHANGED
|
@@ -155,13 +155,13 @@ export async function run(context) {
|
|
|
155
155
|
|
|
156
156
|
const cleanup = registerChildCleanup(children)
|
|
157
157
|
|
|
158
|
-
try {
|
|
159
|
-
await Promise.race([
|
|
160
|
-
...children.map((child, index) =>
|
|
161
|
-
waitForProcessExit(child, index === 0 ? "dev process" : "native host")
|
|
162
|
-
)
|
|
163
|
-
])
|
|
164
|
-
} finally {
|
|
165
|
-
cleanup()
|
|
166
|
-
}
|
|
167
|
-
}
|
|
158
|
+
try {
|
|
159
|
+
await Promise.race([
|
|
160
|
+
...children.map((child, index) =>
|
|
161
|
+
waitForProcessExit(child, index === 0 ? "dev process" : "native host")
|
|
162
|
+
)
|
|
163
|
+
])
|
|
164
|
+
} finally {
|
|
165
|
+
await cleanup()
|
|
166
|
+
}
|
|
167
|
+
}
|
package/src/commands/init.js
CHANGED
|
@@ -176,90 +176,7 @@ function App() {
|
|
|
176
176
|
export default App
|
|
177
177
|
`
|
|
178
178
|
|
|
179
|
-
const
|
|
180
|
-
import path from 'node:path'
|
|
181
|
-
import { spawn } from 'node:child_process'
|
|
182
|
-
|
|
183
|
-
const script = process.argv[2]
|
|
184
|
-
if (!script) {
|
|
185
|
-
throw new Error('Missing frontend script name.')
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const appRoot = process.cwd()
|
|
189
|
-
const config = JSON.parse(readFileSync(path.join(appRoot, 'reset.config.json'), 'utf8'))
|
|
190
|
-
const frontendDir =
|
|
191
|
-
typeof config?.project?.frontendDir === 'string' && config.project.frontendDir.trim() !== ''
|
|
192
|
-
? path.resolve(appRoot, config.project.frontendDir)
|
|
193
|
-
: path.join(appRoot, 'frontend')
|
|
194
|
-
|
|
195
|
-
function shouldUseShell(command) {
|
|
196
|
-
return process.platform === 'win32' && typeof command === 'string' && /\\.(cmd|bat)$/i.test(command)
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function resolvePackageManagerCommand() {
|
|
200
|
-
const packageJsonPath = path.join(appRoot, 'package.json')
|
|
201
|
-
const manifest = JSON.parse(readFileSync(packageJsonPath, 'utf8'))
|
|
202
|
-
const packageManager = typeof manifest.packageManager === 'string' ? manifest.packageManager.trim() : ''
|
|
203
|
-
const name = packageManager.split('@')[0]
|
|
204
|
-
|
|
205
|
-
if (name === 'bun') {
|
|
206
|
-
return process.platform === 'win32' ? 'bun.exe' : 'bun'
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if (name === 'pnpm') {
|
|
210
|
-
return process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm'
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
if (name === 'yarn') {
|
|
214
|
-
return process.platform === 'win32' ? 'yarn.cmd' : 'yarn'
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
if (name === 'npm') {
|
|
218
|
-
return process.platform === 'win32' ? 'npm.cmd' : 'npm'
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
const candidates = [
|
|
222
|
-
['bun.lock', process.platform === 'win32' ? 'bun.exe' : 'bun'],
|
|
223
|
-
['bun.lockb', process.platform === 'win32' ? 'bun.exe' : 'bun'],
|
|
224
|
-
['pnpm-lock.yaml', process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm'],
|
|
225
|
-
['yarn.lock', process.platform === 'win32' ? 'yarn.cmd' : 'yarn'],
|
|
226
|
-
['package-lock.json', process.platform === 'win32' ? 'npm.cmd' : 'npm']
|
|
227
|
-
]
|
|
228
|
-
|
|
229
|
-
for (const [fileName, command] of candidates) {
|
|
230
|
-
try {
|
|
231
|
-
readFileSync(path.join(appRoot, fileName), 'utf8')
|
|
232
|
-
return command
|
|
233
|
-
} catch {}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
return process.platform === 'win32' ? 'npm.cmd' : 'npm'
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const command = resolvePackageManagerCommand()
|
|
240
|
-
const child = spawn(command, ['run', script, '--', ...process.argv.slice(3)], {
|
|
241
|
-
cwd: frontendDir,
|
|
242
|
-
stdio: 'inherit',
|
|
243
|
-
env: process.env,
|
|
244
|
-
shell: shouldUseShell(command)
|
|
245
|
-
})
|
|
246
|
-
|
|
247
|
-
child.once('error', (error) => {
|
|
248
|
-
console.error(error)
|
|
249
|
-
process.exit(1)
|
|
250
|
-
})
|
|
251
|
-
|
|
252
|
-
child.once('exit', (code, signal) => {
|
|
253
|
-
if (signal) {
|
|
254
|
-
process.kill(process.pid, signal)
|
|
255
|
-
return
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
process.exit(code ?? 1)
|
|
259
|
-
})
|
|
260
|
-
`
|
|
261
|
-
|
|
262
|
-
export const description = "Scaffold a starter app with an interactive project setup"
|
|
179
|
+
export const description = "Scaffold a starter app with an interactive project setup"
|
|
263
180
|
|
|
264
181
|
function listTemplates(templatesDir) {
|
|
265
182
|
return readdirSync(templatesDir, { withFileTypes: true })
|
|
@@ -383,9 +300,31 @@ function resolvePackageManagerOption(context) {
|
|
|
383
300
|
return "npm"
|
|
384
301
|
}
|
|
385
302
|
|
|
386
|
-
function describeInstallCommand(packageManager) {
|
|
387
|
-
return [packageManager, ...getInstallCommandArgs(packageManager)].join(" ")
|
|
388
|
-
}
|
|
303
|
+
function describeInstallCommand(packageManager) {
|
|
304
|
+
return [packageManager, ...getInstallCommandArgs(packageManager)].join(" ")
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function createFrontendScriptCommand(packageManager, frontendDir, scriptName) {
|
|
308
|
+
const frontendPath = JSON.stringify(frontendDir.replace(/\\/g, "/"))
|
|
309
|
+
|
|
310
|
+
if (packageManager === "npm") {
|
|
311
|
+
return `npm --workspace ${frontendPath} run ${scriptName} --`
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (packageManager === "pnpm") {
|
|
315
|
+
return `pnpm --dir ${frontendPath} run ${scriptName} --`
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (packageManager === "yarn") {
|
|
319
|
+
return `yarn --cwd ${frontendPath} run ${scriptName}`
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (packageManager === "bun") {
|
|
323
|
+
return `bun --cwd ${frontendPath} run ${scriptName}`
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
throw new Error(`Unsupported package manager: ${packageManager}`)
|
|
327
|
+
}
|
|
389
328
|
|
|
390
329
|
async function ensureWritableTarget(targetDir, force) {
|
|
391
330
|
if (!existsSync(targetDir)) {
|
|
@@ -491,13 +430,13 @@ function createRootPackageJson(options) {
|
|
|
491
430
|
base.packageManager = packageManagerVersion
|
|
492
431
|
}
|
|
493
432
|
|
|
494
|
-
if (options.frontendDir !== ".") {
|
|
495
|
-
base.workspaces = [options.frontendDir]
|
|
496
|
-
base.scripts["dev:web"] =
|
|
497
|
-
base.scripts["build:web"] =
|
|
498
|
-
base.scripts["lint:web"] =
|
|
499
|
-
base.scripts["preview:web"] =
|
|
500
|
-
}
|
|
433
|
+
if (options.frontendDir !== ".") {
|
|
434
|
+
base.workspaces = [options.frontendDir]
|
|
435
|
+
base.scripts["dev:web"] = createFrontendScriptCommand(options.packageManager, options.frontendDir, "dev")
|
|
436
|
+
base.scripts["build:web"] = createFrontendScriptCommand(options.packageManager, options.frontendDir, "build")
|
|
437
|
+
base.scripts["lint:web"] = createFrontendScriptCommand(options.packageManager, options.frontendDir, "lint")
|
|
438
|
+
base.scripts["preview:web"] = createFrontendScriptCommand(options.packageManager, options.frontendDir, "preview")
|
|
439
|
+
}
|
|
501
440
|
|
|
502
441
|
return base
|
|
503
442
|
}
|
|
@@ -538,18 +477,14 @@ async function writeRootPackageFiles(options) {
|
|
|
538
477
|
"utf8"
|
|
539
478
|
)
|
|
540
479
|
|
|
541
|
-
if (options.frontendDir !== ".") {
|
|
542
|
-
await writeFile(
|
|
543
|
-
path.join(options.targetDir, "package.json"),
|
|
544
|
-
JSON.stringify(createRootPackageJson(options), null, 2) + "\n",
|
|
545
|
-
"utf8"
|
|
546
|
-
)
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
await mkdir(scriptsDir, { recursive: true })
|
|
550
|
-
await writeFile(path.join(scriptsDir, "run-frontend.mjs"), rootFrontendRunner, "utf8")
|
|
551
|
-
}
|
|
552
|
-
}
|
|
480
|
+
if (options.frontendDir !== ".") {
|
|
481
|
+
await writeFile(
|
|
482
|
+
path.join(options.targetDir, "package.json"),
|
|
483
|
+
JSON.stringify(createRootPackageJson(options), null, 2) + "\n",
|
|
484
|
+
"utf8"
|
|
485
|
+
)
|
|
486
|
+
}
|
|
487
|
+
}
|
|
553
488
|
|
|
554
489
|
async function writeProjectFiles(options) {
|
|
555
490
|
const templateConfig = JSON.parse(await readFile(options.templateConfigPath, "utf8"))
|
|
@@ -846,14 +781,9 @@ export async function run(context) {
|
|
|
846
781
|
["plan", "Write Vite config", path.join(targetFrontendDir, "vite.config.ts")],
|
|
847
782
|
["plan", "Write TS config", path.join(targetFrontendDir, "tsconfig.app.json")]
|
|
848
783
|
])
|
|
849
|
-
if (options.
|
|
850
|
-
printStatusTable([
|
|
851
|
-
["plan", "
|
|
852
|
-
])
|
|
853
|
-
}
|
|
854
|
-
if (options.styling === "tailwindcss") {
|
|
855
|
-
printStatusTable([
|
|
856
|
-
["plan", "Patch package.json", path.join(targetFrontendDir, "package.json")],
|
|
784
|
+
if (options.styling === "tailwindcss") {
|
|
785
|
+
printStatusTable([
|
|
786
|
+
["plan", "Patch package.json", path.join(targetFrontendDir, "package.json")],
|
|
857
787
|
["plan", "Write styles", path.join(targetFrontendDir, "src", "index.css")],
|
|
858
788
|
["plan", "Write starter screen", path.join(targetFrontendDir, "src", "App.tsx")]
|
|
859
789
|
])
|
package/src/lib/process.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { spawn } from "node:child_process"
|
|
1
|
+
import { spawn, spawnSync } from "node:child_process"
|
|
2
2
|
|
|
3
3
|
import { logger } from "./logger.js"
|
|
4
4
|
|
|
@@ -129,10 +129,10 @@ export async function captureCommandOutput(command, args = [], options = {}) {
|
|
|
129
129
|
})
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
export function spawnCommand(command, args = [], options = {}) {
|
|
133
|
-
const { cwd, dryRun = false, env } = options
|
|
134
|
-
|
|
135
|
-
logger.info(`$ ${formatCommand(command, args)}`)
|
|
132
|
+
export function spawnCommand(command, args = [], options = {}) {
|
|
133
|
+
const { cwd, dryRun = false, env } = options
|
|
134
|
+
|
|
135
|
+
logger.info(`$ ${formatCommand(command, args)}`)
|
|
136
136
|
|
|
137
137
|
if (dryRun) {
|
|
138
138
|
return null
|
|
@@ -141,6 +141,7 @@ export function spawnCommand(command, args = [], options = {}) {
|
|
|
141
141
|
return spawn(command, args, {
|
|
142
142
|
cwd,
|
|
143
143
|
env: env ? { ...process.env, ...env } : process.env,
|
|
144
|
+
detached: process.platform !== "win32",
|
|
144
145
|
stdio: "inherit",
|
|
145
146
|
shell: shouldUseShell(command)
|
|
146
147
|
})
|
|
@@ -166,31 +167,120 @@ export function waitForProcessExit(child, label) {
|
|
|
166
167
|
})
|
|
167
168
|
}
|
|
168
169
|
|
|
169
|
-
export function registerChildCleanup(children) {
|
|
170
|
-
const activeChildren = children.filter(Boolean)
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
170
|
+
export function registerChildCleanup(children) {
|
|
171
|
+
const activeChildren = children.filter(Boolean)
|
|
172
|
+
let cleanupPromise = null
|
|
173
|
+
|
|
174
|
+
const waitForChildExit = (child, timeoutMs = 3000) =>
|
|
175
|
+
new Promise((resolve) => {
|
|
176
|
+
if (!child || child.exitCode !== null || child.signalCode !== null) {
|
|
177
|
+
resolve(true)
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
|
|
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)
|
|
201
|
+
})
|
|
202
|
+
|
|
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
|
+
}
|
|
221
|
+
|
|
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
|
+
}
|
|
235
|
+
}
|
|
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
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const handleSignal = () => {
|
|
270
|
+
void cleanup().finally(() => {
|
|
271
|
+
process.exit(0)
|
|
272
|
+
})
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
process.on("SIGINT", handleSignal)
|
|
276
|
+
process.on("SIGTERM", handleSignal)
|
|
277
|
+
|
|
278
|
+
return async () => {
|
|
279
|
+
process.off("SIGINT", handleSignal)
|
|
280
|
+
process.off("SIGTERM", handleSignal)
|
|
281
|
+
await cleanup()
|
|
282
|
+
}
|
|
283
|
+
}
|
|
194
284
|
|
|
195
285
|
export async function waitForUrl(url, options = {}) {
|
|
196
286
|
const { intervalMs = 250, timeoutMs = 15000 } = options
|