buildBlockTypeMap = (
  blockRenderMap: DraftBlockRenderMap,
): BlockTypeMap => {
  const blockTypeMap: {[string]: any | Array<any | string>} = {};

  blockRenderMap.mapKeys((blockType, desc) => {
    const elements = [desc.element];
    if (desc.aliasedElements !== undefined) {
      elements.push(...desc.aliasedElements);
    }
    elements.forEach(element => {
      if (blockTypeMap[element] === undefined) {
        blockTypeMap[element] = blockType;
      } else if (typeof blockTypeMap[element] === 'string') {
        blockTypeMap[element] = [blockTypeMap[element], blockType];
      } else {
        blockTypeMap[element].push(blockType);
      }
    });
  });

  return Map(blockTypeMap);
};

const detectInlineStyle = (node: Node): string | null => {
  if (isHTMLElement(node)) {
    const element: HTMLElement = (node: any);
    // Currently only used to detect preformatted inline code
    if (element.style.fontFamily.includes('monospace')) {
      return 'CODE';
    }
  }
  return null;
};

/**
 * If we're pasting from one DraftEditor to another we can check to see if
 * existing list item depth classes are being used and preserve this style
 */
const getListItemDepth = (node: HTMLElement, depth: number = 0): number => {
  Object.keys(knownListItemDepthClasses).some(depthClass => {
    if (node.classList.contains(depthClass)) {
      depth = knownListItemDepthClasses[depthClass];
    }
  });
  return depth;
};

/**
 * Return true if the provided HTML Element can be used to build a
 * Draftjs-compatible link.
 */
const isValidAnchor = (node: Node) => {
  if (!isHTMLAnchorElement(node)) {
    return false;
  }
  const anchorNode: HTMLAnchorElement = (node: any);

  if (
    !anchorNode.href ||
    (anchorNode.protocol !== 'http:' &&
      anchorNode.protocol !== 'https:' &&
      anchorNode.protocol !== 'mailto:' &&
      anchorNode.protocol !== 'tel:')
  ) {
    return false;
  }

  try {
    // Just checking whether we can actually create a URI
    const _ = new URI(anchorNode.href);
    return true;
  } catch {
    return false;
  }
};

/**
 * Return true if the provided HTML Element can be used to build a
 * Draftjs-compatible image.
 */
const isValidImage = (node: Node): boolean => {
  if (!isHTMLImageElement(node)) {
    return false;
  }
  const imageNode: HTMLImageElement = (node: any);
  return !!(
    imageNode.attributes.getNamedItem('src') &&
    imageNode.attributes.getNamedItem('src').value
  );
};

/**
 * Try to guess the inline style of an HTML element based on its css
 * styles (font-weight, font-style and text-decoration).
 */
const styleFromNodeAttributes = (
  node: Node,
  style: DraftInlineStyle,
): DraftInlineStyle => {
  if (!isHTMLElement(node)) {
    return style;
  }

  const htmlElement: HTMLElement = (node: any);
  const fontWeight = htmlElement.style.fontWeight;
  const fontStyle = htmlElement.style.fontStyle;
  const textDecoration = htmlElement.style.textDecoration;

  return style.withMutations(style => {
    if (boldValues.indexOf(fontWeight) >= 0) {
      style.add('BOLD');
    } else if (notBoldValues.indexOf(fontWeight) >= 0) {
      style.remove('BOLD');
    }

    if (fontStyle === 'italic') {
      style.add('ITALIC');
    } else if (fontStyle === 'normal') {
      style.remove('ITALIC');
    }

    if (textDecoration === 'underline') {
      style.add('UNDERLINE');
    }
    if (textDecoration === 'line-through') {
      style.add('STRIKETHROUGH');
    }
    if (textDecoration === 'none') {
      style.remove('UNDERLINE');
      style.remove('STRIKETHROUGH');
    }
  });
}
Build a mapping from HTML tags to draftjs block types
out of a BlockRenderMap.

The BlockTypeMap for the default BlockRenderMap looks like this:
  Map({
    h1: 'header-one',
    h2: 'header-two',
    h3: 'header-three',
    h4: 'header-four',
    h5: 'header-five',
    h6: 'header-six',
    blockquote: 'blockquote',
    figure: 'atomic',
    pre: ['code-block'],
    div: 'unstyled',
    p: 'unstyled',
    li: ['ordered-list-item', 'unordered-list-item'],
  })