async _symbolicate()

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}));
    }
  }