1
1
use std:: { collections:: BTreeSet , str:: FromStr } ;
2
2
3
3
use anyhow:: { Context , Result , bail} ;
4
+ use either:: Either ;
4
5
use rustc_hash:: FxHashSet ;
5
6
use serde:: { Deserialize , Deserializer , Serialize } ;
6
7
use serde_json:: Value as JsonValue ;
@@ -558,7 +559,7 @@ pub enum RemotePatternProtocol {
558
559
pub struct TurbopackConfig {
559
560
/// This option has been replaced by `rules`.
560
561
pub loaders : Option < JsonValue > ,
561
- pub rules : Option < FxIndexMap < RcStr , RuleConfigItemOrShortcut > > ,
562
+ pub rules : Option < FxIndexMap < RcStr , RuleConfigCollection > > ,
562
563
#[ turbo_tasks( trace_ignore) ]
563
564
pub conditions : Option < FxIndexMap < RcStr , ConfigConditionItem > > ,
564
565
pub resolve_alias : Option < FxIndexMap < RcStr , JsonValue > > ,
@@ -666,6 +667,16 @@ impl TryFrom<ConfigConditionItem> for ConditionItem {
666
667
}
667
668
}
668
669
670
+ #[ derive(
671
+ Clone , Debug , PartialEq , Eq , Serialize , Deserialize , TraceRawVcs , NonLocalValue , OperationValue ,
672
+ ) ]
673
+ #[ serde( rename_all = "camelCase" , untagged) ]
674
+ pub enum RuleConfigItem {
675
+ Options ( RuleConfigItemOptions ) ,
676
+ LegacyConditional ( FxIndexMap < RcStr , RuleConfigItem > ) ,
677
+ LegacyBoolean ( bool ) ,
678
+ }
679
+
669
680
#[ derive(
670
681
Clone , Debug , PartialEq , Eq , Serialize , Deserialize , TraceRawVcs , NonLocalValue , OperationValue ,
671
682
) ]
@@ -678,23 +689,33 @@ pub struct RuleConfigItemOptions {
678
689
pub condition : Option < ConfigConditionItem > ,
679
690
}
680
691
681
- #[ derive(
682
- Clone , Debug , PartialEq , Eq , Serialize , Deserialize , TraceRawVcs , NonLocalValue , OperationValue ,
683
- ) ]
684
- #[ serde( rename_all = "camelCase" , untagged) ]
685
- pub enum RuleConfigItemOrShortcut {
686
- Loaders ( Vec < LoaderItem > ) ,
687
- Advanced ( RuleConfigItem ) ,
692
+ #[ derive( Clone , Debug , PartialEq , Eq , Serialize , TraceRawVcs , NonLocalValue , OperationValue ) ]
693
+ #[ serde( transparent) ]
694
+ pub struct RuleConfigCollection ( Vec < RuleConfigCollectionItem > ) ;
695
+
696
+ impl < ' de > Deserialize < ' de > for RuleConfigCollection {
697
+ fn deserialize < D > ( deserializer : D ) -> Result < Self , D :: Error >
698
+ where
699
+ D : Deserializer < ' de > ,
700
+ {
701
+ match either:: serde_untagged:: deserialize :: < Vec < RuleConfigCollectionItem > , RuleConfigItem , D > (
702
+ deserializer,
703
+ ) ? {
704
+ Either :: Left ( collection) => Ok ( RuleConfigCollection ( collection) ) ,
705
+ Either :: Right ( item) => Ok ( RuleConfigCollection ( vec ! [ RuleConfigCollectionItem :: Full (
706
+ item,
707
+ ) ] ) ) ,
708
+ }
709
+ }
688
710
}
689
711
690
712
#[ derive(
691
713
Clone , Debug , PartialEq , Eq , Serialize , Deserialize , TraceRawVcs , NonLocalValue , OperationValue ,
692
714
) ]
693
- #[ serde( rename_all = "camelCase" , untagged) ]
694
- pub enum RuleConfigItem {
695
- Options ( RuleConfigItemOptions ) ,
696
- LegacyConditional ( FxIndexMap < RcStr , RuleConfigItem > ) ,
697
- LegacyBoolean ( bool ) ,
715
+ #[ serde( untagged) ]
716
+ pub enum RuleConfigCollectionItem {
717
+ Shorthand ( LoaderItem ) ,
718
+ Full ( RuleConfigItem ) ,
698
719
}
699
720
700
721
#[ derive(
@@ -1392,11 +1413,12 @@ impl NextConfig {
1392
1413
return Ok ( Vc :: cell ( Vec :: new ( ) ) ) ;
1393
1414
}
1394
1415
let mut rules = Vec :: new ( ) ;
1395
- for ( glob, rule) in turbo_rules. iter ( ) {
1396
- fn transform_loaders ( loaders : & [ LoaderItem ] ) -> ResolvedVc < WebpackLoaderItems > {
1416
+ for ( glob, rule_collection) in turbo_rules. iter ( ) {
1417
+ fn transform_loaders (
1418
+ loaders : & mut dyn Iterator < Item = & LoaderItem > ,
1419
+ ) -> ResolvedVc < WebpackLoaderItems > {
1397
1420
ResolvedVc :: cell (
1398
1421
loaders
1399
- . iter ( )
1400
1422
. map ( |item| match item {
1401
1423
LoaderItem :: LoaderName ( name) => WebpackLoaderItem {
1402
1424
loader : name. clone ( ) ,
@@ -1445,65 +1467,67 @@ impl NextConfig {
1445
1467
}
1446
1468
}
1447
1469
let config_file_path = || project_path. join ( & self . config_file_name ) ;
1448
- match rule {
1449
- RuleConfigItemOrShortcut :: Loaders ( loaders) => {
1450
- rules. push ( (
1451
- glob. clone ( ) ,
1452
- LoaderRuleItem {
1453
- loaders : transform_loaders ( loaders) ,
1454
- rename_as : None ,
1455
- condition : None ,
1456
- } ,
1457
- ) ) ;
1458
- }
1459
- RuleConfigItemOrShortcut :: Advanced ( rule) => {
1460
- if let FindRuleResult :: Found ( RuleConfigItemOptions {
1461
- loaders,
1462
- rename_as,
1463
- condition,
1464
- } ) = find_rule ( rule, & active_conditions)
1465
- {
1466
- // If the extension contains a wildcard, and the rename_as does not,
1467
- // emit an issue to prevent users from encountering duplicate module names.
1468
- if glob. contains ( "*" )
1469
- && let Some ( rename_as) = rename_as. as_ref ( )
1470
- && !rename_as. contains ( "*" )
1470
+ for item in & rule_collection. 0 {
1471
+ match item {
1472
+ RuleConfigCollectionItem :: Shorthand ( loaders) => {
1473
+ rules. push ( (
1474
+ glob. clone ( ) ,
1475
+ LoaderRuleItem {
1476
+ loaders : transform_loaders ( & mut [ loaders] . into_iter ( ) ) ,
1477
+ rename_as : None ,
1478
+ condition : None ,
1479
+ } ,
1480
+ ) ) ;
1481
+ }
1482
+ RuleConfigCollectionItem :: Full ( rule_config_item) => {
1483
+ if let FindRuleResult :: Found ( RuleConfigItemOptions {
1484
+ loaders,
1485
+ rename_as,
1486
+ condition,
1487
+ } ) = find_rule ( rule_config_item, & active_conditions)
1471
1488
{
1472
- InvalidLoaderRuleRenameAsIssue {
1473
- glob : glob. clone ( ) ,
1474
- config_file_path : config_file_path ( ) ?,
1475
- rename_as : rename_as. clone ( ) ,
1476
- }
1477
- . resolved_cell ( )
1478
- . emit ( ) ;
1479
- }
1480
-
1481
- // convert from Next.js-specific condition type to internal Turbopack
1482
- // condition type
1483
- let condition = if let Some ( condition) = condition {
1484
- if let Ok ( cond) = ConditionItem :: try_from ( condition. clone ( ) ) {
1485
- Some ( cond)
1486
- } else {
1487
- InvalidLoaderRuleConditionIssue {
1488
- condition : condition. clone ( ) ,
1489
+ // If the extension contains a wildcard, and the rename_as does not,
1490
+ // emit an issue to prevent users from encountering duplicate module
1491
+ // names.
1492
+ if glob. contains ( "*" )
1493
+ && let Some ( rename_as) = rename_as. as_ref ( )
1494
+ && !rename_as. contains ( "*" )
1495
+ {
1496
+ InvalidLoaderRuleRenameAsIssue {
1497
+ glob : glob. clone ( ) ,
1489
1498
config_file_path : config_file_path ( ) ?,
1499
+ rename_as : rename_as. clone ( ) ,
1490
1500
}
1491
1501
. resolved_cell ( )
1492
1502
. emit ( ) ;
1493
- None
1494
1503
}
1495
- } else {
1496
- None
1497
- } ;
1498
1504
1499
- rules. push ( (
1500
- glob. clone ( ) ,
1501
- LoaderRuleItem {
1502
- loaders : transform_loaders ( loaders) ,
1503
- rename_as : rename_as. clone ( ) ,
1504
- condition,
1505
- } ,
1506
- ) ) ;
1505
+ // convert from Next.js-specific condition type to internal Turbopack
1506
+ // condition type
1507
+ let condition = if let Some ( condition) = condition {
1508
+ if let Ok ( cond) = ConditionItem :: try_from ( condition. clone ( ) ) {
1509
+ Some ( cond)
1510
+ } else {
1511
+ InvalidLoaderRuleConditionIssue {
1512
+ condition : condition. clone ( ) ,
1513
+ config_file_path : config_file_path ( ) ?,
1514
+ }
1515
+ . resolved_cell ( )
1516
+ . emit ( ) ;
1517
+ None
1518
+ }
1519
+ } else {
1520
+ None
1521
+ } ;
1522
+ rules. push ( (
1523
+ glob. clone ( ) ,
1524
+ LoaderRuleItem {
1525
+ loaders : transform_loaders ( & mut loaders. iter ( ) ) ,
1526
+ rename_as : rename_as. clone ( ) ,
1527
+ condition,
1528
+ } ,
1529
+ ) ) ;
1530
+ }
1507
1531
}
1508
1532
}
1509
1533
}
0 commit comments