From 76fa4b838f7eacbd4e1a1d85b2ad739e40d4d1c9 Mon Sep 17 00:00:00 2001 From: James Whitney Date: Fri, 24 Apr 2015 12:16:11 +1000 Subject: [PATCH] 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 00ddd43317910..1abc8f57c44d1 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 d946fdcfe3036..c07c5c4a6cc49 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 15a67db77e037..da31878403a1c 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 7ebdb3026ce67..dff0a2ba391dc 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 4799f31406369..9e7e6ac732804 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 6af77e3d74600..4a26cfdfe2b5d 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 0000000000000..8db5cd862bf5d --- /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 0000000000000..efd281c812bff --- /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 0000000000000..d25bd88255c42 --- /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 0000000000000..cb37c0db961cf --- /dev/null +++ b/tests/cases/compiler/noEmitHelpers.ts @@ -0,0 +1,4 @@ +// @noemithelpers: true + +class A { } +class B extends A { }