Skip to content

Commit ef78e59

Browse files
committed
Avoid printing comments on static fields twice.
In TS4.4, when a transformer adds a static field with a synthetic comment to a decorated class, TS prints the synthetic comment twice: @decorator class MyClass { /* comment */ staticField = 'x'; // field and comment added by transformer } Becomes: var MyClass = class MyClass {} /*comment*/ /*comment*/ MyClass.newField = "x"; __decorate(MyClass, Decorator, ...) This is because the classFields transformer calls `setOriginalNode(n, propertyDeclaration)` on both the expression statement , and the assignment expression contained in it, leading to the synthetic comment appearing twice. This change avoids the problem by explicitly deleting any synthetic comments from the assignment expression created for static fields when creating the expression statement containing the assignment. This allows us to retain the information of the original node without printing the synthetic comment twice.
1 parent 3b086e1 commit ef78e59

File tree

4 files changed

+81
-0
lines changed

4 files changed

+81
-0
lines changed

src/compiler/transformers/classFields.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1335,6 +1335,11 @@ namespace ts {
13351335
setSourceMapRange(statement, moveRangePastModifiers(property));
13361336
setCommentRange(statement, property);
13371337
setOriginalNode(statement, property);
1338+
// `setOriginalNode` *copies* the `emitNode` from `property`, so now both
1339+
// `statement` and `expression` have a copy of the synthesized comments.
1340+
// Drop the comments from expression to avoid printing them twice.
1341+
setSyntheticLeadingComments(expression, undefined);
1342+
setSyntheticTrailingComments(expression, undefined);
13381343
statements.push(statement);
13391344
}
13401345
}

src/testRunner/unittests/transform.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,63 @@ module MyModule {
599599
}, exports => {
600600
assert.equal(exports.stringLength, 5);
601601
});
602+
603+
function addStaticFieldWithComment(context: TransformationContext) {
604+
return (sourceFile: SourceFile): SourceFile => {
605+
return visitNode(sourceFile, rootTransform, isSourceFile);
606+
};
607+
function rootTransform<T extends Node>(node: T): Node {
608+
if (isClassDeclaration(node) || isClassExpression(node)) {
609+
const newMembers = [factory.createPropertyDeclaration(/* decorators */ undefined, [factory.createModifier(SyntaxKind.StaticKeyword)], "newField", /* questionOrExclamationToken */ undefined, /* type */ undefined, factory.createStringLiteral("x"))];
610+
setSyntheticLeadingComments(newMembers[0], [{ kind: SyntaxKind.MultiLineCommentTrivia, text: "comment", pos: -1, end: -1, hasTrailingNewLine: true }]);
611+
return isClassDeclaration(node) ?
612+
factory.updateClassDeclaration(
613+
node, node.decorators,
614+
/* modifierFlags */ undefined, node.name,
615+
node.typeParameters, node.heritageClauses,
616+
newMembers) :
617+
factory.updateClassExpression(
618+
node, node.decorators,
619+
/* modifierFlags */ undefined, node.name,
620+
node.typeParameters, node.heritageClauses,
621+
newMembers);
622+
}
623+
return visitEachChild(node, rootTransform, context);
624+
}
625+
}
626+
627+
testBaseline("transformSyntheticCommentOnStaticFieldInClassDeclaration", () => {
628+
return transpileModule(`
629+
declare const Decorator: any;
630+
@Decorator
631+
class MyClass {
632+
}
633+
`, {
634+
transformers: {
635+
before: [addStaticFieldWithComment],
636+
},
637+
compilerOptions: {
638+
target: ScriptTarget.ES2015,
639+
newLine: NewLineKind.CarriageReturnLineFeed,
640+
}
641+
}).outputText;
642+
});
643+
644+
testBaseline("transformSyntheticCommentOnStaticFieldInClassExpression", () => {
645+
return transpileModule(`
646+
const MyClass = class {
647+
};
648+
`, {
649+
transformers: {
650+
before: [addStaticFieldWithComment],
651+
},
652+
compilerOptions: {
653+
target: ScriptTarget.ES2015,
654+
newLine: NewLineKind.CarriageReturnLineFeed,
655+
}
656+
}).outputText;
657+
});
658+
602659
});
603660
}
604661

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5+
return c > 3 && r && Object.defineProperty(target, key, r), r;
6+
};
7+
let MyClass = class MyClass {
8+
};
9+
/*comment*/
10+
MyClass.newField = "x";
11+
MyClass = __decorate([
12+
Decorator
13+
], MyClass);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
var _a;
2+
const MyClass = (_a = class {
3+
},
4+
/*comment*/
5+
_a.newField = "x",
6+
_a);

0 commit comments

Comments
 (0)