11import { raw } from '../helper/html'
22import type { HtmlEscapedCallback , HtmlEscapedString } from '../utils/html'
33import { HtmlEscapedCallbackPhase , resolveCallback } from '../utils/html'
4- import { jsx , Fragment } from './base'
4+ import { jsx , Fragment , isUntrustedObject , renderChildren , renderUntrustedObject } from './base'
55import { DOM_RENDERER } from './constants'
66import { captureRenderContext , useContext } from './context'
77import { ErrorBoundary as ErrorBoundaryDomRenderer } from './dom/components'
@@ -13,9 +13,7 @@ let errorBoundaryCounter = 0
1313
1414export const childrenToString = async ( children : Child [ ] ) : Promise < HtmlEscapedString [ ] > => {
1515 try {
16- return children
17- . flat ( )
18- . map ( ( c ) => ( c == null || typeof c === 'boolean' ? '' : c . toString ( ) ) ) as HtmlEscapedString [ ]
16+ return children . flat ( ) . map ( resolveChildEarly ) as HtmlEscapedString [ ]
1917 } catch ( e ) {
2018 if ( e instanceof Promise ) {
2119 // Capture before `await`: on the fallback path the render context is
@@ -29,18 +27,16 @@ export const childrenToString = async (children: Child[]): Promise<HtmlEscapedSt
2927 }
3028}
3129
32- const resolveChildEarly = ( c : Child ) : HtmlEscapedString | Promise < HtmlEscapedString > => {
33- if ( c == null || typeof c === 'boolean' ) {
30+ const resolveChildEarly = ( child : Child ) : HtmlEscapedString | Promise < HtmlEscapedString > => {
31+ if ( child == null || typeof child === 'boolean' ) {
3432 return '' as HtmlEscapedString
35- } else if ( typeof c === 'string' ) {
36- return c as HtmlEscapedString
33+ } else if ( typeof child === 'string' || Array . isArray ( child ) ) {
34+ return renderChildren ( [ child ] )
35+ } else if ( isUntrustedObject ( child ) ) {
36+ return renderUntrustedObject ( child )
3737 } else {
38- const str = c . toString ( )
39- if ( ! ( str instanceof Promise ) ) {
40- return raw ( str )
41- } else {
42- return str as Promise < HtmlEscapedString >
43- }
38+ const str = child . toString ( )
39+ return str instanceof Promise ? ( str as Promise < HtmlEscapedString > ) : raw ( str )
4440 }
4541}
4642
@@ -76,20 +72,21 @@ export const ErrorBoundary: FC<
7672 const resolveFallbackStr = ( ) : Promise < HtmlEscapedString | string | undefined > =>
7773 ( fallbackStrPromise ||= ( async ( ) => {
7874 const awaitedFallback = await fallback
79- if ( typeof awaitedFallback === 'string' ) {
80- return awaitedFallback
81- } else {
82- const fallbackResult = await getResume ( ) ( ( ) => awaitedFallback ?. toString ( ) )
83- if ( typeof fallbackResult === 'string' ) {
84- // Don't apply `raw` to undefined/null/boolean. Preserve callbacks from
85- // the stringified result, or the original thenable for plain strings.
86- return raw (
87- fallbackResult ,
88- ( fallbackResult as HtmlEscapedString ) . callbacks ||
89- ( awaitedFallback as unknown as HtmlEscapedString ) ?. callbacks
90- )
91- }
75+ if ( awaitedFallback === null || awaitedFallback === undefined ) {
76+ return
77+ }
78+ if ( typeof awaitedFallback === 'string' || Array . isArray ( awaitedFallback ) ) {
79+ return getResume ( ) ( ( ) => renderChildren ( [ awaitedFallback ] ) )
9280 }
81+ if ( isUntrustedObject ( awaitedFallback ) ) {
82+ return getResume ( ) ( ( ) => renderUntrustedObject ( awaitedFallback ) )
83+ }
84+ const fallbackResult = await getResume ( ) ( ( ) => awaitedFallback . toString ( ) )
85+ return raw (
86+ fallbackResult ,
87+ ( fallbackResult as HtmlEscapedString ) . callbacks ||
88+ ( awaitedFallback as unknown as HtmlEscapedString ) . callbacks
89+ )
9390 } ) ( ) )
9491 const renderFallback = async ( error : Error ) : Promise < HtmlEscapedString > => {
9592 const fallbackStr = await resolveFallbackStr ( )
@@ -100,9 +97,7 @@ export const ErrorBoundary: FC<
10097 ? fallbackStr
10198 : ( fallbackRender && jsx ( Fragment , { } , fallbackRender ( error ) as HtmlEscapedString ) ) || ''
10299 ) as HtmlEscapedString
103- const fallbackResString = await Fragment ( {
104- children : fallbackRes ,
105- } ) . toString ( )
100+ const fallbackResString = await Fragment ( { children : fallbackRes } ) . toString ( )
106101 return raw (
107102 fallbackResString ,
108103 ( fallbackResString as HtmlEscapedString ) . callbacks || fallbackRes . callbacks
@@ -142,7 +137,7 @@ export const ErrorBoundary: FC<
142137 const fallbackResString = await renderFallback ( error )
143138 const fallbackCallbacks = fallbackResString . callbacks
144139 if ( buffer ) {
145- buffer [ 0 ] = buffer [ 0 ] . replace ( replaceRe , fallbackResString )
140+ buffer [ 0 ] = buffer [ 0 ] . replace ( replaceRe , ( ) => fallbackResString )
146141 return fallbackCallbacks ?. length ? raw ( '' , fallbackCallbacks ) : ''
147142 }
148143 return raw (
@@ -188,7 +183,7 @@ d.parentElement.insertBefore(c.content,d.nextSibling)
188183
189184 if ( htmlArray . every ( ( html ) => ! ( html as HtmlEscapedString ) . callbacks ?. length ) ) {
190185 if ( buffer ) {
191- buffer [ 0 ] = buffer [ 0 ] . replace ( replaceRe , content )
186+ buffer [ 0 ] = buffer [ 0 ] . replace ( replaceRe , ( ) => content )
192187 }
193188 return html
194189 }
0 commit comments