Skip to content

Add support for combined AMD+CommonJS module export format #2605

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 23, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,12 @@ module ts {
shortName: "m",
type: {
"commonjs": ModuleKind.CommonJS,
"amd": ModuleKind.AMD
"amd": ModuleKind.AMD,
"umd": ModuleKind.UMD
},
description: Diagnostics.Specify_module_code_generation_Colon_commonjs_or_amd,
description: Diagnostics.Specify_module_code_generation_Colon_commonjs_amd_or_umd,
paramType: Diagnostics.KIND,
error: Diagnostics.Argument_for_module_option_must_be_commonjs_or_amd
error: Diagnostics.Argument_for_module_option_must_be_commonjs_amd_or_umd
},
{
name: "noEmit",
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/diagnosticInformationMap.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ module ts {
Do_not_emit_comments_to_output: { code: 6009, category: DiagnosticCategory.Message, key: "Do not emit comments to output." },
Do_not_emit_outputs: { code: 6010, category: DiagnosticCategory.Message, key: "Do not emit outputs." },
Specify_ECMAScript_target_version_Colon_ES3_default_ES5_or_ES6_experimental: { code: 6015, category: DiagnosticCategory.Message, key: "Specify ECMAScript target version: 'ES3' (default), 'ES5', or 'ES6' (experimental)" },
Specify_module_code_generation_Colon_commonjs_or_amd: { code: 6016, category: DiagnosticCategory.Message, key: "Specify module code generation: 'commonjs' or 'amd'" },
Specify_module_code_generation_Colon_commonjs_amd_or_umd: { code: 6016, category: DiagnosticCategory.Message, key: "Specify module code generation: 'commonjs', 'amd', or 'umd'" },
Print_this_message: { code: 6017, category: DiagnosticCategory.Message, key: "Print this message." },
Print_the_compiler_s_version: { code: 6019, category: DiagnosticCategory.Message, key: "Print the compiler's version." },
Compile_the_project_in_the_given_directory: { code: 6020, category: DiagnosticCategory.Message, key: "Compile the project in the given directory." },
Expand All @@ -484,7 +484,7 @@ module ts {
Generates_corresponding_map_file: { code: 6043, category: DiagnosticCategory.Message, key: "Generates corresponding '.map' file." },
Compiler_option_0_expects_an_argument: { code: 6044, category: DiagnosticCategory.Error, key: "Compiler option '{0}' expects an argument." },
Unterminated_quoted_string_in_response_file_0: { code: 6045, category: DiagnosticCategory.Error, key: "Unterminated quoted string in response file '{0}'." },
Argument_for_module_option_must_be_commonjs_or_amd: { code: 6046, category: DiagnosticCategory.Error, key: "Argument for '--module' option must be 'commonjs' or 'amd'." },
Argument_for_module_option_must_be_commonjs_amd_or_umd: { code: 6046, category: DiagnosticCategory.Error, key: "Argument for '--module' option must be 'commonjs', 'amd', or 'umd'." },
Argument_for_target_option_must_be_es3_es5_or_es6: { code: 6047, category: DiagnosticCategory.Error, key: "Argument for '--target' option must be 'es3', 'es5', or 'es6'." },
Locale_must_be_of_the_form_language_or_language_territory_For_example_0_or_1: { code: 6048, category: DiagnosticCategory.Error, key: "Locale must be of the form <language> or <language>-<territory>. For example '{0}' or '{1}'." },
Unsupported_locale_0: { code: 6049, category: DiagnosticCategory.Error, key: "Unsupported locale '{0}'." },
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1840,7 +1840,7 @@
"category": "Message",
"code": 6015
},
"Specify module code generation: 'commonjs' or 'amd'": {
"Specify module code generation: 'commonjs', 'amd', or 'umd'": {
"category": "Message",
"code": 6016
},
Expand Down Expand Up @@ -1924,7 +1924,7 @@
"category": "Error",
"code": 6045
},
"Argument for '--module' option must be 'commonjs' or 'amd'.": {
"Argument for '--module' option must be 'commonjs', 'amd', or 'umd'.": {
"category": "Error",
"code": 6046
},
Expand Down
68 changes: 50 additions & 18 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4645,27 +4645,25 @@ var __param = this.__param || function(index, decorator) { return function (targ
}
}

function emitAMDModule(node: SourceFile, startIndex: number) {
collectExternalModuleInfo(node);

function emitAMDDependencies(node: SourceFile, includeNonAmdDependencies: boolean) {
// An AMD define function has the following shape:
// define(id?, dependencies?, factory);
//
// This has the shape of
// define(name, ["module1", "module2"], function (module1Alias) {
// The location of the alias in the parameter list in the factory function needs to
// The location of the alias in the parameter list in the factory function needs to
// match the position of the module name in the dependency list.
//
// To ensure this is true in cases of modules with no aliases, e.g.:
// `import "module"` or `<amd-dependency path= "a.css" />`
// To ensure this is true in cases of modules with no aliases, e.g.:
// `import "module"` or `<amd-dependency path= "a.css" />`
// we need to add modules without alias names to the end of the dependencies list
let aliasedModuleNames: string[] = []; // names of modules with corresponding parameter in the

let aliasedModuleNames: string[] = []; // names of modules with corresponding parameter in the
// factory function.
let unaliasedModuleNames: string[] = []; // names of modules with no corresponding parameters in
// factory function.
let importAliasNames: string[] = []; // names of the parameters in the factory function; these
// paramters need to match the indexes of the corresponding
let importAliasNames: string[] = []; // names of the parameters in the factory function; these
// parameters need to match the indexes of the corresponding
// module names in aliasedModuleNames.

// Fill in amd-dependency tags
Expand All @@ -4687,7 +4685,7 @@ var __param = this.__param || function(index, decorator) { return function (targ
externalModuleName = getLiteralText(<LiteralExpression>moduleName);
}

// Find the name of the module alais, if there is one
// Find the name of the module alias, if there is one
let importAliasName: string;
let namespaceDeclaration = getNamespaceDeclarationNode(importNode);
if (namespaceDeclaration && !isDefaultImport(importNode)) {
Expand All @@ -4697,20 +4695,15 @@ var __param = this.__param || function(index, decorator) { return function (targ
importAliasName = getGeneratedNameForNode(<ImportDeclaration | ExportDeclaration>importNode);
}

if (importAliasName) {
if (includeNonAmdDependencies && importAliasName) {
aliasedModuleNames.push(externalModuleName);
importAliasNames.push(importAliasName);
}
else {
unaliasedModuleNames.push(externalModuleName);
}
}

writeLine();
write("define(");
if (node.amdModuleName) {
write("\"" + node.amdModuleName + "\", ");
}

write("[\"require\", \"exports\"");
if (aliasedModuleNames.length) {
write(", ");
Expand All @@ -4725,6 +4718,17 @@ var __param = this.__param || function(index, decorator) { return function (targ
write(", ");
write(importAliasNames.join(", "));
}
}

function emitAMDModule(node: SourceFile, startIndex: number) {
collectExternalModuleInfo(node);

writeLine();
write("define(");
if (node.amdModuleName) {
write("\"" + node.amdModuleName + "\", ");
}
emitAMDDependencies(node, /*includeNonAmdDependencies*/ true);
write(") {");
increaseIndent();
emitExportStarHelper();
Expand All @@ -4746,6 +4750,31 @@ var __param = this.__param || function(index, decorator) { return function (targ
emitExportEquals(/*emitAsReturn*/ false);
}

function emitUMDModule(node: SourceFile, startIndex: number) {
collectExternalModuleInfo(node);

// Module is detected first to support Browserify users that load into a browser with an AMD loader
writeLines(`(function (deps, factory) {
if (typeof module === 'object' && typeof module.exports === 'object') {
var v = factory(require, exports); if (v !== undefined) module.exports = v;
}
else if (typeof define === 'function' && define.amd) {
define(deps, factory);
}
})(`);
emitAMDDependencies(node, false);
write(") {");
increaseIndent();
emitExportStarHelper();
emitCaptureThisForNodeIfNecessary(node);
emitLinesStartingAt(node.statements, startIndex);
emitTempDeclarations(/*newLine*/ true);
emitExportEquals(/*emitAsReturn*/ true);
decreaseIndent();
writeLine();
write("});");
}

function emitES6Module(node: SourceFile, startIndex: number) {
externalImports = undefined;
exportSpecifiers = undefined;
Expand Down Expand Up @@ -4830,6 +4859,9 @@ var __param = this.__param || function(index, decorator) { return function (targ
else if (compilerOptions.module === ModuleKind.AMD) {
emitAMDModule(node, startIndex);
}
else if (compilerOptions.module === ModuleKind.UMD) {
emitUMDModule(node, startIndex);
}
else {
emitCommonJSModule(node, startIndex);
}
Expand Down
1 change: 1 addition & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1671,6 +1671,7 @@ module ts {
None = 0,
CommonJS = 1,
AMD = 2,
UMD = 3,
}

export interface LineAndCharacter {
Expand Down
2 changes: 2 additions & 0 deletions src/harness/harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,8 @@ module Harness {
if (typeof setting.value === 'string') {
if (setting.value.toLowerCase() === 'amd') {
options.module = ts.ModuleKind.AMD;
} else if (setting.value.toLowerCase() === 'umd') {
options.module = ts.ModuleKind.UMD;
} else if (setting.value.toLowerCase() === 'commonjs') {
options.module = ts.ModuleKind.CommonJS;
} else if (setting.value.toLowerCase() === 'unspecified') {
Expand Down
32 changes: 32 additions & 0 deletions tests/baselines/reference/es5-umd.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//// [es5-umd.ts]

class A
{
constructor ()
{

}

public B()
{
return 42;
}
}


//// [es5-umd.js]
var A = (function () {
function A() {
}
A.prototype.B = function () {
return 42;
};
return A;
})();
//# sourceMappingURL=es5-umd.js.map

//// [es5-umd.d.ts]
declare class A {
constructor();
B(): number;
}
2 changes: 2 additions & 0 deletions tests/baselines/reference/es5-umd.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

115 changes: 115 additions & 0 deletions tests/baselines/reference/es5-umd.sourcemap.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
===================================================================
JsFile: es5-umd.js
mapUrl: es5-umd.js.map
sourceRoot:
sources: es5-umd.ts
===================================================================
-------------------------------------------------------------------
emittedFile:tests/cases/compiler/es5-umd.js
sourceFile:es5-umd.ts
-------------------------------------------------------------------
>>>var A = (function () {
1 >
2 >^^^^^^^^^^^^^^^^^^^->
1 >
>
1 >Emitted(1, 1) Source(2, 1) + SourceIndex(0)
---
>>> function A() {
1->^^^^
2 > ^^->
1->class A
>{
>
1->Emitted(2, 5) Source(4, 5) + SourceIndex(0) name (A)
---
>>> }
1->^^^^
2 > ^
3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^->
1->constructor ()
> {
>
>
2 > }
1->Emitted(3, 5) Source(7, 5) + SourceIndex(0) name (A.constructor)
2 >Emitted(3, 6) Source(7, 6) + SourceIndex(0) name (A.constructor)
---
>>> A.prototype.B = function () {
1->^^^^
2 > ^^^^^^^^^^^^^
3 > ^^^
1->
>
> public
2 > B
3 >
1->Emitted(4, 5) Source(9, 12) + SourceIndex(0) name (A)
2 >Emitted(4, 18) Source(9, 13) + SourceIndex(0) name (A)
3 >Emitted(4, 21) Source(9, 5) + SourceIndex(0) name (A)
---
>>> return 42;
1 >^^^^^^^^
2 > ^^^^^^
3 > ^
4 > ^^
5 > ^
1 >public B()
> {
>
2 > return
3 >
4 > 42
5 > ;
1 >Emitted(5, 9) Source(11, 9) + SourceIndex(0) name (A.B)
2 >Emitted(5, 15) Source(11, 15) + SourceIndex(0) name (A.B)
3 >Emitted(5, 16) Source(11, 16) + SourceIndex(0) name (A.B)
4 >Emitted(5, 18) Source(11, 18) + SourceIndex(0) name (A.B)
5 >Emitted(5, 19) Source(11, 19) + SourceIndex(0) name (A.B)
---
>>> };
1 >^^^^
2 > ^
3 > ^^^^^^^^^->
1 >
>
2 > }
1 >Emitted(6, 5) Source(12, 5) + SourceIndex(0) name (A.B)
2 >Emitted(6, 6) Source(12, 6) + SourceIndex(0) name (A.B)
---
>>> return A;
1->^^^^
2 > ^^^^^^^^
1->
>
2 > }
1->Emitted(7, 5) Source(13, 1) + SourceIndex(0) name (A)
2 >Emitted(7, 13) Source(13, 2) + SourceIndex(0) name (A)
---
>>>})();
1 >
2 >^
3 >
4 > ^^^^
5 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^->
1 >
2 >}
3 >
4 > class A
> {
> constructor ()
> {
>
> }
>
> public B()
> {
> return 42;
> }
> }
1 >Emitted(8, 1) Source(13, 1) + SourceIndex(0) name (A)
2 >Emitted(8, 2) Source(13, 2) + SourceIndex(0) name (A)
3 >Emitted(8, 2) Source(2, 1) + SourceIndex(0)
4 >Emitted(8, 6) Source(13, 2) + SourceIndex(0)
---
>>>//# sourceMappingURL=es5-umd.js.map
17 changes: 17 additions & 0 deletions tests/baselines/reference/es5-umd.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
=== tests/cases/compiler/es5-umd.ts ===

class A
>A : Symbol(A, Decl(es5-umd.ts, 0, 0))
{
constructor ()
{

}

public B()
>B : Symbol(B, Decl(es5-umd.ts, 6, 5))
{
return 42;
}
}

18 changes: 18 additions & 0 deletions tests/baselines/reference/es5-umd.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
=== tests/cases/compiler/es5-umd.ts ===

class A
>A : A
{
constructor ()
{

}

public B()
>B : () => number
{
return 42;
>42 : number
}
}

Loading