@@ -577,13 +577,19 @@ impl<'i> RecipeCollector<'i, '_> {
577
577
let located_ingredient = ingredient. clone ( ) ;
578
578
let ( ingredient, location) = ingredient. take_pair ( ) ;
579
579
580
- let name = ingredient. name . text_trimmed ( ) ;
580
+ let mut name = ingredient. name . text_trimmed ( ) ;
581
+ let reference = parse_reference ( & name) ;
582
+
583
+ if let Some ( reference) = & reference {
584
+ name = reference. name . clone ( ) . into ( ) ;
585
+ }
581
586
582
587
let mut new_igr = Ingredient {
583
588
name : name. into_owned ( ) ,
584
589
alias : ingredient. alias . map ( |t| t. text_trimmed ( ) . into_owned ( ) ) ,
585
590
quantity : ingredient. quantity . clone ( ) . map ( |q| self . quantity ( q, true ) ) ,
586
591
note : ingredient. note . map ( |n| n. text_trimmed ( ) . into_owned ( ) ) ,
592
+ reference,
587
593
modifiers : ingredient. modifiers . into_inner ( ) ,
588
594
relation : IngredientRelation :: definition (
589
595
Vec :: new ( ) ,
@@ -1488,3 +1494,84 @@ fn yaml_find_key_position(text: &str, key: &str) -> Option<usize> {
1488
1494
}
1489
1495
None
1490
1496
}
1497
+
1498
+ fn parse_reference ( name : & str ) -> Option < RecipeReference > {
1499
+ if name. starts_with ( "./" ) || name. starts_with ( "../" ) || name. starts_with ( ".\\ " ) || name. starts_with ( "..\\ " ) {
1500
+ let path = name. replace ( '\\' , "/" ) ;
1501
+ let mut components: Vec < String > = path. split ( '/' ) . map ( String :: from) . skip ( 1 ) . collect ( ) ;
1502
+ let file_stem = components. pop ( ) . unwrap ( ) ;
1503
+ Some ( RecipeReference {
1504
+ components,
1505
+ name : file_stem. into ( )
1506
+ } )
1507
+ } else {
1508
+ None
1509
+ }
1510
+ }
1511
+
1512
+ #[ cfg( test) ]
1513
+ mod tests {
1514
+ use super :: * ;
1515
+
1516
+ #[ test]
1517
+ fn test_parse_reference ( ) {
1518
+ // Test Unix-style paths
1519
+ assert_eq ! (
1520
+ parse_reference( "./pasta/spaghetti" ) ,
1521
+ Some ( RecipeReference {
1522
+ components: vec![ "pasta" . to_string( ) ] ,
1523
+ name: "spaghetti" . into( )
1524
+ } )
1525
+ ) ;
1526
+
1527
+ assert_eq ! (
1528
+ parse_reference( "../sauces/tomato" ) ,
1529
+ Some ( RecipeReference {
1530
+ components: vec![ "sauces" . to_string( ) ] ,
1531
+ name: "tomato" . into( )
1532
+ } )
1533
+ ) ;
1534
+
1535
+ // Test Windows-style paths
1536
+ assert_eq ! (
1537
+ parse_reference( r#".\pasta\spaghetti"# ) ,
1538
+ Some ( RecipeReference {
1539
+ components: vec![ "pasta" . to_string( ) ] ,
1540
+ name: "spaghetti" . into( )
1541
+ } )
1542
+ ) ;
1543
+
1544
+ assert_eq ! (
1545
+ parse_reference( r#"..\sauces\tomato"# ) ,
1546
+ Some ( RecipeReference {
1547
+ components: vec![ "sauces" . to_string( ) ] ,
1548
+ name: "tomato" . into( )
1549
+ } )
1550
+ ) ;
1551
+
1552
+ // Test deeper paths
1553
+ assert_eq ! (
1554
+ parse_reference( "./recipes/italian/pasta/spaghetti" ) ,
1555
+ Some ( RecipeReference {
1556
+ components: vec![ "recipes" . to_string( ) , "italian" . to_string( ) , "pasta" . to_string( ) ] ,
1557
+ name: "spaghetti" . into( )
1558
+ } )
1559
+ ) ;
1560
+
1561
+ // Test paths with no components (just file)
1562
+ assert_eq ! (
1563
+ parse_reference( "./spaghetti" ) ,
1564
+ Some ( RecipeReference {
1565
+ components: vec![ ] ,
1566
+ name: "spaghetti" . into( )
1567
+ } )
1568
+ ) ;
1569
+
1570
+ // Test non-path names (should return None)
1571
+ assert_eq ! ( parse_reference( "spaghetti" ) , None ) ;
1572
+ assert_eq ! ( parse_reference( "pasta/spaghetti" ) , None ) ;
1573
+ assert_eq ! ( parse_reference( "pasta\\ spaghetti" ) , None ) ;
1574
+ assert_eq ! ( parse_reference( "/pasta/spaghetti" ) , None ) ;
1575
+ assert_eq ! ( parse_reference( "\\ pasta\\ spaghetti" ) , None ) ;
1576
+ }
1577
+ }
0 commit comments