{"record":{"id":"7d56cad8b02eac5d","repo":"swc-project/swc","slug":"emitting-decorator-metadata-while-using-new-propos","errorCode":null,"errorMessage":"emitting decorator metadata while using new proposal","messagePattern":"emitting decorator metadata while using new proposal","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/swc_ecma_transforms_proposal/src/decorators/mod.rs","lineNumber":65,"sourceCode":"/// ```js\n/// class C {\n///   @enumerable(false)\n///   method() { }\n/// }\n///\n/// function enumerable(value) {\n///   return function (target, key, descriptor) {\n///      descriptor.enumerable = value;\n///      return descriptor;\n///   }\n/// }\n/// ```\npub fn decorators(c: Config) -> impl Pass {\n    if c.legacy {\n        Either::Left(visit_mut_pass(self::legacy::new(c.emit_metadata)))\n    } else {\n        if c.emit_metadata {\n            unimplemented!(\"emitting decorator metadata while using new proposal\")\n        }\n        Either::Right(fold_pass(Decorators {\n            is_in_strict: false,\n            vars: Default::default(),\n        }))\n    }\n}\n\n#[derive(Debug, Default, Deserialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct Config {\n    pub legacy: bool,\n    #[serde(default)]\n    pub emit_metadata: bool,\n\n    pub use_define_for_class_fields: bool,\n}\n","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/swc-project/swc/blob/d7d74346665e36e692aa07e13d4ee3ee692ee35c/crates/swc_ecma_transforms_proposal/src/decorators/mod.rs#L47-L83","documentation":"The decorator pass supports two modes: legacy decorators (with optional metadata emission via `legacy::new(c.emit_metadata)`) and the 2022-03 spec transform, which has no metadata story in swc. Constructing the pass with `legacy: false` and `emit_metadata: true` hits `unimplemented!` at pass-construction time.","triggerScenarios":"Configure decorators with `jsc.parser.decorators: true`, `jsc.transform.legacyDecorator: false` and `jsc.transform.decoratorMetadata: true` (swc core maps these fields onto the Config struct in decorators/mod.rs).","commonSituations":"Migrating off `experimentalDecorators` in TypeScript while keeping `emitDecoratorMetadata: true` (TS itself warns this combination is unsupported); porting Babel configs that set decorators + decoratorMetadata without the legacy flag; NestJS-style codebases trying the new proposal.","solutions":["Set `jsc.transform.legacyDecorator: true` — metadata emission is supported in legacy mode","Or disable `jsc.transform.decoratorMetadata` and stay on the modern proposal","If you must stay on the new proposal, emit metadata in a follow-up pass of your own"],"exampleFix":"// .swcrc before\n{ \"jsc\": { \"transform\": { \"legacyDecorator\": false, \"decoratorMetadata\": true } } }\n\n// after\n{ \"jsc\": { \"transform\": { \"legacyDecorator\": true, \"decoratorMetadata\": true } } }","handlingStrategy":"validation","validationCode":"// Reject the unsupported combination before compiling\nconst t = cfg.jsc?.transform ?? {};\nif (t.decoratorMetadata === true && t.legacyDecorator === false) {\n  throw new Error('decoratorMetadata requires legacyDecorator: true in swc');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat `decoratorMetadata: true` as implying `legacyDecorator: true` in your config loader","Mirror TypeScript's rule: no `emitDecoratorMetadata` without `experimentalDecorators`"],"tags":["decorators","typescript","config","proposal","metadata"],"backgroundTag":null,"analyzedSha":"d7d74346665e36e692aa07e13d4ee3ee692ee35c","analyzedAt":"2026-08-16T12:41:13.160Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}