This solution is generated by ChatGPT, correctness is not guaranteed.

AI solution for JavaScript Coding Question on BFE.dev
143. Virtual DOM IV - JSX 1

const h = (tag, props, ...children) => ({
  tag,
  props: props || {},
  children
});

// helper function to extract JSX text content
const extractJSXText = (JSXNode) => {
  const jsxChild = JSXNode.children[0];
  if (jsxChild && jsxChild.type === 'JSXText') {
    return jsxChild.value;
  }
  return null;
};

const parse = (code) => {
  // remove spaces and newline for simplicity
  const cleanedCode = code.replace(/\s+/g, '');
  
  let currentIndex = 0;
  
  const parseOpeningElement = () => {
    if (cleanedCode[currentIndex] !== '<') {
      throw new Error('Invalid JSX Element');
    }
    currentIndex++;
    const tagName = [];
    const attributes = {};
    while (cleanedCode[currentIndex] !== '>' && cleanedCode[currentIndex] !== ' ') {
      tagName.push(cleanedCode[currentIndex]);
      currentIndex++;
    }
    while (cleanedCode[currentIndex] !== '>') {
      currentIndex++;
      if (cleanedCode[currentIndex] === '/') {
        return {
          type: 'JSXElement',
          openingElement: {
            type: 'JSXOpeningElement',
            tagName: tagName.join(''),
            attributes
          },
          children: []
        };
      }
      let attrName = [];
      let attrValue = [];
      let isParsingAttrName = true;
      while (cleanedCode[currentIndex] !== '>' && cleanedCode[currentIndex] !== ' ') {
        if (isParsingAttrName) {
          attrName.push(cleanedCode[currentIndex]);
        } else {
          attrValue.push(cleanedCode[currentIndex]);
        }
        currentIndex++;
        if (cleanedCode[currentIndex] === '=') {
          isParsingAttrName = false;
          currentIndex++;
        }
      }
      attributes[attrName.join('')] = attrValue.join('');
    }
    currentIndex++;
    return {
      type: 'JSXElement',
      openingElement: {
        type: 'JSXOpeningElement',
        tagName: tagName.join(''),
        attributes,
      },
      children: []
    };
  };
  
  const parseClosingElement = () => {
    if (cleanedCode[currentIndex] !== '<') {
      throw new Error('Invalid JSX Element');
    }
    currentIndex++;
    const tagName = [];
    while (cleanedCode[currentIndex] !== '>') {
      tagName.push(cleanedCode[currentIndex]);
      currentIndex++;
    }
    currentIndex++;
    return tagName.join('');
  };
  
  const parseJSXText = () => {
    const text = extractJSXText(parseOpeningElement());
    if (cleanedCode[currentIndex] === '<' && cleanedCode[currentIndex + 1] === '/' && cleanedCode[currentIndex + 2] === text[0] && cleanedCode[currentIndex + 3] === '>') {
      currentIndex += 4;
    } else {
      throw new Error('Invalid JSX Element');
    }
    return {
      type: 'JSXText',
      value: text
    };
  };
  
  const parseChild = () => {
    if (cleanedCode[currentIndex] === '<') {
      if (cleanedCode[currentIndex + 1] === '/') {
        throw new Error('Invalid JSX Element');
      }
      const jsxNode = parseOpeningElement();
      let jsxText = extractJSXText(jsxNode);
      if (cleanedCode[currentIndex] === '<') {
        const closingTagName = parseClosingElement();
        if (closingTagName !== jsxNode.openingElement.tagName) {
          throw new Error('Invalid JSX Element');
        }
        jsxNode.children.push({type: 'JSXText', value: jsxText}); 
        return jsxNode;
      } else {
        throw new Error('Invalid JSX Element');
      }
    } else if (cleanedCode[currentIndex] !== '<') {
      return parseJSXText();
    } else {
      throw new Error('Invalid JSX Element');
    }
  };
  
  const parseJSXChildren = () => {
    const jsxChildren = [];
    while (currentIndex < cleanedCode.length && cleanedCode[currentIndex] !== '<' && cleanedCode[currentIndex - 1] && cleanedCode[currentIndex - 1] !== '>') {
      currentIndex++;
    }
    while (currentIndex < cleanedCode.length) {
      jsxChildren.push(parseChild());
      while (currentIndex < cleanedCode.length && cleanedCode[currentIndex] !== '<' && cleanedCode[currentIndex - 1] && cleanedCode[currentIndex - 1] !== '>') {
        currentIndex++;
      }
      if (cleanedCode[currentIndex] === '<' && cleanedCode[currentIndex + 1] === '/') {
        break;
      }
    }
    return jsxChildren;
  };
  
  const jsxElement = parseOpeningElement();
  jsxElement.children = parseJSXChildren();
  if (cleanedCode[currentIndex] === '<' && cleanedCode[currentIndex + 2] === '/') {
    const closingTagName = parseClosingElement();
    if (closingTagName !== jsxElement.openingElement.tagName) {
      throw new Error('Invalid JSX Element');
    }
  }
  return jsxElement;
};

const generate = (ast) => {
  if (ast.type === 'JSXText') {
    return JSON.stringify(ast.value);
  }
  const children = ast.children.map(child => generate(child)).join('');
  return `h('${ast.openingElement.tagName}',${JSON.stringify(ast.openingElement.attributes)}, ${children})`;
};