Compare commits

...

1 commit

Author SHA1 Message Date
Ron Buckton abfcdc268c Prototype implementation of umdExport/umdGlobal 2020-08-11 19:10:20 -07:00
14 changed files with 401 additions and 60 deletions

View file

@ -8,6 +8,7 @@ interface DiagnosticDetails {
reportsDeprecated?: {};
isEarly?: boolean;
elidedInCompatabilityPyramid?: boolean;
retired?: boolean; // indicates the code has been retired and is present only to prevent reuse
}
type InputDiagnosticMessageTable = Map<string, DiagnosticDetails>;
@ -34,6 +35,7 @@ function main(): void {
const diagnosticMessages: InputDiagnosticMessageTable = new Map();
for (const key in diagnosticMessagesJson) {
if (Object.hasOwnProperty.call(diagnosticMessagesJson, key)) {
if (diagnosticMessagesJson[key].retired) continue;
diagnosticMessages.set(key, diagnosticMessagesJson[key]);
}
}

View file

@ -323,6 +323,7 @@ namespace ts {
const compilerOptions = host.getCompilerOptions();
const languageVersion = getEmitScriptTarget(compilerOptions);
const moduleKind = getEmitModuleKind(compilerOptions);
const umdExport = getSingleFileUmdExport(compilerOptions);
const allowSyntheticDefaultImports = getAllowSyntheticDefaultImports(compilerOptions);
const strictNullChecks = getStrictOptionValue(compilerOptions, "strictNullChecks");
const strictFunctionTypes = getStrictOptionValue(compilerOptions, "strictFunctionTypes");
@ -924,6 +925,7 @@ namespace ts {
const diagnostics = createDiagnosticCollection();
const suggestionDiagnostics = createDiagnosticCollection();
let hasReportedUmdExportDiagnostic = false;
const typeofTypesByName: ReadonlyESMap<string, Type> = new Map(getEntries({
string: stringType,
@ -965,7 +967,7 @@ namespace ts {
if (jsxFragmentPragma) {
const chosenPragma = isArray(jsxFragmentPragma) ? jsxFragmentPragma[0] : jsxFragmentPragma;
file.localJsxFragmentFactory = parseIsolatedEntityName(chosenPragma.arguments.factory, languageVersion);
visitNode(file.localJsxFragmentFactory, markAsSynthetic);
markAsSynthetic(file.localJsxFragmentFactory);
if (file.localJsxFragmentFactory) {
return file.localJsxFragmentNamespace = getFirstIdentifier(file.localJsxFragmentFactory).escapedText;
}
@ -984,7 +986,7 @@ namespace ts {
if (jsxPragma) {
const chosenPragma = isArray(jsxPragma) ? jsxPragma[0] : jsxPragma;
file.localJsxFactory = parseIsolatedEntityName(chosenPragma.arguments.factory, languageVersion);
visitNode(file.localJsxFactory, markAsSynthetic);
markAsSynthetic(file.localJsxFactory);
if (file.localJsxFactory) {
return file.localJsxNamespace = getFirstIdentifier(file.localJsxFactory).escapedText;
}
@ -996,7 +998,7 @@ namespace ts {
_jsxNamespace = "React" as __String;
if (compilerOptions.jsxFactory) {
_jsxFactoryEntity = parseIsolatedEntityName(compilerOptions.jsxFactory, languageVersion);
visitNode(_jsxFactoryEntity, markAsSynthetic);
markAsSynthetic(_jsxFactoryEntity);
if (_jsxFactoryEntity) {
_jsxNamespace = getFirstIdentifier(_jsxFactoryEntity).escapedText;
}
@ -1010,9 +1012,12 @@ namespace ts {
}
return _jsxNamespace;
function markAsSynthetic(node: Node): VisitResult<Node> {
}
function markAsSynthetic(node: Node | undefined) {
if (node) {
setTextRangePosEnd(node, -1, -1);
return visitEachChild(node, markAsSynthetic, nullTransformationContext);
forEachChild(node, markAsSynthetic);
}
}
@ -36076,6 +36081,16 @@ namespace ts {
if (isExternalOrCommonJsModule(node)) {
checkExternalModuleExports(node);
}
else if (!node.isDeclarationFile && umdExport && !hasReportedUmdExportDiagnostic) {
hasReportedUmdExportDiagnostic = true;
const umdExportNamespace = parseIsolatedEntityName(umdExport, languageVersion);
if (umdExportNamespace) {
markAsSynthetic(umdExportNamespace);
if (!resolveEntityName(umdExportNamespace, SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ false, node)) {
error(undefined, Diagnostics.Cannot_find_namespace_0_specified_by_umdExport_option, umdExport);
}
}
}
if (potentialThisCollisions.length) {
forEach(potentialThisCollisions, checkIfThisIsCapturedInEnclosingScope);

View file

@ -999,6 +999,27 @@ namespace ts {
category: Diagnostics.Advanced_Options,
description: Diagnostics.Resolve_keyof_to_string_valued_property_names_only_no_numbers_or_symbols,
},
{
name: "umdExport",
type: "string",
affectsEmit: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Specifies_the_sole_export_for_a_single_file_output_UMD_module
},
{
name: "umdGlobal",
type: "string",
affectsEmit: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Wraps_a_single_file_output_as_a_UMD_module_with_specified_name_used_as_a_global_value_for_the_sole_export
},
{
name: "umdGlobalAlways",
type: "boolean",
affectsEmit: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Always_set_the_global_value_for_a_single_file_output_UMD_module
},
{
// A list of plugins to load in the language service
name: "plugins",

View file

@ -3016,7 +3016,10 @@
"category": "Error",
"code": 2792
},
"Cannot find namespace '{0}' specified by 'umdExport' option.": {
"category": "Error",
"code": 2793
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
@ -3467,7 +3470,7 @@
"category": "Error",
"code": 5058
},
"Invalid value for '--reactNamespace'. '{0}' is not a valid identifier.": {
"Invalid value for '{0}'. '{1}' is not a valid identifier.": {
"category": "Error",
"code": 5059
},
@ -3499,7 +3502,7 @@
"category": "Error",
"code": 5066
},
"Invalid value for 'jsxFactory'. '{0}' is not a valid identifier or qualified-name.": {
"Invalid value for '{0}'. '{1}' is not a valid identifier or qualified-name.": {
"category": "Error",
"code": 5067
},
@ -3587,6 +3590,10 @@
"category": "Error",
"code": 5088
},
"Option '{0} can only be specified when module code generation is 'umd'.": {
"category": "Error",
"code": 5089
},
"Generates a sourcemap for each corresponding '.d.ts' file.": {
"category": "Message",
@ -4482,6 +4489,18 @@
"category": "Error",
"code": 6236
},
"Specifies the sole export for a single-file output UMD module.": {
"category": "Message",
"code": 6237
},
"Wraps a single-file output as a UMD module with specified name used as a global value for the sole export.": {
"category": "Message",
"code": 6238
},
"Always set the global value for a single-file output UMD module.": {
"category": "Message",
"code": 6239
},
"Projects to reference": {
"category": "Message",
@ -5981,8 +6000,9 @@
"category": "Message",
"code": 18034
},
"Invalid value for 'jsxFragmentFactory'. '{0}' is not a valid identifier or qualified-name.": {
"retired:18035": {
"category": "Error",
"code": 18035
"code": 18035,
"retired": true
}
}

View file

@ -1550,7 +1550,9 @@ namespace ts {
case SyntaxKind.JSDocComment:
return emitJSDoc(node as JSDoc);
// Transformation nodes (ignored)
// Transformation nodes
case SyntaxKind.EmbeddedSourceFileStatement:
return emitEmbeddedSourceFileStatement(node as EmbeddedSourceFileStatement);
}
if (isExpression(node)) {
@ -3707,6 +3709,10 @@ namespace ts {
// Transformation nodes
function emitEmbeddedSourceFileStatement(node: EmbeddedSourceFileStatement) {
print(EmitHint.SourceFile, node.sourceFile, node.sourceFile);
}
function emitPartiallyEmittedExpression(node: PartiallyEmittedExpression) {
emitExpression(node.expression);
}

View file

@ -415,6 +415,8 @@ namespace ts {
createSyntheticExpression,
createSyntaxList,
createNotEmittedStatement,
createEmbeddedSourceFileStatement,
updateEmbeddedSourceFileStatement,
createPartiallyEmittedExpression,
updatePartiallyEmittedExpression,
createCommaListExpression,
@ -4954,6 +4956,20 @@ namespace ts {
return node;
}
// @api
function createEmbeddedSourceFileStatement(sourceFile: SourceFile) {
const node = createBaseNode<EmbeddedSourceFileStatement>(SyntaxKind.EmbeddedSourceFileStatement);
node.sourceFile = sourceFile;
return node;
}
// @api
function updateEmbeddedSourceFileStatement(node: EmbeddedSourceFileStatement, sourceFile: SourceFile) {
return sourceFile !== node.sourceFile
? update(createEmbeddedSourceFileStatement(sourceFile), node)
: node;
}
/**
* Creates a synthetic expression to act as a placeholder for a not-emitted expression in
* order to preserve comments or sourcemap positions.

View file

@ -546,7 +546,8 @@ namespace ts {
return factory.createStringLiteral(file.moduleName);
}
if (!file.isDeclarationFile && outFile(options)) {
return factory.createStringLiteral(getExternalModuleNameFromPath(host, file.fileName));
const moduleName = getExternalModuleNameFromPath(host, file.fileName);
return moduleName ? factory.createStringLiteral(moduleName) : undefined;
}
return undefined;
}

View file

@ -3091,6 +3091,35 @@ namespace ts {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "out", "outFile");
}
const languageVersion = getEmitScriptTarget(options);
if (options.umdExport) {
if (!options.out && !options.outFile) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "umdExport", "out", "outFile");
}
if (options.module !== ModuleKind.UMD) {
createDiagnosticForOptionName(Diagnostics.Option_0_can_only_be_specified_when_module_code_generation_is_umd, "umdExport");
}
if (!isEntityNameText(options.umdExport, languageVersion)) {
createOptionValueDiagnostic("umdExport", Diagnostics.Invalid_value_for_0_1_is_not_a_valid_identifier_or_qualified_name, options.umdExport);
}
}
if (options.umdGlobal) {
if (!options.umdExport) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "umdGlobal", "umdExport");
}
if (!isIdentifierText(options.umdGlobal, languageVersion)) {
createOptionValueDiagnostic("umdGlobal", Diagnostics.Invalid_value_for_0_1_is_not_a_valid_identifier, options.umdGlobal);
}
}
if (options.umdGlobalAlways) {
if (!options.umdGlobal) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "umdGlobalAlways", "umdGlobal");
}
}
if (options.mapRoot && !(options.sourceMap || options.declarationMap)) {
// Error to specify --mapRoot without --sourcemap
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "mapRoot", "sourceMap", "declarationMap");
@ -3117,8 +3146,6 @@ namespace ts {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noImplicitUseStrict", "alwaysStrict");
}
const languageVersion = options.target || ScriptTarget.ES3;
const firstNonAmbientExternalModuleSourceFile = find(files, f => isExternalModule(f) && !f.isDeclarationFile);
if (options.isolatedModules) {
if (options.module === ModuleKind.None && languageVersion < ScriptTarget.ES2015) {
@ -3139,7 +3166,7 @@ namespace ts {
// Cannot specify module gen that isn't amd or system with --out
if (outputFile && !options.emitDeclarationOnly) {
if (options.module && !(options.module === ModuleKind.AMD || options.module === ModuleKind.System)) {
if (options.module && !(options.module === ModuleKind.AMD || options.module === ModuleKind.System || options.module === ModuleKind.UMD)) {
createDiagnosticForOptionName(Diagnostics.Only_amd_and_system_modules_are_supported_alongside_0, options.out ? "out" : "outFile", "module");
}
else if (options.module === undefined && firstNonAmbientExternalModuleSourceFile) {
@ -3200,20 +3227,20 @@ namespace ts {
if (options.reactNamespace) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "reactNamespace", "jsxFactory");
}
if (!parseIsolatedEntityName(options.jsxFactory, languageVersion)) {
createOptionValueDiagnostic("jsxFactory", Diagnostics.Invalid_value_for_jsxFactory_0_is_not_a_valid_identifier_or_qualified_name, options.jsxFactory);
if (!isEntityNameText(options.jsxFactory, languageVersion)) {
createOptionValueDiagnostic("jsxFactory", Diagnostics.Invalid_value_for_0_1_is_not_a_valid_identifier_or_qualified_name, options.jsxFactory);
}
}
else if (options.reactNamespace && !isIdentifierText(options.reactNamespace, languageVersion)) {
createOptionValueDiagnostic("reactNamespace", Diagnostics.Invalid_value_for_reactNamespace_0_is_not_a_valid_identifier, options.reactNamespace);
createOptionValueDiagnostic("reactNamespace", Diagnostics.Invalid_value_for_0_1_is_not_a_valid_identifier, options.reactNamespace);
}
if (options.jsxFragmentFactory) {
if (!options.jsxFactory) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "jsxFragmentFactory", "jsxFactory");
}
if (!parseIsolatedEntityName(options.jsxFragmentFactory, languageVersion)) {
createOptionValueDiagnostic("jsxFragmentFactory", Diagnostics.Invalid_value_for_jsxFragmentFactory_0_is_not_a_valid_identifier_or_qualified_name, options.jsxFragmentFactory);
if (!isEntityNameText(options.jsxFragmentFactory, languageVersion)) {
createOptionValueDiagnostic("jsxFragmentFactory", Diagnostics.Invalid_value_for_0_1_is_not_a_valid_identifier_or_qualified_name, options.jsxFragmentFactory);
}
}
@ -3378,7 +3405,7 @@ namespace ts {
}
function createOptionValueDiagnostic(option1: string, message: DiagnosticMessage, arg0: string) {
createDiagnosticForOption(/*onKey*/ false, option1, /*option2*/ undefined, message, arg0);
createDiagnosticForOption(/*onKey*/ false, option1, /*option2*/ undefined, message, option1, arg0);
}
function createDiagnosticForReference(sourceFile: JsonSourceFile | undefined, index: number, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number) {
@ -3808,4 +3835,32 @@ namespace ts {
}
return res;
}
function isEntityNameText(text: string, languageVersion: ScriptTarget) {
if (hasTriviaAt(0)) return false;
const entity = parseIsolatedEntityName(text, languageVersion);
if (!entity) return false;
let pos = 0;
return visit(entity);
function hasTriviaAt(pos: number) {
return skipTrivia(text, pos) !== pos;
}
function visit(node: EntityName): boolean {
if (pos !== node.pos) return false;
if (node.kind === SyntaxKind.QualifiedName) {
if (!visit(node.left)) return false;
pos++; // .
if (hasTriviaAt(pos)) return false;
return visit(node.right);
}
else {
pos = node.end;
return !hasTriviaAt(pos);
}
}
}
}

View file

@ -86,6 +86,8 @@ namespace ts {
let emittedImports: readonly AnyImportSyntax[] | undefined; // must be declared in container so it can be `undefined` while transformer's first pass
const resolver = context.getEmitResolver();
const options = context.getCompilerOptions();
const umdExport = getSingleFileUmdExport(options);
const umdGlobal = getSingleFileUmdGlobalNamespace(options);
const { noResolve, stripInternal } = options;
return transformRoot;
@ -235,7 +237,7 @@ namespace ts {
libs = new Map();
let hasNoDefaultLib = false;
const bundle = factory.createBundle(map(node.sourceFiles,
sourceFile => {
(sourceFile, index) => {
if (sourceFile.isDeclarationFile) return undefined!; // Omit declaration files from bundle results, too // TODO: GH#18217
hasNoDefaultLib = hasNoDefaultLib || sourceFile.hasNoDefaultLib;
currentSourceFile = sourceFile;
@ -262,7 +264,19 @@ namespace ts {
}
needsDeclare = true;
const updated = isSourceFileJS(sourceFile) ? factory.createNodeArray(transformDeclarationsForJS(sourceFile)) : visitNodes(sourceFile.statements, visitDeclarationStatements);
return factory.updateSourceFile(sourceFile, transformAndReplaceLatePaintedStatements(updated), /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false, /*libReferences*/ []);
let statements = transformAndReplaceLatePaintedStatements(updated);
if (umdExport && index === node.sourceFiles.length - 1) {
const umdExportNamespace = parseIsolatedEntityName(umdExport, ScriptTarget.ESNext);
if (umdExportNamespace) {
const statementsArray = [...statements];
statementsArray.push(factory.createExportAssignment(/*decorators*/ undefined, /*modifiers*/ undefined, /*isExportEquals*/ true, createExpressionFromEntityName(factory, umdExportNamespace)));
if (umdGlobal) {
statementsArray.push(factory.createNamespaceExportDeclaration(umdGlobal));
}
statements = setTextRange(factory.createNodeArray(statementsArray), statements);
}
}
return factory.updateSourceFile(sourceFile, statements, /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false, /*libReferences*/ []);
}
), mapDefined(node.prepends, prepend => {
if (prepend.kind === SyntaxKind.InputFiles) {

View file

@ -41,13 +41,46 @@ namespace ts {
const moduleInfoMap: ExternalModuleInfo[] = []; // The ExternalModuleInfo for each file.
const deferredExports: (Statement[] | undefined)[] = []; // Exports to defer until an EndOfDeclarationMarker is found.
const umdExport = getSingleFileUmdExport(compilerOptions);
const umdGlobal = getSingleFileUmdGlobalNamespace(compilerOptions);
const umdGlobalAlways = !!umdGlobal && compilerOptions.umdGlobalAlways;
let currentSourceFile: SourceFile; // The current file.
let currentModuleInfo: ExternalModuleInfo; // The ExternalModuleInfo for the current file.
let noSubstitution: boolean[]; // Set of nodes for which substitution rules should be ignored.
let needUMDDynamicImportHelper: boolean;
return chainBundle(context, transformSourceFile);
return transformSourceFileOrBundle;
function transformSourceFileOrBundle(node: SourceFile | Bundle) {
return node.kind === SyntaxKind.SourceFile ? transformSourceFile(node) : transformBundle(node);
}
function transformBundle(node: Bundle) {
if (umdExport) {
const statements: Statement[] = map(node.sourceFiles, factory.createEmbeddedSourceFileStatement);
const exportEqualsStatement = factory.createExportAssignment(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*isExportEquals*/ true,
factory.createIdentifier(umdExport)
);
statements.push(exportEqualsStatement);
const wrapper = factory.createSourceFile(
statements,
factory.createToken(SyntaxKind.EndOfFileToken),
NodeFlags.None
);
wrapper.moduleName = umdGlobal;
wrapper.externalModuleIndicator = exportEqualsStatement;
wrapper.amdDependencies = [];
for (const sourceFile of node.sourceFiles) {
moveEmitHelpers(sourceFile, wrapper, helper => !helper.scoped);
}
return context.factory.createBundle([transformSourceFile(wrapper)], node.prepends);
}
return context.factory.createBundle(map(node.sourceFiles, transformSourceFile), node.prepends);
}
/**
* Transforms the module aspects of a SourceFile.
@ -62,6 +95,9 @@ namespace ts {
return node;
}
const savedCurrentSourceFile = currentSourceFile;
const savedCurrentModuleInfo = currentModuleInfo;
const savedNeedUMDDynamicImportHelper = needUMDDynamicImportHelper;
currentSourceFile = node;
currentModuleInfo = collectExternalModuleInfo(context, node, resolver, compilerOptions);
moduleInfoMap[getOriginalNodeId(node)] = currentModuleInfo;
@ -69,13 +105,12 @@ namespace ts {
// Perform the transformation.
const transformModule = getTransformModuleDelegate(moduleKind);
const updated = transformModule(node);
currentSourceFile = undefined!;
currentModuleInfo = undefined!;
needUMDDynamicImportHelper = false;
currentSourceFile = savedCurrentSourceFile;
currentModuleInfo = savedCurrentModuleInfo;
needUMDDynamicImportHelper = savedNeedUMDDynamicImportHelper;
return updated;
}
function shouldEmitUnderscoreUnderscoreESModule() {
if (!currentModuleInfo.exportEquals && isExternalModule(currentSourceFile)) {
return true;
@ -207,12 +242,89 @@ namespace ts {
function transformUMDModule(node: SourceFile) {
const { aliasedModuleNames, unaliasedModuleNames, importAliasNames } = collectAsynchronousDependencies(node, /*includeNonAmdDependencies*/ false);
const moduleName = tryGetModuleNameFromFile(factory, node, host, compilerOptions);
// Create an updated SourceFile:
// Without '--umdGlobal':
//
// (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 ...)
//
// With '--outFile foo.js --umdExport foo --umdGlobal foo' (single-file output with a single namespace export):
//
// (function (root, 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);
// }
// else if (root) {
// root.foo = factory();
// }
// })(typeof globalThis === "object" ? globalThis : typeof self === "object" ? self : this, function () {
// ...
// return foo;
// })
let rootParameter: ParameterDeclaration | undefined;
let rootExpression: Expression | undefined;
let rootStatement: IfStatement | undefined;
if (umdGlobal) {
rootParameter = factory.createParameterDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "root");
rootExpression = factory.createConditionalExpression(
factory.createTypeCheck(factory.createIdentifier("globalThis"), "object"),
/*questionToken*/ undefined,
factory.createIdentifier("globalThis"),
/*colonToken*/ undefined,
factory.createConditionalExpression(
factory.createTypeCheck(factory.createIdentifier("self"), "object"),
/*questionToken*/ undefined,
factory.createIdentifier("self"),
/*colonToken*/ undefined,
factory.createConditionalExpression(
factory.createTypeCheck(factory.createIdentifier("global"), "object"),
/*questionToken*/ undefined,
factory.createIdentifier("global"),
/*colonToken*/ undefined,
factory.createThis()
)
)
);
rootStatement = factory.createIfStatement(
factory.createIdentifier("root"),
factory.createBlock([
factory.createExpressionStatement(
factory.createAssignment(
factory.createPropertyAccessExpression(
factory.createIdentifier("root"),
factory.createIdentifier(umdGlobal)
),
factory.createCallExpression(
factory.createIdentifier("factory"),
/*typeArguments*/ undefined,
[]
)
)
)
], true)
);
}
const factoryParameter = factory.createParameterDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "factory");
const umdHeader = factory.createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
/*name*/ undefined,
/*typeParameters*/ undefined,
[factory.createParameterDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "factory")],
rootParameter ? [rootParameter, factoryParameter] : [factoryParameter],
/*type*/ undefined,
setTextRange(
factory.createBlock(
@ -255,7 +367,20 @@ namespace ts {
)
),
EmitFlags.SingleLine
)
),
...(umdGlobal && umdGlobalAlways ? [
factory.createIfStatement(
factory.createIdentifier("root"),
factory.createBlock([
factory.createExpressionStatement(
factory.createAssignment(
factory.createPropertyAccessExpression(factory.createIdentifier("root"), umdGlobal),
factory.createPropertyAccessExpression(factory.createIdentifier("module"), "exports")
)
)
], true)
)
] : [])
]),
factory.createIfStatement(
factory.createLogicalAnd(
@ -276,11 +401,48 @@ namespace ts {
...aliasedModuleNames,
...unaliasedModuleNames
]),
factory.createIdentifier("factory")
umdGlobal && umdGlobalAlways ?
factory.createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
/*name*/ undefined,
/*typeParameters*/ undefined,
/*parameters*/ undefined,
/*type*/ undefined,
factory.createBlock([
factory.createVariableStatement(/*modifiers*/ undefined, [
factory.createVariableDeclaration("result",
/*exclamationToken*/ undefined,
/*type*/ undefined,
factory.createFunctionApplyCall(
factory.createIdentifier("factory"),
factory.createThis(),
factory.createIdentifier("arguments")
)
)
]),
factory.createIfStatement(
factory.createIdentifier("root"),
factory.createBlock([
factory.createExpressionStatement(
factory.createAssignment(
factory.createPropertyAccessExpression(factory.createIdentifier("root"), umdGlobal),
factory.createIdentifier("result")
)
)
], true)
),
factory.createReturnStatement(
factory.createIdentifier("result")
)
], true)
) :
factory.createIdentifier("factory")
]
)
)
])
]),
rootStatement
)
)
],
@ -290,17 +452,22 @@ namespace ts {
)
);
// Create an updated SourceFile:
// Add the module body function argument:
//
// (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 ...)
// function (require, exports) ...
const bodyFunction = factory.createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
/*name*/ undefined,
/*typeParameters*/ undefined,
[
factory.createParameterDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "require"),
factory.createParameterDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "exports"),
...importAliasNames
],
/*type*/ undefined,
transformAsynchronousModuleBody(node)
);
const updated = factory.updateSourceFile(
node,
@ -310,24 +477,7 @@ namespace ts {
factory.createCallExpression(
umdHeader,
/*typeArguments*/ undefined,
[
// Add the module body function argument:
//
// function (require, exports) ...
factory.createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
/*name*/ undefined,
/*typeParameters*/ undefined,
[
factory.createParameterDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "require"),
factory.createParameterDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, "exports"),
...importAliasNames
],
/*type*/ undefined,
transformAsynchronousModuleBody(node)
)
]
rootExpression ? [rootExpression, bodyFunction] : [bodyFunction]
)
)
]),
@ -521,6 +671,9 @@ namespace ts {
case SyntaxKind.EndOfDeclarationMarker:
return visitEndOfDeclarationMarker(<EndOfDeclarationMarker>node);
case SyntaxKind.EmbeddedSourceFileStatement:
return visitEmbeddedSourceFileStatement(<EmbeddedSourceFileStatement>node);
default:
return visitEachChild(node, moduleExpressionElementVisitor, context);
}
@ -1362,6 +1515,10 @@ namespace ts {
return node;
}
function visitEmbeddedSourceFileStatement(node: EmbeddedSourceFileStatement) {
return factory.updateEmbeddedSourceFileStatement(node, transformSourceFile(node.sourceFile));
}
/**
* Appends the exports of an ImportDeclaration to a statement list, returning the
* statement list.

View file

@ -396,6 +396,7 @@ namespace ts {
// Transformation nodes
NotEmittedStatement,
EmbeddedSourceFileStatement,
PartiallyEmittedExpression,
CommaListExpression,
MergeDeclarationMarker,
@ -2536,6 +2537,15 @@ namespace ts {
readonly kind: SyntaxKind.NotEmittedStatement;
}
/**
* Embeds a source file as a statement
*/
/* @internal */
export interface EmbeddedSourceFileStatement extends Statement {
readonly kind: SyntaxKind.EmbeddedSourceFileStatement;
readonly sourceFile: SourceFile;
}
/**
* Marks the end of transformed declaration to properly emit exports.
*/
@ -5756,6 +5766,9 @@ namespace ts {
esModuleInterop?: boolean;
/* @internal */ showConfig?: boolean;
useDefineForClassFields?: boolean;
umdGlobal?: string;
umdGlobalAlways?: boolean;
umdExport?: string;
[option: string]: CompilerOptionsValue | TsConfigSourceFile | undefined;
}
@ -7096,6 +7109,8 @@ namespace ts {
/* @internal */ updateSyntheticReferenceExpression(node: SyntheticReferenceExpression, expression: Expression, thisArg: Expression): SyntheticReferenceExpression;
createCommaListExpression(elements: readonly Expression[]): CommaListExpression;
updateCommaListExpression(node: CommaListExpression, elements: readonly Expression[]): CommaListExpression;
/* @internal */ createEmbeddedSourceFileStatement(sourceFile: SourceFile): EmbeddedSourceFileStatement;
/* @internal */ updateEmbeddedSourceFileStatement(node: EmbeddedSourceFileStatement, sourceFile: SourceFile): EmbeddedSourceFileStatement;
createBundle(sourceFiles: readonly SourceFile[], prepends?: readonly (UnparsedSource | InputFiles)[]): Bundle;
updateBundle(node: Bundle, sourceFiles: readonly SourceFile[], prepends?: readonly (UnparsedSource | InputFiles)[]): Bundle;

View file

@ -5867,6 +5867,20 @@ namespace ts {
}
}
export function getSingleFileUmdGlobalNamespace(options: CompilerOptions) {
const moduleKind = getEmitModuleKind(options);
if (moduleKind === ModuleKind.UMD && outFile(options)) {
return options.umdGlobal;
}
}
export function getSingleFileUmdExport(options: CompilerOptions) {
const moduleKind = getEmitModuleKind(options);
if (moduleKind === ModuleKind.UMD && outFile(options)) {
return options.umdExport;
}
}
export function unreachableCodeIsError(options: CompilerOptions): boolean {
return options.allowUnreachableCode === false;
}

View file

@ -1699,6 +1699,7 @@ namespace ts {
|| kind === SyntaxKind.WhileStatement
|| kind === SyntaxKind.WithStatement
|| kind === SyntaxKind.NotEmittedStatement
|| kind === SyntaxKind.EmbeddedSourceFileStatement
|| kind === SyntaxKind.EndOfDeclarationMarker
|| kind === SyntaxKind.MergeDeclarationMarker;
}

View file

@ -1079,6 +1079,10 @@ namespace ts {
visitLexicalEnvironment((<SourceFile>node).statements, visitor, context));
// Transformation nodes
case SyntaxKind.EmbeddedSourceFileStatement:
return factory.updateEmbeddedSourceFileStatement(<EmbeddedSourceFileStatement>node,
nodeVisitor((<EmbeddedSourceFileStatement>node).sourceFile, visitor, isSourceFile));
case SyntaxKind.PartiallyEmittedExpression:
return factory.updatePartiallyEmittedExpression(<PartiallyEmittedExpression>node,
nodeVisitor((<PartiallyEmittedExpression>node).expression, visitor, isExpression));