Skip to content

jsx: let bunfig.toml / --jsx-* override tsconfig.json - #36728

Open
robobun wants to merge 1 commit into
mainfrom
claude/c55aa873/bunfig-jsx-overrides-tsconfig
Open

robobun wants to merge 1 commit into
mainfrom
claude/c55aa873/bunfig-jsx-overrides-tsconfig

Conversation

@robobun

@robobun robobun commented Aug 1, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #15844.

Repro

printf '{ "compilerOptions": { "jsx": "react-jsx" } }' > tsconfig.json
printf 'jsx = "react"\njsxFactory = "React.createElement"\n' > bunfig.toml
printf 'export const App = () => <div className="app">hello</div>;\n' > index.tsx

bun build ./index.tsx --external react
# before: jsxDEV from react/jsx-dev-runtime  (bunfig ignored)
# after:  React.createElement                (bunfig wins)

Cause

TSConfigJSON::merge_jsx applied every field tsconfig set, regardless of whether the incoming Pragma already carried a user-set value. The user-set side (api::Jsx / Pragma) had no per-field was-set tracking, so nothing could gate that overwrite. configure_linker_with_auto_jsx likewise did a wholesale options.jsx = tsconfig.jsx copy (or skipped tsconfig entirely) instead of merging.

Fix

  • options_types::jsx: add JsxField / JsxFieldSet (moved from the resolver) and Pragma.set_fields; carry it through api::Jsx and Pragma::from_api.
  • bunfig.rs: populate set_fields for each jsx* key actually present, and stop materialising an api::Jsx when no jsx* keys are present (previously every bunfig load created one with default values, which itself masked tsconfig).
  • Arguments.rs / JSBundler.rs: populate set_fields for each --jsx-* flag / Bun.build({jsx}) option passed.
  • tsconfig_json.rs: merge_jsx now computes jsx_flags.difference(current.set_fields) and only applies those. The tsconfig extends chain still merges child-over-parent because the base config's set_fields is empty.
  • transpiler.rs configure_linker_with_auto_jsx: always merge the root tsconfig instead of the wholesale copy, so explicit user config survives and non-tracked fields like side_effects are preserved.
  • test/parallel/runner.rs: the bun test --parallel coordinator re-emits the jsx config to each worker as --jsx-* flags. It forwarded --jsx-runtime whenever any jsx config existed, which under the new rule would mark the runtime user-set in the worker and block its tsconfig. It now forwards only the fields in set_fields, so a parallel run transpiles the same as a serial one.
  • docs/runtime/bunfig.mdx: document the precedence.

Precedence

--jsx-* / bunfig.toml jsx* / Bun.build({jsx}) > tsconfig.json compilerOptions.jsx* > defaults, per field. A field not set in the higher tier still falls through to tsconfig.

Behavior change

Bun.build({jsx: {runtime: "automatic"}}) with a tsconfig.json that sets "jsx": "react-jsx" now emits the production jsx runtime (tsconfig's development: false fills the gap the user did not set) instead of jsxDEV. Previously Bun.build({jsx}) caused tsconfig JSX to be skipped entirely. One jsxSideEffects snapshot in bundler_jsx.test.ts updated to reflect this; its sideEffects assertion is unchanged.

Verification

test/regression/issue/15844.test.ts covers bunfig jsx/jsxFactory/jsxImportSource overriding tsconfig, --jsx-runtime overriding tsconfig, tsconfig still applying when bunfig has no jsx keys, the jsxImportSource key-after-spread fallback, a bunfig react-jsxDEV surviving an unrelated --jsx-* flag, and bun test versus bun test --parallel=2 producing the same runtime on one fixture (the bunfig/CLI override cases fail on the released binary and pass here).

bundler_jsx.test.ts, esbuild/tsconfig.test.ts, jsx-tsconfig-react-jsx.test.ts, transpiler-tsconfig-uaf.test.ts, and test/config/bunfig/ all pass.

Overlap

This PR originally also carried the one-line --tsconfig-override fd fix for #22023; that is the same change as #34980, which is now the PR for it, so the resolver hunk and its tests were dropped from this branch (b97aa8c) and the two no longer touch the same files. #36269 addresses the --jsx-* vs tsconfig dev/prod interaction from the bundler side with a different mechanism and will need reconciling with the set_fields approach here. #36209 changes the development default in Arguments.rs and is orthogonal.

Rebase notes

The branch is squashed to one commit and rebased onto main. Two rebases needed manual resolution:


[review] gate passed · iteration 4 · 15 files touched

fails on main (without fix)
ASAN without fix: BUILD FAILED (no junit output)
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/bundler/bundler_jsx.test.ts "test/regression/issue/15844.test.ts"
ninja: Entering directory `/workspace/bun/build/debug'
[1/4] gen generated_host_exports.rs
generated_host_exports.rs: 92 exports (host=3, lazy=10, generic=79, rust=0); 240 extern-C blocks audited
[1/4] 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)

FAILED: rust-target/x86_64-unknown-linux-gnu/debug/libbun_rust.a 
/workspace/bun/build/release/bun /workspace/bun/scripts/build/stream.ts rust --console --env=CARGO_TERM_COLOR=always --env=BUN_CODEGEN_DIR=/workspace/bun/build/debug/codegen --env=CC=/usr/lib/llvm-21/bin/clang --env=CXX=/usr/lib/llvm-21/bin/clang++ --env=AR=/usr/lib/llvm-21/bin/llvm-ar --env=CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=/usr/lib/llvm-21/bin/clang++ --env=CARGO_HOME=/root/.cargo --env=RUSTUP_HOME=/root/.rustup --env=RUSTUP_TOOLCHAIN=nightly-2026-07-20 --env=CARGO_PROFILE_RELEASE_LTO=off --env=CARGO_PROFILE_RELEASE_CODEG
... (truncated)

release without fix: 14 failed, 4 skipped
bun test v1.4.0-canary.1 (6e906e468)

test/bundler/bundler_jsx.test.ts:
(pass) bundler > jsx/AutomaticDev [22.06ms]
(pass) bundler > jsx/AutomaticProd [12.11ms]
(todo) bundler > jsx/AutomaticFragmentDev
(todo) bundler > jsx/AutomaticFragmentProd
(pass) bundler > jsx/AutomaticFragmentNamedImportDev [12.63ms]
(pass) bundler > jsx/AutomaticFragmentNamedImportProd [11.95ms]
(pass) bundler > jsx/AutomaticLocalShadowDev [12.51ms]
(pass) bundler > jsx/AutomaticLocalShadowProd [14.73ms]
(pass) bundler > jsx/AutomaticLocalShadowMinifyIdentifiersProd [7.41ms]
(pass) bundler > jsx/AutomaticLocalShadowMinifyIdentifiersDev [5.39ms]
(pass) bundler > jsx/ClassicDev [12.10ms]
(pass) bundler > jsx/ClassicProd [12.98ms]
(pass) bundler > jsx/ClassicPragmaDev [11.35ms]
(pass) bundler > jsx/ClassicPragmaProd [14.49ms]
(todo) bundler > jsx/PragmaMultipleDev
(todo) bundler > jsx/PragmaMultipleProd
(pass) bundler > jsx/FactoryDev [13.08ms]
(pass) bundler > jsx/FactoryProd [13.25ms]
(pass) bundler > jsx/FactoryImportDev [12.67ms]
(pass) bundler > jsx/FactoryImportProd [13.06ms]
(pass) bundler > jsx/FactoryImportExplicitReactDefaultDev [7.25ms]
(pass) bundler > jsx/FactoryImportExplicitReact
... (truncated)
passes on PR (with fix)
ASAN with fix: 4 skipped
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/bundler/bundler_jsx.test.ts "test/regression/issue/15844.test.ts"
bun test v1.4.0 (6e906e468)

test/bundler/bundler_jsx.test.ts:
(pass) bundler > jsx/AutomaticDev [1034.77ms]
(pass) bundler > jsx/AutomaticProd [664.03ms]
(todo) bundler > jsx/AutomaticFragmentDev
(todo) bundler > jsx/AutomaticFragmentProd
(pass) bundler > jsx/AutomaticFragmentNamedImportDev [633.79ms]
(pass) bundler > jsx/AutomaticFragmentNamedImportProd [623.48ms]
(pass) bundler > jsx/AutomaticLocalShadowDev [675.23ms]
(pass) bundler > jsx/AutomaticLocalShadowProd [655.63ms]
(pass) bundler > jsx/AutomaticLocalShadowMinifyIdentifiersProd [347.75ms]
(pass) bundler > jsx/AutomaticLocalShadowMinifyIdentifiersDev [319.09ms]
(pass) bundler > jsx/ClassicDev [691.13ms]
(pass) bundler > jsx/ClassicProd [722.17ms]
(pass) bundler > jsx/ClassicPragmaDev [669.17ms]
(pass) bundler > jsx/ClassicPragmaProd [660.26ms]
(todo) bundler > jsx/PragmaMultipleDev
(todo) bundler > jsx/PragmaMultipleProd
(pass) bundler > jsx/FactoryDev [655.32ms]
(pass) bundler > jsx/FactoryProd [683.29ms]
... (truncated)

release with fix: 4 skipped
$ bun scripts/build.ts --profile=release
[configured] bun-profile → bun (stripped)
  target       linux-x64-gnu
  build type   Release
  build dir    ./build/release
  revision     2b315348f9
  features     baseline

23 deps, 129 codegen, 1172 objects in 726ms

ninja: Entering directory `/workspace/bun/build/release'
[1/1244] install /workspace/bun
bun install v1.4.0-canary.1 (6e906e468)

Checked 26 installs across 63 packages (no changes) [4.00ms]
[2/1244] gen ErrorCode+*.h
[3/1244] install /workspace/bun/packages/bun-error
bun install v1.4.0-canary.1 (6e906e468)

Checked 1 install across 2 packages (no changes) [1.00ms]
[4/1244] install /workspace/bun/src/node-fallbacks
bun install v1.4.0-canary.1 (6e906e468)

Checked 111 installs across 104 packages (no changes) [11.00ms]
[5/1244] gen bindgenv2
[6/1244] gen node-fallbacks/react-refresh.js
Bundled 1 module in 10ms

  react-refresh.js  4.81 KB  (entry point)

[7/1244] fetch tinycc
[tinycc] up to date
[8/1243] fetch zlib
[zlib] up to date
[9/1243] gen ProcessBindingConstants.lut.h
Generating /workspace/bun/build/release/codegen/ProcessBindingConstants.lut.h from /workspace/bun/src/jsc/bindings/ProcessBindingConsta
... (truncated)
diff hotspot
Cargo.lock                                   |   2 +-
 docs/runtime/bunfig.mdx                      |   2 +
 src/bundler/transpiler.rs                    |   6 +-
 src/bunfig/bunfig.rs                         |  21 +++-
 src/options_types/Cargo.toml                 |   1 +
 src/options_types/jsx.rs                     |  18 ++++
 src/options_types/schema.rs                  |   2 +
 src/resolver/Cargo.toml                      |   1 -
 src/resolver/tsconfig_json.rs                |  29 ++---
 src/runtime/api/JSBundler.rs                 |   6 ++
 src/runtime/api/js_bundle_completion_task.rs |   1 +
 src/runtime/cli/Arguments.rs                 |  20 +++-
 src/runtime/cli/test/parallel/runner.rs      |  18 ++--
 test/bundler/bundler_jsx.test.ts             |  16 ++-
 test/regression/issue/15844.test.ts          | 153 +++++++++++++++++++++++++++
 15 files changed, 251 insertions(+), 45 deletions(-)

gate history · 9 passed · 0 rejected · iteration 4

evidence per changed file
file                                          reads  edits  tests
Cargo.lock                                        0      0      0
docs/runtime/bunfig.mdx                           1      1      0
src/bundler/transpiler.rs                        10      6      0
src/bunfig/bunfig.rs                              1      1      0
src/options_types/Cargo.toml                      1      1      0
src/options_types/jsx.rs                          3      5      0
src/options_types/schema.rs                       1      1      0
src/resolver/Cargo.toml                           1      1      0
src/resolver/tsconfig_json.rs                     7      8      0
src/runtime/api/JSBundler.rs                      2      1      0
src/runtime/api/js_bundle_completion_task.rs      5      1      0
src/runtime/cli/Arguments.rs                      2      2      0
src/runtime/cli/test/parallel/runner.rs           3      3      0
test/bundler/bundler_jsx.test.ts                  0      0      0
test/regression/issue/15844.test.ts               5      6      0

@coderabbitai

coderabbitai Bot commented Aug 1, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

JSX precedence and tsconfig overrides

Layer / File(s) Summary
Track explicit JSX fields
src/options_types/jsx.rs, src/options_types/schema.rs, src/bunfig/bunfig.rs, src/runtime/api/JSBundler.rs, src/runtime/cli/Arguments.rs, src/runtime/api/js_bundle_completion_task.rs
JSX configuration records explicitly supplied fields and propagates them through Bunfig, API, and CLI parsing.
Merge tsconfig JSX settings
src/resolver/tsconfig_json.rs, src/bundler/transpiler.rs, test/bundler/bundler_jsx.test.ts
tsconfig JSX fields apply only when corresponding options were not already set.
Handle external tsconfig overrides
src/resolver/resolver.rs, test/cli/run/tsconfig-override.test.ts
External override files use the corrected directory descriptor, and tests require empty stderr.
Cover precedence behavior
test/regression/issue/15844.test.ts, docs/runtime/bunfig.mdx
Regression tests and documentation cover Bunfig, CLI, and tsconfig precedence and fallback behavior.

Possibly related PRs

  • oven-sh/bun#36209: Both changes preserve JSX runtime and development settings during CLI merging.
  • oven-sh/bun#36261: Both changes update CLI JSX merging, including side_effects and development.
  • oven-sh/bun#36269: Both changes modify JSX precedence across explicit options and tsconfig.json.

Suggested reviewers: jarred-sumner

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the primary JSX precedence change over tsconfig.json.
Description check ✅ Passed The description explains the change, cause, fix, precedence, behavior impact, and verification with relevant test evidence.

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the claude label Aug 1, 2026
@robobun

robobun commented Aug 1, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 9:55 PM PT - Aug 20th, 2026

❌ @robobun, your commit 2b31534 has 2 failures in Build #102214 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 36728

That installs a local version of the PR into your bun-36728 executable, so you can run:

bun-36728 --bun

Comment thread src/bundler/transpiler.rs Outdated
Comment thread src/options_types/jsx.rs Outdated
Comment thread src/options_types/jsx.rs Outdated
Comment thread src/resolver/resolver.rs Outdated
Comment thread src/resolver/tsconfig_json.rs Outdated
Comment thread src/bundler/transpiler.rs Outdated
Comment thread src/resolver/resolver.rs Outdated
Comment thread src/resolver/tsconfig_json.rs Outdated
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Found 3 issues this PR may fix:

  1. --tsconfig-override show internal error #22023 - Reports the exact "Internal error: directory mismatch" warning when using --tsconfig-override, which this PR fixes by using FD::INVALID instead of the wrong directory fd with openat()
  2. API Bun.build(...) doesn't read JSX directives from bunfig.toml (but CLI "bun build" does) #19556 - Bun.build() ignores JSX directives from bunfig.toml while CLI bun build respects them; this PR fixes Bun.build({jsx}) to properly populate set_fields and merge with tsconfig
  3. Bun.build() tsconfig option doesn't resolve path aliases (CLI works) #26793 - Reports the "Internal error: directory mismatch" warning when using --tsconfig-override with Bun.build() (note: the path alias part of this issue is a separate bug)

If this is helpful, copy the block below into the PR description to auto-close these issues on merge.

Fixes #22023
Fixes #19556
Fixes #26793

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

This PR may be a duplicate of:

  1. cli: stop --jsx-* flags from switching the automatic JSX runtime to production #36209 - Fixes the same CLI --jsx-* flags vs tsconfig dev/prod precedence issue, a subset of this PR's bunfig/CLI override logic
  2. bundler: stop --jsx-* flags from overriding tsconfig jsx dev/prod #36269 - Fixes the same bundler-side --jsx-* / Bun.build({jsx}) vs tsconfig dev/prod precedence in JSBundler.rs and transpiler.rs
  3. resolver: suppress spurious "directory mismatch" warning from --tsconfig-override #34980 - Fixes the identical --tsconfig-override spurious "directory mismatch" fd warning in resolver.rs

🤖 Generated with Claude Code

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional findings (outside current diff — PR may have been updated during review):

  • 🔴 src/bundler/transpiler.rs:697-702 — Replacing the wholesale options.jsx = tsconfig.jsx.clone() with merge_tsconfig_jsx_into drops package_name (and classic_import_source), which merge_jsx does not copy. With no bunfig/CLI jsx and tsconfig.json: {jsx: "react-jsx", jsxImportSource: "preact"}, <div {...spread} key="k" /> now emits import { createElement } from "react" instead of "preact", breaking preact-only builds. Fix: in merge_jsx, when apply.contains(JsxField::ImportSource), also assign out.package_name and out.classic_import_source from self.jsx.

    Extended reasoning...

    What changed

    configure_linker_with_auto_jsx previously did a full clone of the root tsconfig's JSX pragma when the user hadn't supplied any explicit JSX config:

    // old (transpiler.rs:655-659 — jsx_pragma_from_resolver is src.clone())
    if self.options.transform_options.jsx.is_none() {
        self.options.jsx = jsx_pragma_from_resolver(&tsconfig.jsx);
    }

    This PR replaces that with an unconditional field-selective merge:

    // new (transpiler.rs:702)
    merge_tsconfig_jsx_into(tsconfig, &mut self.options.jsx);
    // == *out = tsconfig.merge_jsx(mem::take(out))

    TSConfigJSON::merge_jsx (tsconfig_json.rs:221-244) only copies the five JsxField-tracked members: factory, fragment, import_source, runtime, development. It does not copy package_name or classic_import_source, which the previous full clone carried.

    Why package_name matters

    TSConfigJSON::parse populates it from jsxImportSource:

    // tsconfig_json.rs, jsxImportSource arm
    result.jsx.package_name = str.to_vec().into();
    result.jsx.set_import_source();
    result.jsx_flags.insert(JsxField::ImportSource);

    The parser reads package_name (not import_source) to emit the automatic-runtime key-after-spread fallback import — the createElement call the automatic runtime falls back to when a key prop appears after a spread:

    // parse_entry.rs:1946, 1965-1972
    let package_name: &'a [u8] = p.arena.alloc_slice_copy(&p.options.jsx.package_name);
    ...
    let source_import_names = jsx_imports.source_import_names(); // ["createElement"] when jsx_imports.create_element.is_some()
    if !source_import_names.is_empty() {
        p.generate_import_stmt(package_name, source_import_names, ...);
    }

    classic_import_source is likewise read at parse_entry.rs:491-503 for the require-record path.

    Step-by-step regression

    Setup — CLI bun build ./index.tsx, no bunfig.toml, no --jsx-* flags:

    // tsconfig.json
    { "compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "preact" } }
    // index.tsx
    export const A = (p: any) => <div {...p} key="k" />;
    1. Arguments::parse sets opts.jsx = None (no --jsx-* flag passed), so options.jsx starts as Pragma::default() with package_name = Cow::Borrowed(b"react") and set_fields = empty.
    2. configure_linker_with_auto_jsx reads the root tsconfig, whose jsx.package_name = "preact" and jsx_flags = {Runtime, Development, ImportSource}.
    3. Before this PR: wholesale clone → options.jsx.package_name = "preact".
      After this PR: merge_jsx copies import_source = ImportSource{dev: "preact/jsx-dev-runtime", prod: "preact/jsx-runtime"}, runtime = Automatic, development = false — but leaves package_name = "react".
    4. sync_resolver_opts() clones options.jsx (with the stale package_name) into resolver.opts.jsx; every result.jsx in the resolver is seeded from self.opts.jsx.clone(), and the per-file merge_jsx at resolver.rs:1644 also does not touch package_name. This flows into ParseTask.jsx (bundle_v2.rs:3469 for entry points, :6417 for resolved files).
    5. Parser hits <div {...p} key="k" />, emits the "key prop after a {...spread}" warning, sets jsx_imports.create_element, and at parse_entry.rs:1968 emits:
      import { createElement } from "react";   // ← should be "preact"

    Impact

    For a preact-only project this is a hard Could not resolve "react" build failure. If both react and preact are installed, it silently imports React's createElement for those elements while the rest of the tree uses preact's jsx — a subtle runtime mismatch. This is a concrete regression introduced by this PR: previously the wholesale clone seeded package_name correctly, and the pre-existing merge_jsx at resolver.rs:1644 was fine because its input already carried the right value.

    Fix

    In TSConfigJSON::merge_jsx, when apply.contains(JsxField::ImportSource), also copy the derived fields — mirroring what Pragma::from_api and TSConfigJSON::parse do for the same input:

    if apply.contains(JsxField::ImportSource) {
        out.import_source = self.jsx.import_source.clone();
        out.package_name = self.jsx.package_name.clone();
        out.classic_import_source = self.jsx.classic_import_source.clone();
    }

    A test in 15844.test.ts covering tsconfig {jsx: "react-jsx", jsxImportSource: "preact"} with no bunfig jsx keys and a key-after-spread element (asserting the output contains from "preact" and not from "react") would lock this in.

Comment thread src/runtime/cli/Arguments.rs
@robobun

robobun commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator Author

Both review findings addressed in 50dc85b:

  • merge_jsx now copies package_name and classic_import_source alongside import_source, so the key-after-spread createElement fallback imports from the tsconfig jsxImportSource package. Covered by the new tsconfig jsxImportSource reaches the key-after-spread createElement fallback test.
  • The --jsx-* merge-with-bunfig branch now falls back to prev.development / prev.side_effects instead of hardcoding false. Covered by bunfig jsx = 'react-jsxDEV' survives an unrelated --jsx-* flag.

Comment thread src/bundler/transpiler.rs

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both prior inline findings are addressed in 50dc85b; no new issues found. Deferring to a human because this is a cross-cutting precedence change (bunfig / CLI / Bun.build vs tsconfig) with an acknowledged output-shape change and overlap with #34980 / #36209 / #36269 that needs a maintainer call on which approach lands.

What was reviewed:

  • merge_jsx now gated on set_fields.difference and copies package_name/classic_import_source alongside import_source — the key-after-spread createElement fallback regression is fixed and covered by a test.
  • Arguments.rs else-branch now preserves prev.development/prev.side_effects when merging bunfig + --jsx-*; covered by the new react-jsxDEV test.
  • resolver.rs --tsconfig-override fd fix matches the extends-chain path (FD::INVALID); tsconfig-override.test.ts guards removed so stderr must be empty.
  • Checked the ruled-out concern that Bun.serve HTML bundler's explicit jsx.development could now be overridden by tsconfig — set_fields is populated in JSBundler.rs when development is passed, so merge_jsx skips it.
Extended reasoning...

Overview

The PR threads a per-field JsxFieldSet (set_fields) through api::Jsx → Pragma so that TSConfigJSON::merge_jsx can compute jsx_flags.difference(set_fields) and only fill fields the user did not explicitly set via bunfig / --jsx-* / Bun.build({jsx}). It also replaces the wholesale options.jsx = tsconfig.jsx copy in configure_linker_with_auto_jsx with the same merge, and fixes the --tsconfig-override "directory mismatch" fd warning by passing FD::INVALID instead of the root DirInfo's cached fd. Touches options_types/{jsx,schema}.rs, bunfig.rs, Arguments.rs, JSBundler.rs, js_bundle_completion_task.rs, resolver.rs, tsconfig_json.rs, transpiler.rs, plus docs and three test files.

Security risks

None identified. This is config-precedence plumbing for the JSX transform; no auth, crypto, network, or untrusted-input parsing changes. The FD::INVALID change routes to an absolute-path open instead of openat(wrong_fd, basename), which is strictly safer.

Level of scrutiny

Medium-high. The mechanical parts (adding JsxFieldSet, populating it at each entry point, gating merge_jsx) are straightforward and well-tested. But this is a user-visible behavior change — Bun.build({jsx: {runtime: "automatic"}}) with a "jsx": "react-jsx" tsconfig now emits production jsx instead of jsxDEV (one existing snapshot updated to reflect this), and the PR description explicitly flags overlap with three other open PRs (#34980 identical fd fix, #36269 different mechanism for the same bundler-side precedence problem, #36209 orthogonal development default change). A maintainer should decide which approach lands and how the others rebase.

Other factors

Two prior review rounds from me found (1) the Arguments.rs else-branch dropping prev.development and (2) merge_jsx not copying package_name/classic_import_source — both fixed in 50dc85b with dedicated tests. The regression test file (8 concurrent subprocess tests) covers bunfig-wins, CLI-wins, tsconfig-still-applies-when-bunfig-absent, the package_name key-after-spread fallback, the react-jsxDEV-survives-unrelated-flag case, and the fd-warning fix. tsconfig-override.test.ts had its "ignore the directory-mismatch warning" guards removed so the fix is load-bearing there too. The tsconfig extends chain still merges child-over-parent because base configs' Pragma.set_fields is empty. Given the cross-PR reconciliation and the intentional output change, this warrants human review rather than auto-approval.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both earlier findings (the development: prev.development fallthrough and the dropped package_name/classic_import_source in merge_jsx) are fixed with covering tests, and I found nothing new this pass. Deferring to a human for the precedence-semantics decision and the reconciliation with #36209 / #36269 / #34980.

Checked: set_fields propagation through bunfig → Arguments.rs → Pragma::from_api → merge_jsx; the tsconfig extends chain still merges child-over-parent (base's set_fields is empty); configure_linker_with_auto_jsx at both call sites (698, 753) now goes through merge_jsx; the bundler_jsx.test.ts snapshot change matches the described Bun.build({jsx})-now-merges-tsconfig behavior change.

Extended reasoning...

Overview

Adds per-field JsxFieldSet tracking on api::Jsx/Pragma so bunfig / --jsx-* / Bun.build({jsx}) win over tsconfig.json field-by-field, and switches configure_linker_with_auto_jsx from a wholesale tsconfig.jsx clone to merge_jsx. Also fixes the --tsconfig-override "directory mismatch" warning by passing FD::INVALID when the override path lives outside the cached dir fd. 13 files, ~250 net lines.

Security risks

None. Config-precedence plumbing and an fd selection fix; no untrusted-input parsing changes, no new syscall paths.

Level of scrutiny

Moderate–high. The mechanism is straightforward, but it changes user-facing precedence semantics for JSX config across three entry points and introduces a cross-cutting set_fields bitset that must stay consistent across bunfig, CLI, JSBundler, js_bundle_completion_task, Pragma::from_api, and merge_jsx. The Bun.build({jsx}) behavior change (previously skipped tsconfig JSX entirely, now merges) is acknowledged in the description and reflected in one updated snapshot; a maintainer should confirm that's the intended contract.

Other factors

My two prior inline findings on this PR were both addressed in 50dc85b with dedicated tests (bunfig jsx = 'react-jsxDEV' survives an unrelated --jsx-* flag and tsconfig jsxImportSource reaches the key-after-spread createElement fallback). The new 15844.test.ts covers the main precedence matrix and the fd-warning fix; tsconfig-override.test.ts had its warning-masking guards removed so stderr must now be empty. The PR self-reports overlap with three open PRs (#36209, #36269, #34980) that touch the same precedence machinery via different mechanisms — that reconciliation is a maintainer call, not something I should approve around.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/bundler/transpiler.rs (1)

692-703: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Preserve NODE_ENV precedence over tsconfig JSX.

configure_env_for_run calls configure_linker() before run_env_loader(). With NODE_ENV=production and "jsx": "react-jsxDEV", the later tsconfig merge restores jsx.development = true. This path does not call configure_defines() to restore the production setting. Apply the tsconfig merge before the environment override, or skip JsxField::Development when production is forced. Add a regression test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/bundler/transpiler.rs` around lines 692 - 703, Update the auto-JSX
configuration flow around merge_tsconfig_jsx_into so a production NODE_ENV
override remains authoritative over tsconfig’s JSX development setting; either
perform the tsconfig merge before the environment override or exclude
JsxField::Development when production is forced. Add a regression test covering
NODE_ENV=production with jsx set to react-jsxDEV and verify development mode
remains disabled.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/bundler/transpiler.rs`:
- Around line 692-703: Update the auto-JSX configuration flow around
merge_tsconfig_jsx_into so a production NODE_ENV override remains authoritative
over tsconfig’s JSX development setting; either perform the tsconfig merge
before the environment override or exclude JsxField::Development when production
is forced. Add a regression test covering NODE_ENV=production with jsx set to
react-jsxDEV and verify development mode remains disabled.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 583c1861-4a02-47a1-af6f-aa2179ee4e08

📥 Commits

Reviewing files that changed from the base of the PR and between f91d5c9 and ba12f8f.

📒 Files selected for processing (13)
  • docs/runtime/bunfig.mdx
  • src/bundler/transpiler.rs
  • src/bunfig/bunfig.rs
  • src/options_types/jsx.rs
  • src/options_types/schema.rs
  • src/resolver/resolver.rs
  • src/resolver/tsconfig_json.rs
  • src/runtime/api/JSBundler.rs
  • src/runtime/api/js_bundle_completion_task.rs
  • src/runtime/cli/Arguments.rs
  • test/bundler/bundler_jsx.test.ts
  • test/cli/run/tsconfig-override.test.ts
  • test/regression/issue/15844.test.ts

@robobun

robobun commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator Author

Re the CodeRabbit NODE_ENV / react-jsxDEV finding: verified it does not manifest.

# tsconfig.json: {"compilerOptions": {"jsx": "react-jsxdev"}}
NODE_ENV=production bun ./a.jsx      # -> PROD
NODE_ENV=production bun run ./a.jsx  # -> PROD
bun ./a.jsx                          # -> DEV

configure_env_for_run is the package.json script-runner transpiler (filter_run / pack / bunx / multi_run); the runtime JSX transpile goes through the VM transpiler, where force_node_env at the ParseTask layer already gates jsx.development. The merge_tsconfig_jsx_into call in run_env_loader predates this PR and is unchanged here.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both earlier findings (the development: prev.development fallthrough and merge_jsx dropping package_name/classic_import_source) are fixed in 50dc85b and covered by new tests; I found nothing further this pass. Deferring to a human because this is a user-visible precedence change (one existing bundler_jsx snapshot flipped from jsxDEV to jsx) and it overlaps with #36209 / #36269 / #34980, so a maintainer should pick which approach lands.

What was reviewed:

  • merge_jsx now gates on jsx_flags.difference(set_fields) — checked that the tsconfig extends-chain merge (base has empty set_fields) and the per-resolve resolver.rs:1644 call still layer child-over-parent correctly.
  • resolver.rs fd fix uses FD::INVALID only when tsconfig_override.is_some(); the discovered-tsconfig path keeps the cached dir fd.
  • bunfig.rs now leaves ctx.args.jsx = None when no jsx* keys are present, so tsconfig still applies (covered by the "bunfig has no jsx keys" test).
  • Confirmed jsx_pragma_from_resolver is still live (transpiler.rs:2850), not newly-dead.
Extended reasoning...

Overview

Introduces per-field JsxField/JsxFieldSet tracking on api::Jsx and Pragma so that bunfig / --jsx-* / Bun.build({jsx}) values survive the tsconfig merge instead of being clobbered. merge_jsx now computes jsx_flags.difference(current.set_fields) and only applies the remainder; configure_linker_with_auto_jsx switches from a wholesale tsconfig.jsx clone to that merge. The --tsconfig-override fd-mismatch warning is fixed by passing FD::INVALID so parse_tsconfig opens by absolute path. Touches options_types/{jsx,schema}.rs, bunfig.rs, Arguments.rs, JSBundler.rs, js_bundle_completion_task.rs, resolver.rs, tsconfig_json.rs, transpiler.rs, plus docs and three test files.

Security risks

None. This is config-precedence plumbing; no untrusted input parsing, auth, or crypto is touched. The resolver change narrows an fd usage rather than widening it.

Level of scrutiny

Medium-high. The mechanism is straightforward (a bitset gating field copies), but it threads through four config entry points and changes user-visible output — the jsx/sideEffectsTrueTsconfigAutomatic snapshot now emits jsx() instead of jsxDEV() because tsconfig's development: false fills a gap the user didn't set. Two real bugs were caught in earlier review passes on this PR (both fixed and tested), which is evidence the merge matrix is easy to get subtly wrong.

Other factors

  • Overlapping PRs: the description names #36209, #36269, and #34980 as touching the same precedence / fd-warning ground with different mechanisms. A maintainer should decide which lands and how to reconcile.
  • Test coverage: 8 new concurrent subprocess tests in 15844.test.ts cover bunfig-runtime, bunfig-importSource, bunfig-factory, CLI --jsx-runtime, bunfig-with-no-jsx-keys, key-after-spread package_name, bunfig react-jsxDEV + unrelated CLI flag, and the fd warning. The tsconfig-override.test.ts guards that used to filter out the "directory mismatch" warning are removed so stderr must be empty.
  • Behavior change: acknowledged in the PR description and reflected in one updated snapshot; whether that's the desired precedence for Bun.build({jsx}) + tsconfig is a product call.

@robobun

robobun commented Aug 1, 2026 •

Copy link
Copy Markdown
Collaborator Author

Status: diff is ready at 2b31534, squashed to one commit and rebased onto current main (past #39631 and #39732; conflict resolution is in the Rebase notes section of the description).

  • Scope: the JSX precedence change plus the bun test --parallel worker argv fix it required. The --tsconfig-override fd hunk lives in resolver: suppress spurious "directory mismatch" warning from --tsconfig-override #34980.
  • Reproduced with test/regression/issue/15844.test.ts: 5 of 8 cases fail on the released binary, 8 of 8 pass with the fix. bundler_jsx.test.ts, esbuild/tsconfig.test.ts, jsx-tsconfig-react-jsx.test.ts and transpiler-tsconfig-uaf.test.ts also pass on the rebased build.
  • Buildkite #102214 finished: 177 lanes green, 2 red. Both red lanes fail on tests this diff does not touch and both are reported to main-break triage separately: alpine x64 fails 7 --isolate leaked-handle cases in test/cli/test/isolation.test.ts (area changed on main today by bun test --isolate: stop finished files from pinning their global via mocks and plugins #39818), and windows 2019 x64 fails one GC wrapper-count assertion in test/js/bun/http/bun-server.test.ts. Neither fixture involves jsx config. Everything else flagged in the build passed on retry. The jsx, tsconfig and parallel suites passed on all 179 lanes, including the two red ones.
  • All review threads are addressed and resolved. Ready for a maintainer.

@robobun robobun changed the title jsx: let bunfig.toml / --jsx-* override tsconfig.json; fix --tsconfig-override fd warning jsx: let bunfig.toml / --jsx-* override tsconfig.json Aug 13, 2026
@robobun

robobun commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator Author

Consolidation note: the --tsconfig-override fd fix this PR shared with #34980 has been dropped from this branch (b97aa8c), since #34980 is the PR for #22023 and has that change plus the tests. This PR now only changes the bunfig / --jsx-* / Bun.build({jsx}) vs tsconfig precedence for #15844; title and description updated to match.

Comment thread test/regression/issue/15844.test.ts
Comment thread test/regression/issue/15844.test.ts
@robobun
robobun force-pushed the claude/c55aa873/bunfig-jsx-overrides-tsconfig branch from b97aa8c to 3845a4b Compare August 13, 2026 03:27

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both earlier nits are addressed (stderr now asserts the key-after-spread warning; title/description no longer reference #22023), and this pass found no further issues. Leaving the merge call to a maintainer given the documented Bun.build({jsx}) × tsconfig behavior change and the pending reconciliation with #36269's competing approach.

What was reviewed:

  • merge_jsx's new jsx_flags.difference(set_fields) gate — confirmed the tsconfig extends chain still merges child-over-parent (base's set_fields is empty).
  • transpiler.rs switching from wholesale clone to merge_tsconfig_jsx_into — side_effects/parse are preserved from the incoming Pragma, and package_name/classic_import_source now copy alongside import_source.
  • Arguments.rs else-branch — prev.development/prev.side_effects fallthrough is in place; the opts.jsx.is_none() branch's development: false is unchanged pre-existing behavior with no bunfig/CLI Development bit set, so tsconfig can still fill it.
  • bunfig.rs — an unrecognized jsx = "…" value leaves jsx_set empty and no longer materializes a default api::Jsx, so tsconfig still applies.
Extended reasoning...

Overview

The PR threads a per-field JsxFieldSet (set_fields) through api::Jsx → Pragma so that TSConfigJSON::merge_jsx can skip fields the user explicitly set via bunfig, --jsx-* flags, or Bun.build({jsx}). It touches the option type definitions (options_types/{jsx,schema}.rs), all three config entry points (bunfig.rs, Arguments.rs, JSBundler.rs), the tsconfig merge (tsconfig_json.rs), the transpiler's root-tsconfig application (transpiler.rs), and the completion-task Pragma construction. Tests cover bunfig/CLI overriding tsconfig, tsconfig still applying when bunfig has no jsx keys, the key-after-spread package_name path, and bunfig react-jsxDEV surviving an unrelated CLI flag. One bundler_jsx.test.ts snapshot updated to reflect the documented behavior change.

Security risks

None. This is config-precedence plumbing for JSX transpile options; no untrusted input parsing, no filesystem/network surface, no auth or crypto.

Level of scrutiny

Moderate-to-high. The mechanical changes are straightforward, but the PR (a) changes user-visible Bun.build({jsx}) × tsconfig semantics (previously specifying jsx skipped tsconfig entirely; now unset fields fall through), (b) introduces a design choice — per-field set_fields tracking — that the PR description itself notes conflicts with #36269's different mechanism, and (c) touches config precedence across four entry points where subtle ordering matters. That is a maintainer-level design/compat decision, not a mechanical fix.

Other factors

All four of my earlier findings across two review passes were addressed (the two 🔴 bugs in 50dc85b, the two 🟡 nits by 3845a4b and the metadata edit). Buildkite #87454 was green on all relevant lanes per the author's status comment; a fresh build (#94016) is running on the latest commit. The evidence gate confirmed fail-before/pass-after on both ASAN and release. The remaining reasons not to auto-approve are already stated by the author in the PR description, so this defer is just confirming the automated review is clean on the latest revision.

Comment thread src/runtime/cli/Arguments.rs
Comment thread src/runtime/cli/test/parallel/runner.rs Outdated
Comment thread test/regression/issue/15844.test.ts Outdated

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this PR across five passes and the current head (66dac82) addresses everything raised; this run found no further issues. Because it changes config-precedence semantics across bunfig / CLI / Bun.build({jsx}) / tsconfig, carries an acknowledged behavior change to Bun.build({jsx}) + tsconfig, and the description notes #36269 solves an overlapping problem with a different mechanism that will need reconciling, a human look at the precedence design is still worthwhile.

What was reviewed:

  • merge_jsx now gated on set_fields.difference; verified the tsconfig extends chain still merges child-over-parent (base's set_fields is empty).
  • configure_linker_with_auto_jsx no longer drops package_name/classic_import_source — covered by the key-after-spread test.
  • runner.rs was the only internal --jsx-* emitter; forwarding is now set_fields-gated and the serial/parallel parity test guards it.
  • The Arguments.rs bunfig+CLI merge branch now falls back to prev.development/prev.side_effects; covered by the react-jsxDEV test.
Extended reasoning...

Overview

The PR threads a per-field JsxFieldSet (set_fields) through every JSX config producer — bunfig.toml, --jsx-* CLI flags, Bun.build({jsx}) — and into Pragma, then makes TSConfigJSON::merge_jsx skip fields already in that set. It also switches configure_linker_with_auto_jsx from a wholesale tsconfig-jsx clone to a merge, updates the bun test --parallel worker-argv builder to only forward user-set jsx fields, moves the JsxField enum from the resolver into bun_options_types, and adds docs + 8 regression tests. 14 files, ~249 net lines.

Security risks

None identified. All inputs are local config (bunfig, tsconfig, CLI flags, Bun.build options); no network, auth, or untrusted-data parsing is touched. The change is purely about which config layer wins for JSX transform selection.

Level of scrutiny

High. This is a cross-cutting semantic change to config precedence, not a mechanical fix: it alters what Bun.build({jsx: {...}}) emits when a tsconfig is also present (previously tsconfig JSX was skipped entirely; now unset fields fall through to it — one existing snapshot in bundler_jsx.test.ts was updated to reflect this). The five prior review passes each found a real issue (dropped package_name, hardcoded development: false in the CLI merge branch, the parallel-runner unconditionally forwarding --jsx-runtime, test-strength gaps), all of which were fixed with dedicated tests. That history plus the description's own note that #36269 addresses the same interaction "with a different mechanism and will need reconciling" means the precedence design itself deserves a human decision before merge.

Other factors

All prior review threads are resolved. Test coverage is thorough (bunfig/CLI/import-source overrides, tsconfig fallthrough, key-after-spread package_name, bunfig-dev + unrelated CLI flag, serial vs --parallel=2 parity), and the gate evidence shows the new tests fail on main and pass here. The enumset removal from src/resolver/Cargo.toml is correct — JsxField moved to bun_options_types and the resolver re-exports it from there. Given the scope, the behavior change, and the open reconciliation question with #36269, deferring to a human rather than auto-approving.

A JSX field set explicitly in bunfig.toml, via a --jsx-* CLI flag, or via
Bun.build({jsx}) is no longer overwritten by a tsconfig.json that sets the
same field. Fields not set explicitly still fall through to tsconfig.

TSConfigJSON::merge_jsx applied every field tsconfig set regardless of
whether the incoming Pragma already carried a user-set value, and the
user-set side had no per-field was-set tracking to gate it.

- options_types::jsx: add JsxField/JsxFieldSet (moved from the resolver)
  and Pragma.set_fields; carry it through api::Jsx and Pragma::from_api.
  The enumset dependency moves from the resolver to options_types with it.
- bunfig.rs: populate set_fields per jsx* key and stop materialising an
  api::Jsx when no jsx* keys are present.
- Arguments.rs / JSBundler.rs: populate set_fields per --jsx-* flag /
  Bun.build({jsx}) option. The merge-with-bunfig branch in Arguments.rs
  now falls back to prev.development / prev.side_effects like the other
  fields instead of hardcoding false.
- tsconfig_json.rs: merge_jsx skips fields already in set_fields, and
  copies package_name / classic_import_source along with import_source so
  the key-after-spread createElement fallback imports from the configured
  package.
- transpiler.rs configure_linker_with_auto_jsx: merge the root tsconfig
  (honouring set_fields) instead of a wholesale copy or a skip.
- test/parallel/runner.rs: forward a --jsx-* flag to workers only when
  its field is in set_fields. Forwarding the default runtime would mark it
  user-set in the worker and block the worker's tsconfig, so a parallel
  run would transpile differently from a serial one.

Fixes #15844.
@robobun
robobun force-pushed the claude/c55aa873/bunfig-jsx-overrides-tsconfig branch from 66dac82 to 2b31534 Compare August 21, 2026 03:52

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this PR and the bug hunting system found no issues this pass; every earlier finding has been addressed and resolved. Because it changes user-facing JSX config precedence across four sources (bunfig / --jsx-* / Bun.build({jsx}) / tsconfig), carries an intentional behavior change to Bun.build({jsx}) + tsconfig, and the description flags #36269 as needing reconciling with the set_fields approach, a maintainer sign-off on the precedence model is still worthwhile.

What was reviewed:

  • merge_jsx's new jsx_flags.difference(set_fields) gating and the tsconfig extends chain (base config's set_fields is empty, so child-over-parent still holds).
  • set_fields propagation through every producer: bunfig, Arguments.rs, JSBundler.rs, js_bundle_completion_task.rs, and the --parallel worker argv forwarder.
  • The transpiler.rs wholesale-copy → merge switch, including package_name/classic_import_source now copied alongside import_source (covered by the key-after-spread test).
  • hash_for_runtime_transpiler — set_fields is precedence metadata only and correctly not hashed; the fields it gates already are.
Extended reasoning...

Overview

This PR fixes #15844 by giving bunfig.toml jsx* keys, --jsx-* CLI flags, and Bun.build({jsx}) per-field precedence over tsconfig.json's compilerOptions.jsx*. It introduces JsxField/JsxFieldSet on api::Jsx and Pragma, populates the set at each config source, and makes TSConfigJSON::merge_jsx skip fields already in set_fields. It touches 15 files across options_types, bunfig, resolver, bundler, runtime/api, runtime/cli (including the bun test --parallel worker argv builder), docs, and adds an 8-case regression suite plus one updated bundler snapshot.

Security risks

None. This is transpiler-config precedence; no untrusted-input parsing, no auth, no filesystem/network surface changes. The enumset dependency move is a workspace-internal Cargo shuffle.

Level of scrutiny

Moderate-to-high. The mechanism (a bitset gating a merge) is small, but it threads through five producers and two merge sites, and it changes observable output for anyone combining Bun.build({jsx}) or bunfig with a tsconfig. The PR has already been through four review iterations that caught real bugs (dropped package_name, hardcoded development: false in the CLI+bunfig branch, the parallel-runner unconditional --jsx-runtime forward), all of which are now fixed and covered by tests. The remaining question is design-level: the precedence model itself, the intentional Bun.build({jsx}) dev→prod behavior change, and how this reconciles with #36269's competing approach — decisions a maintainer should own.

Other factors

Test coverage is thorough (bunfig runtime/factory/importSource overrides, CLI override, tsconfig-still-applies-when-bunfig-absent, key-after-spread package_name propagation, bunfig react-jsxDEV surviving an unrelated CLI flag, and serial vs --parallel=2 parity). All prior review threads are marked resolved. The updated bundler_jsx.test.ts snapshot reflects the documented behavior change and its sideEffects invariant is unchanged. The enumset removal from src/resolver/Cargo.toml is correct (JsxField moved to bun_options_types and is re-exported).

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bunfig.toml should override tsconfig.json

2 participants