Skip to content

Commit

Permalink
Fix UMD header to work with r.js
Browse files Browse the repository at this point in the history
  • Loading branch information
rbuckton committed Dec 28, 2016
1 parent 3eabf97 commit 708f9e5
Show file tree
Hide file tree
Showing 24 changed files with 298 additions and 207 deletions.
2 changes: 0 additions & 2 deletions src/compiler/emitter.ts
Expand Up @@ -670,8 +670,6 @@ namespace ts {
// Transformation nodes
case SyntaxKind.PartiallyEmittedExpression:
return emitPartiallyEmittedExpression(<PartiallyEmittedExpression>node);
case SyntaxKind.RawExpression:
return writeLines((<RawExpression>node).text);
}
}

Expand Down
13 changes: 0 additions & 13 deletions src/compiler/factory.ts
Expand Up @@ -1529,19 +1529,6 @@ namespace ts {
return node;
}

/**
* Creates a node that emits a string of raw text in an expression position. Raw text is never
* transformed, should be ES3 compliant, and should have the same precedence as
* PrimaryExpression.
*
* @param text The raw text of the node.
*/
export function createRawExpression(text: string) {
const node = <RawExpression>createNode(SyntaxKind.RawExpression);
node.text = text;
return node;
}

// Compound nodes

export function createComma(left: Expression, right: Expression) {
Expand Down
165 changes: 132 additions & 33 deletions src/compiler/transformers/module/module.ts
Expand Up @@ -102,28 +102,7 @@ namespace ts {
function transformAMDModule(node: SourceFile) {
const define = createIdentifier("define");
const moduleName = tryGetModuleNameFromFile(node, host, compilerOptions);
return transformAsynchronousModule(node, define, moduleName, /*includeNonAmdDependencies*/ true);
}

/**
* Transforms a SourceFile into a UMD module.
*
* @param node The SourceFile node.
*/
function transformUMDModule(node: SourceFile) {
const define = createRawExpression(umdHelper);
return transformAsynchronousModule(node, define, /*moduleName*/ undefined, /*includeNonAmdDependencies*/ false);
}

/**
* Transforms a SourceFile into an AMD or UMD module.
*
* @param node The SourceFile node.
* @param define The expression used to define the module.
* @param moduleName An expression for the module name, if available.
* @param includeNonAmdDependencies A value indicating whether to incldue any non-AMD dependencies.
*/
function transformAsynchronousModule(node: SourceFile, define: Expression, moduleName: Expression, includeNonAmdDependencies: boolean) {
// An AMD define function has the following shape:
//
// define(id?, dependencies?, factory);
Expand All @@ -145,7 +124,7 @@ namespace ts {
//
// we need to add modules without alias names to the end of the dependencies list

const { aliasedModuleNames, unaliasedModuleNames, importAliasNames } = collectAsynchronousDependencies(node, includeNonAmdDependencies);
const { aliasedModuleNames, unaliasedModuleNames, importAliasNames } = collectAsynchronousDependencies(node, /*includeNonAmdDependencies*/ true);

// Create an updated SourceFile:
//
Expand Down Expand Up @@ -194,6 +173,137 @@ namespace ts {
);
}

/**
* Transforms a SourceFile into a UMD module.
*
* @param node The SourceFile node.
*/
function transformUMDModule(node: SourceFile) {
const { aliasedModuleNames, unaliasedModuleNames, importAliasNames } = collectAsynchronousDependencies(node, /*includeNonAmdDependencies*/ false);
const umdHeader = createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
/*name*/ undefined,
/*typeParameters*/ undefined,
[createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "factory")],
/*type*/ undefined,
createBlock(
[
createIf(
createLogicalAnd(
createTypeCheck(createIdentifier("module"), "object"),
createTypeCheck(createPropertyAccess(createIdentifier("module"), "exports"), "object")
),
createBlock([
createVariableStatement(
/*modifiers*/ undefined,
[
createVariableDeclaration(
"v",
/*type*/ undefined,
createCall(
createIdentifier("factory"),
/*typeArguments*/ undefined,
[
createIdentifier("require"),
createIdentifier("exports")
]
)
)
]
),
setEmitFlags(
createIf(
createStrictInequality(
createIdentifier("v"),
createIdentifier("undefined")
),
createStatement(
createAssignment(
createPropertyAccess(createIdentifier("module"), "exports"),
createIdentifier("v")
)
)
),
EmitFlags.SingleLine
)
]),
createIf(
createLogicalAnd(
createTypeCheck(createIdentifier("define"), "function"),
createPropertyAccess(createIdentifier("define"), "amd")
),
createBlock([
createStatement(
createCall(
createIdentifier("define"),
/*typeArguments*/ undefined,
[
createArrayLiteral([
createLiteral("require"),
createLiteral("exports"),
...aliasedModuleNames,
...unaliasedModuleNames
]),
createIdentifier("factory")
]
)
)
])
)
)
],
/*location*/ undefined,
/*multiLine*/ true
)
);

// Create an updated SourceFile:
//
// (function (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(["require", "exports"], factory);
// }
// })(function ...)

return updateSourceFileNode(
node,
createNodeArray(
[
createStatement(
createCall(
umdHeader,
/*typeArguments*/ undefined,
[
// Add the module body function argument:
//
// function (require, exports) ...
createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
/*name*/ undefined,
/*typeParameters*/ undefined,
[
createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "require"),
createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "exports"),
...importAliasNames
],
/*type*/ undefined,
transformAsynchronousModuleBody(node)
)
]
)
)
],
/*location*/ node.statements
)
);
}

/**
* Collect the additional asynchronous dependencies for the module.
*
Expand Down Expand Up @@ -1333,15 +1443,4 @@ namespace ts {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}`
};

// emit output for the UMD helper function.
const umdHelper = `
(function (dependencies, 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(dependencies, factory);
}
})`;
}
11 changes: 0 additions & 11 deletions src/compiler/types.ts
Expand Up @@ -370,7 +370,6 @@ namespace ts {
PartiallyEmittedExpression,
MergeDeclarationMarker,
EndOfDeclarationMarker,
RawExpression,

// Enum value count
Count,
Expand Down Expand Up @@ -1520,16 +1519,6 @@ namespace ts {
kind: SyntaxKind.EndOfDeclarationMarker;
}

/**
* Emits a string of raw text in an expression position. Raw text is never transformed, should
* be ES3 compliant, and should have the same precedence as PrimaryExpression.
*/
/* @internal */
export interface RawExpression extends PrimaryExpression {
kind: SyntaxKind.RawExpression;
text: string;
}

/**
* Marks the beginning of a merged transformed declaration.
*/
Expand Down
15 changes: 5 additions & 10 deletions src/compiler/utilities.ts
Expand Up @@ -2118,7 +2118,6 @@ namespace ts {
case SyntaxKind.TemplateExpression:
case SyntaxKind.ParenthesizedExpression:
case SyntaxKind.OmittedExpression:
case SyntaxKind.RawExpression:
return 19;

case SyntaxKind.TaggedTemplateExpression:
Expand Down Expand Up @@ -2342,13 +2341,11 @@ namespace ts {
* Note that this doesn't actually wrap the input in double quotes.
*/
export function escapeString(s: string): string {
s = escapedCharsRegExp.test(s) ? s.replace(escapedCharsRegExp, getReplacement) : s;

return s;
return s.replace(escapedCharsRegExp, getReplacement);
}

function getReplacement(c: string) {
return escapedCharsMap[c] || get16BitUnicodeEscapeSequence(c.charCodeAt(0));
}
function getReplacement(c: string) {
return escapedCharsMap[c] || get16BitUnicodeEscapeSequence(c.charCodeAt(0));
}

export function isIntrinsicJsxName(name: string) {
Expand Down Expand Up @@ -3865,8 +3862,7 @@ namespace ts {
|| kind === SyntaxKind.ThisKeyword
|| kind === SyntaxKind.TrueKeyword
|| kind === SyntaxKind.SuperKeyword
|| kind === SyntaxKind.NonNullExpression
|| kind === SyntaxKind.RawExpression;
|| kind === SyntaxKind.NonNullExpression;
}

export function isLeftHandSideExpression(node: Node): node is LeftHandSideExpression {
Expand Down Expand Up @@ -3896,7 +3892,6 @@ namespace ts {
|| kind === SyntaxKind.SpreadElement
|| kind === SyntaxKind.AsExpression
|| kind === SyntaxKind.OmittedExpression
|| kind === SyntaxKind.RawExpression
|| isUnaryExpressionKind(kind);
}

Expand Down
26 changes: 14 additions & 12 deletions tests/baselines/reference/anonymousDefaultExportsUmd.js
Expand Up @@ -7,29 +7,31 @@ export default class {}
export default function() {}

//// [a.js]
(function (dependencies, factory) {
if (typeof module === 'object' && typeof module.exports === 'object') {
var v = factory(require, exports); if (v !== undefined) module.exports = v;
(function (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(dependencies, factory);
else if (typeof define === "function" && define.amd) {
define(["require", "exports"], factory);
}
})(["require", "exports"], function (require, exports) {
})(function (require, exports) {
"use strict";
class default_1 {
}
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = default_1;
});
//// [b.js]
(function (dependencies, factory) {
if (typeof module === 'object' && typeof module.exports === 'object') {
var v = factory(require, exports); if (v !== undefined) module.exports = v;
(function (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(dependencies, factory);
else if (typeof define === "function" && define.amd) {
define(["require", "exports"], factory);
}
})(["require", "exports"], function (require, exports) {
})(function (require, exports) {
"use strict";
function default_1() { }
Object.defineProperty(exports, "__esModule", { value: true });
Expand Down
26 changes: 14 additions & 12 deletions tests/baselines/reference/decoratedDefaultExportsGetExportedUmd.js
Expand Up @@ -20,14 +20,15 @@ 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;
};
(function (dependencies, factory) {
if (typeof module === 'object' && typeof module.exports === 'object') {
var v = factory(require, exports); if (v !== undefined) module.exports = v;
(function (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(dependencies, factory);
else if (typeof define === "function" && define.amd) {
define(["require", "exports"], factory);
}
})(["require", "exports"], function (require, exports) {
})(function (require, exports) {
"use strict";
var decorator;
let Foo = class Foo {
Expand All @@ -45,14 +46,15 @@ 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;
};
(function (dependencies, factory) {
if (typeof module === 'object' && typeof module.exports === 'object') {
var v = factory(require, exports); if (v !== undefined) module.exports = v;
(function (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(dependencies, factory);
else if (typeof define === "function" && define.amd) {
define(["require", "exports"], factory);
}
})(["require", "exports"], function (require, exports) {
})(function (require, exports) {
"use strict";
var decorator;
let default_1 = class {
Expand Down

0 comments on commit 708f9e5

Please sign in to comment.