create-deka-app 0.0.4 → 0.0.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-deka-app",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "Scaffold a new deka app",
5
5
  "bin": {
6
6
  "create-deka-app": "./index.js"
@@ -8,11 +8,17 @@
8
8
  // arm64". `npm_execpath` is a fallback for the rarer case where that header
9
9
  // is absent but the package manager's own launcher script is still visible
10
10
  // on the path it invoked us with.
11
+ // `runScript` renders the command we tell the user to run for a
12
+ // package.json script (currently always "dev"). It must work with zero
13
+ // global installs, using only what the install step above already put on
14
+ // disk -- so it is each package manager's own idiom for running a local
15
+ // script, never a bare `deka ...` invocation (deka itself only lives in
16
+ // this project's node_modules/.bin).
11
17
  const MANAGERS = {
12
- npm: { name: 'npm', install: ['npm', ['install']] },
13
- pnpm: { name: 'pnpm', install: ['pnpm', ['install']] },
14
- yarn: { name: 'yarn', install: ['yarn', ['install']] },
15
- bun: { name: 'bun', install: ['bun', ['install']] },
18
+ npm: { name: 'npm', install: ['npm', ['install']], runScript: (script) => `npm run ${script}` },
19
+ pnpm: { name: 'pnpm', install: ['pnpm', ['install']], runScript: (script) => `pnpm ${script}` },
20
+ yarn: { name: 'yarn', install: ['yarn', ['install']], runScript: (script) => `yarn ${script}` },
21
+ bun: { name: 'bun', install: ['bun', ['install']], runScript: (script) => `bun run ${script}` },
16
22
  }
17
23
 
18
24
  export function detectPackageManager(env = process.env) {
package/src/scaffold.js CHANGED
@@ -29,6 +29,36 @@ function dekaBinPath(targetDir, platform) {
29
29
  return path.join(targetDir, 'node_modules', '.bin', platform === 'win32' ? 'deka.cmd' : 'deka')
30
30
  }
31
31
 
32
+ // `deka init`'s own "next steps" block always starts with a line beginning
33
+ // "[init]" (verified against the real binary: `[init] DekaScript app
34
+ // ready` followed by 1-2 indented command lines). Everything from that
35
+ // line onward is deka's suggestion for what to run next, and we always
36
+ // replace it with our own -- see printNextSteps below for why. Everything
37
+ // before it (the banner, the per-file `[create] ...` lines) is left
38
+ // intact so the user still sees the scaffold happen.
39
+ function stripDekaNextSteps(output) {
40
+ if (!output) return ''
41
+ const lines = String(output).split(/\r?\n/)
42
+ const cutIndex = lines.findIndex((line) => line.startsWith('[init]'))
43
+ return cutIndex === -1 ? String(output) : lines.slice(0, cutIndex).join('\n')
44
+ }
45
+
46
+ // deka init's own next-steps text always tells the user to run a bare
47
+ // `deka ...` command, because that's correct advice for someone who ran
48
+ // `deka init` by hand with deka already on their PATH. It is wrong advice
49
+ // here: create-deka-app only ever installs deka into this project's own
50
+ // node_modules/.bin, so a bare `deka` command fails for a user who has no
51
+ // global install. We suppress deka's block (stripDekaNextSteps) and print
52
+ // our own -- the `cd` line plus the detected package manager's own idiom
53
+ // for running the "dev" script already sitting in package.json, which
54
+ // works with nothing beyond what the install step just put on disk.
55
+ function printNextSteps(log, dirName, pm) {
56
+ log('')
57
+ log(' Next steps:')
58
+ log(` cd ${dirName}`)
59
+ log(` ${pm.runScript('dev')}`)
60
+ }
61
+
32
62
  export const RUNTIME_PACKAGE = '@dekaruntime/deka'
33
63
 
34
64
  // Builds the package.json this package writes into every scaffolded
@@ -168,17 +198,38 @@ export function createApp({
168
198
  )
169
199
  }
170
200
 
171
- const init = spawn(dekaBin, ['init'], { cwd: targetDir, stdio: 'inherit' })
201
+ // Invoked as `deka init <dirName>` from the *parent* directory -- the
202
+ // same shape as someone typing `deka init myapp` by hand -- rather than
203
+ // `deka init` with cwd already set to targetDir. deka init never
204
+ // overwrites a file that already exists (package.json, written above,
205
+ // survives untouched), and this shape is what makes deka's own output
206
+ // reference the right directory name if any of it leaks through.
207
+ const dirName = path.basename(targetDir)
208
+ const parentDir = path.dirname(targetDir)
209
+ const init = spawn(dekaBin, ['init', dirName], {
210
+ cwd: parentDir,
211
+ stdio: ['inherit', 'pipe', 'pipe'],
212
+ encoding: 'utf8',
213
+ })
172
214
 
173
215
  if (init.error) {
174
216
  throw new ScaffoldError(`Could not run "deka init" in ${targetDir}: ${init.error.message}`)
175
217
  }
176
218
  if (init.status !== 0) {
219
+ // Something went wrong -- show everything deka printed, unfiltered,
220
+ // so the real error is visible. Filtering only ever happens below, on
221
+ // the success path, where we know exactly what we're throwing away.
222
+ if (init.stdout) log(String(init.stdout))
223
+ if (init.stderr) log(String(init.stderr))
177
224
  throw new ScaffoldError(
178
225
  `"deka init" failed in ${targetDir} (exit code ${init.status}).`,
179
226
  init.status ?? 1
180
227
  )
181
228
  }
182
229
 
230
+ if (init.stdout) log(stripDekaNextSteps(init.stdout))
231
+ if (init.stderr) log(stripDekaNextSteps(init.stderr))
232
+ printNextSteps(log, dirName, pm)
233
+
183
234
  return 0
184
235
  }