Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 36.4k
process: add lineLength to source-map-cache#29863
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| 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, | ||
| }; | ||
| 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; | ||
ContributorAuthor 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.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| // 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, | ||
| }; | ||
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.jsinto its own file, because it seemed like it wasn't directly related to the source map caching functionality (andsource_map_cache.jswas starting to get a bit confusing).