docs: private void strongConnect(int firstNode) {
          final Stack<TarjanState> stateStack = new Stack<>();
          stateStack.push(TarjanState.startState(firstNode));
  
          // nextState label is equivalent to the function entry point in the recursive Tarjan's algorithm.
          nextState:
  
          while (!stateStack.empty()) {
              TarjanState state = stateStack.pop();
              final int start = state.start;
              final EdgeIterator iter;
  
              if (state.isStart()) {
                  // We're traversing a new node 'start'.  Set the depth index for this node to the smallest unused index.
                  nodeIndex[start] = index;
                  nodeLowLink[start] = index;
                  index++;
                  nodeStack.addLast(start);
                  onStack.add(start);
  
                  iter = graph.createEdgeExplorer(edgeFilter).setBaseNode(start);
  
              } else {
                  // We're resuming iteration over the next child of 'start', set lowLink as appropriate.
                  iter = state.iter;
  
                  int prevConnectedId = iter.getAdjNode();
                  nodeLowLink[start] = Math.min(nodeLowLink[start], nodeLowLink[prevConnectedId]);
              }
  
              // Each element (excluding the first) in the current component should be able to find
              // a successor with a lower nodeLowLink.
              while (iter.next()) {
                  int connectedId = iter.getAdjNode();
                  if (ignoreSet.contains(start))
                      continue;
  
                  if (nodeIndex[connectedId] == 0) {
                      // Push resume and start states onto state stack to continue our DFS through the graph after the jump.
                      // Ideally we'd just call strongConnectIterative(connectedId);
                      stateStack.push(TarjanState.resumeState(start, iter));
                      stateStack.push(TarjanState.startState(connectedId));
                      continue nextState;
                  } else if (onStack.contains(connectedId)) {
                      nodeLowLink[start] = Math.min(nodeLowLink[start], nodeIndex[connectedId]);
                  }
              }
  
              // If nodeLowLink == nodeIndex, then we are the first element in a component.
              // Add all nodes higher up on nodeStack to this component.
              if (nodeIndex[start] == nodeLowLink[start]) {
                  IntArrayList component = new IntArrayList();
                  int node;
                  while ((node = nodeStack.removeLast()) != start) {
                      component.add(node);
                      onStack.remove(node);
                  }
                  component.add(start);
                  component.trimToSize();
                  onStack.remove(start);
                  components.add(component);
              }
          }
      }