create-jst 0.3.0 → 0.3.1
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 +0 -2
- package/package.json +2 -1
- package/src/cli.mjs +3 -2
- package/src/infrastructure/nodeProjectGateway.mjs +8 -4
- package/src/ui/command.mjs +38 -11
- package/src/ui/reporter.mjs +41 -3
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-jst",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Create a web application from the JST template.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"homepage": "https://github.com/jst-stack/jst#readme",
|
|
26
26
|
"license": "MIT",
|
|
27
27
|
"dependencies": {
|
|
28
|
+
"@clack/prompts": "^1.8.1",
|
|
28
29
|
"degit": "^3.10.0"
|
|
29
30
|
}
|
|
30
31
|
}
|
package/src/cli.mjs
CHANGED
|
@@ -17,9 +17,9 @@ export async function run(argv, environment = process, application = createProje
|
|
|
17
17
|
if (command.values.version) return environment.stdout.write(`${process.env.npm_package_version ?? '0.3.0'}\n`)
|
|
18
18
|
|
|
19
19
|
const request = await resolveProjectRequest(command, environment)
|
|
20
|
-
if (request.dryRun) return reporter.plan(request.specification)
|
|
20
|
+
if (request.dryRun) return reporter.plan(request.specification, request)
|
|
21
21
|
|
|
22
|
-
reporter.start()
|
|
22
|
+
reporter.start(request)
|
|
23
23
|
const unsubscribe = reporter.subscribe(application.events)
|
|
24
24
|
try {
|
|
25
25
|
await application.initializer.execute(request.specification)
|
|
@@ -29,6 +29,7 @@ export async function run(argv, environment = process, application = createProje
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
catch (error) {
|
|
32
|
+
if (error instanceof Error && error.name === 'PromptCancelledError') return
|
|
32
33
|
reporter.error(error instanceof Error ? error.message : String(error))
|
|
33
34
|
environment.exitCode = 1
|
|
34
35
|
}
|
|
@@ -62,21 +62,25 @@ export function createNodeProjectGateway({ nodeExecutable }) {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
function installDependencies(destination, packageManager) {
|
|
65
|
-
return run(packageManager, installCommands[packageManager], destination
|
|
65
|
+
return run(packageManager, installCommands[packageManager], destination)
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
function run(command, args, cwd
|
|
69
|
+
function run(command, args, cwd) {
|
|
70
70
|
return new Promise((resolve, reject) => {
|
|
71
|
-
const child = spawn(command, args, { cwd, stdio:
|
|
71
|
+
const child = spawn(command, args, { cwd, stdio: 'pipe' })
|
|
72
|
+
let stdout = ''
|
|
72
73
|
let stderr = ''
|
|
74
|
+
child.stdout?.on('data', chunk => {
|
|
75
|
+
stdout += chunk
|
|
76
|
+
})
|
|
73
77
|
child.stderr?.on('data', chunk => {
|
|
74
78
|
stderr += chunk
|
|
75
79
|
})
|
|
76
80
|
child.once('error', error => reject(new Error(`Could not run ${command}: ${error.message}`)))
|
|
77
81
|
child.once('close', code => {
|
|
78
82
|
if (code === 0) resolve()
|
|
79
|
-
else reject(new Error(`${command} ${args.join(' ')} failed.${stderr ? `\n${stderr.trim()}` : ''}`))
|
|
83
|
+
else reject(new Error(`${command} ${args.join(' ')} failed.${[stdout, stderr].filter(Boolean).join('\n').trim() ? `\n${[stdout, stderr].filter(Boolean).join('\n').trim()}` : ''}`))
|
|
80
84
|
})
|
|
81
85
|
})
|
|
82
86
|
}
|
package/src/ui/command.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { basename, resolve } from 'node:path'
|
|
2
2
|
import { parseArgs } from 'node:util'
|
|
3
|
+
import * as prompts from '@clack/prompts'
|
|
3
4
|
import { buildProjectSpecification, normalizePackageName, PACKAGE_MANAGERS, toTitle } from '../domain/projectSpecification.mjs'
|
|
4
5
|
|
|
5
6
|
export function parseCommandLine(args) {
|
|
@@ -51,13 +52,15 @@ export async function resolveProjectRequest(command, environment) {
|
|
|
51
52
|
|
|
52
53
|
return {
|
|
53
54
|
dryRun: values['dry-run'] ?? false,
|
|
55
|
+
interactive: Boolean(prompt),
|
|
56
|
+
terminal: Boolean(environment.stdin.isTTY),
|
|
54
57
|
specification: buildProjectSpecification({
|
|
55
58
|
colorScheme: values['color-scheme'],
|
|
56
59
|
demo: values.demo ?? await prompt?.choice('Start from', ['remove', 'keep'], 'remove') ?? 'remove',
|
|
57
60
|
description: values.description ?? `${title} web application.`,
|
|
58
61
|
destination: resolve(environment.cwd(), directory),
|
|
59
|
-
initGit: prompt ? await prompt.
|
|
60
|
-
install: prompt ? await prompt.
|
|
62
|
+
initGit: prompt ? await prompt.confirm('Initialize a Git repository?', initGit) : initGit,
|
|
63
|
+
install: prompt ? await prompt.confirm('Install dependencies?', install) : install,
|
|
61
64
|
language: values.lang,
|
|
62
65
|
name,
|
|
63
66
|
packageManager,
|
|
@@ -110,21 +113,45 @@ Options:
|
|
|
110
113
|
|
|
111
114
|
async function createPrompt(environment, values) {
|
|
112
115
|
if (!environment.stdin.isTTY || values.yes || values['no-interactive']) return undefined
|
|
113
|
-
|
|
114
|
-
const reader = createInterface({ input: environment.stdin, output: environment.stdout })
|
|
116
|
+
prompts.intro('create-jst')
|
|
115
117
|
return {
|
|
116
118
|
async choice(label, choices, fallback) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
119
|
+
return resolvePrompt(await prompts.select({
|
|
120
|
+
initialValue: fallback,
|
|
121
|
+
message: label,
|
|
122
|
+
options: choices.map(value => ({ hint: choiceHint(value), label: choiceLabel(value), value })),
|
|
123
|
+
}))
|
|
122
124
|
},
|
|
123
125
|
close() {
|
|
124
|
-
|
|
126
|
+
return undefined
|
|
127
|
+
},
|
|
128
|
+
async confirm(label, initialValue) {
|
|
129
|
+
return resolvePrompt(await prompts.confirm({ initialValue, message: label }))
|
|
125
130
|
},
|
|
126
131
|
async text(label, fallback) {
|
|
127
|
-
return (await
|
|
132
|
+
return resolvePrompt(await prompts.text({ initialValue: fallback, message: label }))
|
|
128
133
|
},
|
|
129
134
|
}
|
|
130
135
|
}
|
|
136
|
+
|
|
137
|
+
function choiceLabel(value) {
|
|
138
|
+
return {
|
|
139
|
+
keep: 'Keep the JST demo',
|
|
140
|
+
remove: 'Start with a clean application',
|
|
141
|
+
}[value] ?? value
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function choiceHint(value) {
|
|
145
|
+
return {
|
|
146
|
+
npm: 'default',
|
|
147
|
+
remove: 'recommended',
|
|
148
|
+
}[value]
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function resolvePrompt(value) {
|
|
152
|
+
if (!prompts.isCancel(value)) return value
|
|
153
|
+
prompts.cancel('Setup cancelled.')
|
|
154
|
+
const error = new Error('Setup cancelled.')
|
|
155
|
+
error.name = 'PromptCancelledError'
|
|
156
|
+
throw error
|
|
157
|
+
}
|
package/src/ui/reporter.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { basename } from 'node:path'
|
|
2
|
+
import * as prompts from '@clack/prompts'
|
|
2
3
|
|
|
3
4
|
const progressMessages = {
|
|
4
5
|
'dependencies.installation.started': specification => `Installing dependencies with ${specification.packageManager}`,
|
|
@@ -12,12 +13,32 @@ export function createReporter(output, environment = {}) {
|
|
|
12
13
|
const color = Boolean(output.isTTY) && !environment.NO_COLOR
|
|
13
14
|
const paint = (code, value) => color ? `\u001B[${code}m${value}\u001B[0m` : value
|
|
14
15
|
const dim = value => paint('2', value)
|
|
16
|
+
let activeSpinner
|
|
17
|
+
let usesClack = false
|
|
15
18
|
|
|
16
19
|
return {
|
|
17
20
|
error(message) {
|
|
21
|
+
if (usesClack) {
|
|
22
|
+
activeSpinner?.stop('Failed')
|
|
23
|
+
prompts.cancel(message)
|
|
24
|
+
return
|
|
25
|
+
}
|
|
18
26
|
output.write(`\n${paint('31', '✕')} ${message}\n`)
|
|
19
27
|
},
|
|
20
|
-
plan(specification) {
|
|
28
|
+
plan(specification, request) {
|
|
29
|
+
usesClack = request.terminal
|
|
30
|
+
if (usesClack) {
|
|
31
|
+
if (!request.interactive) prompts.intro('create-jst')
|
|
32
|
+
prompts.note([
|
|
33
|
+
`Template: ${specification.template}`,
|
|
34
|
+
`Package manager: ${specification.packageManager}`,
|
|
35
|
+
`Starter demo: ${specification.demo}`,
|
|
36
|
+
`Install dependencies: ${specification.install ? 'yes' : 'no'}`,
|
|
37
|
+
`Initialize Git: ${specification.initGit ? 'yes' : 'no'}`,
|
|
38
|
+
].join('\n'), specification.destination)
|
|
39
|
+
prompts.outro('Dry run complete — no files were written.')
|
|
40
|
+
return
|
|
41
|
+
}
|
|
21
42
|
output.write(`\n${paint('38;5;203', 'JST')} ${dim('plan only — no files will be written')}\n\n`)
|
|
22
43
|
output.write(` destination ${specification.destination}\n`)
|
|
23
44
|
output.write(` template ${specification.template}\n`)
|
|
@@ -26,17 +47,34 @@ export function createReporter(output, environment = {}) {
|
|
|
26
47
|
output.write(` install ${specification.install ? 'yes' : 'no'}\n`)
|
|
27
48
|
output.write(` git ${specification.initGit ? 'yes' : 'no'}\n\n`)
|
|
28
49
|
},
|
|
29
|
-
start() {
|
|
50
|
+
start(request) {
|
|
51
|
+
usesClack = request.terminal
|
|
52
|
+
if (usesClack) {
|
|
53
|
+
if (!request.interactive) prompts.intro('create-jst')
|
|
54
|
+
return
|
|
55
|
+
}
|
|
30
56
|
output.write(`\n${paint('38;5;203', 'JST')} ${dim('A foundation for replaceable layers')}\n\n`)
|
|
31
57
|
},
|
|
32
58
|
subscribe(events) {
|
|
33
59
|
return events.subscribe(event => {
|
|
34
60
|
if (event.type === 'project.initialized') return this.success(event.specification)
|
|
35
61
|
const message = progressMessages[event.type]
|
|
36
|
-
if (message)
|
|
62
|
+
if (!message) return
|
|
63
|
+
if (usesClack) {
|
|
64
|
+
activeSpinner?.stop()
|
|
65
|
+
activeSpinner = prompts.spinner()
|
|
66
|
+
activeSpinner.start(message(event.specification))
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
output.write(`${dim(' ◌')} ${message(event.specification)}\n`)
|
|
37
70
|
})
|
|
38
71
|
},
|
|
39
72
|
success(specification) {
|
|
73
|
+
if (usesClack) {
|
|
74
|
+
activeSpinner?.stop('Project created')
|
|
75
|
+
prompts.outro(`Ready. Run \`${specification.packageManager} run dev\` in ${basename(specification.destination)}.`)
|
|
76
|
+
return
|
|
77
|
+
}
|
|
40
78
|
output.write(`\n${paint('38;5;114', 'Ready.')} ${specification.title} is in ${paint('38;5;203', basename(specification.destination))}.\n\n`)
|
|
41
79
|
output.write(` ${dim('$')} cd ${basename(specification.destination)}\n`)
|
|
42
80
|
output.write(` ${dim('$')} ${specification.packageManager} run dev\n\n`)
|