We want to sort all the marks of all the spans in the following order: 1. Marks that are shared amongst the most adjacent siblings 2. Non-default marks (links, custom metadata) 3. Built-in, plain marks (bold, emphasis, code etc)
function sortMarksByOccurences(span, i, spans) {
  if (!span.marks || span.marks.length === 0) {
    return span.marks || []
  }

  const markOccurences = span.marks.reduce((occurences, mark) => {
    occurences[mark] = occurences[mark] ? occurences[mark] + 1 : 1

    for (let siblingIndex = i + 1; siblingIndex < spans.length; siblingIndex++) {
      const sibling = spans[siblingIndex]

      if (sibling.marks && Array.isArray(sibling.marks) && sibling.marks.indexOf(mark) !== -1) {
        occurences[mark]++
      } else {
        break
      }
    }

    return occurences
  }, {})

  const sortByOccurence = sortMarks.bind(null, markOccurences)

  // Slicing because sort() mutates the input
  return span.marks.slice().sort(sortByOccurence)
}