mirror of https://github.com/nodejs/node.git
module: add SourceMap.findOrigin
This adds the `SourceMap.findOrigin(lineNumber, columnNumber)` method, for finding the origin source file and 1-indexed line and column numbers corresponding to the 1-indexed line and column numbers from a call site in generated source code. Fix: #47770 PR-URL: https://github.com/nodejs/node/pull/47790 Fixes: https://github.com/nodejs/node/issues/47770 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
This commit is contained in:
parent
e934003811
commit
e26ffe7358
|
@ -293,23 +293,67 @@ Creates a new `sourceMap` instance.
|
|||
|
||||
Getter for the payload used to construct the [`SourceMap`][] instance.
|
||||
|
||||
#### `sourceMap.findEntry(lineNumber, columnNumber)`
|
||||
#### `sourceMap.findEntry(lineOffset, columnOffset)`
|
||||
|
||||
* `lineNumber` {number}
|
||||
* `columnNumber` {number}
|
||||
* `lineOffset` {number} The zero-indexed line number offset in
|
||||
the generated source
|
||||
* `columnOffset` {number} The zero-indexed column number offset
|
||||
in the generated source
|
||||
* Returns: {Object}
|
||||
|
||||
Given a line number and column number in the generated source file, returns
|
||||
an object representing the position in the original file. The object returned
|
||||
consists of the following keys:
|
||||
Given a line offset and column offset in the generated source
|
||||
file, returns an object representing the SourceMap range in the
|
||||
original file if found, or an empty object if not.
|
||||
|
||||
* generatedLine: {number}
|
||||
* generatedColumn: {number}
|
||||
* originalSource: {string}
|
||||
* originalLine: {number}
|
||||
* originalColumn: {number}
|
||||
The object returned contains the following keys:
|
||||
|
||||
* generatedLine: {number} The line offset of the start of the
|
||||
range in the generated source
|
||||
* generatedColumn: {number} The column offset of start of the
|
||||
range in the generated source
|
||||
* originalSource: {string} The file name of the original source,
|
||||
as reported in the SourceMap
|
||||
* originalLine: {number} The line offset of the start of the
|
||||
range in the original source
|
||||
* originalColumn: {number} The column offset of start of the
|
||||
range in the original source
|
||||
* name: {string}
|
||||
|
||||
The returned value represents the raw range as it appears in the
|
||||
SourceMap, based on zero-indexed offsets, _not_ 1-indexed line and
|
||||
column numbers as they appear in Error messages and CallSite
|
||||
objects.
|
||||
|
||||
To get the corresponding 1-indexed line and column numbers from a
|
||||
lineNumber and columnNumber as they are reported by Error stacks
|
||||
and CallSite objects, use `sourceMap.findOrigin(lineNumber,
|
||||
columnNumber)`
|
||||
|
||||
#### `sourceMap.findOrigin(lineNumber, columnNumber)`
|
||||
|
||||
* `lineNumber` {number} The 1-indexed line number of the call
|
||||
site in the generated source
|
||||
* `columnOffset` {number} The 1-indexed column number
|
||||
of the call site in the generated source
|
||||
* Returns: {Object}
|
||||
|
||||
Given a 1-indexed lineNumber and columnNumber from a call site in
|
||||
the generated source, find the corresponding call site location
|
||||
in the original source.
|
||||
|
||||
If the lineNumber and columnNumber provided are not found in any
|
||||
source map, then an empty object is returned. Otherwise, the
|
||||
returned object contains the following keys:
|
||||
|
||||
* name: {string | undefined} The name of the range in the
|
||||
source map, if one was provided
|
||||
* fileName: {string} The file name of the original source, as
|
||||
reported in the SourceMap
|
||||
* lineNumber: {number} The 1-indexed lineNumber of the
|
||||
corresponding call site in the original source
|
||||
* columnNumber: {number} The 1-indexed columnNumber of the
|
||||
corresponding call site in the original source
|
||||
|
||||
[CommonJS]: modules.md
|
||||
[ES Modules]: esm.md
|
||||
[Source map v3 format]: https://sourcemaps.info/spec.html#h.mofvlxcwqzej
|
||||
|
|
|
@ -169,19 +169,19 @@ class SourceMap {
|
|||
};
|
||||
|
||||
/**
|
||||
* @param {number} lineNumber in compiled resource
|
||||
* @param {number} columnNumber in compiled resource
|
||||
* @return {?Array}
|
||||
* @param {number} lineOffset 0-indexed line offset in compiled resource
|
||||
* @param {number} columnOffset 0-indexed column offset in compiled resource
|
||||
* @return {object} representing start of range if found, or empty object
|
||||
*/
|
||||
findEntry(lineNumber, columnNumber) {
|
||||
findEntry(lineOffset, columnOffset) {
|
||||
let first = 0;
|
||||
let count = this.#mappings.length;
|
||||
while (count > 1) {
|
||||
const step = count >> 1;
|
||||
const middle = first + step;
|
||||
const mapping = this.#mappings[middle];
|
||||
if (lineNumber < mapping[0] ||
|
||||
(lineNumber === mapping[0] && columnNumber < mapping[1])) {
|
||||
if (lineOffset < mapping[0] ||
|
||||
(lineOffset === mapping[0] && columnOffset < mapping[1])) {
|
||||
count = step;
|
||||
} else {
|
||||
first = middle;
|
||||
|
@ -189,8 +189,8 @@ class SourceMap {
|
|||
}
|
||||
}
|
||||
const entry = this.#mappings[first];
|
||||
if (!first && entry && (lineNumber < entry[0] ||
|
||||
(lineNumber === entry[0] && columnNumber < entry[1]))) {
|
||||
if (!first && entry && (lineOffset < entry[0] ||
|
||||
(lineOffset === entry[0] && columnOffset < entry[1]))) {
|
||||
return {};
|
||||
} else if (!entry) {
|
||||
return {};
|
||||
|
@ -205,6 +205,32 @@ class SourceMap {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} lineNumber 1-indexed line number in compiled resource call site
|
||||
* @param {number} columnNumber 1-indexed column number in compiled resource call site
|
||||
* @return {object} representing origin call site if found, or empty object
|
||||
*/
|
||||
findOrigin(lineNumber, columnNumber) {
|
||||
const range = this.findEntry(lineNumber - 1, columnNumber - 1);
|
||||
if (
|
||||
range.originalSource === undefined ||
|
||||
range.originalLine === undefined ||
|
||||
range.originalColumn === undefined ||
|
||||
range.generatedLine === undefined ||
|
||||
range.generatedColumn === undefined
|
||||
) {
|
||||
return {};
|
||||
}
|
||||
const lineOffset = lineNumber - range.generatedLine;
|
||||
const columnOffset = columnNumber - range.generatedColumn;
|
||||
return {
|
||||
name: range.name,
|
||||
fileName: range.originalSource,
|
||||
lineNumber: range.originalLine + lineOffset,
|
||||
columnNumber: range.originalColumn + columnOffset,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
|
|
|
@ -49,6 +49,14 @@ const { readFileSync } = require('fs');
|
|||
assert.strictEqual(originalLine, 2);
|
||||
assert.strictEqual(originalColumn, 4);
|
||||
assert(originalSource.endsWith('disk.js'));
|
||||
const {
|
||||
fileName,
|
||||
lineNumber,
|
||||
columnNumber,
|
||||
} = sourceMap.findOrigin(1, 30);
|
||||
assert.strictEqual(fileName, originalSource);
|
||||
assert.strictEqual(lineNumber, 3);
|
||||
assert.strictEqual(columnNumber, 6);
|
||||
}
|
||||
|
||||
// findSourceMap() can be used in Error.prepareStackTrace() to lookup
|
||||
|
@ -89,6 +97,18 @@ const { readFileSync } = require('fs');
|
|||
assert.strictEqual(originalLine, 17);
|
||||
assert.strictEqual(originalColumn, 10);
|
||||
assert(originalSource.endsWith('typescript-throw.ts'));
|
||||
|
||||
const {
|
||||
fileName,
|
||||
lineNumber,
|
||||
columnNumber,
|
||||
} = sourceMap.findOrigin(
|
||||
callSite.getLineNumber(),
|
||||
callSite.getColumnNumber()
|
||||
);
|
||||
assert.strictEqual(fileName, originalSource);
|
||||
assert.strictEqual(lineNumber, 18);
|
||||
assert.strictEqual(columnNumber, 11);
|
||||
}
|
||||
|
||||
// SourceMap can be instantiated with Source Map V3 object as payload.
|
||||
|
@ -112,8 +132,8 @@ const { readFileSync } = require('fs');
|
|||
assert.notStrictEqual(payload.sources, sourceMap.payload.sources);
|
||||
}
|
||||
|
||||
// findEntry() must return empty object instead error when
|
||||
// receive a malformed mappings.
|
||||
// findEntry() and findOrigin() must return empty object instead of
|
||||
// error when receiving a malformed mappings.
|
||||
{
|
||||
const payload = JSON.parse(readFileSync(
|
||||
require.resolve('../fixtures/source-map/disk.map'), 'utf8'
|
||||
|
@ -124,6 +144,9 @@ const { readFileSync } = require('fs');
|
|||
const result = sourceMap.findEntry(0, 5);
|
||||
assert.strictEqual(typeof result, 'object');
|
||||
assert.strictEqual(Object.keys(result).length, 0);
|
||||
const origin = sourceMap.findOrigin(0, 5);
|
||||
assert.strictEqual(typeof origin, 'object');
|
||||
assert.strictEqual(Object.keys(origin).length, 0);
|
||||
}
|
||||
|
||||
// SourceMap can be instantiated with Index Source Map V3 object as payload.
|
||||
|
|
Loading…
Reference in New Issue