@@ -389,17 +389,7 @@ export class JavaScriptExecutor {
389389 break ;
390390
391391 case 'ExpressionStatement' :
392- // For expression statements, we need to track them
393- if (
394- node . expression . type === 'AssignmentExpression' &&
395- node . expression . left . type === 'Identifier'
396- ) {
397- // Named assignment like `x = 5;`
398- registry . statements . push ( node ) ;
399- } else {
400- // Other expressions (function calls, etc.) - keep in order
401- registry . statements . push ( node ) ;
402- }
392+ registry . statements . push ( node ) ;
403393 break ;
404394
405395 default :
@@ -545,13 +535,7 @@ export class JavaScriptExecutor {
545535 }
546536
547537 // Handle Error objects
548- if (
549- this . _isInstanceOfRealm (
550- value ,
551- 'Error' ,
552- typeof Error === 'undefined' ? undefined : Error
553- )
554- ) {
538+ if ( this . _isInstanceOfRealm ( value , 'Error' ) ) {
555539 const errorValue = value as Error ;
556540 return {
557541 'text/plain' : errorValue . stack || errorValue . toString ( ) ,
@@ -564,13 +548,7 @@ export class JavaScriptExecutor {
564548 }
565549
566550 // Handle Date objects
567- if (
568- this . _isInstanceOfRealm (
569- value ,
570- 'Date' ,
571- typeof Date === 'undefined' ? undefined : Date
572- )
573- ) {
551+ if ( this . _isInstanceOfRealm ( value , 'Date' ) ) {
574552 const dateValue = value as Date ;
575553 return {
576554 'text/plain' : dateValue . toISOString ( ) ,
@@ -579,24 +557,12 @@ export class JavaScriptExecutor {
579557 }
580558
581559 // Handle RegExp objects
582- if (
583- this . _isInstanceOfRealm (
584- value ,
585- 'RegExp' ,
586- typeof RegExp === 'undefined' ? undefined : RegExp
587- )
588- ) {
560+ if ( this . _isInstanceOfRealm ( value , 'RegExp' ) ) {
589561 return { 'text/plain' : ( value as RegExp ) . toString ( ) } ;
590562 }
591563
592564 // Handle Map
593- if (
594- this . _isInstanceOfRealm (
595- value ,
596- 'Map' ,
597- typeof Map === 'undefined' ? undefined : Map
598- )
599- ) {
565+ if ( this . _isInstanceOfRealm ( value , 'Map' ) ) {
600566 const mapValue = value as Map < any , any > ;
601567 const entries = Array . from ( mapValue . entries ( ) ) ;
602568 try {
@@ -610,13 +576,7 @@ export class JavaScriptExecutor {
610576 }
611577
612578 // Handle Set
613- if (
614- this . _isInstanceOfRealm (
615- value ,
616- 'Set' ,
617- typeof Set === 'undefined' ? undefined : Set
618- )
619- ) {
579+ if ( this . _isInstanceOfRealm ( value , 'Set' ) ) {
620580 const setValue = value as Set < any > ;
621581 const items = Array . from ( setValue ) ;
622582 try {
@@ -656,13 +616,7 @@ export class JavaScriptExecutor {
656616 }
657617
658618 // Handle Promise (show as pending)
659- if (
660- this . _isInstanceOfRealm (
661- value ,
662- 'Promise' ,
663- typeof Promise === 'undefined' ? undefined : Promise
664- )
665- ) {
619+ if ( this . _isInstanceOfRealm ( value , 'Promise' ) ) {
666620 return { 'text/plain' : 'Promise { <pending> }' } ;
667621 }
668622
@@ -1354,10 +1308,7 @@ export class JavaScriptExecutor {
13541308 * Checks for _toHtml, _toSvg, _toPng, _toJpeg, _toMime, inspect.
13551309 */
13561310 private _getCustomMimeBundle ( value : any ) : IMimeBundle | null {
1357- const bundle : IMimeBundle = { } ;
1358- let hasCustomOutput = false ;
1359-
1360- // Check for _toMime() - returns full MIME bundle
1311+ // Check for _toMime() first - returns a full MIME bundle directly.
13611312 if ( typeof value . _toMime === 'function' ) {
13621313 try {
13631314 const mimeResult = value . _toMime ( ) ;
@@ -1369,113 +1320,58 @@ export class JavaScriptExecutor {
13691320 }
13701321 }
13711322
1372- if ( typeof value . _toHtml === 'function' ) {
1373- try {
1374- const html = value . _toHtml ( ) ;
1375- if ( typeof html === 'string' ) {
1376- bundle [ 'text/html' ] = html ;
1377- hasCustomOutput = true ;
1378- }
1379- } catch {
1380- // Ignore errors
1381- }
1382- }
1383-
1384- if ( typeof value . _toSvg === 'function' ) {
1385- try {
1386- const svg = value . _toSvg ( ) ;
1387- if ( typeof svg === 'string' ) {
1388- bundle [ 'image/svg+xml' ] = svg ;
1389- hasCustomOutput = true ;
1390- }
1391- } catch {
1392- // Ignore errors
1393- }
1394- }
1323+ // Try each custom output method. Each returns a string for its MIME type.
1324+ const customMimeMethods : [ string , string ] [ ] = [
1325+ [ '_toHtml' , 'text/html' ] ,
1326+ [ '_toSvg' , 'image/svg+xml' ] ,
1327+ [ '_toPng' , 'image/png' ] ,
1328+ [ '_toJpeg' , 'image/jpeg' ] ,
1329+ [ '_toMarkdown' , 'text/markdown' ] ,
1330+ [ '_toLatex' , 'text/latex' ]
1331+ ] ;
13951332
1396- // Check for _toPng() - should return base64 string
1397- if ( typeof value . _toPng === 'function' ) {
1398- try {
1399- const png = value . _toPng ( ) ;
1400- if ( typeof png === 'string' ) {
1401- bundle [ 'image/png' ] = png ;
1402- hasCustomOutput = true ;
1403- }
1404- } catch {
1405- // Ignore errors
1406- }
1407- }
1333+ const bundle : IMimeBundle = { } ;
1334+ let hasCustomOutput = false ;
14081335
1409- // Check for _toJpeg() - should return base64 string
1410- if ( typeof value . _toJpeg === 'function' ) {
1411- try {
1412- const jpeg = value . _toJpeg ( ) ;
1413- if ( typeof jpeg === 'string' ) {
1414- bundle [ 'image/jpeg' ] = jpeg ;
1415- hasCustomOutput = true ;
1336+ for ( const [ method , mimeType ] of customMimeMethods ) {
1337+ if ( typeof value [ method ] === 'function' ) {
1338+ try {
1339+ const result = value [ method ] ( ) ;
1340+ if ( typeof result === 'string' ) {
1341+ bundle [ mimeType ] = result ;
1342+ hasCustomOutput = true ;
1343+ }
1344+ } catch {
1345+ // Ignore errors in custom methods
14161346 }
1417- } catch {
1418- // Ignore errors
14191347 }
14201348 }
14211349
1422- if ( typeof value . _toMarkdown === 'function' ) {
1423- try {
1424- const md = value . _toMarkdown ( ) ;
1425- if ( typeof md === 'string' ) {
1426- bundle [ 'text/markdown' ] = md ;
1427- hasCustomOutput = true ;
1428- }
1429- } catch {
1430- // Ignore errors
1431- }
1350+ if ( ! hasCustomOutput ) {
1351+ return null ;
14321352 }
14331353
1434- if ( typeof value . _toLatex === 'function' ) {
1354+ // Add text/plain representation using inspect() if available.
1355+ if ( typeof value . inspect === 'function' ) {
14351356 try {
1436- const latex = value . _toLatex ( ) ;
1437- if ( typeof latex === 'string' ) {
1438- bundle [ 'text/latex' ] = latex ;
1439- hasCustomOutput = true ;
1440- }
1357+ bundle [ 'text/plain' ] = value . inspect ( ) ;
14411358 } catch {
1442- // Ignore errors
1443- }
1444- }
1445-
1446- // Add text/plain representation
1447- if ( hasCustomOutput ) {
1448- // Use custom inspect() if available, otherwise use toString()
1449- if ( typeof value . inspect === 'function' ) {
1450- try {
1451- bundle [ 'text/plain' ] = value . inspect ( ) ;
1452- } catch {
1453- bundle [ 'text/plain' ] = String ( value ) ;
1454- }
1455- } else {
14561359 bundle [ 'text/plain' ] = String ( value ) ;
14571360 }
1458- return bundle ;
1361+ } else {
1362+ bundle [ 'text/plain' ] = String ( value ) ;
14591363 }
14601364
1461- return null ;
1365+ return bundle ;
14621366 }
14631367
14641368 /**
14651369 * Check if value is a DOM element.
14661370 */
14671371 private _isDOMElement ( value : any ) : boolean {
14681372 return (
1469- this . _isInstanceOfRealm (
1470- value ,
1471- 'HTMLElement' ,
1472- typeof HTMLElement === 'undefined' ? undefined : HTMLElement
1473- ) ||
1474- this . _isInstanceOfRealm (
1475- value ,
1476- 'SVGElement' ,
1477- typeof SVGElement === 'undefined' ? undefined : SVGElement
1478- )
1373+ this . _isInstanceOfRealm ( value , 'HTMLElement' ) ||
1374+ this . _isInstanceOfRealm ( value , 'SVGElement' )
14791375 ) ;
14801376 }
14811377
@@ -1484,11 +1380,7 @@ export class JavaScriptExecutor {
14841380 */
14851381 private _getDOMElementMimeBundle ( element : any ) : IMimeBundle {
14861382 const isCanvasElement =
1487- this . _isInstanceOfRealm (
1488- element ,
1489- 'HTMLCanvasElement' ,
1490- typeof HTMLCanvasElement === 'undefined' ? undefined : HTMLCanvasElement
1491- ) ||
1383+ this . _isInstanceOfRealm ( element , 'HTMLCanvasElement' ) ||
14921384 ( typeof element ?. toDataURL === 'function' &&
14931385 typeof element ?. getContext === 'function' ) ;
14941386
@@ -1524,16 +1416,16 @@ export class JavaScriptExecutor {
15241416
15251417 /**
15261418 * Check `instanceof` against runtime-realm constructors when available.
1419+ *
1420+ * Looks up the constructor by name in both the runtime scope and
1421+ * `globalThis`, so callers don't need to pass a fallback constructor.
15271422 */
1528- private _isInstanceOfRealm (
1529- value : any ,
1530- ctorName : string ,
1531- fallbackCtor ?: any
1532- ) : boolean {
1423+ private _isInstanceOfRealm ( value : any , ctorName : string ) : boolean {
15331424 if ( value === null || value === undefined ) {
15341425 return false ;
15351426 }
15361427
1428+ // Check against the runtime scope constructor (e.g. iframe window).
15371429 const scopeCtor = this . _globalScope ?. [ ctorName ] ;
15381430 if ( typeof scopeCtor === 'function' ) {
15391431 try {
@@ -1545,9 +1437,11 @@ export class JavaScriptExecutor {
15451437 }
15461438 }
15471439
1548- if ( typeof fallbackCtor === 'function' ) {
1440+ // Fall back to the current realm's globalThis constructor.
1441+ const globalCtor = ( globalThis as Record < string , any > ) [ ctorName ] ;
1442+ if ( typeof globalCtor === 'function' ) {
15491443 try {
1550- return value instanceof fallbackCtor ;
1444+ return value instanceof globalCtor ;
15511445 } catch {
15521446 return false ;
15531447 }
0 commit comments