From 76fa4b838f7eacbd4e1a1d85b2ad739e40d4d1c9 Mon Sep 17 00:00:00 2001 From: James Whitney Date: Fri, 24 Apr 2015 12:16:11 +1000 Subject: [PATCH 1/3] Add support for --noEmitHelpers flag This PR is a Work In Progress that addresses multiple `__extends` being output as described in #1350: Multiple `__extends` being output when `--module amd` is set. The issue still exists as of `v1.5.0 - f53e6a8`. Apparently a fix was created for this in #1356 but according to #2009, a [comment](https://github.com/Microsoft/TypeScript/issues/2009#issuecomment-74136291) later indicated that this was never merged in. Further conversation continued in #2487 but did not yield any result. I refer to my earlier recommendation in #1350. > My question is this, would the TypeScript team be open to a flag that > can be passed to tsc that will generate something like the following > ```ts > define(["require", "exports", "__extends", './mammal'], function (require, exports, __extends, Mammal) { > var Human = (function (_super) { > __extends(Human, _super); > function Human() { > _super.apply(this, arguments); > } > return Human; > })(Mammal); > return Human; > }); > ``` To continue with the naming convention I have chosen the flag `--noEmitHelpers`. --- bin/typescript.d.ts | 1 + bin/typescriptServices.d.ts | 1 + src/compiler/commandLineParser.ts | 4 ++ src/compiler/emitter.ts | 42 ++++++++++++------- src/compiler/types.ts | 1 + src/harness/harness.ts | 6 ++- tests/baselines/reference/noEmitHelpers.js | 19 +++++++++ .../baselines/reference/noEmitHelpers.symbols | 9 ++++ tests/baselines/reference/noEmitHelpers.types | 9 ++++ tests/cases/compiler/noEmitHelpers.ts | 4 ++ 10 files changed, 80 insertions(+), 16 deletions(-) create mode 100644 tests/baselines/reference/noEmitHelpers.js create mode 100644 tests/baselines/reference/noEmitHelpers.symbols create mode 100644 tests/baselines/reference/noEmitHelpers.types create mode 100644 tests/cases/compiler/noEmitHelpers.ts diff --git a/bin/typescript.d.ts b/bin/typescript.d.ts index 00ddd43317..1abc8f57c4 100644 --- a/bin/typescript.d.ts +++ b/bin/typescript.d.ts @@ -1087,6 +1087,7 @@ declare module "typescript" { mapRoot?: string; module?: ModuleKind; noEmit?: boolean; + noEmitHelpers?: boolean; noEmitOnError?: boolean; noErrorTruncation?: boolean; noImplicitAny?: boolean; diff --git a/bin/typescriptServices.d.ts b/bin/typescriptServices.d.ts index d946fdcfe3..c07c5c4a6c 100644 --- a/bin/typescriptServices.d.ts +++ b/bin/typescriptServices.d.ts @@ -1087,6 +1087,7 @@ declare module ts { mapRoot?: string; module?: ModuleKind; noEmit?: boolean; + noEmitHelpers?: boolean; noEmitOnError?: boolean; noErrorTruncation?: boolean; noImplicitAny?: boolean; diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 15a67db77e..da31878403 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -71,6 +71,10 @@ module ts { type: "boolean", description: Diagnostics.Do_not_emit_outputs, }, + { + name: "noEmitHelpers", + type: "boolean" + }, { name: "noEmitOnError", type: "boolean", diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 7ebdb3026c..dff0a2ba39 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -5487,6 +5487,9 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { } write("[\"require\", \"exports\""); + if (compilerOptions.noEmitHelpers) { + write(", \"__extends\""); + } if (aliasedModuleNames.length) { write(", "); write(aliasedModuleNames.join(", ")); @@ -5496,6 +5499,9 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { write(unaliasedModuleNames.join(", ")); } write("], function (require, exports"); + if (compilerOptions.noEmitHelpers) { + write(", __extends"); + } if (importAliasNames.length) { write(", "); write(importAliasNames.join(", ")); @@ -5614,24 +5620,30 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { // emit prologue directives prior to __extends var startIndex = emitDirectivePrologues(node.statements, /*startWithNewLine*/ false); - // Only Emit __extends function when target ES5. - // For target ES6 and above, we can emit classDeclaration as is. - if ((languageVersion < ScriptTarget.ES6) && (!extendsEmitted && resolver.getNodeCheckFlags(node) & NodeCheckFlags.EmitExtends)) { - writeLines(extendsHelper); - extendsEmitted = true; - } - if (!decorateEmitted && resolver.getNodeCheckFlags(node) & NodeCheckFlags.EmitDecorate) { - writeLines(decorateHelper); - if (compilerOptions.emitDecoratorMetadata) { - writeLines(metadataHelper); + // Only emit helpers if the user did not say otherwise. + if (!compilerOptions.noEmitHelpers) { + + // Only Emit __extends function when target ES5. + // For target ES6 and above, we can emit classDeclaration as is. + if ((languageVersion < ScriptTarget.ES6) && (!extendsEmitted && resolver.getNodeCheckFlags(node) & NodeCheckFlags.EmitExtends)) { + writeLines(extendsHelper); + extendsEmitted = true; + } + + if (!decorateEmitted && resolver.getNodeCheckFlags(node) & NodeCheckFlags.EmitDecorate) { + writeLines(decorateHelper); + if (compilerOptions.emitDecoratorMetadata) { + writeLines(metadataHelper); + } + decorateEmitted = true; + } + + if (!paramEmitted && resolver.getNodeCheckFlags(node) & NodeCheckFlags.EmitParam) { + writeLines(paramHelper); + paramEmitted = true; } - decorateEmitted = true; - } - if (!paramEmitted && resolver.getNodeCheckFlags(node) & NodeCheckFlags.EmitParam) { - writeLines(paramHelper); - paramEmitted = true; } if (isExternalModule(node) || compilerOptions.separateCompilation) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 4799f31406..9e7e6ac732 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1657,6 +1657,7 @@ module ts { mapRoot?: string; module?: ModuleKind; noEmit?: boolean; + noEmitHelpers?: boolean; noEmitOnError?: boolean; noErrorTruncation?: boolean; noImplicitAny?: boolean; diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 6af77e3d74..4a26cfdfe2 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -990,6 +990,10 @@ module Harness { } break; + case 'noemithelpers': + options.noEmitHelpers = !!setting.value; + break; + case 'noemitonerror': options.noEmitOnError = !!setting.value; break; @@ -1477,7 +1481,7 @@ module Harness { // List of allowed metadata names var fileMetadataNames = ["filename", "comments", "declaration", "module", - "nolib", "sourcemap", "target", "out", "outdir", "noemitonerror", + "nolib", "sourcemap", "target", "out", "outdir", "noemithelpers", "noemitonerror", "noimplicitany", "noresolve", "newline", "newlines", "emitbom", "errortruncation", "usecasesensitivefilenames", "preserveconstenums", "includebuiltfile", "suppressimplicitanyindexerrors", "stripinternal", diff --git a/tests/baselines/reference/noEmitHelpers.js b/tests/baselines/reference/noEmitHelpers.js new file mode 100644 index 0000000000..8db5cd862b --- /dev/null +++ b/tests/baselines/reference/noEmitHelpers.js @@ -0,0 +1,19 @@ +//// [noEmitHelpers.ts] + +class A { } +class B extends A { } + + +//// [noEmitHelpers.js] +var A = (function () { + function A() { + } + return A; +})(); +var B = (function (_super) { + __extends(B, _super); + function B() { + _super.apply(this, arguments); + } + return B; +})(A); diff --git a/tests/baselines/reference/noEmitHelpers.symbols b/tests/baselines/reference/noEmitHelpers.symbols new file mode 100644 index 0000000000..efd281c812 --- /dev/null +++ b/tests/baselines/reference/noEmitHelpers.symbols @@ -0,0 +1,9 @@ +=== tests/cases/compiler/noEmitHelpers.ts === + +class A { } +>A : Symbol(A, Decl(noEmitHelpers.ts, 0, 0)) + +class B extends A { } +>B : Symbol(B, Decl(noEmitHelpers.ts, 1, 11)) +>A : Symbol(A, Decl(noEmitHelpers.ts, 0, 0)) + diff --git a/tests/baselines/reference/noEmitHelpers.types b/tests/baselines/reference/noEmitHelpers.types new file mode 100644 index 0000000000..d25bd88255 --- /dev/null +++ b/tests/baselines/reference/noEmitHelpers.types @@ -0,0 +1,9 @@ +=== tests/cases/compiler/noEmitHelpers.ts === + +class A { } +>A : A + +class B extends A { } +>B : B +>A : A + diff --git a/tests/cases/compiler/noEmitHelpers.ts b/tests/cases/compiler/noEmitHelpers.ts new file mode 100644 index 0000000000..cb37c0db96 --- /dev/null +++ b/tests/cases/compiler/noEmitHelpers.ts @@ -0,0 +1,4 @@ +// @noemithelpers: true + +class A { } +class B extends A { } From 101aedbf4e97a2c5dff2c38df70eeed2ddc006f8 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Fri, 1 May 2015 16:29:41 -0700 Subject: [PATCH 2/3] Do not emit __extends if --noEmitHelpers is set --- src/compiler/emitter.ts | 8 -------- tests/baselines/reference/noEmitHelpers2.js | 17 +++++++++++++++++ tests/cases/compiler/noEmitHelpers2.ts | 10 ++++++++++ 3 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 tests/baselines/reference/noEmitHelpers2.js create mode 100644 tests/cases/compiler/noEmitHelpers2.ts diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index dff0a2ba39..a5f3987eae 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -5487,9 +5487,6 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { } write("[\"require\", \"exports\""); - if (compilerOptions.noEmitHelpers) { - write(", \"__extends\""); - } if (aliasedModuleNames.length) { write(", "); write(aliasedModuleNames.join(", ")); @@ -5499,9 +5496,6 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { write(unaliasedModuleNames.join(", ")); } write("], function (require, exports"); - if (compilerOptions.noEmitHelpers) { - write(", __extends"); - } if (importAliasNames.length) { write(", "); write(importAliasNames.join(", ")); @@ -5623,7 +5617,6 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { // Only emit helpers if the user did not say otherwise. if (!compilerOptions.noEmitHelpers) { - // Only Emit __extends function when target ES5. // For target ES6 and above, we can emit classDeclaration as is. if ((languageVersion < ScriptTarget.ES6) && (!extendsEmitted && resolver.getNodeCheckFlags(node) & NodeCheckFlags.EmitExtends)) { @@ -5643,7 +5636,6 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { writeLines(paramHelper); paramEmitted = true; } - } if (isExternalModule(node) || compilerOptions.separateCompilation) { diff --git a/tests/baselines/reference/noEmitHelpers2.js b/tests/baselines/reference/noEmitHelpers2.js new file mode 100644 index 0000000000..6ee07cd625 --- /dev/null +++ b/tests/baselines/reference/noEmitHelpers2.js @@ -0,0 +1,17 @@ +//// [noEmitHelpers2.ts] + +function decorator() { } + +@decorator +class A { } + +//// [noEmitHelpers2.js] +function decorator() { } +var A = (function () { + function A() { + } + A = __decorate([ + decorator + ], A); + return A; +})(); diff --git a/tests/cases/compiler/noEmitHelpers2.ts b/tests/cases/compiler/noEmitHelpers2.ts new file mode 100644 index 0000000000..676b742c23 --- /dev/null +++ b/tests/cases/compiler/noEmitHelpers2.ts @@ -0,0 +1,10 @@ +// @noemithelpers: true +// @target: es5 + +function decorator() { } + +@decorator +class A { + constructor(a: number, b: string) { + } +} \ No newline at end of file From 3c99527e6e587a3546183082ddb97626f7089560 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Fri, 1 May 2015 16:30:30 -0700 Subject: [PATCH 3/3] Add tests for __metadata and __param --- src/harness/harness.ts | 8 ++++++-- tests/baselines/reference/noEmitHelpers2.js | 11 ++++++++--- .../baselines/reference/noEmitHelpers2.symbols | 17 +++++++++++++++++ tests/baselines/reference/noEmitHelpers2.types | 17 +++++++++++++++++ tests/cases/compiler/noEmitHelpers2.ts | 3 ++- 5 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 tests/baselines/reference/noEmitHelpers2.symbols create mode 100644 tests/baselines/reference/noEmitHelpers2.types diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 4a26cfdfe2..30ae22a9e4 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -990,8 +990,12 @@ module Harness { } break; + case 'emitdecoratormetadata': + options.emitDecoratorMetadata = setting.value === 'true'; + break; + case 'noemithelpers': - options.noEmitHelpers = !!setting.value; + options.noEmitHelpers = setting.value === 'true'; break; case 'noemitonerror': @@ -1486,7 +1490,7 @@ module Harness { "errortruncation", "usecasesensitivefilenames", "preserveconstenums", "includebuiltfile", "suppressimplicitanyindexerrors", "stripinternal", "separatecompilation", "inlinesourcemap", "maproot", "sourceroot", - "inlinesources"]; + "inlinesources", "emitdecoratormetadata"]; function extractCompilerSettings(content: string): CompilerSetting[] { diff --git a/tests/baselines/reference/noEmitHelpers2.js b/tests/baselines/reference/noEmitHelpers2.js index 6ee07cd625..1bd4237767 100644 --- a/tests/baselines/reference/noEmitHelpers2.js +++ b/tests/baselines/reference/noEmitHelpers2.js @@ -3,15 +3,20 @@ function decorator() { } @decorator -class A { } +class A { + constructor(a: number, @decorator b: string) { + } +} //// [noEmitHelpers2.js] function decorator() { } var A = (function () { - function A() { + function A(a, b) { } A = __decorate([ - decorator + decorator, + __param(1, decorator), + __metadata('design:paramtypes', [Number, String]) ], A); return A; })(); diff --git a/tests/baselines/reference/noEmitHelpers2.symbols b/tests/baselines/reference/noEmitHelpers2.symbols new file mode 100644 index 0000000000..3a3e3ec94c --- /dev/null +++ b/tests/baselines/reference/noEmitHelpers2.symbols @@ -0,0 +1,17 @@ +=== tests/cases/compiler/noEmitHelpers2.ts === + +function decorator() { } +>decorator : Symbol(decorator, Decl(noEmitHelpers2.ts, 0, 0)) + +@decorator +>decorator : Symbol(decorator, Decl(noEmitHelpers2.ts, 0, 0)) + +class A { +>A : Symbol(A, Decl(noEmitHelpers2.ts, 1, 24)) + + constructor(a: number, @decorator b: string) { +>a : Symbol(a, Decl(noEmitHelpers2.ts, 5, 16)) +>decorator : Symbol(decorator, Decl(noEmitHelpers2.ts, 0, 0)) +>b : Symbol(b, Decl(noEmitHelpers2.ts, 5, 26)) + } +} diff --git a/tests/baselines/reference/noEmitHelpers2.types b/tests/baselines/reference/noEmitHelpers2.types new file mode 100644 index 0000000000..2a5b5413a7 --- /dev/null +++ b/tests/baselines/reference/noEmitHelpers2.types @@ -0,0 +1,17 @@ +=== tests/cases/compiler/noEmitHelpers2.ts === + +function decorator() { } +>decorator : () => void + +@decorator +>decorator : () => void + +class A { +>A : A + + constructor(a: number, @decorator b: string) { +>a : number +>decorator : () => void +>b : string + } +} diff --git a/tests/cases/compiler/noEmitHelpers2.ts b/tests/cases/compiler/noEmitHelpers2.ts index 676b742c23..df71f4fae8 100644 --- a/tests/cases/compiler/noEmitHelpers2.ts +++ b/tests/cases/compiler/noEmitHelpers2.ts @@ -1,10 +1,11 @@ // @noemithelpers: true +// @emitdecoratormetadata: true // @target: es5 function decorator() { } @decorator class A { - constructor(a: number, b: string) { + constructor(a: number, @decorator b: string) { } } \ No newline at end of file