@@ -117,6 +117,10 @@ struct RawSourceMap<'a> {
117117 mappings : & ' a str ,
118118 #[ serde( default , rename = "ignoreList" ) ]
119119 ignore_list : Vec < u32 > ,
120+ /// Debug ID for associating generated files with source maps (ECMA-426).
121+ /// Accepts both `debugId` (spec) and `debug_id` (Sentry compat).
122+ #[ serde( default , rename = "debugId" , alias = "debug_id" ) ]
123+ debug_id : Option < String > ,
120124 /// Indexed source maps use `sections` instead of `mappings`.
121125 #[ serde( default ) ]
122126 sections : Option < Vec < RawSection > > ,
@@ -146,6 +150,8 @@ pub struct SourceMap {
146150 pub sources_content : Vec < Option < String > > ,
147151 pub names : Vec < String > ,
148152 pub ignore_list : Vec < u32 > ,
153+ /// Debug ID (UUID) for associating generated files with source maps (ECMA-426).
154+ pub debug_id : Option < String > ,
149155
150156 /// Flat decoded mappings, ordered by (generated_line, generated_column).
151157 mappings : Vec < Mapping > ,
@@ -213,6 +219,7 @@ impl SourceMap {
213219 sources_content,
214220 names : raw. names ,
215221 ignore_list : raw. ignore_list ,
222+ debug_id : raw. debug_id ,
216223 mappings,
217224 line_offsets,
218225 reverse_index : OnceCell :: new ( ) ,
@@ -354,6 +361,7 @@ impl SourceMap {
354361 sources_content : all_sources_content,
355362 names : all_names,
356363 ignore_list : all_ignore_list,
364+ debug_id : None ,
357365 mappings : all_mappings,
358366 line_offsets,
359367 reverse_index : OnceCell :: new ( ) ,
@@ -553,6 +561,11 @@ impl SourceMap {
553561 json. push ( ']' ) ;
554562 }
555563
564+ if let Some ( ref id) = self . debug_id {
565+ json. push_str ( r#","debugId":"# ) ;
566+ json_quote_into ( & mut json, id) ;
567+ }
568+
556569 json. push ( '}' ) ;
557570 json
558571 }
@@ -2069,6 +2082,51 @@ mod tests {
20692082 assert_eq ! ( sm2. source( loc. source) , "a.js" ) ;
20702083 }
20712084
2085+ #[ test]
2086+ fn parse_debug_id ( ) {
2087+ let json = r#"{"version":3,"sources":["a.js"],"names":[],"mappings":"AAAA","debugId":"85314830-023f-4cf1-a267-535f4e37bb17"}"# ;
2088+ let sm = SourceMap :: from_json ( json) . unwrap ( ) ;
2089+ assert_eq ! (
2090+ sm. debug_id. as_deref( ) ,
2091+ Some ( "85314830-023f-4cf1-a267-535f4e37bb17" )
2092+ ) ;
2093+ }
2094+
2095+ #[ test]
2096+ fn parse_debug_id_snake_case ( ) {
2097+ let json = r#"{"version":3,"sources":["a.js"],"names":[],"mappings":"AAAA","debug_id":"85314830-023f-4cf1-a267-535f4e37bb17"}"# ;
2098+ let sm = SourceMap :: from_json ( json) . unwrap ( ) ;
2099+ assert_eq ! (
2100+ sm. debug_id. as_deref( ) ,
2101+ Some ( "85314830-023f-4cf1-a267-535f4e37bb17" )
2102+ ) ;
2103+ }
2104+
2105+ #[ test]
2106+ fn parse_no_debug_id ( ) {
2107+ let json = r#"{"version":3,"sources":["a.js"],"names":[],"mappings":"AAAA"}"# ;
2108+ let sm = SourceMap :: from_json ( json) . unwrap ( ) ;
2109+ assert_eq ! ( sm. debug_id, None ) ;
2110+ }
2111+
2112+ #[ test]
2113+ fn debug_id_roundtrip ( ) {
2114+ let json = r#"{"version":3,"sources":["a.js"],"names":[],"mappings":"AAAA","debugId":"85314830-023f-4cf1-a267-535f4e37bb17"}"# ;
2115+ let sm = SourceMap :: from_json ( json) . unwrap ( ) ;
2116+ let output = sm. to_json ( ) ;
2117+ assert ! ( output. contains( r#""debugId":"85314830-023f-4cf1-a267-535f4e37bb17""# ) ) ;
2118+ let sm2 = SourceMap :: from_json ( & output) . unwrap ( ) ;
2119+ assert_eq ! ( sm. debug_id, sm2. debug_id) ;
2120+ }
2121+
2122+ #[ test]
2123+ fn debug_id_not_in_json_when_absent ( ) {
2124+ let json = r#"{"version":3,"sources":["a.js"],"names":[],"mappings":"AAAA"}"# ;
2125+ let sm = SourceMap :: from_json ( json) . unwrap ( ) ;
2126+ let output = sm. to_json ( ) ;
2127+ assert ! ( !output. contains( "debugId" ) ) ;
2128+ }
2129+
20722130 /// Generate a test source map JSON with realistic structure.
20732131 fn generate_test_sourcemap ( lines : usize , segs_per_line : usize , num_sources : usize ) -> String {
20742132 let sources: Vec < String > = ( 0 ..num_sources)
0 commit comments