function insertNode({
  treeData,
  depth: targetDepth,
  minimumTreeIndex,
  newNode,
  getNodeKey = () => {},
  ignoreCollapsed = true,
  expandParent = false,
}) {
  if (!treeData && targetDepth === 0) {
    return {
      treeData: [newNode],
      treeIndex: 0,
      path: [getNodeKey({ node: newNode, treeIndex: 0 })],
      parentNode: null,
    };
  }

  const insertResult = addNodeAtDepthAndIndex({
    targetDepth,
    minimumTreeIndex,
    newNode,
    ignoreCollapsed,
    expandParent,
    getNodeKey,
    isPseudoRoot: true,
    isLastChild: true,
    node: { children: treeData },
    currentIndex: -1,
    currentDepth: -1,
  });

  if (!('insertedTreeIndex' in insertResult)) {
    throw new Error('No suitable position found to insert.');
  }

  const treeIndex = insertResult.insertedTreeIndex;
  return {
    treeData: insertResult.node.children,
    treeIndex,
    path: [
      ...insertResult.parentPath,
      getNodeKey({ node: newNode, treeIndex }),
    ],
    parentNode: insertResult.parentNode,
  };
}
Insert a node into the tree at the given depth, after the minimum index

@param {!Object[]} treeData - Tree data
@param {!number} depth - The depth to insert the node at (the first level of the array being depth 0)
@param {!number} minimumTreeIndex - The lowest possible treeIndex to insert the node at
@param {!Object} newNode - The node to insert into the tree
@param {boolean=} ignoreCollapsed - Ignore children of nodes without `expanded` set to `true`
@param {boolean=} expandParent - If true, expands the parent of the inserted node
@param {!function} getNodeKey - Function to get the key from the nodeData and tree index

@return {Object} result
@return {Object[]} result.treeData - The tree data with the node added
@return {number} result.treeIndex - The tree index at which the node was inserted
@return {number[]|string[]} result.path - Array of keys leading to the node location after insertion
@return {Object} result.parentNode - The parent node of the inserted node