Find extents of a mark given a selection

If you’re not interested in marks outside of the current textblock, you could just iterate over the child nodes of the textblock in both directions, and keep going until you find one that doesn’t have the mark.

Here’s some (untested) code to that effect:

// :: (ResolvedPos, Mark)
function markExtend($start, mark) {
  let startIndex = $start.index(), endIndex = $end.indexAfter()
  while (startIndex > 0 && mark.isInSet($start.parent.child(startIndex - 1).marks)) startIndex--
  while (startIndex < $start.parent.childCount && mark.isInSet($start.parent.child(endIndex).marks)) endIndex++
  // (This will be easier in the next release with Fragment.offsetAt)
  let startPos = $start.start(), endPos = startPos
  for (let i = 0; i < endIndex; i++) {
    let size = $start.parent.child(i).nodeSize
    if (i < startPos) startPos += size
    endPos += size
  }
  return {from: startPos, to: endPos}
}