Skip to content

fix: surface error instead of panicking on unclosed exported namespace/module - #803

Closed
ammubhave wants to merge 1 commit into
dprint:mainfrom
ammubhave:fix/unclosed-exported-namespace-panic
Closed

fix: surface error instead of panicking on unclosed exported namespace/module#803
ammubhave wants to merge 1 commit into
dprint:mainfrom
ammubhave:fix/unclosed-exported-namespace-panic

Conversation

@ammubhave

Copy link
Copy Markdown

Summary

Fixes #802.

Formatting a file with an unclosed exported namespace/module panicked with Expected to find a close brace token. instead of reporting a syntax error:

export namespace Foo {
  const x = 1;

Root cause

swc's parser recovers from the missing } for the export namespace/export module case and produces a TsModuleDecl without emitting any diagnostic (verified: 0 diagnostics). The parse-time gate ensure_no_specific_syntax_errors therefore has nothing to filter, so code generation proceeds and gen_membered_body panics on .expect("Expected to find a close brace token.").

Every other unclosed form (bare namespace, declare namespace/module/global, bare module, dotted namespace Foo.Bar) does emit an swc diagnostic and was already handled.

Fix

When no close-brace token is found in gen_membered_body, push a generation diagnostic (which makes generate return an Err) instead of .expect()-panicking. This reuses the existing context.diagnostics error channel and, because it relies on the view's direct-token-ownership, also handles nested cases where the single } belongs to the inner block.

The resulting error is, e.g.:

Unexpected end of file. Expected a close brace token for the block starting on line 1.

Tests

Added unit tests in src/format_text.rs covering the panic→error variants (simple, export module, empty body, nested, unclosed-outer-with-complete-inner, dotted name) — including exact-message assertions that pin the reported line — plus regression cases confirming well-formed namespaces still format.

🤖 Generated with Claude Code

…e/module

swc's parser recovers from a missing close brace for an unclosed
`export namespace`/`export module` without emitting any diagnostic, so it
isn't caught by `ensure_no_specific_syntax_errors` and reaches code
generation, where `gen_membered_body` panicked via
`.expect("Expected to find a close brace token.")`.

Push a generation diagnostic (which makes `generate` return an error)
instead of panicking when the close brace token is missing.

Closes dprint#802

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dsherret

dsherret commented Aug 21, 2026

Copy link
Copy Markdown
Member

Thanks, but I’d rather this get fixed properly in swc.

AI comment: Thanks for the detailed root-cause work here — I verified it independently and it held up, including the "0 diagnostics" observation.

Digging into why swc reports nothing, the cause turns out to be upstream and more general than namespaces. try_parse_ts sets Context::IgnoreError for the duration of the speculative parse and only restores it after the closure returns. On the success path the parse is kept, but every recoverable error emitted while producing it has already been discarded. export namespace / export module reach the parser through try_parse_ts_export_decl, which is why only the exported forms are silent — the non-export path calls parse_ts_decl directly and its diagnostic survives. (export declare namespace takes yet another branch, which is why it was never affected.)

So swc does generate the error — it just throws it away.

I've opened a fix upstream: swc-project/swc#12137. It makes recoverable errors roll back with the parser checkpoint instead of being suppressed, so export namespace Foo { reports the missing } like every other form, and dprint's existing syntax-error gate catches it with no plugin-side change needed.

Going to close this one in favour of fixing it at the source. Your diagnosis is what made the upstream fix possible — thanks for taking the time to dig into the parser properly rather than just papering over the panic.

@dsherret dsherret closed this Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Panic "Expected to find a close brace token" formatting an unclosed exported namespace/module

2 participants