create-stator 1.2.0 → 1.3.0
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/index.js +96 -2
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
// pnpm create stator → prompts
|
|
10
10
|
// pnpm create stator my-app --template todomvc → no prompts
|
|
11
11
|
// pnpm create stator my-app -t github:you/your-template
|
|
12
|
+
import { spawn, spawnSync } from 'node:child_process'
|
|
12
13
|
import { readdir, readFile, writeFile } from 'node:fs/promises'
|
|
13
14
|
import { basename, join, resolve } from 'node:path'
|
|
14
15
|
import { parseArgs } from 'node:util'
|
|
@@ -26,6 +27,21 @@ const TEMPLATES = [
|
|
|
26
27
|
label: 'TodoMVC',
|
|
27
28
|
hint: 'the classic, with server-owned todos and zero-JS editing',
|
|
28
29
|
},
|
|
30
|
+
{
|
|
31
|
+
value: 'desksmith',
|
|
32
|
+
label: 'Desksmith',
|
|
33
|
+
hint: "the tutorial's finished app — catalog, cart, checkout, theme island",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
value: 'live-poll',
|
|
37
|
+
label: 'Live poll',
|
|
38
|
+
hint: 'shared app-machine state, pushed to every visitor over SSE',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
value: 'with-auth',
|
|
42
|
+
label: 'With auth',
|
|
43
|
+
hint: 'accounts, guarded login, roles, session rotation (Node 24+)',
|
|
44
|
+
},
|
|
29
45
|
]
|
|
30
46
|
|
|
31
47
|
/** First-party templates resolve into the monorepo's examples/. */
|
|
@@ -39,16 +55,48 @@ const { values: flags, positionals } = parseArgs({
|
|
|
39
55
|
options: {
|
|
40
56
|
template: { type: 'string', short: 't' },
|
|
41
57
|
ref: { type: 'string' },
|
|
58
|
+
install: { type: 'boolean' },
|
|
59
|
+
'no-install': { type: 'boolean' },
|
|
60
|
+
git: { type: 'boolean' },
|
|
61
|
+
'no-git': { type: 'boolean' },
|
|
62
|
+
yes: { type: 'boolean', short: 'y' },
|
|
42
63
|
help: { type: 'boolean', short: 'h' },
|
|
43
64
|
},
|
|
44
65
|
})
|
|
45
66
|
|
|
67
|
+
/** The package manager that LAUNCHED us (`pnpm create stator` → pnpm), via
|
|
68
|
+
* the standard npm_config_user_agent header. Defaults to npm. */
|
|
69
|
+
function detectPackageManager() {
|
|
70
|
+
const agent = process.env.npm_config_user_agent ?? ''
|
|
71
|
+
if (agent.startsWith('pnpm')) return 'pnpm'
|
|
72
|
+
if (agent.startsWith('yarn')) return 'yarn'
|
|
73
|
+
if (agent.startsWith('bun')) return 'bun'
|
|
74
|
+
return 'npm'
|
|
75
|
+
}
|
|
76
|
+
const pm = detectPackageManager()
|
|
77
|
+
const runCmd = (script) => (pm === 'npm' ? `npm run ${script}` : `${pm} ${script}`)
|
|
78
|
+
|
|
79
|
+
/** Resolve a yes/no choice: explicit flag > --yes > prompt (TTY) > safe
|
|
80
|
+
* default for non-interactive runs. */
|
|
81
|
+
async function decide({ yesFlag, noFlag, message, fallback }) {
|
|
82
|
+
if (yesFlag) return true
|
|
83
|
+
if (noFlag) return false
|
|
84
|
+
if (flags.yes) return true
|
|
85
|
+
if (!process.stdout.isTTY) return fallback
|
|
86
|
+
const answer = await p.confirm({ message, initialValue: true })
|
|
87
|
+
bailIfCancelled(answer)
|
|
88
|
+
return answer
|
|
89
|
+
}
|
|
90
|
+
|
|
46
91
|
if (flags.help) {
|
|
47
92
|
console.log(
|
|
48
93
|
`Usage: pnpm create stator [directory] [--template ${TEMPLATES.map((t) => t.value).join('|')}]`,
|
|
49
94
|
)
|
|
50
95
|
console.log(' pnpm create stator my-app --template github:user/repo/path')
|
|
51
|
-
console.log(' --ref <branch|tag>
|
|
96
|
+
console.log(' --ref <branch|tag> fetch first-party templates from a specific ref')
|
|
97
|
+
console.log(' --install/--no-install install dependencies after scaffolding')
|
|
98
|
+
console.log(' --git/--no-git initialize a git repository')
|
|
99
|
+
console.log(' -y, --yes accept all defaults (install + git)')
|
|
52
100
|
process.exit(0)
|
|
53
101
|
}
|
|
54
102
|
|
|
@@ -128,7 +176,53 @@ try {
|
|
|
128
176
|
s.stop(`Scaffolded ${name} (${template}) — no package.json to stamp`)
|
|
129
177
|
}
|
|
130
178
|
|
|
131
|
-
|
|
179
|
+
// --- install? ---
|
|
180
|
+
const wantInstall = await decide({
|
|
181
|
+
yesFlag: flags.install,
|
|
182
|
+
noFlag: flags['no-install'],
|
|
183
|
+
message: `Install dependencies with ${pm}?`,
|
|
184
|
+
fallback: false,
|
|
185
|
+
})
|
|
186
|
+
let installed = false
|
|
187
|
+
if (wantInstall) {
|
|
188
|
+
const si = p.spinner()
|
|
189
|
+
si.start(`Installing with ${pm}`)
|
|
190
|
+
installed = await new Promise((done) => {
|
|
191
|
+
const child = spawn(pm, ['install'], { cwd: dest, stdio: 'ignore', shell: true })
|
|
192
|
+
child.on('close', (code) => done(code === 0))
|
|
193
|
+
child.on('error', () => done(false))
|
|
194
|
+
})
|
|
195
|
+
si.stop(installed ? 'Dependencies installed' : `${pm} install failed — run it yourself`)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// --- git? ---
|
|
199
|
+
const wantGit = await decide({
|
|
200
|
+
yesFlag: flags.git,
|
|
201
|
+
noFlag: flags['no-git'],
|
|
202
|
+
message: 'Initialize a git repository?',
|
|
203
|
+
fallback: false,
|
|
204
|
+
})
|
|
205
|
+
if (wantGit) {
|
|
206
|
+
const hasGit = spawnSync('git', ['--version'], { stdio: 'ignore' }).status === 0
|
|
207
|
+
if (hasGit) {
|
|
208
|
+
spawnSync('git', ['init', '-q'], { cwd: dest, stdio: 'ignore' })
|
|
209
|
+
spawnSync('git', ['add', '-A'], { cwd: dest, stdio: 'ignore' })
|
|
210
|
+
// May no-op if user.name/email are unset — an initialized repo without
|
|
211
|
+
// a first commit is still a win.
|
|
212
|
+
spawnSync('git', ['commit', '-q', '-m', 'Initial commit from create-stator'], {
|
|
213
|
+
cwd: dest,
|
|
214
|
+
stdio: 'ignore',
|
|
215
|
+
})
|
|
216
|
+
p.log.success('Initialized a git repository')
|
|
217
|
+
} else {
|
|
218
|
+
p.log.warn('git not found — skipped repository setup')
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
p.note(
|
|
223
|
+
[`cd ${target}`, ...(installed ? [] : [`${pm} install`]), runCmd('dev')].join('\n'),
|
|
224
|
+
'Next steps',
|
|
225
|
+
)
|
|
132
226
|
p.outro('Docs: https://docs.statorjs.dev · Demo: https://demo.statorjs.dev')
|
|
133
227
|
|
|
134
228
|
function bailIfCancelled(v) {
|