Skip to content

Commit b43b667

Browse files
committed
Now supports source maps correctly
1 parent df9212b commit b43b667

File tree

2 files changed

+174
-22
lines changed

2 files changed

+174
-22
lines changed

dist/main/lang/modules/building.js

+77-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
var mkdirp = require('mkdirp');
22
var path = require('path');
33
var fs = require('fs');
4+
var fsUtil_1 = require("../../utils/fsUtil");
45
var babel;
56
exports.Not_In_Context = "/* NotInContext */";
67
function diagnosticToTSError(diagnostic) {
@@ -30,11 +31,20 @@ function emitFile(proj, filePath) {
3031
var startPosition = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
3132
errors.push(diagnosticToTSError(diagnostic));
3233
});
33-
output.outputFiles.forEach(function (o) {
34-
mkdirp.sync(path.dirname(o.name));
35-
runExternalTranspiler(o, proj);
36-
fs.writeFileSync(o.name, o.text, "utf8");
37-
});
34+
{
35+
var sourceMapContents = {};
36+
output.outputFiles.forEach(function (o) {
37+
mkdirp.sync(path.dirname(o.name));
38+
var additionalEmits = runExternalTranspiler(o, proj, sourceMapContents);
39+
if (!sourceMapContents[o.name]) {
40+
fs.writeFileSync(o.name, o.text, "utf8");
41+
}
42+
additionalEmits.forEach(function (a) {
43+
mkdirp.sync(path.dirname(a.name));
44+
fs.writeFileSync(a.name, a.text, "utf8");
45+
});
46+
});
47+
}
3848
var outputFiles = output.outputFiles.map(function (o) { return o.name; });
3949
if (path.extname(filePath) == '.d.ts') {
4050
outputFiles.push(filePath);
@@ -63,14 +73,71 @@ function getRawOutput(proj, filePath) {
6373
return output;
6474
}
6575
exports.getRawOutput = getRawOutput;
66-
function runExternalTranspiler(outputFile, project) {
67-
var externalTranspiler = project.projectFile.project.externalTranspiler;
76+
function runExternalTranspiler(outputFile, project, sourceMapContents) {
77+
if (!isJSFile(outputFile.name) && !isJSSourceMapFile(outputFile.name)) {
78+
return [];
79+
}
80+
var settings = project.projectFile.project;
81+
var externalTranspiler = settings.externalTranspiler;
6882
if (!externalTranspiler) {
69-
return;
83+
return [];
84+
}
85+
if (isJSSourceMapFile(outputFile.name)) {
86+
var sourceMapPayload = JSON.parse(outputFile.text);
87+
var jsFileName = fsUtil_1.consistentPath(path.resolve(path.dirname(outputFile.name), sourceMapPayload.file));
88+
sourceMapContents[outputFile.name] = { jsFileName: jsFileName, sourceMapPayload: sourceMapPayload };
89+
return [];
7090
}
7191
if (externalTranspiler.toLocaleLowerCase() === "babel") {
7292
babel = require("babel");
73-
outputFile.text = babel.transform(outputFile.text, {}).code;
93+
var babelOptions = {};
94+
var sourceMapFileName = getJSMapNameForJSFile(outputFile.name);
95+
if (sourceMapContents[sourceMapFileName]) {
96+
babelOptions.inputSourceMap = sourceMapContents[sourceMapFileName].sourceMapPayload;
97+
}
98+
if (settings.compilerOptions.sourceMap) {
99+
babelOptions.sourceMaps = true;
100+
}
101+
if (settings.compilerOptions.inlineSourceMap) {
102+
babelOptions.sourceMaps = "inline";
103+
}
104+
if (!settings.compilerOptions.removeComments) {
105+
babelOptions.comments = true;
106+
}
107+
var babelResult = babel.transform(outputFile.text, babelOptions);
108+
outputFile.text = babelResult.code;
109+
if (babelResult.map && settings.compilerOptions.sourceMap) {
110+
var additionalEmit = {
111+
name: sourceMapFileName,
112+
text: JSON.stringify(babelResult.map),
113+
writeByteOrderMark: settings.compilerOptions.emitBOM
114+
};
115+
if (additionalEmit.name === "") {
116+
console.warn("The TypeScript language service did not yet provide a .js.map name for file " + outputFile.name);
117+
return [];
118+
}
119+
return [additionalEmit];
120+
}
121+
return [];
122+
}
123+
function getJSMapNameForJSFile(jsFileName) {
124+
for (var jsMapName in sourceMapContents) {
125+
if (sourceMapContents.hasOwnProperty(jsMapName)) {
126+
if (sourceMapContents[jsMapName].jsFileName === jsFileName) {
127+
return jsMapName;
128+
}
129+
}
130+
}
131+
return "";
132+
}
133+
}
134+
function isJSFile(fileName) {
135+
return (path.extname(fileName).toLocaleLowerCase() === ".js");
136+
}
137+
function isJSSourceMapFile(fileName) {
138+
var lastExt = path.extname(fileName);
139+
if (lastExt === ".map") {
140+
return isJSFile(fileName.substr(0, fileName.length - 4));
74141
}
75-
return;
142+
return false;
76143
}

lib/main/lang/modules/building.ts

+97-12
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,23 @@ export function emitFile(proj: project.Project, filePath: string): EmitOutput {
4141
errors.push(diagnosticToTSError(diagnostic));
4242
});
4343

44-
output.outputFiles.forEach(o => {
45-
mkdirp.sync(path.dirname(o.name));
46-
runExternalTranspiler(o, proj);
47-
fs.writeFileSync(o.name, o.text, "utf8");
48-
});
44+
{
45+
let sourceMapContents: {[index:string]: any} = {};
46+
output.outputFiles.forEach(o => {
47+
mkdirp.sync(path.dirname(o.name));
48+
let additionalEmits = runExternalTranspiler(o, proj, sourceMapContents);
49+
50+
if (!sourceMapContents[o.name]) {
51+
// .js.map files will be written as an "additional emit" later.
52+
fs.writeFileSync(o.name, o.text, "utf8");
53+
}
54+
55+
additionalEmits.forEach(a => {
56+
mkdirp.sync(path.dirname(a.name));
57+
fs.writeFileSync(a.name, a.text, "utf8");
58+
})
59+
});
60+
}
4961

5062
var outputFiles = output.outputFiles.map((o) => o.name);
5163
if (path.extname(filePath) == '.d.ts') {
@@ -74,16 +86,89 @@ export function getRawOutput(proj: project.Project, filePath: string): ts.EmitOu
7486
return output;
7587
}
7688

77-
function runExternalTranspiler(outputFile: ts.OutputFile, project: project.Project) {
78-
var externalTranspiler = project.projectFile.project.externalTranspiler;
89+
function runExternalTranspiler(outputFile: ts.OutputFile, project: project.Project, sourceMapContents: {[index:string]: any}) : ts.OutputFile[] {
90+
if (!isJSFile(outputFile.name) && !isJSSourceMapFile(outputFile.name)) {
91+
return [];
92+
}
93+
94+
let settings = project.projectFile.project;
95+
let externalTranspiler = settings.externalTranspiler;
7996
if (!externalTranspiler) {
80-
return;
97+
return [];
98+
}
99+
100+
if (isJSSourceMapFile(outputFile.name)) {
101+
let sourceMapPayload = JSON.parse(outputFile.text);
102+
let jsFileName = consistentPath(path.resolve(path.dirname(outputFile.name), sourceMapPayload.file));
103+
sourceMapContents[outputFile.name] = {jsFileName: jsFileName, sourceMapPayload};
104+
return [];
81105
}
106+
82107
if (externalTranspiler.toLocaleLowerCase() === "babel") {
83108
babel = require("babel");
84-
//TODO: pass relevant arguments from the project.
85-
//TODO: confirm source maps work as expected.
86-
outputFile.text = babel.transform(outputFile.text, {}).code;
109+
110+
let babelOptions : any = {};
111+
112+
let sourceMapFileName = getJSMapNameForJSFile(outputFile.name);
113+
114+
if (sourceMapContents[sourceMapFileName]) {
115+
babelOptions.inputSourceMap = sourceMapContents[sourceMapFileName].sourceMapPayload;
116+
}
117+
if (settings.compilerOptions.sourceMap) {
118+
babelOptions.sourceMaps = true;
119+
}
120+
if (settings.compilerOptions.inlineSourceMap) {
121+
babelOptions.sourceMaps = "inline";
122+
}
123+
if (!settings.compilerOptions.removeComments) {
124+
babelOptions.comments = true;
125+
}
126+
127+
let babelResult = babel.transform(outputFile.text, babelOptions);
128+
outputFile.text = babelResult.code;
129+
130+
if (babelResult.map && settings.compilerOptions.sourceMap) {
131+
let additionalEmit : ts.OutputFile = {
132+
name: sourceMapFileName,
133+
text : JSON.stringify(babelResult.map),
134+
writeByteOrderMark: settings.compilerOptions.emitBOM
135+
};
136+
137+
if (additionalEmit.name === "") {
138+
// can't emit a blank file name - this should only be reached if the TypeScript
139+
// language service returns the .js file before the .js.map file.
140+
console.warn(`The TypeScript language service did not yet provide a .js.map name for file ${outputFile.name}`);
141+
return [];
142+
}
143+
144+
return [additionalEmit];
145+
}
146+
147+
return [];
148+
}
149+
150+
function getJSMapNameForJSFile(jsFileName: string) {
151+
for (let jsMapName in sourceMapContents) {
152+
if (sourceMapContents.hasOwnProperty(jsMapName)) {
153+
if (sourceMapContents[jsMapName].jsFileName === jsFileName) {
154+
return jsMapName;
155+
}
156+
}
157+
}
158+
return "";
159+
}
160+
}
161+
162+
163+
164+
function isJSFile(fileName: string) {
165+
return (path.extname(fileName).toLocaleLowerCase() === ".js");
166+
}
167+
168+
function isJSSourceMapFile(fileName: string) {
169+
let lastExt = path.extname(fileName);
170+
if (lastExt === ".map") {
171+
return isJSFile(fileName.substr(0,fileName.length - 4));
87172
}
88-
return;
173+
return false;
89174
}

0 commit comments

Comments
 (0)