{"record":{"id":"4dfbf492b9bfc1b0","repo":"swc-project/swc","slug":"decl-in-exportdecl","errorCode":null,"errorMessage":"Decl in ExportDecl: {:?}","messagePattern":"Decl in ExportDecl: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/swc_bundler/src/bundler/export.rs","lineNumber":172,"sourceCode":"                let v = self.info.items.entry(None).or_default();\n                v.push({\n                    let i = match decl.decl {\n                        Decl::Class(ref c) => &c.ident,\n                        Decl::Fn(ref f) => &f.ident,\n                        Decl::Var(ref var) => {\n                            let ids: Vec<Id> = find_pat_ids(&var.decls);\n                            for id in ids {\n                                v.push(Specifier::Specific {\n                                    local: id,\n                                    alias: None,\n                                });\n                            }\n                            return;\n                        }\n                        Decl::TsEnum(ref e) => &e.id,\n                        Decl::TsInterface(ref i) => &i.id,\n                        Decl::TsTypeAlias(ref a) => &a.id,\n                        _ => unreachable!(\"Decl in ExportDecl: {:?}\", decl.decl),\n                    };\n                    Specifier::Specific {\n                        local: i.into(),\n                        alias: None,\n                    }\n                });\n            }\n\n            ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultDecl(_decl)) => {\n                self.info\n                    .items\n                    .entry(None)\n                    .or_default()\n                    .push(Specifier::Specific {\n                        local: Id::new(atom!(\"default\"), SyntaxContext::empty()),\n                        alias: None,\n                    });\n            }","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_bundler/src/bundler/export.rs#L154-L190","documentation":"swc_bundler's export scanner enumerates bindings created by `export <decl>`. It handles Class, Fn, Var (via pattern ids) and the TS declaration kinds TsEnum/TsInterface/TsTypeAlias; the only remaining variant is Decl::TsModule, so `export namespace Foo {}` / `export module Foo {}` reaching the bundler un-stripped triggers this unreachable!(). The bundler expects plain ESM — TypeScript should already be removed.","triggerScenarios":"Feeding swc_bundler a TypeScript source containing `export namespace X { ... }` or `export module M { ... }` without running the TypeScript strip pass first.","commonSituations":"Custom pipelines that run the bundler directly on raw .ts sources; test fixtures containing namespaces; plugins that re-inject TS nodes after stripping.","solutions":["Strip TypeScript before bundling: run swc_ecma_transforms_typescript::strip (or compile via the standard swc chain) so Decl::TsModule is gone before Bundler::bundle","Replace `export namespace`/`export module` in bundled sources with plain ES module exports","If TS is already stripped upstream and it still fires, minimize the repro and report it to swc"],"exampleFix":"// before\nexport namespace Config {\n  export const retries = 3;\n}\n\n// after\nexport const Config = { retries: 3 };","handlingStrategy":"validation","validationCode":"// Reject TS-only `export namespace` / `export module` before bundling\nfn has_exported_ts_namespace(src: &str) -> bool {\n    let re = regex::Regex::new(r#\"(?m)^\\s*export\\s+(?:namespace|module)\\s+\\w\"#).unwrap();\n    re.is_match(src)\n}\nassert!(!sources.values().any(|s| has_exported_ts_namespace(s)),\n    \"strip TypeScript (export namespace/module) before swc_bundler\");","typeGuard":null,"tryCatchPattern":"if let Err(p) = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| bundler.bundle(&entries))) {\n    let msg = panic_message(&p);\n    if msg.contains(\"Decl in ExportDecl\") {\n        // route: run typescript::strip on inputs, then retry the bundle\n    } else { std::panic::resume_unwind(p); }\n}","preventionTips":["Always run the TypeScript strip/compile chain before the bundler","Ban `export namespace`/`export module` via lint rules in codebases that get bundled","Add a CI gate that feeds stripped output (no Decl::Ts* nodes) into bundler fixtures"],"tags":["swc","bundler","typescript","namespace","export"],"backgroundTag":"typescript-strip-before-bundle","analyzedSha":"5176682b65416c6b5de6b47379ae1588ea3ecb3f","analyzedAt":"2026-08-17T16:16:52.067Z","contentChangedAt":"2026-08-17T16:16:52.067Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}