@@ -299,6 +299,30 @@ export default function Playground() {
299
299
try {
300
300
const timestamp = new Date ( ) . toLocaleTimeString ( ) ;
301
301
302
+ // Capture stack trace to find the calling location
303
+ const stack = new Error ( ) . stack ;
304
+ let sourceLocation = null ;
305
+
306
+ if ( stack ) {
307
+ const stackLines = stack . split ( '\n' ) ;
308
+ // Look for the first line that contains 'eval' or 'Function' (user code)
309
+ for ( let i = 1 ; i < stackLines . length ; i ++ ) {
310
+ const line = stackLines [ i ] ;
311
+ if ( line . includes ( 'eval' ) || line . includes ( 'Function' ) ) {
312
+ // Try to extract line number from eval context
313
+ const evalMatch = line . match ( / e v a l .* : ( \d + ) : ( \d + ) / ) ;
314
+ if ( evalMatch ) {
315
+ sourceLocation = {
316
+ file : 'User Code' ,
317
+ line : parseInt ( evalMatch [ 1 ] ) - 8 , // Adjust for wrapper function lines
318
+ column : parseInt ( evalMatch [ 2 ] )
319
+ } ;
320
+ break ;
321
+ }
322
+ }
323
+ }
324
+ }
325
+
302
326
// Safely format arguments with error handling to prevent infinite loops
303
327
const formattedArgs = args . map ( ( arg , index ) => {
304
328
try {
@@ -316,6 +340,7 @@ export default function Playground() {
316
340
type,
317
341
timestamp,
318
342
args : formattedArgs ,
343
+ sourceLocation,
319
344
id : Date . now ( ) + Math . random ( ) // Simple unique ID
320
345
}
321
346
] ) ;
@@ -516,7 +541,7 @@ export default function Playground() {
516
541
517
542
// Memoized console result renderer
518
543
const ConsoleResultComponent = ( { result } ) => {
519
- const { type, args, id } = result ;
544
+ const { type, args, sourceLocation , id } = result ;
520
545
521
546
const getTypeClass = ( type ) => {
522
547
switch ( type ) {
@@ -530,67 +555,80 @@ export default function Playground() {
530
555
531
556
return (
532
557
< div key = { id } className = { `${ styles [ 'console-entry' ] } ${ getTypeClass ( type ) } ` } >
533
- { args . map ( ( arg , index ) => {
534
- try {
535
- // Validate that the argument is suitable for ReactJson
536
- const isValidForReactJson = ( value ) => {
537
- // Only use ReactJson for objects and arrays, not primitives
538
- if ( value === null || value === undefined ) {
539
- return false ; // Render as text
540
- }
541
- if ( typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' ) {
542
- return false ; // Render as text
543
- }
544
-
545
- if ( typeof value === 'object' ) {
546
- try {
547
- // Test if it can be JSON serialized without errors
548
- JSON . stringify ( value ) ;
549
- // Additional check for reasonable size
550
- const keys = Object . keys ( value ) ;
551
- return keys . length < 100 && keys . length > 0 ; // Must have at least 1 property
552
- } catch {
558
+ < div className = { styles [ 'console-content' ] } >
559
+ < div className = { styles [ 'console-output-content' ] } >
560
+ { args . map ( ( arg , index ) => {
561
+ try {
562
+ // Validate that the argument is suitable for ReactJson
563
+ const isValidForReactJson = ( value ) => {
564
+ // Only use ReactJson for objects and arrays, not primitives
565
+ if ( value === null || value === undefined ) {
566
+ return false ; // Render as text
567
+ }
568
+ if ( typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' ) {
569
+ return false ; // Render as text
570
+ }
571
+
572
+ if ( typeof value === 'object' ) {
573
+ try {
574
+ // Test if it can be JSON serialized without errors
575
+ JSON . stringify ( value ) ;
576
+ // Additional check for reasonable size
577
+ const keys = Object . keys ( value ) ;
578
+ return keys . length < 100 && keys . length > 0 ; // Must have at least 1 property
579
+ } catch {
580
+ return false ;
581
+ }
582
+ }
583
+
553
584
return false ;
585
+ } ;
586
+
587
+ // If the argument is not suitable for ReactJson, render as text
588
+ if ( ! isValidForReactJson ( arg ) ) {
589
+ return (
590
+ < div key = { `${ id } -${ index } ` } style = { { marginLeft : '2px' , marginBottom : '1px' , fontFamily : 'monospace' , fontSize : '12px' , lineHeight : '1.2' } } >
591
+ { String ( arg ) }
592
+ </ div >
593
+ ) ;
554
594
}
555
- }
556
-
557
- return false ;
558
- } ;
559
-
560
- // If the argument is not suitable for ReactJson, render as text
561
- if ( ! isValidForReactJson ( arg ) ) {
562
- return (
563
- < div key = { `${ id } -${ index } ` } style = { { marginLeft : '2px' , marginBottom : '1px' , fontFamily : 'monospace' , fontSize : '12px' , lineHeight : '1.2' } } >
564
- { String ( arg ) }
565
- </ div >
566
- ) ;
567
- }
568
595
569
- // Use ReactJson for valid objects/arrays
570
- return (
571
- < ReactJson
572
- key = { `${ id } -${ index } ` }
573
- src = { arg }
574
- collapsed = { 2 }
575
- theme = "solarized"
576
- name = { false }
577
- displayObjectSize = { false }
578
- displayDataTypes = { false }
579
- enableClipboard = { true }
580
- style = { { marginLeft : '2px' , marginBottom : '1px' , fontSize : '12px' } }
581
- onError = { ( ) => {
582
- return false ; // Don't show the error in the UI
583
- } }
584
- />
585
- ) ;
586
- } catch {
587
- return (
588
- < div key = { `${ id } -${ index } ` } style = { { marginLeft : '2px' , marginBottom : '1px' , fontFamily : 'monospace' , color : '#ff6b6b' , fontSize : '12px' , lineHeight : '1.2' } } >
589
- [Error rendering value: { String ( arg ) } ]
590
- </ div >
591
- ) ;
592
- }
593
- } ) }
596
+ // Use ReactJson for valid objects/arrays
597
+ return (
598
+ < ReactJson
599
+ key = { `${ id } -${ index } ` }
600
+ src = { arg }
601
+ collapsed = { 2 }
602
+ theme = "solarized"
603
+ name = { false }
604
+ displayObjectSize = { false }
605
+ displayDataTypes = { false }
606
+ enableClipboard = { true }
607
+ style = { { marginLeft : '2px' , marginBottom : '1px' , fontSize : '12px' } }
608
+ onError = { ( ) => {
609
+ return false ; // Don't show the error in the UI
610
+ } }
611
+ />
612
+ ) ;
613
+ } catch {
614
+ return (
615
+ < div key = { `${ id } -${ index } ` } style = { { marginLeft : '2px' , marginBottom : '1px' , fontFamily : 'monospace' , color : '#ff6b6b' , fontSize : '12px' , lineHeight : '1.2' } } >
616
+ [Error rendering value: { String ( arg ) } ]
617
+ </ div >
618
+ ) ;
619
+ }
620
+ } ) }
621
+ </ div >
622
+ < div className = { styles [ 'console-source' ] } >
623
+ { sourceLocation ? (
624
+ < span title = { `${ sourceLocation . file } :${ sourceLocation . line } :${ sourceLocation . column } ` } >
625
+ { sourceLocation . file } :{ sourceLocation . line }
626
+ </ span >
627
+ ) : (
628
+ < span className = { styles [ 'console-source-unknown' ] } > —</ span >
629
+ ) }
630
+ </ div >
631
+ </ div >
594
632
</ div >
595
633
) ;
596
634
} ;
0 commit comments