1
- use std:: { io:: Write , path:: PathBuf , sync:: Arc , thread, time:: Duration } ;
1
+ use std:: { borrow :: Cow , io:: Write , path:: PathBuf , sync:: Arc , thread, time:: Duration } ;
2
2
3
3
use anyhow:: { Context , Result , anyhow, bail} ;
4
4
use napi:: {
@@ -24,14 +24,16 @@ use next_core::tracing_presets::{
24
24
} ;
25
25
use once_cell:: sync:: Lazy ;
26
26
use rand:: Rng ;
27
+ use serde:: { Deserialize , Serialize } ;
27
28
use tokio:: { io:: AsyncWriteExt , time:: Instant } ;
28
29
use tracing:: Instrument ;
29
30
use tracing_subscriber:: { Registry , layer:: SubscriberExt , util:: SubscriberInitExt } ;
30
31
use turbo_rcstr:: RcStr ;
31
32
use turbo_tasks:: {
32
- Completion , Effects , FxIndexSet , OperationVc , ReadRef , ResolvedVc , TransientInstance ,
33
- TryJoinIterExt , UpdateInfo , Vc , get_effects,
33
+ Completion , Effects , FxIndexSet , NonLocalValue , OperationValue , OperationVc , ReadRef ,
34
+ ResolvedVc , TaskInput , TransientInstance , TryJoinIterExt , UpdateInfo , Vc , get_effects,
34
35
message_queue:: { CompilationEvent , Severity , TimingEvent } ,
36
+ trace:: TraceRawVcs ,
35
37
} ;
36
38
use turbo_tasks_fs:: {
37
39
DiskFileSystem , FileContent , FileSystem , FileSystemPath , get_relative_path_to,
@@ -43,7 +45,7 @@ use turbopack_core::{
43
45
error:: PrettyPrintError ,
44
46
issue:: PlainIssue ,
45
47
output:: { OutputAsset , OutputAssets } ,
46
- source_map:: { OptionSourceMap , OptionStringifiedSourceMap , SourceMap , Token } ,
48
+ source_map:: { OptionStringifiedSourceMap , SourceMap , Token } ,
47
49
version:: { PartialUpdate , TotalUpdate , Update , VersionState } ,
48
50
} ;
49
51
use turbopack_ecmascript_hmr_protocol:: { ClientUpdateInstruction , ResourceIdentifier } ;
@@ -448,7 +450,7 @@ pub async fn project_new(
448
450
) )
449
451
}
450
452
451
- #[ derive( Debug , Clone , serde :: Serialize ) ]
453
+ #[ derive( Debug , Clone , Serialize ) ]
452
454
struct SlowFilesystemEvent {
453
455
directory : String ,
454
456
duration_ms : u128 ,
@@ -1326,21 +1328,36 @@ pub fn project_compilation_events_subscribe(
1326
1328
Ok ( ( ) )
1327
1329
}
1328
1330
1329
- #[ turbo_tasks:: value]
1330
- #[ derive( Debug ) ]
1331
1331
#[ napi( object) ]
1332
+ #[ derive(
1333
+ Clone ,
1334
+ Debug ,
1335
+ Deserialize ,
1336
+ Eq ,
1337
+ Hash ,
1338
+ NonLocalValue ,
1339
+ OperationValue ,
1340
+ PartialEq ,
1341
+ Serialize ,
1342
+ TaskInput ,
1343
+ TraceRawVcs ,
1344
+ ) ]
1332
1345
pub struct StackFrame {
1333
1346
pub is_server : bool ,
1334
1347
pub is_internal : Option < bool > ,
1335
- pub original_file : Option < String > ,
1348
+ pub original_file : Option < RcStr > ,
1336
1349
pub file : RcStr ,
1337
- // 1-indexed, unlike source map tokens
1350
+ /// 1-indexed, unlike source map tokens
1338
1351
pub line : Option < u32 > ,
1339
- // 1-indexed, unlike source map tokens
1352
+ /// 1-indexed, unlike source map tokens
1340
1353
pub column : Option < u32 > ,
1341
1354
pub method_name : Option < RcStr > ,
1342
1355
}
1343
1356
1357
+ #[ turbo_tasks:: value( transparent) ]
1358
+ #[ derive( Clone ) ]
1359
+ pub struct OptionStackFrame ( Option < StackFrame > ) ;
1360
+
1344
1361
#[ turbo_tasks:: function]
1345
1362
pub async fn get_source_map_rope (
1346
1363
container : Vc < ProjectContainer > ,
@@ -1407,12 +1424,97 @@ pub fn get_source_map_rope_operation(
1407
1424
}
1408
1425
1409
1426
#[ turbo_tasks:: function( operation) ]
1410
- pub fn get_source_map_operation (
1427
+ pub async fn project_trace_source_operation (
1411
1428
container : ResolvedVc < ProjectContainer > ,
1412
- file_path : RcStr ,
1413
- ) -> Vc < OptionSourceMap > {
1414
- let map = get_source_map_rope ( * container, file_path) ;
1415
- SourceMap :: new_from_rope_cached ( map)
1429
+ frame : StackFrame ,
1430
+ current_directory_file_url : RcStr ,
1431
+ ) -> Result < Vc < OptionStackFrame > > {
1432
+ let Some ( map) =
1433
+ & * SourceMap :: new_from_rope_cached ( get_source_map_rope ( * container, frame. file ) ) . await ?
1434
+ else {
1435
+ return Ok ( Vc :: cell ( None ) ) ;
1436
+ } ;
1437
+
1438
+ let Some ( line) = frame. line else {
1439
+ return Ok ( Vc :: cell ( None ) ) ;
1440
+ } ;
1441
+
1442
+ let token = map
1443
+ . lookup_token (
1444
+ line. saturating_sub ( 1 ) ,
1445
+ frame. column . unwrap_or ( 1 ) . saturating_sub ( 1 ) ,
1446
+ )
1447
+ . await ?;
1448
+
1449
+ let ( original_file, line, column, method_name) = match token {
1450
+ Token :: Original ( token) => (
1451
+ match urlencoding:: decode ( & token. original_file ) ? {
1452
+ Cow :: Borrowed ( _) => token. original_file ,
1453
+ Cow :: Owned ( original_file) => RcStr :: from ( original_file) ,
1454
+ } ,
1455
+ // JS stack frames are 1-indexed, source map tokens are 0-indexed
1456
+ Some ( token. original_line + 1 ) ,
1457
+ Some ( token. original_column + 1 ) ,
1458
+ token. name ,
1459
+ ) ,
1460
+ Token :: Synthetic ( token) => {
1461
+ let Some ( original_file) = token. guessed_original_file else {
1462
+ return Ok ( Vc :: cell ( None ) ) ;
1463
+ } ;
1464
+ ( original_file, None , None , None )
1465
+ }
1466
+ } ;
1467
+
1468
+ let project_root_uri =
1469
+ uri_from_file ( container. project ( ) . project_root_path ( ) , None ) . await ? + "/" ;
1470
+ let ( file, original_file, is_internal) =
1471
+ if let Some ( source_file) = original_file. strip_prefix ( & project_root_uri) {
1472
+ // Client code uses file://
1473
+ (
1474
+ RcStr :: from (
1475
+ get_relative_path_to ( & current_directory_file_url, & original_file)
1476
+ // TODO(sokra) remove this to include a ./ here to make it a relative path
1477
+ . trim_start_matches ( "./" ) ,
1478
+ ) ,
1479
+ Some ( RcStr :: from ( source_file) ) ,
1480
+ false ,
1481
+ )
1482
+ } else if let Some ( source_file) = original_file. strip_prefix ( & * SOURCE_MAP_PREFIX_PROJECT ) {
1483
+ // Server code uses turbopack:///[project]
1484
+ // TODO should this also be file://?
1485
+ (
1486
+ RcStr :: from (
1487
+ get_relative_path_to (
1488
+ & current_directory_file_url,
1489
+ & format ! ( "{project_root_uri}{source_file}" ) ,
1490
+ )
1491
+ // TODO(sokra) remove this to include a ./ here to make it a relative path
1492
+ . trim_start_matches ( "./" ) ,
1493
+ ) ,
1494
+ Some ( RcStr :: from ( source_file) ) ,
1495
+ false ,
1496
+ )
1497
+ } else if let Some ( source_file) = original_file. strip_prefix ( & * SOURCE_MAP_PREFIX ) {
1498
+ // All other code like turbopack:///[turbopack] is internal code
1499
+ // TODO(veil): Should the protocol be preserved?
1500
+ ( RcStr :: from ( source_file) , None , true )
1501
+ } else {
1502
+ bail ! (
1503
+ "Original file ({}) outside project ({})" ,
1504
+ original_file,
1505
+ project_root_uri
1506
+ )
1507
+ } ;
1508
+
1509
+ Ok ( Vc :: cell ( Some ( StackFrame {
1510
+ file,
1511
+ original_file,
1512
+ method_name,
1513
+ line,
1514
+ column,
1515
+ is_server : frame. is_server ,
1516
+ is_internal : Some ( is_internal) ,
1517
+ } ) ) )
1416
1518
}
1417
1519
1418
1520
#[ napi]
@@ -1425,98 +1527,17 @@ pub async fn project_trace_source(
1425
1527
let container = project. container ;
1426
1528
let traced_frame = turbo_tasks
1427
1529
. run_once ( async move {
1428
- let Some ( map) = & * get_source_map_operation ( container, frame. file )
1429
- . read_strongly_consistent ( )
1430
- . await ?
1431
- else {
1432
- return Ok ( None ) ;
1433
- } ;
1434
-
1435
- let Some ( line) = frame. line else {
1436
- return Ok ( None ) ;
1437
- } ;
1438
-
1439
- let token = map
1440
- . lookup_token (
1441
- line. saturating_sub ( 1 ) ,
1442
- frame. column . unwrap_or ( 1 ) . saturating_sub ( 1 ) ,
1443
- )
1444
- . await ?;
1445
-
1446
- let ( original_file, line, column, name) = match token {
1447
- Token :: Original ( token) => (
1448
- urlencoding:: decode ( & token. original_file ) ?. into_owned ( ) ,
1449
- // JS stack frames are 1-indexed, source map tokens are 0-indexed
1450
- Some ( token. original_line + 1 ) ,
1451
- Some ( token. original_column + 1 ) ,
1452
- token. name . clone ( ) ,
1453
- ) ,
1454
- Token :: Synthetic ( token) => {
1455
- let Some ( file) = & token. guessed_original_file else {
1456
- return Ok ( None ) ;
1457
- } ;
1458
- ( file. to_owned ( ) , None , None , None )
1459
- }
1460
- } ;
1461
-
1462
- let project_root_uri =
1463
- uri_from_file ( project. container . project ( ) . project_root_path ( ) , None ) . await ? + "/" ;
1464
- let ( file, original_file, is_internal) = if let Some ( source_file) =
1465
- original_file. strip_prefix ( & project_root_uri)
1466
- {
1467
- // Client code uses file://
1468
- (
1469
- RcStr :: from (
1470
- get_relative_path_to ( & current_directory_file_url, & original_file)
1471
- // TODO(sokra) remove this to include a ./ here to make it a relative
1472
- // path
1473
- . trim_start_matches ( "./" ) ,
1474
- ) ,
1475
- Some ( source_file. to_string ( ) ) ,
1476
- false ,
1477
- )
1478
- } else if let Some ( source_file) =
1479
- original_file. strip_prefix ( & * SOURCE_MAP_PREFIX_PROJECT )
1480
- {
1481
- // Server code uses turbopack:///[project]
1482
- // TODO should this also be file://?
1483
- (
1484
- RcStr :: from (
1485
- get_relative_path_to (
1486
- & current_directory_file_url,
1487
- & format ! ( "{project_root_uri}{source_file}" ) ,
1488
- )
1489
- // TODO(sokra) remove this to include a ./ here to make it a relative path
1490
- . trim_start_matches ( "./" ) ,
1491
- ) ,
1492
- Some ( source_file. to_string ( ) ) ,
1493
- false ,
1494
- )
1495
- } else if let Some ( source_file) = original_file. strip_prefix ( & * SOURCE_MAP_PREFIX ) {
1496
- // All other code like turbopack:///[turbopack] is internal code
1497
- // TODO(veil): Should the protocol be preserved?
1498
- ( RcStr :: from ( source_file) , None , true )
1499
- } else {
1500
- bail ! (
1501
- "Original file ({}) outside project ({})" ,
1502
- original_file,
1503
- project_root_uri
1504
- )
1505
- } ;
1506
-
1507
- Ok ( Some ( StackFrame {
1508
- file,
1509
- original_file,
1510
- method_name : name,
1511
- line,
1512
- column,
1513
- is_server : frame. is_server ,
1514
- is_internal : Some ( is_internal) ,
1515
- } ) )
1530
+ project_trace_source_operation (
1531
+ container,
1532
+ frame,
1533
+ RcStr :: from ( current_directory_file_url) ,
1534
+ )
1535
+ . read_strongly_consistent ( )
1536
+ . await
1516
1537
} )
1517
1538
. await
1518
1539
. map_err ( |e| napi:: Error :: from_reason ( PrettyPrintError ( & e) . to_string ( ) ) ) ?;
1519
- Ok ( traced_frame)
1540
+ Ok ( ReadRef :: into_owned ( traced_frame) )
1520
1541
}
1521
1542
1522
1543
#[ napi]
0 commit comments