Skip to content
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

--outFile & --module concatenation #5090

Merged
merged 36 commits into from
Nov 9, 2015
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
7d06789
naive change
weswigham Sep 30, 2015
b6a57ea
Concatenated module emit fixes up all included paths
weswigham Oct 1, 2015
122753b
sourcemap correctness
weswigham Oct 2, 2015
8e409f3
new baselines for sourcemaps tests (given that modules can now get em…
weswigham Oct 2, 2015
4c4087c
Add compiler error for incompatible module formats
weswigham Oct 3, 2015
145fa0c
Accept baselines
weswigham Oct 3, 2015
03256e7
cusotm tests, forbid umd
weswigham Oct 3, 2015
3c73a66
removed umd as allowed, accepted new baselines
weswigham Oct 3, 2015
613c51d
Fix jakefile rules build
weswigham Oct 5, 2015
05dc9da
concatenated type emit
weswigham Oct 5, 2015
d8ec703
merge with master
weswigham Oct 5, 2015
d07e33d
Correct output, accept new baselines
weswigham Oct 5, 2015
6c1f3ef
m'lint
weswigham Oct 5, 2015
732ec34
update comment
weswigham Oct 5, 2015
1ae7b7c
Merge branch 'master' into out-module-concat
weswigham Oct 12, 2015
a83b858
Merge branch 'master' into out-module-concat
weswigham Oct 20, 2015
7a4e995
feedback form pr
weswigham Oct 20, 2015
79cf984
feedback form pr
weswigham Oct 20, 2015
d178945
rename variable
weswigham Oct 20, 2015
37bc277
feedback form pr
weswigham Oct 21, 2015
3f52686
cleanup a bit, think toward the future
weswigham Oct 21, 2015
2fcdb0f
bit more cleanup
weswigham Oct 21, 2015
d18facb
fix lint
weswigham Oct 21, 2015
255cde5
remove assertion
weswigham Oct 21, 2015
c165be8
change triple-slash ref emit critaera, add a new tests and accept new…
weswigham Oct 22, 2015
6c81242
Merge branch 'master' into out-module-concat
weswigham Oct 30, 2015
95a3fc7
feedback form pr, new baselines
weswigham Oct 30, 2015
70fba0b
Merge branch 'master' into out-module-concat
weswigham Oct 30, 2015
d4d6078
accept new baselines postmerge
weswigham Oct 30, 2015
f06627f
prevent absolutre paths from leaking through error baselines
weswigham Oct 30, 2015
6de5221
dont mutate
weswigham Nov 2, 2015
265fb51
feedback from CR
weswigham Nov 3, 2015
6f97021
Merge branch 'master' into out-module-concat
weswigham Nov 3, 2015
1baea88
shorten function
weswigham Nov 3, 2015
cadf543
Merge branch 'master' into out-module-concat
weswigham Nov 9, 2015
977c3ee
fix lints
weswigham Nov 9, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 4 additions & 1 deletion Jakefile.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ var builtLocalCompiler = path.join(builtLocalDirectory, compilerFilename);
function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, noOutFile, generateDeclarations, outDir, preserveConstEnums, keepComments, noResolve, stripInternal, callback) {
file(outFile, prereqs, function() {
var compilerPath = useBuiltCompiler ? builtLocalCompiler : LKGCompiler;
var options = "--module commonjs --noImplicitAny --noEmitOnError";
var options = "--noImplicitAny --noEmitOnError";

// Keep comments when specifically requested
// or when in debug mode.
Expand All @@ -248,6 +248,9 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, noOu
if (!noOutFile) {
options += " --out " + outFile;
}
else {
options += " --module commonjs"
}

if(noResolve) {
options += " --noResolve";
Expand Down
51 changes: 48 additions & 3 deletions src/compiler/declarationEmitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ namespace ts {
let errorNameNode: DeclarationName;
let emitJsDocComments = compilerOptions.removeComments ? function (declaration: Node) { } : writeJsDocComments;
let emit = compilerOptions.stripInternal ? stripInternal : emitNode;
let noDeclare = !root;

let moduleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[] = [];
let asynchronousSubModuleDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[];
Expand Down Expand Up @@ -104,8 +105,10 @@ namespace ts {
else {
// Emit references corresponding to this file
let emittedReferencedFiles: SourceFile[] = [];
let prevModuleElementDeclarationEmitInfo: ModuleElementDeclarationEmitInfo[] = [];
forEach(host.getSourceFiles(), sourceFile => {
if (!isExternalModuleOrDeclarationFile(sourceFile)) {
noDeclare = false;
// Check what references need to be added
if (!compilerOptions.noResolve) {
forEach(sourceFile.referencedFiles, fileReference => {
Expand All @@ -123,7 +126,37 @@ namespace ts {

emitSourceFile(sourceFile);
}
else if (isExternalModule(sourceFile)) {
noDeclare = true;
write(`declare module "${sourceFile.moduleName}" {`);
writeLine();
increaseIndent();
emitSourceFile(sourceFile);
decreaseIndent();
write("}");
writeLine();

// create asynchronous output for the importDeclarations
if (moduleElementDeclarationEmitInfo.length) {
let oldWriter = writer;
forEach(moduleElementDeclarationEmitInfo, aliasEmitInfo => {
if (aliasEmitInfo.isVisible && !aliasEmitInfo.asynchronousOutput) {
Debug.assert(aliasEmitInfo.node.kind === SyntaxKind.ImportDeclaration);
createAndSetNewTextWriterWithSymbolWriter();
Debug.assert(aliasEmitInfo.indent === 1);
increaseIndent();
writeImportDeclaration(<ImportDeclaration>aliasEmitInfo.node);
aliasEmitInfo.asynchronousOutput = writer.getText();
decreaseIndent();
}
});
setWriter(oldWriter);
}
prevModuleElementDeclarationEmitInfo = prevModuleElementDeclarationEmitInfo.concat(moduleElementDeclarationEmitInfo);
moduleElementDeclarationEmitInfo = [];
}
});
moduleElementDeclarationEmitInfo = moduleElementDeclarationEmitInfo.concat(prevModuleElementDeclarationEmitInfo);
}

return {
Expand Down Expand Up @@ -601,7 +634,7 @@ namespace ts {
if (node.flags & NodeFlags.Default) {
write("default ");
}
else if (node.kind !== SyntaxKind.InterfaceDeclaration) {
else if (node.kind !== SyntaxKind.InterfaceDeclaration && !noDeclare) {
write("declare ");
}
}
Expand Down Expand Up @@ -696,7 +729,13 @@ namespace ts {
}
write(" from ");
}
writeTextOfNode(currentSourceFile, node.moduleSpecifier);
let match: RegExpMatchArray;
if ((!root) && node.moduleSpecifier.kind === SyntaxKind.StringLiteral && (match = getTextOfNode(node.moduleSpecifier).match(/('|")(\.\/|\.\.\/)/))) {
write(makeModulePathSemiAbsolute(host, currentSourceFile, getTextOfNode(node.moduleSpecifier)));
}
else {
writeTextOfNode(currentSourceFile, node.moduleSpecifier);
}
write(";");
writer.writeLine();
}
Expand Down Expand Up @@ -732,7 +771,13 @@ namespace ts {
}
if (node.moduleSpecifier) {
write(" from ");
writeTextOfNode(currentSourceFile, node.moduleSpecifier);
let match: RegExpMatchArray;
if ((!root) && node.moduleSpecifier.kind === SyntaxKind.StringLiteral && (match = getTextOfNode(node.moduleSpecifier).match(/('|")(\.\/|\.\.\/)/))) {
write(makeModulePathSemiAbsolute(host, currentSourceFile, getTextOfNode(node.moduleSpecifier)));
}
else {
writeTextOfNode(currentSourceFile, node.moduleSpecifier);
}
}
write(";");
writer.writeLine();
Expand Down
20 changes: 12 additions & 8 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -2258,14 +2258,6 @@
"code": 6063
},

"Specify JSX code generation: 'preserve' or 'react'": {
"category": "Message",
"code": 6080
},
"Argument for '--jsx' must be 'preserve' or 'react'.": {
"category": "Message",
"code": 6081
},
"Enables experimental support for ES7 decorators.": {
"category": "Message",
"code": 6065
Expand Down Expand Up @@ -2294,6 +2286,18 @@
"category": "Message",
"code": 6072
},
"Specify JSX code generation: 'preserve' or 'react'": {
"category": "Message",
"code": 6080
},
"Argument for '--jsx' must be 'preserve' or 'react'.": {
"category": "Message",
"code": 6081
},
"Only 'amd' and 'system' modules are supported alongside --{0}.": {
"category": "Error",
"code": 6082
},

"Variable '{0}' implicitly has an '{1}' type.": {
"category": "Error",
Expand Down
52 changes: 43 additions & 9 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -446,14 +446,22 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
/** If removeComments is true, no leading-comments needed to be emitted **/
let emitLeadingCommentsOfPosition = compilerOptions.removeComments ? function (pos: number) { } : emitLeadingCommentsOfPositionWorker;

let moduleEmitDelegates: Map<(node: SourceFile) => void> = {
let moduleEmitDelegates: Map<(node: SourceFile, resolvePath?: boolean) => void> = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it took me a while to figure out what resolvePath realy does, and i am not sure what is a better name here.

[ModuleKind.ES6]: emitES6Module,
[ModuleKind.AMD]: emitAMDModule,
[ModuleKind.System]: emitSystemModule,
[ModuleKind.UMD]: emitUMDModule,
[ModuleKind.CommonJS]: emitCommonJSModule,
};

let bundleEmitDelegates: Map<(node: SourceFile, resolvePath?: boolean) => void> = {
[ModuleKind.ES6]() {},
[ModuleKind.AMD]: emitAMDModule,
[ModuleKind.System]: emitSystemModule,
[ModuleKind.UMD]() {},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not umd too?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only the amd compat part of umd would work - trying to load the concatenated umd file in a commonjs environment would only lead to sadness. So there's no point in allowing it.

[ModuleKind.CommonJS]() {},
};

if (compilerOptions.sourceMap || compilerOptions.inlineSourceMap) {
initializeEmitterWithSourceMaps();
}
Expand All @@ -463,10 +471,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
emitSourceFile(root);
}
else {
if (modulekind) {
forEach(host.getSourceFiles(), emitEmitHelpers);
}
forEach(host.getSourceFiles(), sourceFile => {
if (!isExternalModuleOrDeclarationFile(sourceFile)) {
emitSourceFile(sourceFile);
}
else if (modulekind && isExternalModule(sourceFile)) {
emitConcatenatedModule(sourceFile);
}
});
}

Expand All @@ -480,6 +494,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
emit(sourceFile);
}

function emitConcatenatedModule(sourceFile: SourceFile): void {
currentSourceFile = sourceFile;
exportFunctionForFile = undefined;
let canonicalName = resolveToSemiabsolutePath(host, sourceFile.fileName);
sourceFile.moduleName = sourceFile.moduleName || canonicalName;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would capture this in a variable instead of mutating it. the tree should be immutable post parsing (modulo intentional breaks to the previous rule :D)

emit(sourceFile);
}

function isUniqueName(name: string): boolean {
return !resolver.hasGlobalName(name) &&
!hasProperty(currentSourceFile.identifiers, name) &&
Expand Down Expand Up @@ -6703,7 +6725,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
write("}"); // execute
}

function emitSystemModule(node: SourceFile): void {
function emitSystemModule(node: SourceFile, resolvePath?: boolean): void {
collectExternalModuleInfo(node);
// System modules has the following shape
// System.register(['dep-1', ... 'dep-n'], function(exports) {/* module body function */})
Expand Down Expand Up @@ -6743,6 +6765,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
write(", ");
}

if (resolvePath) {
text = makeModulePathSemiAbsolute(host, currentSourceFile, text);
}
write(text);
}
write(`], function(${exportFunctionForFile}) {`);
Expand All @@ -6763,7 +6788,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
importAliasNames: string[];
}

function getAMDDependencyNames(node: SourceFile, includeNonAmdDependencies: boolean): AMDDependencyNames {
function getAMDDependencyNames(node: SourceFile, includeNonAmdDependencies: boolean, resolvePath?: boolean): AMDDependencyNames {
// names of modules with corresponding parameter in the factory function
let aliasedModuleNames: string[] = [];
// names of modules with no corresponding parameters in factory function
Expand All @@ -6787,6 +6812,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
// Find the name of the external module
let externalModuleName = getExternalModuleNameText(importNode);

if (resolvePath) {
externalModuleName = makeModulePathSemiAbsolute(host, currentSourceFile, externalModuleName);
}

// Find the name of the module alias, if there is one
let importAliasName = getLocalNameForExternalImport(importNode);
if (includeNonAmdDependencies && importAliasName) {
Expand All @@ -6801,7 +6830,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
return { aliasedModuleNames, unaliasedModuleNames, importAliasNames };
}

function emitAMDDependencies(node: SourceFile, includeNonAmdDependencies: boolean) {
function emitAMDDependencies(node: SourceFile, includeNonAmdDependencies: boolean, resolvePath?: boolean) {
// An AMD define function has the following shape:
// define(id?, dependencies?, factory);
//
Expand All @@ -6814,7 +6843,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
// `import "module"` or `<amd-dependency path= "a.css" />`
// we need to add modules without alias names to the end of the dependencies list

let dependencyNames = getAMDDependencyNames(node, includeNonAmdDependencies);
let dependencyNames = getAMDDependencyNames(node, includeNonAmdDependencies, resolvePath);
emitAMDDependencyList(dependencyNames);
write(", ");
emitAMDFactoryHeader(dependencyNames);
Expand Down Expand Up @@ -6842,7 +6871,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
write(") {");
}

function emitAMDModule(node: SourceFile) {
function emitAMDModule(node: SourceFile, resolvePath?: boolean) {
emitEmitHelpers(node);
collectExternalModuleInfo(node);

Expand All @@ -6851,7 +6880,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
if (node.moduleName) {
write("\"" + node.moduleName + "\", ");
}
emitAMDDependencies(node, /*includeNonAmdDependencies*/ true);
emitAMDDependencies(node, /*includeNonAmdDependencies*/ true, resolvePath);
increaseIndent();
let startIndex = emitDirectivePrologues(node.statements, /*startWithNewLine*/ true);
emitExportStarHelper();
Expand Down Expand Up @@ -7100,8 +7129,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
emitDetachedComments(node);

if (isExternalModule(node) || compilerOptions.isolatedModules) {
let emitModule = moduleEmitDelegates[modulekind] || moduleEmitDelegates[ModuleKind.CommonJS];
emitModule(node);
if (root || (!isExternalModule(node) && compilerOptions.isolatedModules)) {
let emitModule = moduleEmitDelegates[modulekind] || moduleEmitDelegates[ModuleKind.CommonJS];
emitModule(node);
}
else {
bundleEmitDelegates[modulekind](node, /*resolvePath*/true);
}
}
else {
// emit prologue directives prior to __extends
Expand Down
58 changes: 36 additions & 22 deletions src/compiler/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,29 @@ namespace ts {
}
}

// there has to be common source directory if user specified --outdir || --sourceRoot
// if user specified --mapRoot, there needs to be common source directory if there would be multiple files being emitted
if (options.outDir || // there is --outDir specified
options.sourceRoot || // there is --sourceRoot specified
options.mapRoot) { // there is --mapRoot specified

if (options.rootDir && checkSourceFilesBelongToPath(files, options.rootDir)) {
// If a rootDir is specified and is valid use it as the commonSourceDirectory
commonSourceDirectory = getNormalizedAbsolutePath(options.rootDir, host.getCurrentDirectory());
}
else {
// Compute the commonSourceDirectory from the input files
commonSourceDirectory = computeCommonSourceDirectory(files);
}

if (commonSourceDirectory && commonSourceDirectory[commonSourceDirectory.length - 1] !== directorySeparator) {
// Make sure directory path ends with directory separator so this string can directly
// used to replace with "" to get the relative path of the source file and the relative path doesn't
// start with / making it rooted path
commonSourceDirectory += directorySeparator;
}
}

verifyCompilerOptions();

// unconditionally set oldProgram to undefined to prevent it from being captured in closure
Expand Down Expand Up @@ -517,6 +540,12 @@ namespace ts {
getSourceFiles: program.getSourceFiles,
writeFile: writeFileCallback || (
(fileName, data, writeByteOrderMark, onError) => host.writeFile(fileName, data, writeByteOrderMark, onError)),
resolveModuleName: (name: string, containingFile?: string) => {
let resolvedModule = resolveModuleNamesWorker([name], containingFile || "dummy.ts")[0];
if (!resolvedModule)
return;
return resolvedModule.resolvedFileName;
},
};
}

Expand Down Expand Up @@ -923,6 +952,10 @@ namespace ts {
}
});

if (!commonPathComponents) { // Can happen when all input files are .d.ts files
return currentDirectory;
}

return getNormalizedPathFromPathComponents(commonPathComponents);
}

Expand Down Expand Up @@ -1025,28 +1058,9 @@ namespace ts {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_compile_modules_into_es6_when_targeting_ES5_or_lower));
}

// there has to be common source directory if user specified --outdir || --sourceRoot
// if user specified --mapRoot, there needs to be common source directory if there would be multiple files being emitted
if (options.outDir || // there is --outDir specified
options.sourceRoot || // there is --sourceRoot specified
(options.mapRoot && // there is --mapRoot specified and there would be multiple js files generated
(!outFile || firstExternalModuleSourceFile !== undefined))) {

if (options.rootDir && checkSourceFilesBelongToPath(files, options.rootDir)) {
// If a rootDir is specified and is valid use it as the commonSourceDirectory
commonSourceDirectory = getNormalizedAbsolutePath(options.rootDir, host.getCurrentDirectory());
}
else {
// Compute the commonSourceDirectory from the input files
commonSourceDirectory = computeCommonSourceDirectory(files);
}

if (commonSourceDirectory && commonSourceDirectory[commonSourceDirectory.length - 1] !== directorySeparator) {
// Make sure directory path ends with directory separator so this string can directly
// used to replace with "" to get the relative path of the source file and the relative path doesn't
// start with / making it rooted path
commonSourceDirectory += directorySeparator;
}
// Cannot specify module gen that isn't amd or system with --out
if (outFile && options.module && options.module !== ModuleKind.AMD && options.module !== ModuleKind.System) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Only_amd_and_system_modules_are_supported_alongside_0, options.out ? "out" : "outFile"));
}

if (options.noEmit) {
Expand Down
Loading