Repository: ianstormtaylor/slate
File: packages/slate/src/transforms/node.ts (TypeScript)

Code before:
            : n => Editor.isEditor(n),
          mode: 'lowest',
          voids,
        })
      )

      for (const [, rootPath] of roots) {
        const a = Range.isRange(at)
          ? Range.intersection(at, Editor.range(editor, rootPath))
          : at

        if (!a) {
          continue
        }

        const matches = Array.from(
          Editor.nodes(editor, { at: a, match, mode, voids })
        )

        if (matches.length > 0) {
          const [first] = matches
          const last = matches[matches.length - 1]
          const [firstNode, firstPath] = first
          const [lastNode, lastPath] = last

          if (firstNode === lastNode && Editor.isEditor(firstNode)) {
            // if the only matching node is an editor, no nodes matched
            continue
          }

          const commonPath = Path.equals(firstPath, lastPath)
            ? Path.parent(firstPath)
            : Path.common(firstPath, lastPath)

          const range = Editor.range(editor, firstPath, lastPath)
          const commonNodeEntry = Editor.node(editor, commonPath)
          const [commonNode] = commonNodeEntry
          const depth = commonPath.length + 1
          const wrapperPath = Path.next(lastPath.slice(0, depth))
          const wrapper = { ...element, children: [] }
          Transforms.insertNodes(editor, wrapper, { at: wrapperPath, voids })

          Transforms.moveNodes(editor, {
            at: range,
            match: n =>
              Element.isAncestor(commonNode) && commonNode.children.includes(n),
            to: wrapperPath.concat(0),
            voids,
          })
        }
      }

Review comment (performance):
Wouldn't this just be `if (firstPath.length === 0 && lastPath.length === 0)`? Since the only way you would ever get editor in a nodePath pair is if the path is an empty path. Would give a slight performance boost since isEditor checks nodes etc. Would be more hard to read though so maybe a comment would make it clearer.

Code after:
            : n => Editor.isEditor(n),
          mode: 'lowest',
          voids,
        })
      )

      for (const [, rootPath] of roots) {
        const a = Range.isRange(at)
          ? Range.intersection(at, Editor.range(editor, rootPath))
          : at

        if (!a) {
          continue
        }

        const matches = Array.from(
          Editor.nodes(editor, { at: a, match, mode, voids })
        )

        if (matches.length > 0) {
          const [first] = matches
          const last = matches[matches.length - 1]
          const [, firstPath] = first
          const [, lastPath] = last

          if (firstPath.length === 0 && lastPath.length === 0) {
            // if there's no matching parent - usually means the node is an editor - don't do anything
            continue
          }

          const commonPath = Path.equals(firstPath, lastPath)
            ? Path.parent(firstPath)
            : Path.common(firstPath, lastPath)

          const range = Editor.range(editor, firstPath, lastPath)
          const commonNodeEntry = Editor.node(editor, commonPath)
          const [commonNode] = commonNodeEntry
          const depth = commonPath.length + 1
          const wrapperPath = Path.next(lastPath.slice(0, depth))
          const wrapper = { ...element, children: [] }
          Transforms.insertNodes(editor, wrapper, { at: wrapperPath, voids })

          Transforms.moveNodes(editor, {
            at: range,
            match: n =>
              Element.isAncestor(commonNode) && commonNode.children.includes(n),
            to: wrapperPath.concat(0),
            voids,
          })
        }
      }