in packages/metro/src/Server.js [1013:1107]
async _symbolicate(req: IncomingMessage, res: ServerResponse) {
const getCodeFrame = (urls, symbolicatedStack) => {
for (let i = 0; i < symbolicatedStack.length; i++) {
const {collapse, column, file, lineNumber} = symbolicatedStack[i];
const fileAbsolute = path.resolve(this._config.projectRoot, file ?? '');
if (collapse || lineNumber == null || urls.has(fileAbsolute)) {
continue;
}
try {
return {
content: codeFrameColumns(
fs.readFileSync(fileAbsolute, 'utf8'),
{
// Metro returns 0 based columns but codeFrameColumns expects 1-based columns
// $FlowFixMe[unsafe-addition]
start: {column: column + 1, line: lineNumber},
},
{forceColor: true},
),
location: {
row: lineNumber,
column,
},
fileName: file,
};
} catch (error) {
console.error(error);
}
}
return null;
};
try {
const symbolicatingLogEntry = log(
createActionStartEntry('Symbolicating'),
);
debug('Start symbolication');
/* $FlowFixMe: where is `rawBody` defined? Is it added by the `connect` framework? */
const body = await req.rawBody;
const stack = JSON.parse(body).stack.map(frame => {
if (frame.file && frame.file.includes('://')) {
return {
...frame,
file: this._config.server.rewriteRequestUrl(frame.file),
};
}
return frame;
});
// In case of multiple bundles / HMR, some stack frames can have different URLs from others
const urls = new Set();
stack.forEach(frame => {
const sourceUrl = frame.file;
// Skip `/debuggerWorker.js` which does not need symbolication.
if (
sourceUrl != null &&
!urls.has(sourceUrl) &&
!sourceUrl.endsWith('/debuggerWorker.js') &&
sourceUrl.startsWith('http')
) {
urls.add(sourceUrl);
}
});
debug('Getting source maps for symbolication');
const sourceMaps = await Promise.all(
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
Array.from(urls.values()).map(this._explodedSourceMapForURL, this),
);
debug('Performing fast symbolication');
const symbolicatedStack = await await symbolicate(
stack,
zip(urls.values(), sourceMaps),
this._config,
);
debug('Symbolication done');
res.end(
JSON.stringify({
codeFrame: getCodeFrame(urls, symbolicatedStack),
stack: symbolicatedStack,
}),
);
process.nextTick(() => {
log(createActionEndEntry(symbolicatingLogEntry));
});
} catch (error) {
console.error(error.stack || error);
res.statusCode = 500;
res.end(JSON.stringify({error: error.message}));
}
}