insertText = (transaction, parent, currPos, text, attributes) => {
  currPos.currentAttributes.forEach((val, key) => {
    if (attributes[key] === undefined) {
      attributes[key] = null;
    }
  });
  const doc = transaction.doc;
  const ownClientId = doc.clientID;
  minimizeAttributeChanges(currPos, attributes);
  const negatedAttributes = insertAttributes(transaction, parent, currPos, attributes); // insert content

  const content = text.constructor === String ? new ContentString(
  /** @type {string} */
  text) : text instanceof AbstractType ? new ContentType(text) : new ContentEmbed(text);
  let {
    left,
    right,
    index
  } = currPos;

  if (parent._searchMarker) {
    updateMarkerChanges(parent._searchMarker, currPos.index, content.getLength());
  }

  right = new Item(createID(ownClientId, getState(doc.store, ownClientId)), left, left && left.lastId, right, right && right.id, parent, null, content);
  right.integrate(transaction, 0);
  currPos.right = right;
  currPos.index = index;
  currPos.forward();
  insertNegatedAttributes(transaction, parent, currPos, negatedAttributes);
}
@param {Transaction} transaction
@param {AbstractType<any>} parent
@param {ItemTextListPosition} currPos
@param {string|object|AbstractType<any>} text
@param {Object<string,any>} attributes

@private
@function