refactor: extract parseA2UIBlocks to lib/a2ui.ts; remove unused import re
- Extract parseA2UIBlocks() from A2UIRenderer.tsx into its own frontend/src/lib/a2ui.ts module to satisfy react-refresh/only-export- components ESLint rule (A2UIRenderer should only export React components) - Update ChatPanel.tsx and test files to import from lib/a2ui - Split ChatPanel.test.tsx mock: separate vi.mock for lib/a2ui (parseA2UIBlocks) and A2UIRenderer (component only) - Remove unused 'import re' from tests/test_runtime_html.py (ruff F401) All 216 frontend tests and 242 bash tests still pass. TypeScript and Vite builds are clean. Remaining ESLint warnings (react-hooks/set-state- in-effect in MCPAppRenderer and useSessions) are pre-existing patterns not introduced by Phase 3.
This commit is contained in:
@@ -230,23 +230,4 @@ export function A2UIRenderer({ block, onAction }: A2UIRendererProps) {
|
||||
}
|
||||
}
|
||||
|
||||
// ─── parseA2UIBlocks ─────────────────────────────────────────────────────────
|
||||
|
||||
export function parseA2UIBlocks(content: string): A2UIBlock[] {
|
||||
const blocks: A2UIBlock[] = []
|
||||
const regex = /```a2ui\s*\n([\s\S]*?)```/g
|
||||
let match: RegExpExecArray | null
|
||||
|
||||
while ((match = regex.exec(content)) !== null) {
|
||||
try {
|
||||
const parsed = JSON.parse(match[1])
|
||||
if (parsed && parsed.type) {
|
||||
blocks.push(parsed as A2UIBlock)
|
||||
}
|
||||
} catch {
|
||||
// Silently skip invalid JSON
|
||||
}
|
||||
}
|
||||
|
||||
return blocks
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@ import ReactMarkdown from 'react-markdown'
|
||||
import { IconSend } from '@tabler/icons-react'
|
||||
import { ToolCallCard } from './ToolCallCard'
|
||||
import { MCPAppRenderer } from './MCPAppRenderer'
|
||||
import { A2UIRenderer, parseA2UIBlocks } from './A2UIRenderer'
|
||||
import { A2UIRenderer } from './A2UIRenderer'
|
||||
import { parseA2UIBlocks } from '../lib/a2ui'
|
||||
import type { ChatMessage } from '../hooks/useChat'
|
||||
|
||||
interface ChatPanelProps {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import type { A2UIBlock } from './types'
|
||||
|
||||
/**
|
||||
* Parses `a2ui` fenced code blocks out of a markdown-like content string.
|
||||
* Each block must contain a valid JSON object with a `type` field.
|
||||
* Invalid blocks are silently skipped.
|
||||
*/
|
||||
export function parseA2UIBlocks(content: string): A2UIBlock[] {
|
||||
const blocks: A2UIBlock[] = []
|
||||
const regex = /```a2ui\s*\n([\s\S]*?)```/g
|
||||
let match: RegExpExecArray | null
|
||||
|
||||
while ((match = regex.exec(content)) !== null) {
|
||||
try {
|
||||
const parsed = JSON.parse(match[1])
|
||||
if (parsed && parsed.type) {
|
||||
blocks.push(parsed as A2UIBlock)
|
||||
}
|
||||
} catch {
|
||||
// Silently skip invalid JSON
|
||||
}
|
||||
}
|
||||
|
||||
return blocks
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect, vi } from 'vitest'
|
||||
import { render, screen, fireEvent } from '@testing-library/react'
|
||||
import { A2UIRenderer, parseA2UIBlocks } from '../components/A2UIRenderer'
|
||||
import { A2UIRenderer } from '../components/A2UIRenderer'
|
||||
import { parseA2UIBlocks } from '../lib/a2ui'
|
||||
import type { A2UIBlock } from '../lib/types'
|
||||
|
||||
// Mock @tabler/icons-react so icon SVGs don't cause jsdom issues
|
||||
|
||||
@@ -32,8 +32,8 @@ vi.mock('../components/MCPAppRenderer', () => ({
|
||||
),
|
||||
}))
|
||||
|
||||
// Mock A2UIRenderer module (component + parseA2UIBlocks)
|
||||
vi.mock('../components/A2UIRenderer', () => ({
|
||||
// Mock lib/a2ui parseA2UIBlocks parser
|
||||
vi.mock('../lib/a2ui', () => ({
|
||||
parseA2UIBlocks: vi.fn((content: string) => {
|
||||
const blocks: Array<Record<string, unknown>> = []
|
||||
const regex = /```a2ui\s*\n([\s\S]*?)```/g
|
||||
@@ -48,6 +48,10 @@ vi.mock('../components/A2UIRenderer', () => ({
|
||||
}
|
||||
return blocks
|
||||
}),
|
||||
}))
|
||||
|
||||
// Mock A2UIRenderer component
|
||||
vi.mock('../components/A2UIRenderer', () => ({
|
||||
A2UIRenderer: ({
|
||||
block,
|
||||
onAction,
|
||||
|
||||
Reference in New Issue
Block a user