bun create: preserve package.json indentation from the template

Closed
RO
1mo ago
+44-3

Fixes #36964

Repro

bun create reepolee/bun-create-repro-1 test1
cat -A test1/package.json | head -3

The template's package.json is indented with tabs, but the scaffolded copy comes out with 2-space indentation. Only package.json is affected; other template files are copied verbatim.

Cause

bun create parses the template's package.json to rewrite the name field and read the bun-create config, then re-prints it with PrintJsonOptions { indent: Default::default(), .. }, which is always 2 spaces.

Fix

Parse with guess_indentation (the same option bun install and bun pm already use to preserve package.json formatting) and pass the detected indentation to the JSON printer.

Verification

New test in test/cli/install/bun-create.test.ts scaffolds from a local template whose package.json uses tabs and asserts the output keeps them. Fails on the current release (tabs become 2 spaces), passes with this change. Full bun-create.test.ts suite passes (22/22).


[stamp-90s] gate passed · iteration 1 · 2 files touched

fails on main (without fix)
ASAN without fix: 1 FAILED
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/cli/install/bun-create.test.ts
bun test v1.4.0 (c4d681a41)

test/cli/install/bun-create.test.ts:
(pass) should not crash > ["create"] [121.56ms]
(pass) should not crash > ["create",""] [103.88ms]
(pass) should not crash > ["create","--"] [101.21ms]
(pass) should not crash > ["create","--",""] [101.16ms]
(pass) should not crash > ["create","--help"] [117.05ms]
(pass) should create selected template with @ prefix [453.50ms]
(pass) should create selected template with @ prefix implicit `/create` [471.46ms]
(pass) should create selected template with @ prefix implicit `/create` with version [431.92ms]
(pass) handles a close-delimited GitHub tarball body split across packets [803.71ms]
(pass) keeps tarball entry paths within the destination when checking for conflicting files [284.89ms]
(pass) reports an error and exits when the template's package.json entry body is truncated [282.54ms]
(pass) does not busy-wait on the futex while git runs [1689.50ms]
Copying files... 

[18.00ms] git

[107.00ms] bun create /tmp/cr8-12GFTsjc/bun-create/
... (truncated)

release without fix: all passed
bun test v1.4.0-canary.1 (2eee748ba)

test/cli/install/bun-create.test.ts:
(pass) should not crash > ["create"] [2.37ms]
(pass) should not crash > ["create",""] [1.68ms]
(pass) should not crash > ["create","--"] [1.46ms]
(pass) should not crash > ["create","--",""] [1.44ms]
(pass) should not crash > ["create","--help"] [1.62ms]
(pass) should create selected template with @ prefix [42.28ms]
(pass) should create selected template with @ prefix implicit `/create` [48.02ms]
(pass) should create selected template with @ prefix implicit `/create` with version [42.46ms]
(pass) handles a close-delimited GitHub tarball body split across packets [32.22ms]
(pass) keeps tarball entry paths within the destination when checking for conflicting files [17.51ms]
(pass) reports an error and exits when the template's package.json entry body is truncated [15.45ms]
(pass) does not busy-wait on the futex while git runs [1512.48ms]
Copying files... 

[16.00ms] git

[16.00ms] bun create /tmp/cr8-12wEigDB/bun-create/test-template

Come hang out in bun's Discord: https://bun.com/discord

Created test-template project successfully

# To get started, run:

  cd test-template
  bun dev

(pass) 
... (truncated)
passes on PR (with fix)
ASAN with fix: all passed
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/cli/install/bun-create.test.ts
bun test v1.4.0 (c4d681a41)

test/cli/install/bun-create.test.ts:
(pass) should not crash > ["create"] [131.11ms]
(pass) should not crash > ["create",""] [103.77ms]
(pass) should not crash > ["create","--"] [97.05ms]
(pass) should not crash > ["create","--",""] [103.11ms]
(pass) should not crash > ["create","--help"] [104.71ms]
(pass) should create selected template with @ prefix [399.09ms]
(pass) should create selected template with @ prefix implicit `/create` [397.66ms]
(pass) should create selected template with @ prefix implicit `/create` with version [395.69ms]
(pass) handles a close-delimited GitHub tarball body split across packets [807.48ms]
(pass) keeps tarball entry paths within the destination when checking for conflicting files [282.30ms]
(pass) reports an error and exits when the template's package.json entry body is truncated [292.57ms]
(pass) does not busy-wait on the futex while git runs [1676.33ms]
Copying files... 

[16.00ms] git

[104.00ms] bun create /tmp/cr8-12llfC1z/bun-create/t
... (truncated)

release with fix: all passed
$ bun scripts/build.ts --profile=release
[configured] bun-profile → bun (stripped) in 774ms (unchanged)
ninja: Entering directory `/workspace/bun/build/release'
[1/6] gen generated_host_exports.rs
generated_host_exports.rs: 94 exports (host=3, lazy=10, generic=81, rust=0); 239 extern-C blocks audited
[1/6] cargo bun_bin → libbun_rust.a (--target x86_64-unknown-linux-gnu)

  nightly-2026-07-20-x86_64-unknown-linux-gnu unchanged - rustc 1.99.0-nightly (9f36de775 2026-07-19)

   Compiling bun_core v0.0.0 (/workspace/bun/src/bun_core)
   Compiling bun_errno v0.0.0 (/workspace/bun/src/errno)
   Compiling bun_ptr v0.0.0 (/workspace/bun/src/ptr)
   Compiling bun_boringssl_sys v0.0.0 (/workspace/bun/src/boringssl_sys)
   Compiling bun_safety v0.0.0 (/workspace/bun/src/safety)
   Compiling bun_zlib_sys v0.0.0 (/workspace/bun/src/zlib_sys)
   Compiling bun_cares_sys v0.0.0 (/workspace/bun/src/cares_sys)
   Compiling bun_zstd v0.0.0 (/workspace/bun/src/zstd)
   Compiling bun_picohttp v0.0.0 (/workspace/bun/src/picohttp)
   Compiling bun_brotli v
... (truncated)
diff hotspot
src/runtime/cli/create_command.rs   | 16 +++++++++++++---
 test/cli/install/bun-create.test.ts | 31 +++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 3 deletions(-)

gate history · 2 passed · 0 rejected · iteration 1

evidence per changed file
file                                 reads  edits  tests
src/runtime/cli/create_command.rs        1      1      0
test/cli/install/bun-create.test.ts      3      3      0

root cause · written by the author bot

During scaffolding, bun create rewrites the template's package.json to set the project name, and it did so by parsing and re-serializing the file with a hardcoded space indentation, discarding the template's original formatting such as tabs. The fix detects the indentation style used in the source package.json and reuses it when emitting the rewritten file, so scaffolded output matches the template. A regression test confirms that a tab-indented template produces tab-indented output.