metro-symbolicate
Advanced tools
Comparing version 0.73.3 to 0.73.5
{ | ||
"name": "metro-symbolicate", | ||
"version": "0.73.3", | ||
"version": "0.73.5", | ||
"description": "🚇 A tool to find the source location from JS bundles and stack traces.", | ||
@@ -24,3 +24,3 @@ "license": "MIT", | ||
"invariant": "^2.2.4", | ||
"metro-source-map": "0.73.3", | ||
"metro-source-map": "0.73.5", | ||
"nullthrows": "^1.1.1", | ||
@@ -27,0 +27,0 @@ "source-map": "^0.5.6", |
@@ -11,10 +11,12 @@ /** | ||
*/ | ||
"use strict"; | ||
const invariant = require("invariant"); | ||
// The snapshot metadata doesn't have a type describing the `children` field | ||
// of `trace_tree`, but modeling it as a type works really well. So we make up | ||
// our own name for it and use that internally. | ||
const CHILDREN_FIELD_TYPE = "__CHILDREN__"; // An adapter for reading and mutating a Chrome heap snapshot in-place, | ||
const CHILDREN_FIELD_TYPE = "__CHILDREN__"; | ||
// An adapter for reading and mutating a Chrome heap snapshot in-place, | ||
// including safely decoding and encoding fields that point into the global | ||
@@ -25,7 +27,8 @@ // string table and into enum types. | ||
// the format leaves us no other choice). | ||
class ChromeHeapSnapshotProcessor { | ||
// The raw snapshot data provided to this processor. Mutable. | ||
// An adapter for the global string table in the raw snapshot data. | ||
// This is shared across all the iterators we will create. | ||
constructor(snapshotData) { | ||
@@ -37,5 +40,5 @@ this._snapshotData = snapshotData; | ||
} | ||
traceFunctionInfos() { | ||
return new ChromeHeapSnapshotRecordIterator( // Flow is being conservative here, but we'll never change a number into RawBuffer or vice versa. | ||
return new ChromeHeapSnapshotRecordIterator( | ||
// Flow is being conservative here, but we'll never change a number into RawBuffer or vice versa. | ||
// $FlowIgnore[incompatible-call] | ||
@@ -49,4 +52,3 @@ this._snapshotData.trace_function_infos, | ||
this._globalStringTable, | ||
undefined | ||
/* start position */ | ||
undefined /* start position */ | ||
); | ||
@@ -56,3 +58,4 @@ } | ||
locations() { | ||
return new ChromeHeapSnapshotRecordIterator( // Flow is being conservative here, but we'll never change a number into RawBuffer or vice versa. | ||
return new ChromeHeapSnapshotRecordIterator( | ||
// Flow is being conservative here, but we'll never change a number into RawBuffer or vice versa. | ||
// $FlowIgnore[incompatible-call] | ||
@@ -63,4 +66,3 @@ this._snapshotData.locations, | ||
this._globalStringTable, | ||
undefined | ||
/* start position */ | ||
undefined /* start position */ | ||
); | ||
@@ -70,3 +72,4 @@ } | ||
nodes() { | ||
return new ChromeHeapSnapshotRecordIterator( // Flow is being conservative here, but we'll never change a number into RawBuffer or vice versa. | ||
return new ChromeHeapSnapshotRecordIterator( | ||
// Flow is being conservative here, but we'll never change a number into RawBuffer or vice versa. | ||
// $FlowIgnore[incompatible-call] | ||
@@ -77,4 +80,3 @@ this._snapshotData.nodes, | ||
this._globalStringTable, | ||
undefined | ||
/* start position */ | ||
undefined /* start position */ | ||
); | ||
@@ -84,3 +86,4 @@ } | ||
edges() { | ||
return new ChromeHeapSnapshotRecordIterator( // Flow is being conservative here, but we'll never change a number into RawBuffer or vice versa. | ||
return new ChromeHeapSnapshotRecordIterator( | ||
// Flow is being conservative here, but we'll never change a number into RawBuffer or vice versa. | ||
// $FlowIgnore[incompatible-call] | ||
@@ -91,4 +94,3 @@ this._snapshotData.edges, | ||
this._globalStringTable, | ||
undefined | ||
/* start position */ | ||
undefined /* start position */ | ||
); | ||
@@ -105,7 +107,8 @@ } | ||
this._globalStringTable, | ||
undefined | ||
/* start position */ | ||
undefined /* start position */ | ||
); | ||
} | ||
} // An uniquing adapter for the heap snapshot's string table that allows | ||
} | ||
// An uniquing adapter for the heap snapshot's string table that allows | ||
// retrieving and adding strings. | ||
@@ -118,28 +121,24 @@ // | ||
// copied / replaced with a new array in its containing object. | ||
class ChromeHeapSnapshotStringTable { | ||
constructor(strings) { | ||
this._strings = strings; | ||
this._indexCache = new Map(); // NOTE: _indexCache is lazily initialised in _syncIndexCache. | ||
} // Looks up a string in the string table, adds it if necessary, and returns | ||
this._indexCache = new Map(); | ||
// NOTE: _indexCache is lazily initialised in _syncIndexCache. | ||
} | ||
// Looks up a string in the string table, adds it if necessary, and returns | ||
// its index. | ||
add(value) { | ||
this._syncIndexCache(); | ||
let index = this._indexCache.get(value); | ||
if (index != null) { | ||
return index; | ||
} | ||
index = this._strings.length; | ||
this._strings.push(value); | ||
this._indexCache.set(value, index); | ||
return index; | ||
} // Retrieve the string at the given index. | ||
} | ||
// Retrieve the string at the given index. | ||
get(index) { | ||
@@ -151,4 +150,5 @@ invariant( | ||
return this._strings[index]; | ||
} // Indexes the string table for fast lookup. | ||
} | ||
// Indexes the string table for fast lookup. | ||
_syncIndexCache() { | ||
@@ -168,3 +168,2 @@ // Because we only grow the string table and we assume it's unique to begin | ||
} | ||
// A cursor pointing to a record-aligned position in a 1D array of N records | ||
@@ -183,10 +182,16 @@ // each with K fields in a fixed order. Supports encoding/decoding field values | ||
// (optional). These are shared with any child iterators. | ||
// The number of fields in every record (i.e. K). | ||
// The raw buffer. Mutable. | ||
// The global string table. Mutable in the ways allowed by the string table | ||
// class. | ||
// The current position in the raw buffer. | ||
constructor( | ||
buffer, | ||
recordFields, // recordTypes can be: | ||
recordFields, | ||
// recordTypes can be: | ||
// 1. An array: Field types as described in the snapshot itself, e.g. | ||
@@ -215,7 +220,7 @@ // node_types, edge_types. | ||
); | ||
if (Array.isArray(recordTypes)) { | ||
this._fieldToType = new Map( | ||
Object.entries(recordTypes).map(([offsetStr, type]) => [ | ||
recordFields[Number(offsetStr)], // $FlowIssue[incompatible-call] Object.entries is incompletely typed | ||
recordFields[Number(offsetStr)], | ||
// $FlowIssue[incompatible-call] Object.entries is incompletely typed | ||
type, | ||
@@ -229,3 +234,2 @@ ]) | ||
} | ||
this._buffer = buffer; | ||
@@ -243,3 +247,5 @@ this._position = position; | ||
} | ||
/** Public API */ | ||
// Reads a scalar string or enum value from the given field. | ||
@@ -249,36 +255,30 @@ // It's an error to read a number (or other non-string) field as a string. | ||
// be read using this method. | ||
getString(field) { | ||
const dynamicValue = this._getScalar(field); | ||
if (typeof dynamicValue === "string") { | ||
return dynamicValue; | ||
} | ||
throw new Error("Not a string or enum field: " + field); | ||
} | ||
throw new Error("Not a string or enum field: " + field); | ||
} // Reads a scalar numeric value from the given field. | ||
// Reads a scalar numeric value from the given field. | ||
// It's an error to read a string (or other non-number) field as a number. | ||
// NOTE: The type "string_or_number" is always treated as a number. | ||
getNumber(field) { | ||
const dynamicValue = this._getScalar(field); | ||
if (typeof dynamicValue === "number") { | ||
return dynamicValue; | ||
} | ||
throw new Error("Not a number field: " + field); | ||
} | ||
throw new Error("Not a number field: " + field); | ||
} // Returns an iterator over the children of this record that are stored in | ||
// Returns an iterator over the children of this record that are stored in | ||
// the given field (typically 'children'). Children conform to the same | ||
// schema as the current record. | ||
getChildren(field) { | ||
const fieldType = this._fieldToType.get(field); | ||
if (fieldType !== CHILDREN_FIELD_TYPE) { | ||
throw new Error("Not a children field: " + field); | ||
} | ||
const childrenBuffer = this._getRaw(field); | ||
invariant( | ||
@@ -290,10 +290,13 @@ Array.isArray(childrenBuffer), | ||
childrenBuffer, | ||
[], // recordFields ignored when there's a parent | ||
null, // recordTypes ignored when there's a parent | ||
[], | ||
// recordFields ignored when there's a parent | ||
null, | ||
// recordTypes ignored when there's a parent | ||
this._globalStringTable, | ||
-this._fieldToOffset.size, | ||
/* start position */ | ||
-this._fieldToOffset.size /* start position */, | ||
this | ||
); | ||
} // Writes a scalar string or enum value into the given field, updating the | ||
} | ||
// Writes a scalar string or enum value into the given field, updating the | ||
// global string table as needed. | ||
@@ -305,12 +308,11 @@ // It's an error to write anything other than a string into a string or enum | ||
// be written using this method. | ||
setString(field, value) { | ||
this._setRaw(field, this._encodeString(field, value)); | ||
} // Writes a scalar numeric value into the given field. | ||
} | ||
// Writes a scalar numeric value into the given field. | ||
// It's an error to write anything other than a number into a numeric field. | ||
// NOTE: The type "string_or_number" is always treated as a number. | ||
setNumber(field, value) { | ||
const fieldType = this._fieldToType.get(field); | ||
if ( | ||
@@ -323,10 +325,12 @@ Array.isArray(fieldType) || | ||
} | ||
this._setRaw(field, value); | ||
} | ||
this._setRaw(field, value); | ||
} // Moves the cursor to a given index in the buffer (expressed in # of | ||
// Moves the cursor to a given index in the buffer (expressed in # of | ||
// records, NOT fields). | ||
moveToRecord(recordIndex) { | ||
this._moveToPosition(recordIndex * this._recordSize); | ||
} // Appends a new record at the end of the buffer. | ||
} | ||
// Appends a new record at the end of the buffer. | ||
// | ||
@@ -337,6 +341,4 @@ // Returns the index of the appended record. All fields must be specified and | ||
// (or throws). | ||
append(record) { | ||
const savedPosition = this._position; | ||
try { | ||
@@ -347,3 +349,5 @@ return this.moveAndInsert(this._buffer.length / this._recordSize, record); | ||
} | ||
} // Moves the cursor to a given index in the buffer (expressed in # of | ||
} | ||
// Moves the cursor to a given index in the buffer (expressed in # of | ||
// records, NOT fields) and inserts a record. | ||
@@ -359,12 +363,5 @@ // | ||
// edge.to_node -> node position, cumulative node.edge_count -> edge indices). | ||
moveAndInsert(recordIndex, record) { | ||
this._moveToPosition( | ||
recordIndex * this._recordSize, | ||
/* allowEnd */ | ||
true | ||
); | ||
this._moveToPosition(recordIndex * this._recordSize, /* allowEnd */ true); | ||
let didResizeBuffer = false; | ||
try { | ||
@@ -377,11 +374,7 @@ for (const field of this._fieldToOffset.keys()) { | ||
} | ||
this._buffer.splice(this._position, 0, ...new Array(this._recordSize)); | ||
didResizeBuffer = true; | ||
for (const field of Object.keys(record)) { | ||
this._set(field, record[field]); | ||
} | ||
return this._position / this._recordSize; | ||
@@ -393,10 +386,10 @@ } catch (e) { | ||
} | ||
throw e; | ||
} | ||
} | ||
/** "Protected" methods (please don't use) */ | ||
// Return true if we can advance the position by one record (including from | ||
// the last record to the "end" position). | ||
protectedHasNext() { | ||
@@ -407,6 +400,6 @@ if (this._position < 0) { | ||
} | ||
return this._position < this._buffer.length; | ||
} // Move to the next record (or the end) if we're not already at the end. | ||
} | ||
// Move to the next record (or the end) if we're not already at the end. | ||
protectedTryMoveNext() { | ||
@@ -416,31 +409,26 @@ if (this.protectedHasNext()) { | ||
this._position + this._recordSize, | ||
/* allowEnd */ | ||
true | ||
/* allowEnd */ true | ||
); | ||
} | ||
} | ||
/** Private methods */ | ||
// Reads the raw numeric value of a field. | ||
_getRaw(field) { | ||
this._validatePosition(); | ||
const offset = this._fieldToOffset.get(field); | ||
if (offset == null) { | ||
throw new Error("Unknown field: " + field); | ||
} | ||
return this._buffer[this._position + offset]; | ||
} // Decodes a scalar (string or number) field. | ||
} | ||
// Decodes a scalar (string or number) field. | ||
_getScalar(field) { | ||
const rawValue = this._getRaw(field); | ||
if (Array.isArray(rawValue)) { | ||
throw new Error("Not a scalar field: " + field); | ||
} | ||
const fieldType = this._fieldToType.get(field); | ||
if (Array.isArray(fieldType)) { | ||
@@ -453,23 +441,20 @@ invariant( | ||
} | ||
if (fieldType === "string") { | ||
return this._globalStringTable.get(rawValue); | ||
} | ||
return rawValue; | ||
} // Writes the raw value of a field. | ||
} | ||
// Writes the raw value of a field. | ||
_setRaw(field, rawValue) { | ||
this._validatePosition(); | ||
const offset = this._fieldToOffset.get(field); | ||
if (offset == null) { | ||
throw new Error("Unknown field: " + field); | ||
} | ||
this._buffer[this._position + offset] = rawValue; | ||
} | ||
this._buffer[this._position + offset] = rawValue; | ||
} // Writes a scalar or children value to `field`, inferring the intended type | ||
// Writes a scalar or children value to `field`, inferring the intended type | ||
// based on the runtime type of `value`. | ||
_set(field, value) { | ||
@@ -485,25 +470,22 @@ if (typeof value === "string") { | ||
} | ||
} // Writes a children array to `field` by appending each element of `value` to | ||
} | ||
// Writes a children array to `field` by appending each element of `value` to | ||
// a new buffer using `append()`s semantics. | ||
_setChildren(field, value) { | ||
const fieldType = this._fieldToType.get(field); | ||
if (fieldType !== CHILDREN_FIELD_TYPE) { | ||
throw new Error("Not a children field: " + field); | ||
} | ||
this._setRaw(field, []); | ||
const childIt = this.getChildren(field); | ||
for (const child of value) { | ||
childIt.append(child); | ||
} | ||
} // Encodes a string value according to its field schema. | ||
} | ||
// Encodes a string value according to its field schema. | ||
// The global string table may be updated as a side effect. | ||
_encodeString(field, value) { | ||
const fieldType = this._fieldToType.get(field); | ||
if (Array.isArray(fieldType)) { | ||
@@ -514,12 +496,11 @@ const index = fieldType.indexOf(value); | ||
} | ||
if (fieldType === "string") { | ||
return this._globalStringTable.add(value); | ||
} | ||
throw new Error("Not a string or enum field: " + field); | ||
} | ||
throw new Error("Not a string or enum field: " + field); | ||
} // Asserts that the given position (default: the current position) is either | ||
// Asserts that the given position (default: the current position) is either | ||
// a valid position for reading a record, or (if allowEnd is true) the end of | ||
// the buffer. | ||
_validatePosition(allowEnd = false, position = this._position) { | ||
@@ -529,3 +510,2 @@ if (!Number.isInteger(position)) { | ||
} | ||
if (position % this._recordSize !== 0) { | ||
@@ -536,15 +516,11 @@ throw new Error( | ||
} | ||
if (position < 0) { | ||
throw new Error(`Position ${position} is out of range`); | ||
} | ||
const maxPosition = allowEnd | ||
? this._buffer.length | ||
: this._buffer.length - 1; | ||
if (position > maxPosition) { | ||
throw new Error(`Position ${position} is out of range`); | ||
} | ||
if (this._buffer.length - position < this._recordSize) { | ||
@@ -559,11 +535,12 @@ if (!(allowEnd && this._buffer.length === position)) { | ||
} | ||
} // Move to the given position or throw an error if it is invalid. | ||
} | ||
// Move to the given position or throw an error if it is invalid. | ||
_moveToPosition(nextPosition, allowEnd = false) { | ||
this._validatePosition(allowEnd, nextPosition); | ||
this._position = nextPosition; | ||
} | ||
} // $FlowIssue[prop-missing] Flow doesn't see that we implement the iteration protocol | ||
} | ||
// $FlowIssue[prop-missing] Flow doesn't see that we implement the iteration protocol | ||
class ChromeHeapSnapshotRecordIterator extends ChromeHeapSnapshotRecordAccessor { | ||
@@ -574,3 +551,4 @@ constructor( | ||
recordTypes, | ||
globalStringTable, // Initialise to "before the first iteration". | ||
globalStringTable, | ||
// Initialise to "before the first iteration". | ||
// The Accessor constructor intentionally checks only alignment, not range, | ||
@@ -590,4 +568,5 @@ // so this works as long as we don't try to read/write (at which point | ||
); | ||
} // JS Iterator protocol | ||
} | ||
// JS Iterator protocol | ||
next() { | ||
@@ -599,5 +578,6 @@ this.protectedTryMoveNext(); | ||
}; | ||
} // JS Iterable protocol | ||
} | ||
// JS Iterable protocol | ||
// $FlowIssue[unsupported-syntax] | ||
[Symbol.iterator]() { | ||
@@ -607,5 +587,4 @@ return this; | ||
} | ||
module.exports = { | ||
ChromeHeapSnapshotProcessor, | ||
}; |
#!/usr/bin/env node | ||
/** | ||
@@ -4,0 +3,0 @@ * Copyright (c) Meta Platforms, Inc. and affiliates. |
@@ -11,10 +11,8 @@ /** | ||
*/ | ||
"use strict"; | ||
const { normalizeSourcePath } = require("metro-source-map"); | ||
const vlq = require("vlq"); | ||
const METADATA_FIELD_FUNCTIONS = 0; | ||
/** | ||
@@ -40,3 +38,2 @@ * Consumes the `x_facebook_sources` metadata field from a source map and | ||
} | ||
/** | ||
@@ -53,3 +50,2 @@ * Retrieves a human-readable name for the function enclosing a particular | ||
const mappings = this._getFunctionMappings(source); | ||
if (mappings) { | ||
@@ -60,3 +56,2 @@ const mapping = findEnclosingMapping(mappings, { | ||
}); | ||
if (mapping) { | ||
@@ -67,5 +62,5 @@ return mapping.name; | ||
} | ||
return null; | ||
} | ||
/** | ||
@@ -78,18 +73,14 @@ * Returns this map's source metadata as a new array with the same order as | ||
*/ | ||
toArray(sources) { | ||
const metadataBySource = this._getMetadataBySource(); | ||
const encoded = []; | ||
for (const source of sources) { | ||
encoded.push(metadataBySource[source] || null); | ||
} | ||
return encoded; | ||
} | ||
/** | ||
* Prepares and caches a lookup table of metadata by source name. | ||
*/ | ||
_getMetadataBySource() { | ||
@@ -101,5 +92,5 @@ if (!this._metadataBySource) { | ||
} | ||
return this._metadataBySource; | ||
} | ||
/** | ||
@@ -109,3 +100,2 @@ * Decodes the function name mappings for the given source if needed, and | ||
*/ | ||
_getFunctionMappings(source) { | ||
@@ -115,7 +105,5 @@ if (this._decodedFunctionMapCache.has(source)) { | ||
} | ||
let parsedFunctionMap = null; | ||
const metadataBySource = this._getMetadataBySource(); // $FlowFixMe[method-unbinding] added when improving typing for this parameters | ||
const metadataBySource = this._getMetadataBySource(); | ||
// $FlowFixMe[method-unbinding] added when improving typing for this parameters | ||
if (Object.prototype.hasOwnProperty.call(metadataBySource, source)) { | ||
@@ -125,7 +113,6 @@ const metadata = metadataBySource[source] || []; | ||
} | ||
this._decodedFunctionMapCache.set(source, parsedFunctionMap); | ||
return parsedFunctionMap; | ||
} | ||
/** | ||
@@ -140,3 +127,2 @@ * Collects source metadata from the given map using the current source name | ||
*/ | ||
_getMetadataObjectsBySourceNames(map) { | ||
@@ -153,3 +139,2 @@ // eslint-disable-next-line lint/strictly-null | ||
} | ||
if ("x_facebook_sources" in map) { | ||
@@ -160,3 +145,2 @@ const basicMap = map; | ||
let source = basicMap.sources[index]; | ||
if (source != null) { | ||
@@ -166,3 +150,2 @@ source = this._normalizeSource(source, basicMap); | ||
} | ||
return acc; | ||
@@ -173,7 +156,5 @@ }, | ||
} | ||
return {}; | ||
} | ||
} | ||
function decodeFunctionMap(functionMap) { | ||
@@ -183,10 +164,7 @@ if (!functionMap) { | ||
} | ||
const parsed = []; | ||
let line = 1; | ||
let nameIndex = 0; | ||
for (const lineMappings of functionMap.mappings.split(";")) { | ||
let column = 0; | ||
for (const mapping of lineMappings.split(",")) { | ||
@@ -204,6 +182,4 @@ const [columnDelta, nameDelta, lineDelta = 0] = vlq.decode(mapping); | ||
} | ||
return parsed; | ||
} | ||
function findEnclosingMapping(mappings, target) { | ||
@@ -214,3 +190,2 @@ let first = 0; | ||
let step; | ||
while (count > 0) { | ||
@@ -220,3 +195,2 @@ it = first; | ||
it += step; | ||
if (comparePositions(target, mappings[it]) >= 0) { | ||
@@ -229,6 +203,4 @@ first = ++it; | ||
} | ||
return first ? mappings[first - 1] : null; | ||
} | ||
function comparePositions(a, b) { | ||
@@ -238,6 +210,4 @@ if (a.line === b.line) { | ||
} | ||
return a.line - b.line; | ||
} | ||
module.exports = SourceMetadataMapConsumer; |
@@ -11,2 +11,3 @@ /** | ||
*/ | ||
// Symbolicates a JavaScript stack trace using a source map. | ||
@@ -19,12 +20,11 @@ // In our first form, we read a stack trace from stdin and symbolicate it via | ||
// optionally a column. | ||
"use strict"; | ||
const Symbolication = require("./Symbolication.js"); | ||
const fs = require("fs"); // flowlint-next-line untyped-import:off | ||
const SourceMapConsumer = require("source-map").SourceMapConsumer; // flowlint-next-line untyped-import:off | ||
const fs = require("fs"); | ||
// flowlint-next-line untyped-import:off | ||
const SourceMapConsumer = require("source-map").SourceMapConsumer; | ||
// flowlint-next-line untyped-import:off | ||
const through2 = require("through2"); | ||
function printHelp() { | ||
@@ -51,12 +51,14 @@ const usages = [ | ||
} | ||
async function main( | ||
argvInput = process.argv.slice(2), // prettier-ignore | ||
{ stdin, stderr, stdout } = process | ||
argvInput = process.argv.slice(2), | ||
// prettier-ignore | ||
{ | ||
stdin, | ||
stderr, | ||
stdout | ||
} = process | ||
) { | ||
const argv = argvInput.slice(); | ||
function checkAndRemoveArg(arg, valuesPerArg = 0) { | ||
let values = null; | ||
for (let idx = argv.indexOf(arg); idx !== -1; idx = argv.indexOf(arg)) { | ||
@@ -67,6 +69,4 @@ argv.splice(idx, 1); | ||
} | ||
return values; | ||
} | ||
function checkAndRemoveArgWithValue(arg) { | ||
@@ -76,3 +76,2 @@ const values = checkAndRemoveArg(arg, 1); | ||
} | ||
try { | ||
@@ -98,3 +97,2 @@ const noFunctionNames = checkAndRemoveArg("--no-function-names"); | ||
); | ||
if (argv.length < 1 || argv.length > 4) { | ||
@@ -105,3 +103,2 @@ /* eslint no-path-concat: "off" */ | ||
} | ||
if (isHermesCrash && isCoverage) { | ||
@@ -113,4 +110,5 @@ console.error( | ||
return 1; | ||
} // Read the source map. | ||
} | ||
// Read the source map. | ||
const sourceMapFileName = argv.shift(); | ||
@@ -125,3 +123,2 @@ const options = { | ||
let context; | ||
if (fs.lstatSync(sourceMapFileName).isDirectory()) { | ||
@@ -141,6 +138,4 @@ context = Symbolication.unstable_createDirectoryContext( | ||
} | ||
if (argv.length === 0) { | ||
const stackTrace = await readAll(stdin); | ||
if (isHermesCrash) { | ||
@@ -181,7 +176,5 @@ const stackTraceJSON = JSON.parse(stackTrace); | ||
const lines = buffer.split("\n"); | ||
for (let i = 0, e = lines.length - 1; i < e; i++) { | ||
this.push(lines[i]); | ||
} | ||
buffer = lines[lines.length - 1]; | ||
@@ -212,6 +205,4 @@ callback(); | ||
var _original$source, _original$line, _original$name; | ||
// read-from-argv form. | ||
let moduleIds; | ||
if (argv[0].endsWith(".js")) { | ||
@@ -223,3 +214,2 @@ moduleIds = context.parseFileName(argv[0]); | ||
} | ||
const lineNumber = argv.shift(); | ||
@@ -229,3 +219,4 @@ const columnNumber = argv.shift() || 0; | ||
+lineNumber, | ||
+columnNumber, // $FlowFixMe context is a union here and so this parameter is a union | ||
+columnNumber, | ||
// $FlowFixMe context is a union here and so this parameter is a union | ||
moduleIds | ||
@@ -252,10 +243,7 @@ ); | ||
} | ||
return 0; | ||
} | ||
function readAll(stream) { | ||
return new Promise((resolve) => { | ||
let data = ""; | ||
if (stream.isTTY === true) { | ||
@@ -265,7 +253,6 @@ resolve(data); | ||
} | ||
stream.setEncoding("utf8"); | ||
stream.on("readable", () => { | ||
let chunk; // flowlint-next-line sketchy-null-string:off | ||
let chunk; | ||
// flowlint-next-line sketchy-null-string:off | ||
while ((chunk = stream.read())) { | ||
@@ -280,3 +267,2 @@ data += chunk.toString(); | ||
} | ||
function waitForStream(stream) { | ||
@@ -287,3 +273,2 @@ return new Promise((resolve) => { | ||
} | ||
module.exports = main; |
@@ -13,15 +13,11 @@ "use strict"; | ||
*/ | ||
// flowlint-next-line untyped-type-import:off | ||
const { ChromeHeapSnapshotProcessor } = require("./ChromeHeapSnapshot"); | ||
const SourceMetadataMapConsumer = require("./SourceMetadataMapConsumer"); | ||
const fs = require("fs"); | ||
const invariant = require("invariant"); | ||
const nullthrows = require("nullthrows"); | ||
const path = require("path"); | ||
const UNKNOWN_MODULE_IDS = { | ||
@@ -31,3 +27,2 @@ segmentId: 0, | ||
}; | ||
class SymbolicationContext { | ||
@@ -42,3 +37,2 @@ constructor(options) { | ||
}; | ||
if (options) { | ||
@@ -55,3 +49,2 @@ for (const option of [ | ||
} | ||
if (options.nameSource != null) { | ||
@@ -62,3 +55,5 @@ // $FlowFixMe[cannot-write] | ||
} | ||
} // parse stack trace with String.replace | ||
} | ||
// parse stack trace with String.replace | ||
// replace the matched part of stack trace to symbolicated result | ||
@@ -73,3 +68,2 @@ // sample stack trace: | ||
// IOS: foo.js:57:foo, Android: bar.js:75:bar | ||
symbolicate(stackTrace) { | ||
@@ -80,3 +74,2 @@ return stackTrace.replace( | ||
var _original$source, _original$line, _original$name; | ||
if (delimiter === ":" && func && !fileName) { | ||
@@ -86,3 +79,2 @@ fileName = func; | ||
} | ||
const original = this.getOriginalPositionFor( | ||
@@ -111,3 +103,5 @@ line, | ||
); | ||
} // Taking in a map like | ||
} | ||
// Taking in a map like | ||
// trampoline offset (optional js function name) | ||
@@ -131,7 +125,5 @@ // JS_0158_xxxxxxxxxxxxxxxxxxxxxx fe 91081 | ||
const offset = parseInt(line_list[2], 10); | ||
if (!offset) { | ||
return trampoline + " " + trampoline; | ||
} | ||
const original = this.getOriginalPositionFor( | ||
@@ -151,3 +143,2 @@ this.options.inputLineStart, | ||
} | ||
symbolicateAttribution(obj) { | ||
@@ -164,3 +155,5 @@ const loc = obj.location; | ||
const virtualOffset = Number(loc.virtualOffset); | ||
const bytecodeSize = Number(loc.bytecodeSize); // Functions compiled from Metro-bundled modules will often have a little bit | ||
const bytecodeSize = Number(loc.bytecodeSize); | ||
// Functions compiled from Metro-bundled modules will often have a little bit | ||
// of unmapped wrapper code right at the beginning - which is where we query. | ||
@@ -173,3 +166,2 @@ // Let's attribute them to where the inner module code originates instead. | ||
// happen for function bodies that never throw (generally very short). | ||
while ( | ||
@@ -182,3 +174,2 @@ isBytecodeRange && | ||
} | ||
obj.location = { | ||
@@ -189,14 +180,13 @@ file: original.source, | ||
}; | ||
} // Symbolicate chrome trace "stackFrames" section. | ||
} | ||
// Symbolicate chrome trace "stackFrames" section. | ||
// Each frame in it has three fields: name, funcVirtAddr(optional), offset(optional). | ||
// funcVirtAddr and offset are only available if trace is generated from | ||
// hbc bundle without debug info. | ||
symbolicateChromeTrace(traceFile, { stdout, stderr }) { | ||
const content = JSON.parse(fs.readFileSync(traceFile, "utf8")); | ||
if (content.stackFrames == null) { | ||
throw new Error("Unable to locate `stackFrames` section in trace."); | ||
} | ||
const keys = Object.keys(content.stackFrames); | ||
@@ -206,17 +196,16 @@ stdout.write("Processing " + keys.length + " frames\n"); | ||
var _addressOriginal$sour, _addressOriginal$line, _addressOriginal$colu; | ||
const entry = content.stackFrames[key]; | ||
let line; | ||
let column; // Function entrypoint line/column; used for symbolicating function name | ||
let column; | ||
// Function entrypoint line/column; used for symbolicating function name | ||
// with legacy source maps (or when --no-function-names is set). | ||
let funcLine; | ||
let funcColumn; | ||
if (entry.funcVirtAddr != null && entry.offset != null) { | ||
// Without debug information. | ||
const funcVirtAddr = parseInt(entry.funcVirtAddr, 10); | ||
const offsetInFunction = parseInt(entry.offset, 10); // Main bundle always use hard-coded line value 1. | ||
const offsetInFunction = parseInt(entry.offset, 10); | ||
// Main bundle always use hard-coded line value 1. | ||
// TODO: support multiple bundle/module. | ||
line = this.options.inputLineStart; | ||
@@ -238,12 +227,12 @@ column = funcVirtAddr + offsetInFunction; | ||
return; | ||
} // Symbolicate original file/line/column. | ||
} | ||
// Symbolicate original file/line/column. | ||
const addressOriginal = this.getOriginalPositionDetailsFor(line, column); | ||
let frameName; | ||
if (addressOriginal.functionName) { | ||
frameName = addressOriginal.functionName; | ||
} else { | ||
frameName = entry.name; // Symbolicate function name. | ||
frameName = entry.name; | ||
// Symbolicate function name. | ||
if (funcLine != null && funcColumn != null) { | ||
@@ -254,3 +243,2 @@ const funcOriginal = this.getOriginalPositionFor( | ||
); | ||
if (funcOriginal.name != null) { | ||
@@ -265,4 +253,5 @@ frameName = funcOriginal.name; | ||
} | ||
} // Output format is: funcName(file:line:column) | ||
} | ||
// Output format is: funcName(file:line:column) | ||
entry.name = [ | ||
@@ -291,2 +280,3 @@ frameName, | ||
} | ||
/* | ||
@@ -296,3 +286,2 @@ * A helper function to return a mapping {line, column} object for a given input | ||
*/ | ||
getOriginalPositionFor(lineNumber, columnNumber, moduleIds) { | ||
@@ -311,2 +300,3 @@ const position = this.getOriginalPositionDetailsFor( | ||
} | ||
/* | ||
@@ -316,6 +306,6 @@ * Symbolicates the JavaScript stack trace extracted from the minidump | ||
*/ | ||
symbolicateHermesMinidumpTrace(crashInfo) { | ||
throw new Error("Not implemented"); | ||
} | ||
/** | ||
@@ -328,3 +318,2 @@ * Symbolicates heap alloction stacks in a Chrome-formatted heap | ||
*/ | ||
symbolicateHeapSnapshot(snapshotContents) { | ||
@@ -336,3 +325,2 @@ const snapshotData = | ||
const processor = new ChromeHeapSnapshotProcessor(snapshotData); | ||
for (const frame of processor.traceFunctionInfos()) { | ||
@@ -342,7 +330,5 @@ const moduleIds = this.parseFileName(frame.getString("script_name")); | ||
const generatedColumn = frame.getNumber("column"); | ||
if (generatedLine === 0 && generatedColumn === 0) { | ||
continue; | ||
} | ||
const { | ||
@@ -358,6 +344,4 @@ line: originalLine, | ||
); | ||
if (originalSource != null) { | ||
frame.setString("script_name", originalSource); | ||
if (originalLine != null) { | ||
@@ -371,3 +355,2 @@ frame.setNumber( | ||
} | ||
if (originalColumn != null) { | ||
@@ -382,3 +365,2 @@ frame.setNumber( | ||
} | ||
frame.setString( | ||
@@ -391,5 +373,5 @@ "name", | ||
} | ||
return snapshotData; | ||
} | ||
/* | ||
@@ -399,7 +381,5 @@ * Symbolicates the JavaScript stack trace extracted from the coverage information | ||
*/ | ||
symbolicateHermesCoverageTrace(coverageInfo) { | ||
const symbolicatedTrace = []; | ||
const { executedFunctions } = coverageInfo; | ||
if (executedFunctions != null) { | ||
@@ -418,3 +398,2 @@ for (const stackItem of executedFunctions) { | ||
} | ||
return symbolicatedTrace; | ||
@@ -427,7 +406,5 @@ } | ||
*/ | ||
getOriginalPositionDetailsFor(lineNumber, columnNumber, moduleIds) { | ||
throw new Error("Not implemented"); | ||
} | ||
parseFileName(str) { | ||
@@ -437,6 +414,11 @@ throw new Error("Not implemented"); | ||
} | ||
class SingleMapSymbolicationContext extends SymbolicationContext { | ||
// $FlowFixMe[value-as-type] | ||
constructor(SourceMapConsumer, sourceMapContent, options = {}) { // $FlowFixMe[value-as-type] | ||
constructor( | ||
// $FlowFixMe[value-as-type] | ||
SourceMapConsumer, | ||
sourceMapContent, | ||
options = {} | ||
) { | ||
super(options); | ||
@@ -451,12 +433,10 @@ this._SourceMapConsumer = SourceMapConsumer; | ||
}; | ||
if (sourceMapJson.x_facebook_segments) { | ||
for (const key of Object.keys(sourceMapJson.x_facebook_segments)) { | ||
// $FlowFixMe[incompatible-use] | ||
const map = sourceMapJson.x_facebook_segments[key]; // $FlowFixMe[prop-missing] | ||
const map = sourceMapJson.x_facebook_segments[key]; | ||
// $FlowFixMe[prop-missing] | ||
segments[key] = this._initSegment(map); | ||
} | ||
} | ||
this._legacyFormat = | ||
@@ -466,4 +446,5 @@ sourceMapJson.x_facebook_segments != null || | ||
this._segments = segments; | ||
} // $FlowFixMe[missing-local-annot] | ||
} | ||
// $FlowFixMe[missing-local-annot] | ||
_initSegment(map) { | ||
@@ -477,9 +458,7 @@ const useFunctionNames = this.options.nameSource === "function_names"; | ||
value: new SourceMapConsumer(map), | ||
}); // $FlowFixMe[object-this-reference] | ||
}); | ||
// $FlowFixMe[object-this-reference] | ||
return this.consumer; | ||
}, | ||
moduleOffsets: map.x_facebook_offsets || [], | ||
get sourceFunctionsConsumer() { | ||
@@ -489,15 +468,12 @@ // $FlowFixMe[object-this-reference] | ||
value: useFunctionNames ? new SourceMetadataMapConsumer(map) : null, | ||
}); // $FlowFixMe[object-this-reference] | ||
}); | ||
// $FlowFixMe[object-this-reference] | ||
return this.sourceFunctionsConsumer; | ||
}, | ||
hermesOffsets: map.x_hermes_function_offsets, | ||
}; | ||
} | ||
symbolicateHermesMinidumpTrace(crashInfo) { | ||
const symbolicatedTrace = []; | ||
const { callstack } = crashInfo; | ||
if (callstack != null) { | ||
@@ -524,6 +500,4 @@ for (const stackItem of callstack) { | ||
cjsModuleOffsetOrSegmentID + this.options.inputLineStart; | ||
const segment = | ||
this._segments[moduleInformation.segmentId.toString()]; | ||
const hermesOffsets = | ||
@@ -533,3 +507,2 @@ segment === null || segment === void 0 | ||
: segment.hermesOffsets; | ||
if (!hermesOffsets) { | ||
@@ -560,10 +533,7 @@ symbolicatedTrace.push({ | ||
} | ||
return symbolicatedTrace; | ||
} | ||
symbolicateHermesCoverageTrace(coverageInfo) { | ||
const symbolicatedTrace = []; | ||
const { executedFunctions } = coverageInfo; | ||
if (executedFunctions != null) { | ||
@@ -582,5 +552,5 @@ for (const stackItem of executedFunctions) { | ||
} | ||
return symbolicatedTrace; | ||
} | ||
/* | ||
@@ -591,3 +561,2 @@ * An internal helper function similar to getOriginalPositionFor. This one | ||
*/ | ||
getOriginalPositionDetailsFor(lineNumber, columnNumber, moduleIds) { | ||
@@ -603,14 +572,10 @@ // Adjust arguments to source-map's input coordinates | ||
: columnNumber; | ||
if (!moduleIds) { | ||
moduleIds = UNKNOWN_MODULE_IDS; | ||
} | ||
let moduleLineOffset = 0; | ||
const metadata = this._segments[moduleIds.segmentId + ""]; | ||
const { localId } = moduleIds; | ||
if (localId != null) { | ||
const { moduleOffsets } = metadata; | ||
if (!moduleOffsets) { | ||
@@ -622,10 +587,7 @@ throw new Error( | ||
} | ||
if (moduleOffsets[localId] == null) { | ||
throw new Error("Unknown module ID: " + localId); | ||
} | ||
moduleLineOffset = moduleOffsets[localId]; | ||
} | ||
const original = metadata.consumer.originalPositionFor({ | ||
@@ -635,3 +597,2 @@ line: Number(lineNumber) + moduleLineOffset, | ||
}); | ||
if (metadata.sourceFunctionsConsumer) { | ||
@@ -643,3 +604,2 @@ original.functionName = | ||
} | ||
return { | ||
@@ -657,3 +617,2 @@ ...original, | ||
} | ||
parseFileName(str) { | ||
@@ -663,10 +622,14 @@ if (this._legacyFormat) { | ||
} | ||
return UNKNOWN_MODULE_IDS; | ||
} | ||
} | ||
class DirectorySymbolicationContext extends SymbolicationContext { | ||
// $FlowFixMe[value-as-type] | ||
constructor(SourceMapConsumer, rootDir, options = {}) { // $FlowFixMe[value-as-type] | ||
constructor( | ||
// $FlowFixMe[value-as-type] | ||
SourceMapConsumer, | ||
rootDir, | ||
options = {} | ||
) { | ||
super(options); | ||
@@ -677,3 +640,2 @@ this._fileMaps = new Map(); | ||
} | ||
_loadMap(mapFilename) { | ||
@@ -684,5 +646,3 @@ invariant( | ||
); | ||
let fileMap = this._fileMaps.get(mapFilename); | ||
if (fileMap == null) { | ||
@@ -694,8 +654,7 @@ fileMap = new SingleMapSymbolicationContext( | ||
); | ||
this._fileMaps.set(mapFilename, fileMap); | ||
} | ||
return fileMap; | ||
} | ||
/* | ||
@@ -706,3 +665,2 @@ * An internal helper function similar to getOriginalPositionFor. This one | ||
*/ | ||
getOriginalPositionDetailsFor(lineNumber, columnNumber, filename) { | ||
@@ -717,8 +675,7 @@ invariant( | ||
path.resolve(this._rootDir, filename) | ||
); // Lock down access to files outside the root dir. | ||
); | ||
// Lock down access to files outside the root dir. | ||
if (!relativeFilename.startsWith("..")) { | ||
mapFilename = path.join(this._rootDir, relativeFilename + ".map"); | ||
} | ||
if (mapFilename == null || !fs.existsSync(mapFilename)) { | ||
@@ -746,3 +703,2 @@ // Adjust arguments to the output coordinates | ||
} | ||
return this._loadMap(mapFilename).getOriginalPositionDetailsFor( | ||
@@ -753,3 +709,2 @@ lineNumber, | ||
} | ||
parseFileName(str) { | ||
@@ -759,2 +714,3 @@ return str; | ||
} | ||
/* | ||
@@ -770,6 +726,4 @@ * If the file name of a stack frame is numeric (+ ".js"), we assume it's a | ||
*/ | ||
function parseSingleMapFileName(str) { | ||
const modMatch = str.match(/^(\d+).js$/); | ||
if (modMatch != null) { | ||
@@ -781,5 +735,3 @@ return { | ||
} | ||
const segMatch = str.match(/^seg-(\d+)(?:_(\d+))?.js$/); | ||
if (segMatch != null) { | ||
@@ -791,7 +743,10 @@ return { | ||
} | ||
return UNKNOWN_MODULE_IDS; | ||
} | ||
function createContext(SourceMapConsumer, sourceMapContent, options = {}) { // $FlowFixMe[value-as-type] | ||
function createContext( | ||
// $FlowFixMe[value-as-type] | ||
SourceMapConsumer, | ||
sourceMapContent, | ||
options = {} | ||
) { | ||
return new SingleMapSymbolicationContext( | ||
@@ -803,4 +758,4 @@ SourceMapConsumer, | ||
} | ||
function unstable_createDirectoryContext( // $FlowFixMe[value-as-type] | ||
function unstable_createDirectoryContext( | ||
// $FlowFixMe[value-as-type] | ||
SourceMapConsumer, | ||
@@ -812,19 +767,14 @@ rootDir, | ||
} | ||
function getOriginalPositionFor(lineNumber, columnNumber, moduleIds, context) { | ||
return context.getOriginalPositionFor(lineNumber, columnNumber, moduleIds); | ||
} | ||
function symbolicate(stackTrace, context) { | ||
return context.symbolicate(stackTrace); | ||
} | ||
function symbolicateProfilerMap(mapFile, context) { | ||
return context.symbolicateProfilerMap(mapFile); | ||
} | ||
function symbolicateAttribution(obj, context) { | ||
context.symbolicateAttribution(obj); | ||
} | ||
function symbolicateChromeTrace(traceFile, { stdout, stderr }, context) { | ||
@@ -836,3 +786,2 @@ return context.symbolicateChromeTrace(traceFile, { | ||
} | ||
module.exports = { | ||
@@ -839,0 +788,0 @@ createContext, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
121334
1672
+ Addedmetro-source-map@0.73.5(transitive)
+ Addedob1@0.73.5(transitive)
- Removedmetro-source-map@0.73.3(transitive)
- Removedob1@0.73.3(transitive)
Updatedmetro-source-map@0.73.5