docs: function convertNode(node, nodes) {
    switch (node.type) {
      /**
       * General
       *
       * Convert simple cases that only require a type and children, with no
       * additional properties.
       */
      case 'root':
      case 'paragraph':
      case 'listItem':
      case 'blockquote':
      case 'tableRow':
      case 'tableCell': {
        return createBlock(typeMap[node.type], nodes);
      }
  
      /**
       * 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 { data } = node;
        const nodes = [createText('')];
        return createBlock(typeMap[node.type], nodes, { data, isVoid: true });
      }
  
      /**
       * Text
       *
       * Text and HTML nodes are both used to render text, and should be treated
       * the same. HTML is treated as text because we never want to escape or
       * encode it.
       */
      case 'text':
      case 'html': {
        return createText(node.value, node.data);
      }
  
      /**
       * 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 "leaf" 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': {
        const leaf = {
          text: node.value,
          marks: [{ type: 'code' }],
        };
        return createText([leaf]);
      }
  
      /**
       * 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 convertMarkNode(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. We also carry
       * over the "lang" data property if it's defined.
       */
      case 'code': {
        const data = { lang: node.lang };
        const text = createText(node.value);
        const nodes = [text];
        return createBlock(typeMap[node.type], nodes, { data });
      }
  
      /**
       * 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 textNode = createText('\n');
        return createInline('break', {}, [textNode]);
      }
  
      /**
       * Thematic Breaks
       *
       * Thematic breaks are void nodes in the Slate schema.
       */
      case 'thematicBreak': {
        return createBlock(typeMap[node.type], { isVoid: true });
      }
  
      /**
       * 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], { isVoid: true, 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 });
      }
    }
  }