-
Notifications
You must be signed in to change notification settings - Fork 29.9k
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
process: add lineLength to source-map-cache #29863
Closed
Closed
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
'use strict'; | ||
|
||
const debug = require('internal/util/debuglog').debuglog('source_map'); | ||
const { findSourceMap } = require('internal/source_map/source_map_cache'); | ||
const { overrideStackTrace } = require('internal/errors'); | ||
|
||
// Create a prettified stacktrace, inserting context from source maps | ||
// if possible. | ||
const ErrorToString = Error.prototype.toString; // Capture original toString. | ||
const prepareStackTrace = (globalThis, error, trace) => { | ||
// API for node internals to override error stack formatting | ||
// without interfering with userland code. | ||
// TODO(bcoe): add support for source-maps to repl. | ||
if (overrideStackTrace.has(error)) { | ||
const f = overrideStackTrace.get(error); | ||
overrideStackTrace.delete(error); | ||
return f(error, trace); | ||
} | ||
|
||
const { SourceMap } = require('internal/source_map/source_map'); | ||
const errorString = ErrorToString.call(error); | ||
|
||
if (trace.length === 0) { | ||
return errorString; | ||
} | ||
const preparedTrace = trace.map((t, i) => { | ||
let str = i !== 0 ? '\n at ' : ''; | ||
str = `${str}${t}`; | ||
try { | ||
const sourceMap = findSourceMap(t.getFileName(), error); | ||
if (sourceMap && sourceMap.data) { | ||
const sm = new SourceMap(sourceMap.data); | ||
// Source Map V3 lines/columns use zero-based offsets whereas, in | ||
// stack traces, they start at 1/1. | ||
const [, , url, line, col] = | ||
sm.findEntry(t.getLineNumber() - 1, t.getColumnNumber() - 1); | ||
if (url && line !== undefined && col !== undefined) { | ||
str += | ||
`\n -> ${url.replace('file://', '')}:${line + 1}:${col + 1}`; | ||
} | ||
} | ||
} catch (err) { | ||
debug(err.stack); | ||
} | ||
return str; | ||
}); | ||
return `${errorString}\n at ${preparedTrace.join('')}`; | ||
}; | ||
|
||
module.exports = { | ||
prepareStackTrace, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,7 +17,6 @@ const cjsSourceMapCache = new WeakMap(); | |
// on filenames. | ||
const esmSourceMapCache = new Map(); | ||
const { fileURLToPath, URL } = require('url'); | ||
const { overrideStackTrace } = require('internal/errors'); | ||
|
||
let experimentalSourceMaps; | ||
function maybeCacheSourceMap(filename, content, cjsModuleInstance) { | ||
|
@@ -38,18 +37,22 @@ function maybeCacheSourceMap(filename, content, cjsModuleInstance) { | |
|
||
const match = content.match(/\/[*/]#\s+sourceMappingURL=(?<sourceMappingURL>[^\s]+)/); | ||
if (match) { | ||
const data = dataFromUrl(basePath, match.groups.sourceMappingURL); | ||
const url = data ? null : match.groups.sourceMappingURL; | ||
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. It's getting to the point where we write quite a bit of data to disk (and memory) -- we don't actually need the |
||
if (cjsModuleInstance) { | ||
cjsSourceMapCache.set(cjsModuleInstance, { | ||
filename, | ||
url: match.groups.sourceMappingURL, | ||
data: dataFromUrl(basePath, match.groups.sourceMappingURL) | ||
lineLengths: lineLengths(content), | ||
data, | ||
url | ||
}); | ||
} else { | ||
// If there is no cjsModuleInstance assume we are in a | ||
// "modules/esm" context. | ||
esmSourceMapCache.set(filename, { | ||
url: match.groups.sourceMappingURL, | ||
data: dataFromUrl(basePath, match.groups.sourceMappingURL) | ||
lineLengths: lineLengths(content), | ||
data, | ||
url | ||
}); | ||
} | ||
} | ||
|
@@ -73,6 +76,18 @@ function dataFromUrl(basePath, sourceMappingURL) { | |
} | ||
} | ||
|
||
// Cache the length of each line in the file that a source map was extracted | ||
// from. This allows translation from byte offset V8 coverage reports, | ||
// to line/column offset Source Map V3. | ||
function lineLengths(content) { | ||
bcoe marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// We purposefully keep \r as part of the line-length calculation, in | ||
// cases where there is a \r\n separator, so that this can be taken into | ||
// account in coverage calculations. | ||
return content.split(/\n|\u2028|\u2029/).map((line) => { | ||
return line.length; | ||
}); | ||
} | ||
|
||
function sourceMapFromFile(sourceMapFile) { | ||
try { | ||
const content = fs.readFileSync(sourceMapFile, 'utf8'); | ||
|
@@ -161,56 +176,14 @@ function appendCJSCache(obj) { | |
const value = cjsSourceMapCache.get(Module._cache[key]); | ||
if (value) { | ||
obj[`file://${key}`] = { | ||
url: value.url, | ||
data: value.data | ||
lineLengths: value.lineLengths, | ||
data: value.data, | ||
url: value.url | ||
}; | ||
} | ||
}); | ||
} | ||
|
||
// Create a prettified stacktrace, inserting context from source maps | ||
// if possible. | ||
const ErrorToString = Error.prototype.toString; // Capture original toString. | ||
const prepareStackTrace = (globalThis, error, trace) => { | ||
// API for node internals to override error stack formatting | ||
// without interfering with userland code. | ||
// TODO(bcoe): add support for source-maps to repl. | ||
if (overrideStackTrace.has(error)) { | ||
const f = overrideStackTrace.get(error); | ||
overrideStackTrace.delete(error); | ||
return f(error, trace); | ||
} | ||
|
||
const { SourceMap } = require('internal/source_map/source_map'); | ||
const errorString = ErrorToString.call(error); | ||
|
||
if (trace.length === 0) { | ||
return errorString; | ||
} | ||
const preparedTrace = trace.map((t, i) => { | ||
let str = i !== 0 ? '\n at ' : ''; | ||
str = `${str}${t}`; | ||
try { | ||
const sourceMap = findSourceMap(t.getFileName(), error); | ||
if (sourceMap && sourceMap.data) { | ||
const sm = new SourceMap(sourceMap.data); | ||
// Source Map V3 lines/columns use zero-based offsets whereas, in | ||
// stack traces, they start at 1/1. | ||
const [, , url, line, col] = | ||
sm.findEntry(t.getLineNumber() - 1, t.getColumnNumber() - 1); | ||
if (url && line !== undefined && col !== undefined) { | ||
str += | ||
`\n -> ${url.replace('file://', '')}:${line + 1}:${col + 1}`; | ||
} | ||
} | ||
} catch (err) { | ||
debug(err.stack); | ||
} | ||
return str; | ||
}); | ||
return `${errorString}\n at ${preparedTrace.join('')}`; | ||
}; | ||
|
||
// Attempt to lookup a source map, which is either attached to a file URI, or | ||
// keyed on an error instance. | ||
function findSourceMap(uri, error) { | ||
|
@@ -230,8 +203,8 @@ function findSourceMap(uri, error) { | |
} | ||
|
||
module.exports = { | ||
findSourceMap, | ||
maybeCacheSourceMap, | ||
prepareStackTrace, | ||
rekeySourceMap, | ||
sourceMapCacheToObject, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
I pulled
prepare_stack_trace.js
into its own file, because it seemed like it wasn't directly related to the source map caching functionality (andsource_map_cache.js
was starting to get a bit confusing).