summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorbcoe <bencoe@google.com>2019-10-06 11:37:42 -0700
committerRich Trott <rtrott@gmail.com>2019-10-13 18:58:21 -0700
commit4ca61f40fed31d590e4d624551044fe7cc7efd42 (patch)
tree8bb59868ac3566ae37e0146578535ad042978790 /lib
parentf8f6a21580544146d5a8527333e1130b336dc094 (diff)
downloadandroid-node-v8-4ca61f40fed31d590e4d624551044fe7cc7efd42.tar.gz
android-node-v8-4ca61f40fed31d590e4d624551044fe7cc7efd42.tar.bz2
android-node-v8-4ca61f40fed31d590e4d624551044fe7cc7efd42.zip
process: add lineLength to source-map-cache
Without the line lengths of in-memory transpiled source, it's not possible to convert from byte ofsets to line/column offsets. PR-URL: https://github.com/nodejs/node/pull/29863 Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: David Carlier <devnexen@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/internal/bootstrap/pre_execution.js2
-rw-r--r--lib/internal/source_map/prepare_stack_trace.js52
-rw-r--r--lib/internal/source_map/source_map_cache.js75
3 files changed, 77 insertions, 52 deletions
diff --git a/lib/internal/bootstrap/pre_execution.js b/lib/internal/bootstrap/pre_execution.js
index c1636d87f4..1126fbcdd7 100644
--- a/lib/internal/bootstrap/pre_execution.js
+++ b/lib/internal/bootstrap/pre_execution.js
@@ -25,7 +25,7 @@ function prepareMainThreadExecution(expandArgv1 = false) {
// prepareStackTrace method, replacing the default in errors.js.
if (getOptionValue('--enable-source-maps')) {
const { prepareStackTrace } =
- require('internal/source_map/source_map_cache');
+ require('internal/source_map/prepare_stack_trace');
const { setPrepareStackTraceCallback } = internalBinding('errors');
setPrepareStackTraceCallback(prepareStackTrace);
}
diff --git a/lib/internal/source_map/prepare_stack_trace.js b/lib/internal/source_map/prepare_stack_trace.js
new file mode 100644
index 0000000000..d6c5fce60a
--- /dev/null
+++ b/lib/internal/source_map/prepare_stack_trace.js
@@ -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,
+};
diff --git a/lib/internal/source_map/source_map_cache.js b/lib/internal/source_map/source_map_cache.js
index 94a4165546..0e77203e9d 100644
--- a/lib/internal/source_map/source_map_cache.js
+++ b/lib/internal/source_map/source_map_cache.js
@@ -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;
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) {
+ // 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,
};