function convertNode(node, nodes) {
    switch (node.type) {
      /**
       * General
       *
       * Convert simple cases that only require a type and children, with no
       * additional properties.
       */
      case 'paragraph':
      case 'blockquote':
      case 'tableRow':
      case 'tableCell': {
        return createBlock(typeMap[node.type], nodes);
      }

      /**
       * Root element
       * If the root node is empty, we need to add a paragraph node to it.
       */
      case 'root': {
        const children = isEmpty(nodes) ? [createBlock('paragraph')] : nodes;
        return createBlock(typeMap[node.type], children);
      }

      /**
       * List Items
       *
       * Markdown list items can be empty, but a list item in the Slate schema
       * should at least have an empty paragraph node.
       */
      case 'listItem': {
        const children = isEmpty(nodes) ? [createBlock('paragraph')] : nodes;
        return createBlock(typeMap[node.type], children);
      }

      /**
       * Shortcodes
       *
       * Shortcode nodes are represented as "void" blocks in the Slate AST. They
       * maintain the same data as MDAST shortcode nodes. Slate void blocks must
       * contain a blank text node.
       */
      case 'shortcode': {
        const nodes = [createText('')];
        const data = { ...node.data, id: node.data.shortcode, shortcodeNew: true };
        return createBlock(typeMap[node.type], nodes, { data });
      }

      case 'text': {
        const text = node.value;
        return createText(text);
      }

      /**
       * HTML
       *
       * HTML nodes contain plain text like text nodes, except they only contain
       * HTML. Our serialization results in non-HTML being placed in HTML nodes
       * sometimes to ensure that we're never escaping HTML from the rich text
       * editor. We do not replace line feeds in HTML because the HTML is raw
       * in the rich text editor, so the writer knows they're writing HTML, and
       * should expect soft breaks to be visually absent in the rendered HTML.
       */
      case 'html': {
        return createText(node.value);
      }

      /**
       * Inline Code
       *
       * Inline code nodes from an MDAST are represented in our Slate schema as
       * text nodes with a "code" mark. We manually create the text containing
       * the inline code value and a "code" mark, and place it in an array for use
       * as a Slate text node's children array.
       */
      case 'inlineCode': {
        return createText({ text: node.value, code: true, marks: [{ type: 'code' }] });
      }

      /**
       * Marks
       *
       * Marks are typically decorative sub-types that apply to text nodes. In an
       * MDAST, marks are nodes that can contain other nodes. This nested
       * hierarchy has to be flattened and split into distinct text nodes with
       * their own set of marks.
       */
      case 'strong':
      case 'emphasis':
      case 'delete': {
        return processMarkNode(node);
      }

      /**
       * Headings
       *
       * MDAST headings use a single type with a separate "depth" property to
       * indicate the heading level, while the Slate schema uses a separate node
       * type for each heading level. Here we get the proper Slate node name based
       * on the MDAST node depth.
       */
      case 'heading': {
        const depthMap = { 1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five', 6: 'six' };
        const slateType = `heading-${depthMap[node.depth]}`;
        return createBlock(slateType, nodes);
      }

      /**
       * Code Blocks
       *
       * MDAST code blocks are a distinct node type with a simple text value. We
       * convert that value into a nested child text node for Slate. If a void
       * node is required due to a custom code block handler, the value is
       * stored in the "code" data property instead. We also carry over the "lang"
       * data property if it's defined.
       */
      case 'code': {
        const data = {
          lang: node.lang,
          ...(voidCodeBlock ? { code: node.value } : {}),
          shortcode: 'code-block',
          shortcodeData: {
            code: node.value,
            lang: node.lang,
          },
        };
        const text = createText(voidCodeBlock ? '' : node.value);
        const nodes = [text];
        const block = createBlock('shortcode', nodes, { data });
        return block;
      }

      /**
       * Lists
       *
       * MDAST has a single list type and an "ordered" property. We derive that
       * information into the Slate schema's distinct list node types. We also
       * include the "start" property, which indicates the number an ordered list
       * starts at, if defined.
       */
      case 'list': {
        const slateType = node.ordered ? 'numbered-list' : 'bulleted-list';
        const data = { start: node.start };
        return createBlock(slateType, nodes, { data });
      }

      /**
       * Breaks
       *
       * MDAST soft break nodes represent a trailing double space or trailing
       * slash from a Markdown document. In Slate, these are simply transformed to
       * line breaks within a text node.
       */
      case 'break': {
        const { data } = node;
        return createInline('break', { data });
      }

      /**
       * Thematic Breaks
       *
       * Thematic breaks are void nodes in the Slate schema.
       */
      case 'thematicBreak': {
        return createBlock(typeMap[node.type]);
      }

      /**
       * Links
       *
       * MDAST stores the link attributes directly on the node, while our Slate
       * schema references them in the data object.
       */
      case 'link': {
        const { title, url, data } = node;
        const newData = { ...data, title, url };
        return createInline(typeMap[node.type], { data: newData }, nodes);
      }

      /**
       * Images
       *
       * Identical to link nodes except for the lack of child nodes and addition
       * of alt attribute data MDAST stores the link attributes directly on the
       * node, while our Slate schema references them in the data object.
       */
      case 'image': {
        const { title, url, alt, data } = node;
        const newData = { ...data, title, alt, url };
        return createInline(typeMap[node.type], { data: newData });
      }

      /**
       * Tables
       *
       * Tables are parsed separately because they may include an "align"
       * property, which should be passed to the Slate node.
       */
      case 'table': {
        const data = { align: node.align };
        return createBlock(typeMap[node.type], nodes, { data });
      }
    }
  }
Convert a single MDAST node to a Slate Raw node. Uses local node factories
that mimic the unist-builder function utilized in the slateRemark
transformer.