From 76100489975b12673c23d1fa040c31e734010e11 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Thu, 10 Sep 2015 16:27:35 -0700 Subject: [PATCH] Allow decorators in ES3 --- src/compiler/checker.ts | 9 ++- .../diagnosticInformationMap.generated.ts | 1 - src/compiler/diagnosticMessages.json | 4 -- src/compiler/emitter.ts | 69 +++++++------------ 4 files changed, 32 insertions(+), 51 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index df432808f3..67c02b0943 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8322,6 +8322,12 @@ namespace ts { case SyntaxKind.SetAccessor: // A method or accessor declaration decorator will have two or three arguments (see // `PropertyDecorator` and `MethodDecorator` in core.d.ts) + + // If we are emitting decorators for ES3, we will only pass two arguments. + if (languageVersion === ScriptTarget.ES3) { + return 2; + } + // If the method decorator signature only accepts a target and a key, we will only // type check those arguments. return signature.parameters.length >= 3 ? 3 : 2; @@ -14627,9 +14633,6 @@ namespace ts { if (!nodeCanBeDecorated(node)) { return grammarErrorOnFirstToken(node, Diagnostics.Decorators_are_not_valid_here); } - else if (languageVersion < ScriptTarget.ES5) { - return grammarErrorOnFirstToken(node, Diagnostics.Decorators_are_only_available_when_targeting_ECMAScript_5_and_higher); - } else if (node.kind === SyntaxKind.GetAccessor || node.kind === SyntaxKind.SetAccessor) { let accessors = getAllAccessorDeclarations((node.parent).members, node); if (accessors.firstAccessor.decorators && node === accessors.secondAccessor) { diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index af48e67d96..c6be478d57 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -161,7 +161,6 @@ namespace ts { Import_assignment_cannot_be_used_when_targeting_ECMAScript_6_or_higher_Consider_using_import_Asterisk_as_ns_from_mod_import_a_from_mod_or_import_d_from_mod_instead: { code: 1202, category: DiagnosticCategory.Error, key: "Import assignment cannot be used when targeting ECMAScript 6 or higher. Consider using 'import * as ns from \"mod\"', 'import {a} from \"mod\"' or 'import d from \"mod\"' instead." }, Export_assignment_cannot_be_used_when_targeting_ECMAScript_6_or_higher_Consider_using_export_default_instead: { code: 1203, category: DiagnosticCategory.Error, key: "Export assignment cannot be used when targeting ECMAScript 6 or higher. Consider using 'export default' instead." }, Cannot_compile_modules_into_commonjs_amd_system_or_umd_when_targeting_ES6_or_higher: { code: 1204, category: DiagnosticCategory.Error, key: "Cannot compile modules into 'commonjs', 'amd', 'system' or 'umd' when targeting 'ES6' or higher." }, - Decorators_are_only_available_when_targeting_ECMAScript_5_and_higher: { code: 1205, category: DiagnosticCategory.Error, key: "Decorators are only available when targeting ECMAScript 5 and higher." }, Decorators_are_not_valid_here: { code: 1206, category: DiagnosticCategory.Error, key: "Decorators are not valid here." }, Decorators_cannot_be_applied_to_multiple_get_Slashset_accessors_of_the_same_name: { code: 1207, category: DiagnosticCategory.Error, key: "Decorators cannot be applied to multiple get/set accessors of the same name." }, Cannot_compile_namespaces_when_the_isolatedModules_flag_is_provided: { code: 1208, category: DiagnosticCategory.Error, key: "Cannot compile namespaces when the '--isolatedModules' flag is provided." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 7abec7b7c4..24508a4fe5 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -631,10 +631,6 @@ "category": "Error", "code": 1204 }, - "Decorators are only available when targeting ECMAScript 5 and higher.": { - "category": "Error", - "code": 1205 - }, "Decorators are not valid here.": { "category": "Error", "code": 1206 diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index c2e09f133d..5ff5973a2f 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -27,12 +27,10 @@ var __extends = (this && this.__extends) || function (d, b) { // emit output for the __decorate helper function const decorateHelper = ` var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc); - switch (arguments.length) { - case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target); - case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0); - case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, 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; };`; // emit output for the __metadata helper function @@ -1382,7 +1380,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // // The emit for the decorated computed property decorator is: // - // Object.defineProperty(C.prototype, _a, __decorate([dec], C.prototype, _a, Object.getOwnPropertyDescriptor(C.prototype, _a))); + // __decorate([dec], C.prototype, _a, Object.getOwnPropertyDescriptor(C.prototype, _a)); // if (nodeIsDecorated(node.parent)) { if (!computedPropertyNamesToGeneratedNames) { @@ -4410,7 +4408,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // // let C = class { // }; - // Object.defineProperty(C, "name", { value: "C", configurable: true }); // C = __decorate([dec], C); // // * For an exported class declaration: @@ -4422,7 +4419,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // // export let C = class { // }; - // Object.defineProperty(C, "name", { value: "C", configurable: true }); // C = __decorate([dec], C); // // * For a default export of a class declaration with a name: @@ -4434,7 +4430,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // // let C = class { // } - // Object.defineProperty(C, "name", { value: "C", configurable: true }); // C = __decorate([dec], C); // export default C; // @@ -4760,21 +4755,19 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi // // The emit for a method is: // - // Object.defineProperty(C.prototype, "method", - // __decorate([ - // dec, - // __param(0, dec2), - // __metadata("design:type", Function), - // __metadata("design:paramtypes", [Object]), - // __metadata("design:returntype", void 0) - // ], C.prototype, "method", Object.getOwnPropertyDescriptor(C.prototype, "method"))); + // __decorate([ + // dec, + // __param(0, dec2), + // __metadata("design:type", Function), + // __metadata("design:paramtypes", [Object]), + // __metadata("design:returntype", void 0) + // ], C.prototype, "method", undefined); // // The emit for an accessor is: // - // Object.defineProperty(C.prototype, "accessor", - // __decorate([ - // dec - // ], C.prototype, "accessor", Object.getOwnPropertyDescriptor(C.prototype, "accessor"))); + // __decorate([ + // dec + // ], C.prototype, "accessor", undefined); // // The emit for a property is: // @@ -4785,18 +4778,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi writeLine(); emitStart(member); - if (member.kind !== SyntaxKind.PropertyDeclaration) { - write("Object.defineProperty("); - emitStart(member.name); - emitClassMemberPrefix(node, member); - write(", "); - emitExpressionForPropertyName(member.name); - emitEnd(member.name); - write(","); - increaseIndent(); - writeLine(); - } - write("__decorate(["); increaseIndent(); writeLine(); @@ -4820,15 +4801,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi emitExpressionForPropertyName(member.name); emitEnd(member.name); - if (member.kind !== SyntaxKind.PropertyDeclaration) { - write(", Object.getOwnPropertyDescriptor("); - emitStart(member.name); - emitClassMemberPrefix(node, member); - write(", "); - emitExpressionForPropertyName(member.name); - emitEnd(member.name); - write("))"); - decreaseIndent(); + if (languageVersion > ScriptTarget.ES3) { + if (member.kind !== SyntaxKind.PropertyDeclaration) { + // We emit `null` here to indicate to `__decorate` that it can invoke `Object.getOwnPropertyDescriptor` directly. + // We have this extra argument here so that we can inject an explicit property descriptor at a later date. + write(", null"); + } + else { + // We emit `void 0` here to indicate to `__decorate` that it can invoke `Object.defineProperty` directly, but that it + // should not invoke `Object.getOwnPropertyDescriptor`. + write(", void 0"); + } } write(");");