Repository navigation
Conversation
Collaborator
Author
|
Updated 1:04 AM PT - Oct 24th, 2026
✅ @robobun, your commit 0d7671138aa735f915238432e4556fca22954e7d passed in 🧪 To try this PR locally: bunx bun-pr 46457That installs a local version of the PR into your bun-46457 --bun |
Collaborator
Author
|
Status
|
robobun
force-pushed
the
robobun/64f2d4c5/stack-base
branch
from
October 24, 2026 05:42
6e0539d to
6015b6e
Compare
robobun
force-pushed
the
robobun/64f2d4c5/repl-tsconfig-decorators
branch
from
October 24, 2026 05:42
ad347d4 to
679eb75
Compare
The lowering of a decorator adds statements after the class, so a REPL input that declares such a class reported what the last of them returns: `undefined` for a TC39 class decorator, and a property descriptor or `undefined` for a legacy member decorator. A class declaration without decorators reports the class. In replMode, a class declaration at the top level of the input is now followed by a read of its name when the lowering added statements.
…g directory `bun repl` passed constants for the decorator options: the legacy TypeScript decorators and no decorator metadata, whatever the tsconfig.json said. An `accessor` field was a SyntaxError and a TC39 decorator got the legacy arguments. The REPL now passes `experimentalDecorators` and `emitDecoratorMetadata` of the root tsconfig.json, which the module loader passes for a file.
robobun
force-pushed
the
robobun/64f2d4c5/repl-tsconfig-decorators
branch
from
October 24, 2026 05:43
679eb75 to
0d76711
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #45915 and #45557. No user reported this.
Problem
class E { accessor a = 1 }inbun replgivesSyntaxError: Unexpected identifier 'a'. Expected a ';' following a class field.Decorators get the legacy arguments. A file runs both.Repl::transform_for_repl(src/runtime/cli/repl.rs:2149) passed constants, not the root tsconfig.json values that the module loader passes.Fix
experimentalDecoratorsandemitDecoratorMetadataof the root tsconfig.json, through theTsconfigOptionsargument of parser: require the tsconfig options in ParserOptions::init, fix scanImports on decorators and accessor fields #45557.src/js_parser/repl_transforms.rs:900).test/js/bun/repl/repl.test.ts(11 new) andtest/js/bun/transpiler/repl-transform.test.ts(2 new), all failing on the base. Also the decorator suites.Background
accessor. A TypeScript file gets the legacy ones when tsconfig.json setsexperimentalDecoratorsoremitDecoratorMetadata.ParserOptions::init, without parser: require the tsconfig options in ParserOptions::init, fix scanImports on decorators and accessor fields #45557: a fourth copy of the formula. It is the fallback.Downsides
(value, context), and a parameter decorator is not called (js_parser: reject parameter decorators when experimental decorators are off #43321).experimentalDecoratorsin tsconfig.json restores the legacy ones..text+512 bytes..load x.jsis parsed as TSX (Notes).Notes
The stack
robobun/64f2d4c5/stack-baseis maina8b5e920c4plus a merge of replMode: keep helper imports and lowering temporaries in the wrapper #45915 and a merge of parser: require the tsconfig options in ParserOptions::init, fix scanImports on decorators and accessor fields #45557. This PR is the two commits on top. I retarget it to main when both are merged.repl_binding_persistsinsrc/js_parser/repl_transforms.rs). With that rule switched off on a scratch build, the two sessions of the new testsa class with ... is not changed by a later onegive[ 201, 202 ]andTypeError: Cannot read from private field.ParserOptions::init.emitDecoratorMetadata, the inputtrue ? (): new () => object => { class A { @dec p: Date } return A } : nullstopped the parser withpanic: index out of bounds. A file had that panic on 1.4.3. The new tests evaluate this input at the prompt and in a file.What changes at the prompt
An input with no decorator and no
accessorfield does not change: the text that the REPL evaluates is byte-identical for 50 such inputs in 3 tsconfig states..tsfile, 1.4.3 and this PRaccessoris a SyntaxErrorexperimentalDecoratorsemitDecoratorMetadatatsconfig.json, orbun repl --tsconfig-overridewith a flat file, keeps the legacy decorators.experimentalDecorators,accessoris still a SyntaxError at the prompt, as in a file (Decorators on accessor class fields fail to parse in Bun #29197, Accept and lower theaccessorkeyword in TypeScript files using experimentalDecorators #38125).descriptor.valuethrowsTypeError: undefined is not an object. That is what the same decorator does in a file there.@dec class D {}reportedundefinedwith TC39 decorators. With the legacy ones,class Q { @dec m() {} }reported a property descriptor andclass T { @dec p = 1 }reportedundefined. This also changes the output ofBun.Transpiler({ replMode: true })for those inputs: one statement that reads the class name is added.Why the default changes without a flag
Bun.Transpilerafter a user report (experimentalDecorators: truein tsconfig has no effect — Bun.Transpiler andbun buildalways emit TC39 decorators #27575).Not in this PR
.load x.js, and every input, is parsed as TSX. Where the tsconfig.json sets a legacy option, a.jsfile gets TC39 decorators and the prompt gets the legacy ones. That is the same as before.accessorfield that is evaluated more than once (a loop body, a parameter default) shares its temporaries, as in a file (js_parser: declare decorator lowering temporaries per iteration inside loops (stacked on #38734) #38933, js_parser: declare decorator lowering temporaries per evaluation in parameter defaults and field initializers #38904).bun replstill ignores--featureand--no-macros.Measurements
Release builds (ThinLTO) of the base and of this diff on main
0793250a5b9, in one build directory. The source diff has not changed since. Tools:llvm-size,llvm-nm -S,qemu-x86_64 -one-insn-per-tb -d exec,nochain -dfilter(instructions inside one function),qemu-x86_64 -strace, gdb 16.3 (breakpoints on 16mi_*entry points, and a dump atBun__REPL__evaluate).perf,valgrind,straceandbloatyare not installed..text81,989,093 to 81,989,605 bytes (+512)..rodata,.dataand.bssdo not change. The stripped binary is 107,583,200 bytes in both.Repl::transform_for_repl3,214 to 3,230 bytes,s_class1,205 to 1,239 (two parser instantiations), and the new coldrepl_report_class_declaration, 255 bytes (two instantiations).Options::init,scanImports,parse_worker::run_from_thread_poolandTranspiler::parseare byte-identical.bun repl, per input: 322 to 325 instructions intransform_for_repl, for 2 inputs in 3 tsconfig states.Options::init: 75 to 75.bun run, per class declaration, ins_class: 75 to 76 instructions (a class with no decorator, with a member decorator, with anaccessorfield, in.tsand.js). 84 to 83 for a class with a class decorator.transform_for_repl: 2,366 to 2,366 for a session of 50 inputs without decorators. Syscalls of that session: 705 to 705, and 709 to 709 with a tsconfig.json (1 open of it in both).clock_gettime). An input with anaccessorfield, which was a SyntaxError: 38 to 124 allocator calls. At a terminal it costs +18 syscalls (7ioctl, 2rt_sigaction), because it is awaited like every input that imports a helper.diff -rover js, jsx, ts and tsx modules with decorators, under no option,experimentalDecorators, and both).Bun.Transpiler({ replMode: true })output for 67 inputs: 6 differ with TC39 decorators and 10 with the legacy ones, by 0 to 8 bytes. All are top-level class declarations with decorators.Tests
repl.test.ts:accessorand TC39 decorators with no tsconfig.json, two lowered classes in one session (two tests), a decorator imported from a module,.load,.copy,-p, and five directory shapes where the prompt andbun program.tsrun the same program and must agree.repl-transform.test.ts: a class declaration reports the class with TC39 and with legacy decorators, and only in replMode at the top level. Withrepl_modedeleted from the guard on a scratch build, both tests fail.repl.test.ts148 pass,repl-transform.test.ts70 pass,transpiler.test.js307,es-decorators.test.ts427,es-decorators-esbuild.test.ts146,decorators.test.ts25,decorator-metadata.test.ts5,runtime-transpiler.test.ts15,test/regression/issue/44915.test.ts,test/cli/test/coverage.test.ts43.test/internal/source-lintspasses with the release binary.Self-review
26 concerns raised, 23 addressed. The two largest: the echo of a class declaration covered only TC39 decorators and moved to the statement visitor, and the metadata option waited for #46270. Not taken:
.load x.jsunder a legacy tsconfig.json. It would pin a mismatch.