mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-13 06:36:26 +03:00
Closes #114. Three orthogonal bugs that surfaced together when live mode picked an element inside a Vite React/TSX component with sibling branches: 1. JSX wrapper insertion produced invalid TSX - Replacing a single picked JSX child with [comment, <div>, comment] yields three adjacent siblings, which oxc rejects with "Adjacent JSX elements must be wrapped in an enclosing tag." - A Fragment `<></>` solves the adjacency case but breaks `cloneElement`-using parents (Radix `asChild`, Headless UI, etc.) with "Invalid prop supplied to React.Fragment." - Fix: keep the wrapper `<div data-impeccable-variants="ID">` as the single JSX-slot child and tuck both marker comments INSIDE it. accept/discard now expands its replacement range to include the wrapper's `<div>` open/close lines via div-depth tracking. 2. carbonize produced nested template literals in TSX `<style>` - extractCss captured `{` / `` `} `` lines from the agent's existing `<style>{`…`}</style>` template, then handleAccept re-wrapped with another pair, producing `<style>{`{`@scope…`}`}</style>` which oxc rejects with "Expected `}` but found `@`". - Fix: extractCss now strips a leading `{` and trailing `` `} `` wherever they appear in the captured content (own line OR attached to the first/last CSS line), so re-wrapping always yields exactly one `{` ` … ` `}` pair. 3. Ambiguous source matching for repeated JSX branches - `findElement` returned the first substring match. Multiple `<aside className="card">` siblings all matched the same query, so wrap silently landed on the first regardless of which one the user picked. - Fix: live-wrap accepts `--text TEXT` (the picked element's textContent), collects ALL candidates via `findAllElements`, and narrows by a tag-stripped, JSX-expression-stripped substring match. Returns `element_ambiguous + candidates[]` when multiple branches match equally; falls back to first-match when source uses dynamic content (`<h1>{title}</h1>`) so existing flows aren't broken. - The fake e2e agent now forwards `event.element.textContent` to wrap, and live.md tells the agent to do the same. Test coverage: - New `vite8-react-tsx-repeated-aside` e2e fixture: three identical `<aside>` branches, picks the second card's <h1>, runs the full wrap → Go → cycle → accept → carbonize cycle on a real Vite + TSX dev server, asserts that Hero One and Hero Three survive untouched (proving wrap landed on the correct branch). - Six new unit tests across live-wrap.test.mjs and live-accept.test.mjs covering the Fragment-replacement design, both leading/trailing template-literal placements, --text disambiguation, the dynamic- content fallback, and the element_ambiguous error shape. - New `runtime.assertSourceContains` fixture hook so other regression fixtures can assert sibling-branch survivability cheaply. All 186 unit + static-fixture tests pass; all 21 live e2e fixtures (20 prior + new TSX) pass with no console errors. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
31 lines
1.0 KiB
JSON
31 lines
1.0 KiB
JSON
{
|
|
"name": "Vite 8 + React TSX with repeated <aside> branches",
|
|
"config": {
|
|
"files": ["index.html"],
|
|
"insertBefore": "</body>",
|
|
"commentSyntax": "html"
|
|
},
|
|
"sourceFiles": ["index.html", "src/App.tsx", "src/main.tsx", "src/styles.css", "vite.config.ts", "tsconfig.json"],
|
|
"generatedFiles": [],
|
|
"wrapCases": [
|
|
{
|
|
"name": "wraps the picked aside (second branch) inside a Fragment so TSX stays valid",
|
|
"args": { "classes": "hero-title", "tag": "h1" },
|
|
"expectedFile": "src/App.tsx"
|
|
}
|
|
],
|
|
"runtime": {
|
|
"styling": "plain-css",
|
|
"install": ["npm", "install", "--no-audit", "--no-fund", "--loglevel=error"],
|
|
"devCommand": ["npx", "vite", "--host", "127.0.0.1"],
|
|
"readyPattern": "Local:\\s+https?://[^:]+:(\\d+)",
|
|
"readyTimeoutMs": 120000,
|
|
"pickSelector": "[data-testid='card-2'] h1.hero-title",
|
|
"assertSourceContains": ["Hero One", "Hero Three", "First card body copy.", "Third card body copy."],
|
|
"probe": {
|
|
"expectLiveInit": true,
|
|
"expectConsoleClean": true
|
|
}
|
|
}
|
|
}
|