Changing the node type of a list

You said that Fragment.content is “not iterable”, but it’s non entirely true. Fragment.content is readonly. It means you shouldn’t mutate it directly.

I recently worked on something somewhat similar and needed to traverse the tree as well.

I came up with these helpers. They iterate on content but create new Fragments.

import { Slice, Fragment, Node } from "prosemirror-model";

export const mapFragment = (
  fragment: Fragment,
  callback: (node: Node) => Node | Node[] | Fragment | null
): Fragment =>
  Fragment.fromArray(
    (fragment as any).content.map((node: Node) => {
      if (node.content.childCount > 0) {
        return node.type.create(
          node.attrs,
          mapFragment(node.content, callback)
        );
      }

      return callback(node);
    })
  );

export const mapSlice = (
  slice: Slice,
  callback: (node: Node) => Node | Node[] | Fragment | null
): Slice => {
  const fragment = mapFragment(slice.content, callback);
  return new Slice(fragment, slice.openStart, slice.openEnd);
};

You can then use it like that:

mapSlice(slice, callbackFunction);

You just need to remember that in callbackFunction whatever transformation you do, you need to create new Nodes even if you don’t want to change them. You can do that by using node.copy(node.content) and/or e.g.

node.type.create({ ...node.attrs, }, node.content, node.marks

(remember to pass marks if you want to preserve them)

I hope that helps you keep going and that I didn’t violate any Prosemirror fundamentals here :smiley: