microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.08k stars 12.37k forks source link

Synthetic comment duplicated 3 times on class with experimental decorators #54742

Open frigus02 opened 1 year ago

frigus02 commented 1 year ago

Bug Report

πŸ”Ž Search Terms

setSyntheticLeadingComments, transformer

πŸ•— Version & Regression Information

In 5.0 TypeScript already emitted the comment twice. In 5.1 it emits it 3 times.

(+1 on both if you count the comment on the __decorate call)

πŸ’» Code

Repro: https://github.com/frigus02/test-ts-triple-synthesized-comment

const FILE = ` 
@decorate()
class Foo {}
`;

const myTransformer = () => {
  return (sf) => {
    ts.setSyntheticLeadingComments(sf.statements[0], [
      {text: 'from transformer', kind: ts.SyntaxKind.MultiLineCommentTrivia, pos: -1, end: -1},
    ]);
    return sf;
  };
};

const result = ts.transpileModule(FILE, {
  compilerOptions: {
    experimentalDecorators: true,
    module: ts.ModuleKind.CommonJS,
    target: ts.ScriptTarget.ESNext,
  },
  transformers: {
    before: [myTransformer],
  }
});

console.log(result.outputText);

πŸ™ Actual behavior

/*from transformer*/ let /*from transformer*/ Foo = /*from transformer*/ class Foo {
};
/*from transformer*/ Foo = __decorate([
    decorate()
], Foo);

The comment between let and Foo is problematic for our use of tsickle and Closure Compiler. But I think the issue is more general. I'd expect the comment to appear only once in the output.

This seems very similar to https://github.com/microsoft/TypeScript/issues/45696

We validated that the same fix (calling setSyntheticLeadingComments(expression, undefined)) after setOriginalNode here and here would fix this. Are you open to such a fix? If so, I'd be happy to send a PR.

πŸ™‚ Expected behavior

/*from transformer*/ let Foo = class Foo {
};
Foo = __decorate([
    decorate()
], Foo);
fatcerberus commented 1 year ago

I count 4. :wink: