-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Inline source maps #2484
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
Inline source maps #2484
Changes from all commits
73e22ed
a998abb
cacf34a
f27cc70
c940b16
658bba9
32409f9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -57,7 +57,7 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { | |
|
||
let compilerOptions = host.getCompilerOptions(); | ||
let languageVersion = compilerOptions.target || ScriptTarget.ES3; | ||
let sourceMapDataList: SourceMapData[] = compilerOptions.sourceMap ? [] : undefined; | ||
let sourceMapDataList: SourceMapData[] = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? [] : undefined; | ||
let diagnostics: Diagnostic[] = []; | ||
let newLine = host.getNewLine(); | ||
|
||
|
@@ -181,7 +181,7 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { | |
/** Sourcemap data that will get encoded */ | ||
let sourceMapData: SourceMapData; | ||
|
||
if (compilerOptions.sourceMap) { | ||
if (compilerOptions.sourceMap || compilerOptions.inlineSourceMap) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe factor this out into a variable and use it above as well. |
||
initializeEmitterWithSourceMaps(); | ||
} | ||
|
||
|
@@ -506,6 +506,13 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { | |
|
||
// The one that can be used from program to get the actual source file | ||
sourceMapData.inputSourceFileNames.push(node.fileName); | ||
|
||
if (compilerOptions.inlineSources) { | ||
if (!sourceMapData.sourceMapSourcesContent) { | ||
sourceMapData.sourceMapSourcesContent = []; | ||
} | ||
sourceMapData.sourceMapSourcesContent.push(node.text); | ||
} | ||
} | ||
|
||
function recordScopeNameOfNode(node: Node, scopeName?: string) { | ||
|
@@ -577,19 +584,25 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { | |
recordSourceMapSpan(comment.end); | ||
} | ||
|
||
function serializeSourceMapContents(version: number, file: string, sourceRoot: string, sources: string[], names: string[], mappings: string) { | ||
function serializeSourceMapContents(version: number, file: string, sourceRoot: string, sources: string[], names: string[], mappings: string, sourcesContent?: string[]) { | ||
if (typeof JSON !== "undefined") { | ||
return JSON.stringify({ | ||
version: version, | ||
file: file, | ||
sourceRoot: sourceRoot, | ||
sources: sources, | ||
names: names, | ||
mappings: mappings | ||
}); | ||
let map: any = { | ||
version, | ||
file, | ||
sourceRoot, | ||
sources, | ||
names, | ||
mappings | ||
}; | ||
|
||
if (sourcesContent !== undefined) { | ||
map.sourcesContent = sourcesContent; | ||
} | ||
|
||
return JSON.stringify(map); | ||
} | ||
|
||
return "{\"version\":" + version + ",\"file\":\"" + escapeString(file) + "\",\"sourceRoot\":\"" + escapeString(sourceRoot) + "\",\"sources\":[" + serializeStringArray(sources) + "],\"names\":[" + serializeStringArray(names) + "],\"mappings\":\"" + escapeString(mappings) + "\"}"; | ||
return "{\"version\":" + version + ",\"file\":\"" + escapeString(file) + "\",\"sourceRoot\":\"" + escapeString(sourceRoot) + "\",\"sources\":[" + serializeStringArray(sources) + "],\"names\":[" + serializeStringArray(names) + "],\"mappings\":\"" + escapeString(mappings) + "\" " + (sourcesContent !== undefined ? ",\"sourcesContent\":[" + serializeStringArray(sourcesContent) + "]" : "") + "}"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Template? Also, factor out the last part into a variable |
||
|
||
function serializeStringArray(list: string[]): string { | ||
let output = ""; | ||
|
@@ -604,19 +617,33 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { | |
} | ||
|
||
function writeJavaScriptAndSourceMapFile(emitOutput: string, writeByteOrderMark: boolean) { | ||
// Write source map file | ||
encodeLastRecordedSourceMapSpan(); | ||
writeFile(host, diagnostics, sourceMapData.sourceMapFilePath, serializeSourceMapContents( | ||
|
||
let sourceMapText = serializeSourceMapContents( | ||
3, | ||
sourceMapData.sourceMapFile, | ||
sourceMapData.sourceMapSourceRoot, | ||
sourceMapData.sourceMapSources, | ||
sourceMapData.sourceMapNames, | ||
sourceMapData.sourceMapMappings), /*writeByteOrderMark*/ false); | ||
sourceMapData.sourceMapMappings, | ||
sourceMapData.sourceMapSourcesContent); | ||
|
||
sourceMapDataList.push(sourceMapData); | ||
|
||
let sourceMapUrl: string; | ||
if (compilerOptions.inlineSourceMap) { | ||
// Encode the sourceMap into the sourceMap url | ||
let base64SourceMapText = convertToBase64(sourceMapText); | ||
sourceMapUrl = `//# sourceMappingURL=data:application/json;base64,${base64SourceMapText}`; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yay! Templates! |
||
} | ||
else { | ||
// Write source map file | ||
writeFile(host, diagnostics, sourceMapData.sourceMapFilePath, sourceMapText, /*writeByteOrderMark*/ false); | ||
sourceMapUrl = `//# sourceMappingURL=${sourceMapData.jsSourceMappingURL}`; | ||
} | ||
|
||
// Write sourcemap url to the js file and write the js file | ||
writeJavaScriptFile(emitOutput + "//# sourceMappingURL=" + sourceMapData.jsSourceMappingURL, writeByteOrderMark); | ||
writeJavaScriptFile(emitOutput + sourceMapUrl, writeByteOrderMark); | ||
} | ||
|
||
// Initialize source map data | ||
|
@@ -630,6 +657,7 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { | |
inputSourceFileNames: [], | ||
sourceMapNames: [], | ||
sourceMapMappings: "", | ||
sourceMapSourcesContent: undefined, | ||
sourceMapDecodedMappings: [] | ||
}; | ||
|
||
|
@@ -874,7 +902,7 @@ if (typeof __param !== "function") __param = function (paramIndex, decorator) { | |
function emitLiteral(node: LiteralExpression) { | ||
let text = getLiteralText(node); | ||
|
||
if (compilerOptions.sourceMap && (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) { | ||
if ((compilerOptions.sourceMap || compilerOptions.inlineSourceMap) && (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) { | ||
writer.writeLiteral(text); | ||
} | ||
// For versions below ES6, emit binary & octal literals in their canonical decimal form. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1695,6 +1695,83 @@ module ts { | |
export function getLocalSymbolForExportDefault(symbol: Symbol) { | ||
return symbol && symbol.valueDeclaration && (symbol.valueDeclaration.flags & NodeFlags.Default) ? symbol.valueDeclaration.localSymbol : undefined; | ||
} | ||
|
||
/** | ||
* Replace each instance of non-ascii characters by one, two, three, or four escape sequences | ||
* representing the UTF-8 encoding of the character, and return the expanded char code list. | ||
*/ | ||
function getExpandedCharCodes(input: string): number[] { | ||
let output: number[] = []; | ||
let length = input.length; | ||
let leadSurrogate: number = undefined; | ||
|
||
for (let i = 0; i < length; i++) { | ||
let charCode = input.charCodeAt(i); | ||
|
||
// handel utf8 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. handle |
||
if (charCode < 0x80) { | ||
output.push(charCode); | ||
} | ||
else if (charCode < 0x800) { | ||
output.push((charCode >> 6) | 0B11000000); | ||
output.push((charCode & 0B00111111) | 0B10000000); | ||
} | ||
else if (charCode < 0x10000) { | ||
output.push((charCode >> 12) | 0B11100000); | ||
output.push(((charCode >> 6) & 0B00111111) | 0B10000000); | ||
output.push((charCode & 0B00111111) | 0B10000000); | ||
} | ||
else if (charCode < 0x20000) { | ||
output.push((charCode >> 18) | 0B11110000); | ||
output.push(((charCode >> 12) & 0B00111111) | 0B10000000); | ||
output.push(((charCode >> 6) & 0B00111111) | 0B10000000); | ||
output.push((charCode & 0B00111111) | 0B10000000); | ||
} | ||
else { | ||
Debug.assert(false, "Unexpected code point"); | ||
} | ||
} | ||
|
||
return output; | ||
} | ||
|
||
const base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; | ||
|
||
/** | ||
* Converts a string to a base-64 encoded ASCII string. | ||
*/ | ||
export function convertToBase64(input: string): string { | ||
var result = ""; | ||
let charCodes = getExpandedCharCodes(input); | ||
let i = 0; | ||
let length = charCodes.length; | ||
let byte1: number, byte2: number, byte3: number, byte4: number; | ||
|
||
while (i < length) { | ||
// Convert every 6-bits in the input 3 character points | ||
// into a base64 digit | ||
byte1 = charCodes[i] >> 2; | ||
byte2 = (charCodes[i] & 0B00000011) << 4 | charCodes[i + 1] >> 4; | ||
byte3 = (charCodes[i + 1] & 0B00001111) << 2 | charCodes[i + 2] >> 6; | ||
byte4 = charCodes[i + 2] & 0B00111111; | ||
|
||
// We are out of characters in the input, set the extra | ||
// digits to 64 (padding character). | ||
if (i + 1 >= length) { | ||
byte3 = byte4 = 64; | ||
} | ||
else if (i + 2 >= length) { | ||
byte4 = 64; | ||
} | ||
|
||
// Write to the ouput | ||
result += base64Digits.charAt(byte1) + base64Digits.charAt(byte2) + base64Digits.charAt(byte3) + base64Digits.charAt(byte4); | ||
|
||
i += 3; | ||
} | ||
|
||
return result; | ||
} | ||
} | ||
|
||
module ts { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -159,7 +159,7 @@ class CompilerBaselineRunner extends RunnerBase { | |
|
||
// Source maps? | ||
it('Correct sourcemap content for ' + fileName, () => { | ||
if (options.sourceMap) { | ||
if (options.sourceMap || options.inlineSourceMap) { | ||
Harness.Baseline.runBaseline('Correct sourcemap content for ' + fileName, justName.replace(/\.ts$/, '.sourcemap.txt'), () => { | ||
var record = result.getSourceMapRecord(); | ||
if (options.noEmitOnError && result.errors.length !== 0 && record === undefined) { | ||
|
@@ -228,7 +228,13 @@ class CompilerBaselineRunner extends RunnerBase { | |
}); | ||
|
||
it('Correct Sourcemap output for ' + fileName, () => { | ||
if (options.sourceMap) { | ||
if (options.inlineSourceMap) { | ||
if (result.sourceMaps.length > 0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would replace it with Debug.assert with custom message |
||
throw new Error('No sourcemap files should be generated if inlineSourceMaps was set.'); | ||
} | ||
return null; | ||
} | ||
else if (options.sourceMap) { | ||
if (result.sourceMaps.length !== result.files.length) { | ||
throw new Error('Number of sourcemap files should be same as js files.'); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we put this on two more lines and maybe put parens around the
||
expression?