function forEachMapping()

in packages/metro-source-map/src/generateFunctionMap.js [97:172]


function forEachMapping(
  ast: BabelNode,
  context: ?Context,
  pushMapping: RangeMapping => void,
) {
  const nameStack = [];
  let tailPos = {line: 1, column: 0};
  let tailName = null;

  function advanceToPos(pos: {column: number, line: number}) {
    if (tailPos && positionGreater(pos, tailPos)) {
      const name = nameStack[0].name; // We always have at least Program
      if (name !== tailName) {
        pushMapping({
          name,
          start: {line: tailPos.line, column: tailPos.column},
        });
        tailName = name;
      }
    }
    tailPos = pos;
  }

  function pushFrame(name: string, loc: BabelNodeSourceLocation) {
    advanceToPos(loc.start);
    nameStack.unshift({name, loc});
  }

  function popFrame() {
    const top = nameStack[0];
    if (top) {
      const {loc} = top;
      advanceToPos(loc.end);
      nameStack.shift();
    }
  }

  if (!context) {
    context = {};
  }

  const basename = context.filename
    ? fsPath.basename(context.filename).replace(/\..+$/, '')
    : null;

  const visitor = {
    enter(
      path:
        | NodePath<BabelNodeProgram>
        | NodePath<BabelNodeFunction>
        | NodePath<BabelNodeClass>,
    ) {
      let name = getNameForPath(path);
      if (basename) {
        name = removeNamePrefix(name, basename);
      }

      pushFrame(name, nullthrows(path.node.loc));
    },

    exit(
      path:
        | NodePath<BabelNodeProgram>
        | NodePath<BabelNodeFunction>
        | NodePath<BabelNodeClass>,
    ): void {
      popFrame();
    },
  };

  traverse(ast, {
    Function: visitor,
    Program: visitor,
    Class: visitor,
  });
}