Skip to content
2 changes: 1 addition & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18100,7 +18100,7 @@ namespace ts {

const baseTypeNode = getClassExtendsHeritageClauseElement(node);
if (baseTypeNode) {
if (languageVersion < ScriptTarget.ES2015) {
if (languageVersion < ScriptTarget.ES2015 && !isInAmbientContext(node)) {
checkExternalEmitHelpers(baseTypeNode.parent, ExternalEmitHelpers.Extends);
}

Expand Down
9 changes: 7 additions & 2 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6337,7 +6337,7 @@ namespace ts {
break;
case SyntaxKind.AsteriskToken:
const asterisk = scanner.getTokenText();
if (state === JSDocState.SawAsterisk) {
if (state === JSDocState.SawAsterisk || state === JSDocState.SavingComments) {
// If we've already seen an asterisk, then we can no longer parse a tag on this line
state = JSDocState.SavingComments;
pushComment(asterisk);
Expand All @@ -6358,14 +6358,19 @@ namespace ts {
case SyntaxKind.WhitespaceTrivia:
// only collect whitespace if we're already saving comments or have just crossed the comment indent margin
const whitespace = scanner.getTokenText();
if (state === JSDocState.SavingComments || margin !== undefined && indent + whitespace.length > margin) {
if (state === JSDocState.SavingComments) {
comments.push(whitespace);
}
else if (margin !== undefined && indent + whitespace.length > margin) {
comments.push(whitespace.slice(margin - indent - 1));
}
indent += whitespace.length;
break;
case SyntaxKind.EndOfFileToken:
break;
default:
// anything other than whitespace or asterisk at the beginning of the line starts the comment text
state = JSDocState.SavingComments;
pushComment(scanner.getTokenText());
break;
}
Expand Down
52 changes: 33 additions & 19 deletions src/compiler/transformers/ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1277,15 +1277,15 @@ namespace ts {
* @param node The declaration node.
* @param allDecorators An object containing all of the decorators for the declaration.
*/
function transformAllDecoratorsOfDeclaration(node: Declaration, allDecorators: AllDecorators) {
function transformAllDecoratorsOfDeclaration(node: Declaration, container: ClassLikeDeclaration, allDecorators: AllDecorators) {
if (!allDecorators) {
return undefined;
}

const decoratorExpressions: Expression[] = [];
addRange(decoratorExpressions, map(allDecorators.decorators, transformDecorator));
addRange(decoratorExpressions, flatMap(allDecorators.parameters, transformDecoratorsOfParameter));
addTypeMetadata(node, decoratorExpressions);
addTypeMetadata(node, container, decoratorExpressions);
return decoratorExpressions;
}

Expand Down Expand Up @@ -1334,7 +1334,7 @@ namespace ts {
*/
function generateClassElementDecorationExpression(node: ClassExpression | ClassDeclaration, member: ClassElement) {
const allDecorators = getAllDecoratorsOfClassElement(node, member);
const decoratorExpressions = transformAllDecoratorsOfDeclaration(member, allDecorators);
const decoratorExpressions = transformAllDecoratorsOfDeclaration(member, node, allDecorators);
if (!decoratorExpressions) {
return undefined;
}
Expand Down Expand Up @@ -1415,7 +1415,7 @@ namespace ts {
*/
function generateConstructorDecorationExpression(node: ClassExpression | ClassDeclaration) {
const allDecorators = getAllDecoratorsOfConstructor(node);
const decoratorExpressions = transformAllDecoratorsOfDeclaration(node, allDecorators);
const decoratorExpressions = transformAllDecoratorsOfDeclaration(node, node, allDecorators);
if (!decoratorExpressions) {
return undefined;
}
Expand Down Expand Up @@ -1468,37 +1468,37 @@ namespace ts {
* @param node The declaration node.
* @param decoratorExpressions The destination array to which to add new decorator expressions.
*/
function addTypeMetadata(node: Declaration, decoratorExpressions: Expression[]) {
function addTypeMetadata(node: Declaration, container: ClassLikeDeclaration, decoratorExpressions: Expression[]) {
if (USE_NEW_TYPE_METADATA_FORMAT) {
addNewTypeMetadata(node, decoratorExpressions);
addNewTypeMetadata(node, container, decoratorExpressions);
}
else {
addOldTypeMetadata(node, decoratorExpressions);
addOldTypeMetadata(node, container, decoratorExpressions);
}
}

function addOldTypeMetadata(node: Declaration, decoratorExpressions: Expression[]) {
function addOldTypeMetadata(node: Declaration, container: ClassLikeDeclaration, decoratorExpressions: Expression[]) {
if (compilerOptions.emitDecoratorMetadata) {
if (shouldAddTypeMetadata(node)) {
decoratorExpressions.push(createMetadataHelper(context, "design:type", serializeTypeOfNode(node)));
}
if (shouldAddParamTypesMetadata(node)) {
decoratorExpressions.push(createMetadataHelper(context, "design:paramtypes", serializeParameterTypesOfNode(node)));
decoratorExpressions.push(createMetadataHelper(context, "design:paramtypes", serializeParameterTypesOfNode(node, container)));
}
if (shouldAddReturnTypeMetadata(node)) {
decoratorExpressions.push(createMetadataHelper(context, "design:returntype", serializeReturnTypeOfNode(node)));
}
}
}

function addNewTypeMetadata(node: Declaration, decoratorExpressions: Expression[]) {
function addNewTypeMetadata(node: Declaration, container: ClassLikeDeclaration, decoratorExpressions: Expression[]) {
if (compilerOptions.emitDecoratorMetadata) {
let properties: ObjectLiteralElementLike[];
if (shouldAddTypeMetadata(node)) {
(properties || (properties = [])).push(createPropertyAssignment("type", createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, createToken(SyntaxKind.EqualsGreaterThanToken), serializeTypeOfNode(node))));
}
if (shouldAddParamTypesMetadata(node)) {
(properties || (properties = [])).push(createPropertyAssignment("paramTypes", createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, createToken(SyntaxKind.EqualsGreaterThanToken), serializeParameterTypesOfNode(node))));
(properties || (properties = [])).push(createPropertyAssignment("paramTypes", createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, createToken(SyntaxKind.EqualsGreaterThanToken), serializeParameterTypesOfNode(node, container))));
}
if (shouldAddReturnTypeMetadata(node)) {
(properties || (properties = [])).push(createPropertyAssignment("returnType", createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, [], /*type*/ undefined, createToken(SyntaxKind.EqualsGreaterThanToken), serializeReturnTypeOfNode(node))));
Expand Down Expand Up @@ -1543,12 +1543,16 @@ namespace ts {
* @param node The node to test.
*/
function shouldAddParamTypesMetadata(node: Declaration): boolean {
const kind = node.kind;
return kind === SyntaxKind.ClassDeclaration
|| kind === SyntaxKind.ClassExpression
|| kind === SyntaxKind.MethodDeclaration
|| kind === SyntaxKind.GetAccessor
|| kind === SyntaxKind.SetAccessor;
switch (node.kind) {
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
return getFirstConstructorWithBody(<ClassLikeDeclaration>node) !== undefined;
case SyntaxKind.MethodDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
return true;
}
return false;
}

/**
Expand Down Expand Up @@ -1596,7 +1600,7 @@ namespace ts {
*
* @param node The node that should have its parameter types serialized.
*/
function serializeParameterTypesOfNode(node: Node): Expression {
function serializeParameterTypesOfNode(node: Node, container: ClassLikeDeclaration): Expression {
const valueDeclaration =
isClassLike(node)
? getFirstConstructorWithBody(node)
Expand All @@ -1606,7 +1610,7 @@ namespace ts {

const expressions: Expression[] = [];
if (valueDeclaration) {
const parameters = valueDeclaration.parameters;
const parameters = getParametersOfDecoratedDeclaration(valueDeclaration, container);
const numParameters = parameters.length;
for (let i = 0; i < numParameters; i++) {
const parameter = parameters[i];
Expand All @@ -1625,6 +1629,16 @@ namespace ts {
return createArrayLiteral(expressions);
}

function getParametersOfDecoratedDeclaration(node: FunctionLikeDeclaration, container: ClassLikeDeclaration) {
if (container && node.kind === SyntaxKind.GetAccessor) {
const { setAccessor } = getAllAccessorDeclarations(container.members, <AccessorDeclaration>node);
if (setAccessor) {
return setAccessor.parameters;
}
}
return node.parameters;
}

/**
* Serializes the return type of a node for use with decorator type metadata.
*
Expand Down
6 changes: 1 addition & 5 deletions tests/baselines/reference/decoratedClassExportsCommonJS1.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,11 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
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;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
let Testing123 = Testing123_1 = class Testing123 {
};
Testing123.prop1 = Testing123_1.prop0;
Testing123 = Testing123_1 = __decorate([
Something({ v: () => Testing123_1 }),
__metadata("design:paramtypes", [])
Something({ v: () => Testing123_1 })
], Testing123);
exports.Testing123 = Testing123;
var Testing123_1;
6 changes: 1 addition & 5 deletions tests/baselines/reference/decoratedClassExportsCommonJS2.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
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;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
let Testing123 = Testing123_1 = class Testing123 {
};
Testing123 = Testing123_1 = __decorate([
Something({ v: () => Testing123_1 }),
__metadata("design:paramtypes", [])
Something({ v: () => Testing123_1 })
], Testing123);
exports.Testing123 = Testing123;
var Testing123_1;
6 changes: 1 addition & 5 deletions tests/baselines/reference/decoratedClassExportsSystem1.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ System.register([], function (exports_1, context_1) {
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;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __moduleName = context_1 && context_1.id;
var Testing123, Testing123_1;
return {
Expand All @@ -29,8 +26,7 @@ System.register([], function (exports_1, context_1) {
};
Testing123.prop1 = Testing123_1.prop0;
Testing123 = Testing123_1 = __decorate([
Something({ v: () => Testing123_1 }),
__metadata("design:paramtypes", [])
Something({ v: () => Testing123_1 })
], Testing123);
exports_1("Testing123", Testing123);
}
Expand Down
6 changes: 1 addition & 5 deletions tests/baselines/reference/decoratedClassExportsSystem2.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ System.register([], function (exports_1, context_1) {
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;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __moduleName = context_1 && context_1.id;
var Testing123, Testing123_1;
return {
Expand All @@ -25,8 +22,7 @@ System.register([], function (exports_1, context_1) {
Testing123 = Testing123_1 = class Testing123 {
};
Testing123 = Testing123_1 = __decorate([
Something({ v: () => Testing123_1 }),
__metadata("design:paramtypes", [])
Something({ v: () => Testing123_1 })
], Testing123);
exports_1("Testing123", Testing123);
}
Expand Down
135 changes: 135 additions & 0 deletions tests/baselines/reference/decoratorOnClassAccessor8.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
//// [decoratorOnClassAccessor8.ts]
declare function dec<T>(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<T>): TypedPropertyDescriptor<T>;

class A {
@dec get x() { return 0; }
set x(value: number) { }
}

class B {
get x() { return 0; }
@dec set x(value: number) { }
}

class C {
@dec set x(value: number) { }
get x() { return 0; }
}

class D {
set x(value: number) { }
@dec get x() { return 0; }
}

class E {
@dec get x() { return 0; }
}

class F {
@dec set x(value: number) { }
}

//// [decoratorOnClassAccessor8.js]
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
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;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var A = (function () {
function A() {
}
Object.defineProperty(A.prototype, "x", {
get: function () { return 0; },
set: function (value) { },
enumerable: true,
configurable: true
});
return A;
}());
__decorate([
dec,
__metadata("design:type", Object),
__metadata("design:paramtypes", [Number])
], A.prototype, "x", null);
var B = (function () {
function B() {
}
Object.defineProperty(B.prototype, "x", {
get: function () { return 0; },
set: function (value) { },
enumerable: true,
configurable: true
});
return B;
}());
__decorate([
dec,
__metadata("design:type", Number),
__metadata("design:paramtypes", [Number])
], B.prototype, "x", null);
var C = (function () {
function C() {
}
Object.defineProperty(C.prototype, "x", {
get: function () { return 0; },
set: function (value) { },
enumerable: true,
configurable: true
});
return C;
}());
__decorate([
dec,
__metadata("design:type", Number),
__metadata("design:paramtypes", [Number])
], C.prototype, "x", null);
var D = (function () {
function D() {
}
Object.defineProperty(D.prototype, "x", {
get: function () { return 0; },
set: function (value) { },
enumerable: true,
configurable: true
});
return D;
}());
__decorate([
dec,
__metadata("design:type", Object),
__metadata("design:paramtypes", [Number])
], D.prototype, "x", null);
var E = (function () {
function E() {
}
Object.defineProperty(E.prototype, "x", {
get: function () { return 0; },
enumerable: true,
configurable: true
});
return E;
}());
__decorate([
dec,
__metadata("design:type", Object),
__metadata("design:paramtypes", [])
], E.prototype, "x", null);
var F = (function () {
function F() {
}
Object.defineProperty(F.prototype, "x", {
set: function (value) { },
enumerable: true,
configurable: true
});
return F;
}());
__decorate([
dec,
__metadata("design:type", Number),
__metadata("design:paramtypes", [Number])
], F.prototype, "x", null);
Loading