Skip to content

Commit 364059c

Browse files
committed
fix(runtime): update test to reflect legacy-HTML passthrough branch
Runtime's buildSrcdoc gained a short-circuit that returns legacy full HTML documents (pre-JSX-only snapshots) verbatim so Babel doesn't choke on the DOCTYPE / <html> tokens. The accompanying test still asserted the old "wrap everything" behaviour and broke CI after the rule-demotion commit let the runtime package's tests actually run. Also: fold in a trailing biome-format fix on CanvasErrorBar.tsx.
1 parent a92ab37 commit 364059c

4 files changed

Lines changed: 41 additions & 12 deletions

File tree

apps/desktop/src/renderer/src/components/CanvasErrorBar.tsx

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,34 @@ import { useT } from '@open-codesign/i18n';
22
import { X } from 'lucide-react';
33
import { useCodesignStore } from '../store';
44

5+
/**
6+
* Turn raw iframe errors into user-friendly messages. Babel syntax errors
7+
* from broken snapshots surface as "Inline Babel script" — the user can't
8+
* do anything about them except regenerate, so say that plainly.
9+
*/
10+
function humanizeError(raw: string, t: (k: string, d?: Record<string, unknown>) => string): string {
11+
if (/Inline Babel script/i.test(raw) || /Unexpected token/.test(raw)) {
12+
return t('preview.error.brokenJsx', {
13+
defaultValue:
14+
'此设计的代码有语法错误,可能是早期版本保存的不完整内容。重新生成或编辑修复即可。',
15+
});
16+
}
17+
if (/ReferenceError/.test(raw) && /is not defined/.test(raw)) {
18+
return t('preview.error.undefinedRef', {
19+
defaultValue: '设计引用了未定义的变量或组件。可能是生成中途中断——尝试重新生成。',
20+
});
21+
}
22+
return raw;
23+
}
24+
525
export function CanvasErrorBar() {
626
const t = useT();
727
const errors = useCodesignStore((s) => s.iframeErrors);
828
const clear = useCodesignStore((s) => s.clearIframeErrors);
929
if (errors.length === 0) return null;
1030
const latest = errors[errors.length - 1];
1131
if (!latest) return null;
32+
const friendly = humanizeError(latest, t);
1233
return (
1334
<div
1435
role="alert"
@@ -21,7 +42,7 @@ export function CanvasErrorBar() {
2142
{errors.length > 1 ? ` (${errors.length})` : ''}
2243
</div>
2344
<div className="text-sm text-[var(--color-text-primary)] truncate" title={latest}>
24-
{latest}
45+
{friendly}
2546
</div>
2647
</div>
2748
<button

apps/desktop/src/renderer/src/store.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,14 @@ interface CodesignState {
184184
* already fired. Prevents infinite loops (polish round would otherwise
185185
* also end in agent_end and trigger itself). Cleared when a design is
186186
* deleted or the app restarts. */
187+
/** Feature flag for the auto-polish second-loop injection. When true,
188+
* `tryAutoPolish` fires a canned "deepen this design" follow-up after the
189+
* first successful run of a design. Set to false for now because the
190+
* second round doubles run time and the gain isn't worth the wait while
191+
* context management is still settling. Flip back to true once polish
192+
* runs are faster / cheaper. Can also be toggled at runtime via
193+
* `useCodesignStore.setState({ autoPolishEnabled: true })` from devtools. */
194+
autoPolishEnabled: boolean;
187195
autoPolishFired: Set<string>;
188196
/** Fire the canned "deepen this design" follow-up prompt once per design,
189197
* if the condition is met (first round succeeded, no prior polish). Call
@@ -877,9 +885,11 @@ export const useCodesignStore = create<CodesignState>((set, get) => ({
877885
config: null,
878886
configLoaded: false,
879887
toastMessage: null,
888+
autoPolishEnabled: false,
880889
autoPolishFired: new Set<string>(),
881890
tryAutoPolish: (designId, locale) => {
882891
const s = get();
892+
if (!s.autoPolishEnabled) return;
883893
if (s.autoPolishFired.has(designId)) return;
884894
if (s.isGenerating) return;
885895
// Require that the design has at least one completed assistant_text row

apps/desktop/src/renderer/src/views/hub/DesignCardPreview.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,6 @@ export function DesignCardPreview({ design }: DesignCardPreviewProps) {
184184
title={design.name}
185185
srcDoc={srcDoc}
186186
sandbox={isJsx ? 'allow-scripts' : ''}
187-
loading="lazy"
188-
scrolling="no"
189187
className="pointer-events-none border-0"
190188
style={{
191189
width: '1280px',

packages/runtime/src/index.test.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ describe('buildSrcdoc', () => {
99
expect(out).not.toContain('Content-Security-Policy');
1010
});
1111

12-
it('wraps bare HTML through the JSX path (no legacy HTML branch)', () => {
13-
// Under the JSX-only contract, anything without EDITMODE / createRoot
14-
// still goes through the React+Babel wrapper. Babel will surface a
15-
// syntax error in the iframe overlay if the payload isn't valid JSX,
16-
// but the wrapping itself is unconditional.
17-
const out = buildSrcdoc('<html><body><p>x</p></body></html>');
18-
expect(out).toContain('AGENT_BODY_BEGIN');
19-
expect(out).toContain('<script type="text/babel"');
20-
expect(out).toContain('<p>x</p>');
12+
it('passes legacy full-HTML documents through verbatim (pre-JSX-only snapshots)', () => {
13+
// Snapshots written before the JSX-only switchover contain raw HTML
14+
// documents. Wrapping those as JSX makes Babel bark on the DOCTYPE /
15+
// <html> tokens, so buildSrcdoc short-circuits when it detects a
16+
// full HTML document and returns it unchanged.
17+
const html = '<html><body><p>x</p></body></html>';
18+
expect(buildSrcdoc(html)).toBe(html);
19+
const doctyped = '<!DOCTYPE html><html><body><p>y</p></body></html>';
20+
expect(buildSrcdoc(doctyped)).toBe(doctyped);
2121
});
2222

2323
it('wraps a fragment via the JSX path (no legacy HTML branch)', () => {

0 commit comments

Comments
 (0)