function condenseNodesReducer(acc, node, idx, nodes) {
  /**
   * Skip any nodes that are being processed as children of an MDAST node
   * through recursive calls.
   */
  if (typeof acc.nextIndex === 'number' && acc.nextIndex > idx) {
    return acc;
  }

  /**
   * Processing for nodes with marks.
   */
  if (node.marks && node.marks.length > 0) {
    /**
     * For each mark on the current node, get the number of consecutive nodes
     * (starting with this one) that have the mark. Whichever mark covers the
     * most nodes is used as the parent node, and the nodes with that mark are
     * processed as children. If the greatest number of consecutive nodes is
     * tied between multiple marks, there is no priority as to which goes
     * first.
     */
    const markLengths = node.marks.map(mark => getMarkLength(mark, nodes.slice(idx)));
    const parentMarkLength = last(sortBy(markLengths, 'length'));
    const { markType: parentType, length: parentLength } = parentMarkLength;

    /**
     * Since this and any consecutive nodes with the parent mark are going to
     * be processed as children of the parent mark, this reducer should simply
     * return the accumulator until after the last node to be covered by the
     * new parent node. Here we set the next index that should be processed,
     * if any.
     */
    const newNextIndex = idx + parentLength;

    /**
     * Get the set of nodes that should be processed as children of the new
     * parent mark node, run each through the reducer as children of the
     * parent node, and create the parent MDAST node with the resulting
     * children.
     */
    const children = nodes.slice(idx, newNextIndex);
    const denestedChildren = children.map(child => ({
      ...child,
      marks: without(child.marks, parentType),
    }));
    const mdastChildren = denestedChildren.reduce(condenseNodesReducer, { nodes: [], parentType })
      .nodes;
    const mdastNode = u(parentType, mdastChildren);

    return { ...acc, nodes: [...acc.nodes, mdastNode], nextIndex: newNextIndex };
  }

  /**
   * Create the base text node, and pass in the array of mark types as data
   * (helpful when optimizing/condensing the final structure).
   */
  const baseNode =
    typeof node.text === 'string'
      ? u(node.textNodeType, { marks: node.marks }, node.text)
      : transform(node.node);

  /**
   * Recursively wrap the base text node in the individual mark nodes, if
   * any exist.
   */
  return { ...acc, nodes: [...acc.nodes, baseNode] };
}
function condenseNodesReducer(acc, node, idx, nodes) {
  /**
   * Skip any nodes that are being processed as children of an MDAST node
   * through recursive calls.
   */
  if (typeof acc.nextIndex === 'number' && acc.nextIndex > idx) {
    return acc;
  }

  /**
   * Processing for nodes with marks.
   */
  if (node.marks && node.marks.length > 0) {
    /**
     * For each mark on the current node, get the number of consecutive nodes
     * (starting with this one) that have the mark. Whichever mark covers the
     * most nodes is used as the parent node, and the nodes with that mark are
     * processed as children. If the greatest number of consecutive nodes is
     * tied between multiple marks, there is no priority as to which goes
     * first.
     */
    const markLengths = node.marks.map(mark => getMarkLength(mark, nodes.slice(idx)));
    const parentMarkLength = last(sortBy(markLengths, 'length'));
    const { markType: parentType, length: parentLength } = parentMarkLength;

    /**
     * Since this and any consecutive nodes with the parent mark are going to
     * be processed as children of the parent mark, this reducer should simply
     * return the accumulator until after the last node to be covered by the
     * new parent node. Here we set the next index that should be processed,
     * if any.
     */
    const newNextIndex = idx + parentLength;

    /**
     * Get the set of nodes that should be processed as children of the new
     * parent mark node, run each through the reducer as children of the
     * parent node, and create the parent MDAST node with the resulting
     * children.
     */
    const children = nodes.slice(idx, newNextIndex);
    const denestedChildren = children.map(child => ({
      ...child,
      marks: without(child.marks, parentType),
    }));
    const mdastChildren = denestedChildren.reduce(condenseNodesReducer, { nodes: [], parentType })
      .nodes;
    const mdastNode = u(parentType, mdastChildren);

    return { ...acc, nodes: [...acc.nodes, mdastNode], nextIndex: newNextIndex };
  }

  /**
   * Create the base text node, and pass in the array of mark types as data
   * (helpful when optimizing/condensing the final structure).
   */
  const baseNode =
    typeof node.text === 'string'
      ? u(node.textNodeType, { marks: node.marks }, node.text)
      : transform(node.node);

  /**
   * Recursively wrap the base text node in the individual mark nodes, if
   * any exist.
   */
  return { ...acc, nodes: [...acc.nodes, baseNode] };
}
function condenseNodesReducer ( acc , node , idx , nodes ) { /**
   * Skip any nodes that are being processed as children of an MDAST node
   * through recursive calls.
   */ if ( typeof acc . nextIndex === 'number' && acc . nextIndex > idx ) { return acc ; } /**
   * Processing for nodes with marks.
   */ if ( node . marks && node . marks . length > 0 ) { /**
     * For each mark on the current node, get the number of consecutive nodes
     * (starting with this one) that have the mark. Whichever mark covers the
     * most nodes is used as the parent node, and the nodes with that mark are
     * processed as children. If the greatest number of consecutive nodes is
     * tied between multiple marks, there is no priority as to which goes
     * first.
     */ const markLengths = node . marks . map ( mark => getMarkLength ( mark , nodes . slice ( idx ) ) ) ; const parentMarkLength = last ( sortBy ( markLengths , 'length' ) ) ; const { markType : parentType , length : parentLength } = parentMarkLength ; /**
     * Since this and any consecutive nodes with the parent mark are going to
     * be processed as children of the parent mark, this reducer should simply
     * return the accumulator until after the last node to be covered by the
     * new parent node. Here we set the next index that should be processed,
     * if any.
     */ const newNextIndex = idx + parentLength ; /**
     * Get the set of nodes that should be processed as children of the new
     * parent mark node, run each through the reducer as children of the
     * parent node, and create the parent MDAST node with the resulting
     * children.
     */ const children = nodes . slice ( idx , newNextIndex ) ; const denestedChildren = children . map ( child => ( { ... child , marks : without ( child . marks , parentType ) , } ) ) ; const mdastChildren = denestedChildren . reduce ( condenseNodesReducer , { nodes : [ ] , parentType } ) . nodes ; const mdastNode = u ( parentType , mdastChildren ) ; return { ... acc , nodes : [ ... acc . nodes , mdastNode ] , nextIndex : newNextIndex } ; } /**
   * Create the base text node, and pass in the array of mark types as data
   * (helpful when optimizing/condensing the final structure).
   */ const baseNode = typeof node . text === 'string' ? u ( node . textNodeType , { marks : node . marks } , node . text ) : transform ( node . node ) ; /**
   * Recursively wrap the base text node in the individual mark nodes, if
   * any exist.
   */ return { ... acc , nodes : [ ... acc . nodes , baseNode ] } ; }
Slate's AST doesn't group adjacent text nodes with the same marks - a
change in marks from letter to letter, even if some are in common, results
in a separate leaf. For example, given "**a_b_**", transformation to and
from Slate's AST will result in "**a****_b_**".

MDAST treats styling entities as distinct nodes that contain children, so a
"strong" node can contain a plain text node with a sibling "emphasis" node,
which contains more text. This reducer serves to create an optimized nested
MDAST without the typical redundancies that Slate's AST would produce if
transformed as-is. The reducer can be called recursively to produce nested
structures.
Slate s AST doesn t group adjacent text nodes with the same marks - a change in marks from letter to letter even if some are in common results in a separate leaf . For example given ** a_b_ ** transformation to and from Slate s AST will result in ** a **** _b_ ** .
Reduce the nodes into a single node that is a child of the current node.