/*
Copyright (C) 2023-2026 QuantumNous
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
For commercial licensing, please contact support@quantumnous.com
*/
import type { ReactNode } from 'react'
import type { FootnoteNode, ParsedNode } from 'stream-markdown-parser'
import { getNodeKey } from './response-content'
import {
hasParsedChildren,
isBlockquoteNode,
isCodeBlockNode,
isDefinitionListNode,
isHeadingNode,
isHtmlBlockNode,
isImageNode,
isLinkNode,
isListNode,
isMathBlockNode,
isMathInlineNode,
isTableNode,
isTextNode,
} from './response-node-guards'
import { renderBlockquote } from './response-renderer-alert'
import {
renderCodeBlock,
renderDefinitionList,
renderHeading,
renderList,
renderMathBlock,
renderMathInline,
} from './response-renderer-blocks'
import { renderDetails } from './response-renderer-details'
import { renderFootnotes as renderFootnotesBlock } from './response-renderer-footnotes'
import {
renderImage,
renderLink,
renderTextNode,
} from './response-renderer-inline'
import { renderTable } from './response-renderer-table'
export function renderChildren(nodes: ParsedNode[]): ReactNode {
return nodes.map((node, index) => renderNode(node, getNodeKey(node, index)))
}
export function renderFootnotes(footnotes: FootnoteNode[]): ReactNode {
return renderFootnotesBlock(footnotes, { renderChildren })
}
function renderNode(node: ParsedNode, key: string): ReactNode {
if (isTextNode(node)) {
return renderTextNode(node)
}
if (isHeadingNode(node)) {
return renderHeading(node, key, { renderChildren })
}
if (node.type === 'paragraph' && hasParsedChildren(node)) {
return (
{renderChildren(node.children)}
)
}
if (node.type === 'inline' && hasParsedChildren(node)) {
return {renderChildren(node.children)}
}
if (isListNode(node)) {
return renderList(node, key, { renderChildren })
}
if (isCodeBlockNode(node)) {
return renderCodeBlock(node, key)
}
if (node.type === 'inline_code' && 'code' in node) {
return (
{String(node.code)}
)
}
if (isLinkNode(node)) {
return renderLink(node, key, renderChildren)
}
if (isImageNode(node)) {
return renderImage(node, key)
}
if (isBlockquoteNode(node)) {
return renderBlockquote(node, key, { renderChildren })
}
if (isTableNode(node)) {
return renderTable(node, key, { renderChildren })
}
if (isDefinitionListNode(node)) {
return renderDefinitionList(node, key, { renderChildren })
}
if (node.type === 'strong' && hasParsedChildren(node)) {
return (
{renderChildren(node.children)}
)
}
if (node.type === 'emphasis' && hasParsedChildren(node)) {
return {renderChildren(node.children)}
}
if (node.type === 'strikethrough' && hasParsedChildren(node)) {
return {renderChildren(node.children)}
}
if (node.type === 'highlight' && hasParsedChildren(node)) {
return {renderChildren(node.children)}
}
if (node.type === 'insert' && hasParsedChildren(node)) {
return {renderChildren(node.children)}
}
if (node.type === 'subscript' && hasParsedChildren(node)) {
return {renderChildren(node.children)}
}
if (node.type === 'superscript' && hasParsedChildren(node)) {
return {renderChildren(node.children)}
}
if (
(node.type === 'checkbox' || node.type === 'checkbox_input') &&
'checked' in node
) {
return (
)
}
if (node.type === 'hardbreak') {
return
}
if (node.type === 'thematic_break') {
return
}
if (isMathBlockNode(node)) {
return renderMathBlock(node, key)
}
if (isMathInlineNode(node)) {
return renderMathInline(node, key)
}
if (node.type === 'footnote_reference' && 'id' in node) {
return (
[{String(node.id)}]
)
}
if (node.type === 'footnote_anchor') {
return null
}
if (isHtmlBlockNode(node) && node.tag === 'details') {
return renderDetails(node, key, { renderChildren })
}
if (node.type === 'html_block' && 'content' in node) {
return {String(node.content)}
}
if (node.type === 'html_inline' && 'content' in node) {
return {String(node.content)}
}
if (hasParsedChildren(node)) {
return {renderChildren(node.children)}
}
if ('content' in node && typeof node.content === 'string') {
return {node.content}
}
return {node.raw}
}