Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbcoe <bencoe@google.com>2020-01-05 06:17:42 +0300
committerBenjamin Coe <bencoe@google.com>2020-01-14 23:39:06 +0300
commit521b2224c3b06de811f3d8353cce5e4a69239864 (patch)
tree74cdf8cdab9a256f19389e7185b0730ad2ed642d /lib/internal/source_map
parent2bb85b85c94465246841c8f4bcd73a6bec0917a6 (diff)
module: add API for interacting with source maps
PR-URL: https://github.com/nodejs/node/pull/31132 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'lib/internal/source_map')
-rw-r--r--lib/internal/source_map/prepare_stack_trace.js18
-rw-r--r--lib/internal/source_map/source_map.js72
-rw-r--r--lib/internal/source_map/source_map_cache.js12
3 files changed, 71 insertions, 31 deletions
diff --git a/lib/internal/source_map/prepare_stack_trace.js b/lib/internal/source_map/prepare_stack_trace.js
index df559b2cdfe..037a8dc53e0 100644
--- a/lib/internal/source_map/prepare_stack_trace.js
+++ b/lib/internal/source_map/prepare_stack_trace.js
@@ -29,7 +29,6 @@ const prepareStackTrace = (globalThis, error, trace) => {
maybeOverridePrepareStackTrace(globalThis, error, trace);
if (globalOverride !== kNoOverride) return globalOverride;
- const { SourceMap } = require('internal/source_map/source_map');
const errorString = ErrorToString.call(error);
if (trace.length === 0) {
@@ -39,16 +38,19 @@ const prepareStackTrace = (globalThis, error, trace) => {
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);
+ const sm = findSourceMap(t.getFileName(), error);
+ if (sm) {
// 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) {
+ const {
+ originalLine,
+ originalColumn,
+ originalSource
+ } = sm.findEntry(t.getLineNumber() - 1, t.getColumnNumber() - 1);
+ if (originalSource && originalLine !== undefined &&
+ originalColumn !== undefined) {
str +=
- `\n -> ${url.replace('file://', '')}:${line + 1}:${col + 1}`;
+`\n -> ${originalSource.replace('file://', '')}:${originalLine + 1}:${originalColumn + 1}`;
}
}
} catch (err) {
diff --git a/lib/internal/source_map/source_map.js b/lib/internal/source_map/source_map.js
index 9044521b6d6..32fe43ac8f6 100644
--- a/lib/internal/source_map/source_map.js
+++ b/lib/internal/source_map/source_map.js
@@ -66,6 +66,14 @@
'use strict';
+const {
+ Array
+} = primordials;
+
+const {
+ ERR_INVALID_ARG_TYPE
+} = require('internal/errors').codes;
+
let base64Map;
const VLQ_BASE_SHIFT = 5;
@@ -112,6 +120,7 @@ class StringCharIterator {
* @param {SourceMapV3} payload
*/
class SourceMap {
+ #payload;
#reverseMappingsBySourceURL = [];
#mappings = [];
#sources = {};
@@ -129,17 +138,25 @@ class SourceMap {
for (let i = 0; i < base64Digits.length; ++i)
base64Map[base64Digits[i]] = i;
}
- this.#parseMappingPayload(payload);
+ this.#payload = cloneSourceMapV3(payload);
+ this.#parseMappingPayload();
+ }
+
+ /**
+ * @return {Object} raw source map v3 payload.
+ */
+ get payload() {
+ return cloneSourceMapV3(this.#payload);
}
/**
* @param {SourceMapV3} mappingPayload
*/
- #parseMappingPayload = (mappingPayload) => {
- if (mappingPayload.sections)
- this.#parseSections(mappingPayload.sections);
+ #parseMappingPayload = () => {
+ if (this.#payload.sections)
+ this.#parseSections(this.#payload.sections);
else
- this.#parseMap(mappingPayload, 0, 0);
+ this.#parseMap(this.#payload, 0, 0);
}
/**
@@ -175,24 +192,18 @@ class SourceMap {
const entry = this.#mappings[first];
if (!first && entry && (lineNumber < entry[0] ||
(lineNumber === entry[0] && columnNumber < entry[1]))) {
- return null;
+ return {};
+ } else if (!entry) {
+ return {};
+ } else {
+ return {
+ generatedLine: entry[0],
+ generatedColumn: entry[1],
+ originalSource: entry[2],
+ originalLine: entry[3],
+ originalColumn: entry[4]
+ };
}
- return entry;
- }
-
- /**
- * @param {string} sourceURL of the originating resource
- * @param {number} lineNumber in the originating resource
- * @return {Array}
- */
- findEntryReversed(sourceURL, lineNumber) {
- const mappings = this.#reverseMappingsBySourceURL[sourceURL];
- for (; lineNumber < mappings.length; ++lineNumber) {
- const mapping = mappings[lineNumber];
- if (mapping)
- return mapping;
- }
- return this.#mappings[0];
}
/**
@@ -296,6 +307,23 @@ function decodeVLQ(stringCharIterator) {
return negative ? -result : result;
}
+/**
+ * @param {SourceMapV3} payload
+ * @return {SourceMapV3}
+ */
+function cloneSourceMapV3(payload) {
+ if (typeof payload !== 'object') {
+ throw new ERR_INVALID_ARG_TYPE('payload', ['Object'], payload);
+ }
+ payload = { ...payload };
+ for (const key in payload) {
+ if (payload.hasOwnProperty(key) && Array.isArray(payload[key])) {
+ payload[key] = payload[key].slice(0);
+ }
+ }
+ return payload;
+}
+
module.exports = {
SourceMap
};
diff --git a/lib/internal/source_map/source_map_cache.js b/lib/internal/source_map/source_map_cache.js
index 593c2c8277f..b64af7eed6e 100644
--- a/lib/internal/source_map/source_map_cache.js
+++ b/lib/internal/source_map/source_map_cache.js
@@ -37,6 +37,7 @@ const cjsSourceMapCache = new WeakMap();
const esmSourceMapCache = new Map();
const { fileURLToPath, URL } = require('url');
let Module;
+let SourceMap;
let experimentalSourceMaps;
function maybeCacheSourceMap(filename, content, cjsModuleInstance) {
@@ -222,8 +223,13 @@ function appendCJSCache(obj) {
// Attempt to lookup a source map, which is either attached to a file URI, or
// keyed on an error instance.
+// TODO(bcoe): once WeakRefs are available in Node.js, refactor to drop
+// requirement of error parameter.
function findSourceMap(uri, error) {
if (!Module) Module = require('internal/modules/cjs/loader').Module;
+ if (!SourceMap) {
+ SourceMap = require('internal/source_map/source_map').SourceMap;
+ }
let sourceMap = cjsSourceMapCache.get(Module._cache[uri]);
if (!uri.startsWith('file://')) uri = normalizeReferrerURL(uri);
if (sourceMap === undefined) {
@@ -235,7 +241,11 @@ function findSourceMap(uri, error) {
sourceMap = candidateSourceMap;
}
}
- return sourceMap;
+ if (sourceMap && sourceMap.data) {
+ return new SourceMap(sourceMap.data);
+ } else {
+ return undefined;
+ }
}
module.exports = {