33const  { 
44  ArrayPrototypePush, 
55  JSONParse, 
6-   ObjectKeys, 
76  RegExpPrototypeExec, 
87  SafeMap, 
98  StringPrototypeCodePointAt, 
@@ -25,24 +24,22 @@ const {
2524}  =  require ( 'internal/errors' ) ; 
2625const  {  getLazy }  =  require ( 'internal/util' ) ; 
2726
28- // Since the CJS module cache is mutable, which leads to memory leaks when 
29- // modules are deleted, we use a WeakMap so that the source map cache will 
30- // be purged automatically: 
31- const  getCjsSourceMapCache  =  getLazy ( ( )  =>  { 
32-   const  {  IterableWeakMap }  =  require ( 'internal/util/iterable_weak_map' ) ; 
33-   return  new  IterableWeakMap ( ) ; 
27+ const  getModuleSourceMapCache  =  getLazy ( ( )  =>  { 
28+   const  {  SourceMapCacheMap }  =  require ( 'internal/source_map/source_map_cache_map' ) ; 
29+   return  new  SourceMapCacheMap ( ) ; 
3430} ) ; 
3531
36- // The esm cache is not mutable, so we can use a Map without memory concerns: 
37- const  esmSourceMapCache  =  new  SafeMap ( ) ; 
38- // The generated sources is not mutable, so we can use a Map without memory concerns: 
32+ // The generated source module/script instance is not accessible, so we can use 
33+ // a Map without memory concerns. Separate generated source entries with the module 
34+ // source entries to avoid overriding the module source entries with arbitrary 
35+ // source url magic comments. 
3936const  generatedSourceMapCache  =  new  SafeMap ( ) ; 
4037const  kLeadingProtocol  =  / ^ \w + : \/ \/ / ; 
4138const  kSourceMappingURLMagicComment  =  / \/ [ * / ] # \s + s o u r c e M a p p i n g U R L = (?< sourceMappingURL > [ ^ \s ] + ) / g; 
4239const  kSourceURLMagicComment  =  / \/ [ * / ] # \s + s o u r c e U R L = (?< sourceURL > [ ^ \s ] + ) / g; 
4340
4441const  {  isAbsolute }  =  require ( 'path' ) ; 
45- const  {  fileURLToPath,  pathToFileURL,  URL  }  =  require ( 'internal/url' ) ; 
42+ const  {  fileURLToPath,  pathToFileURL,  URL ,  URLParse  }  =  require ( 'internal/url' ) ; 
4643
4744let  SourceMap ; 
4845
@@ -52,6 +49,10 @@ function getSourceMapsEnabled() {
5249  return  sourceMapsEnabled ; 
5350} 
5451
52+ /** 
53+  * Enables or disables source maps programmatically. 
54+  * @param  {boolean } val 
55+  */ 
5556function  setSourceMapsEnabled ( val )  { 
5657  validateBoolean ( val ,  'val' ) ; 
5758
@@ -72,6 +73,14 @@ function setSourceMapsEnabled(val) {
7273  sourceMapsEnabled  =  val ; 
7374} 
7475
76+ /** 
77+  * Extracts the source url from the content if present. For example 
78+  * //# sourceURL=file:///path/to/file 
79+  * 
80+  * Read more at: https://tc39.es/source-map-spec/#linking-evald-code-to-named-generated-code 
81+  * @param  {string } content - source content 
82+  * @returns  {string | null } source url or null if not present 
83+  */ 
7584function  extractSourceURLMagicComment ( content )  { 
7685  let  match ; 
7786  let  matchSourceURL ; 
@@ -90,6 +99,14 @@ function extractSourceURLMagicComment(content) {
9099  return  sourceURL ; 
91100} 
92101
102+ /** 
103+  * Extracts the source map url from the content if present. For example 
104+  * //# sourceMappingURL=file:///path/to/file 
105+  * 
106+  * Read more at: https://tc39.es/source-map-spec/#linking-generated-code 
107+  * @param  {string } content - source content 
108+  * @returns  {string | null } source map url or null if not present 
109+  */ 
93110function  extractSourceMapURLMagicComment ( content )  { 
94111  let  match ; 
95112  let  lastMatch ; 
@@ -104,7 +121,17 @@ function extractSourceMapURLMagicComment(content) {
104121  return  lastMatch . groups . sourceMappingURL ; 
105122} 
106123
107- function  maybeCacheSourceMap ( filename ,  content ,  cjsModuleInstance ,  isGeneratedSource ,  sourceURL ,  sourceMapURL )  { 
124+ /** 
125+  * Caches the source map if it is present in the content, with the given filename, moduleInstance, and sourceURL. 
126+  * @param  {string } filename - the actual filename 
127+  * @param  {string } content - the actual source content 
128+  * @param  {import('internal/modules/cjs/loader').Module | ModuleWrap } moduleInstance - a module instance that 
129+  * associated with the source, once this is reclaimed, the source map entry will be removed from the cache 
130+  * @param  {boolean } isGeneratedSource - if the source was generated and evaluated with the global eval 
131+  * @param  {string | undefined } sourceURL - the source url 
132+  * @param  {string | undefined } sourceMapURL - the source map url 
133+  */ 
134+ function  maybeCacheSourceMap ( filename ,  content ,  moduleInstance ,  isGeneratedSource ,  sourceURL ,  sourceMapURL )  { 
108135  const  sourceMapsEnabled  =  getSourceMapsEnabled ( ) ; 
109136  if  ( ! ( process . env . NODE_V8_COVERAGE  ||  sourceMapsEnabled ) )  return ; 
110137  const  {  normalizeReferrerURL }  =  require ( 'internal/modules/helpers' ) ; 
@@ -130,45 +157,32 @@ function maybeCacheSourceMap(filename, content, cjsModuleInstance, isGeneratedSo
130157  } 
131158
132159  const  data  =  dataFromUrl ( filename ,  sourceMapURL ) ; 
133-   const  url  =  data  ? null  : sourceMapURL ; 
134-   if  ( cjsModuleInstance )  { 
135-     getCjsSourceMapCache ( ) . set ( cjsModuleInstance ,  { 
136-       __proto__ : null , 
137-       filename, 
138-       lineLengths : lineLengths ( content ) , 
139-       data, 
140-       url, 
141-       sourceURL, 
142-     } ) ; 
143-   }  else  if  ( isGeneratedSource )  { 
144-     const  entry  =  { 
145-       __proto__ : null , 
146-       lineLengths : lineLengths ( content ) , 
147-       data, 
148-       url, 
149-       sourceURL, 
150-     } ; 
160+   const  entry  =  { 
161+     __proto__ : null , 
162+     lineLengths : lineLengths ( content ) , 
163+     data, 
164+     // Save the source map url if it is not a data url. 
165+     sourceMapURL : data  ? null  : sourceMapURL , 
166+     sourceURL, 
167+   } ; 
168+ 
169+   if  ( isGeneratedSource )  { 
151170    generatedSourceMapCache . set ( filename ,  entry ) ; 
152171    if  ( sourceURL )  { 
153172      generatedSourceMapCache . set ( sourceURL ,  entry ) ; 
154173    } 
155-   }  else  { 
156-     // If there is no cjsModuleInstance and is not generated source assume we are in a 
157-     // "modules/esm" context. 
158-     const  entry  =  { 
159-       __proto__ : null , 
160-       lineLengths : lineLengths ( content ) , 
161-       data, 
162-       url, 
163-       sourceURL, 
164-     } ; 
165-     esmSourceMapCache . set ( filename ,  entry ) ; 
166-     if  ( sourceURL )  { 
167-       esmSourceMapCache . set ( sourceURL ,  entry ) ; 
168-     } 
174+     return ; 
169175  } 
176+   // If it is not a generated source, we assume we are in a "cjs/esm" 
177+   // context. 
178+   const  keys  =  sourceURL  ? [ filename ,  sourceURL ]  : [ filename ] ; 
179+   getModuleSourceMapCache ( ) . set ( keys ,  entry ,  moduleInstance ) ; 
170180} 
171181
182+ /** 
183+  * Caches the source map if it is present in the eval'd source. 
184+  * @param  {string } content - the eval'd source code 
185+  */ 
172186function  maybeCacheGeneratedSourceMap ( content )  { 
173187  const  sourceMapsEnabled  =  getSourceMapsEnabled ( ) ; 
174188  if  ( ! ( process . env . NODE_V8_COVERAGE  ||  sourceMapsEnabled ) )  return ; 
@@ -186,22 +200,29 @@ function maybeCacheGeneratedSourceMap(content) {
186200  } 
187201} 
188202
203+ /** 
204+  * Resolves source map payload data from the source url and source map url. 
205+  * If the source map url is a data url, the data is returned. 
206+  * Otherwise the source map url is resolved to a file path and the file is read. 
207+  * @param  {string } sourceURL - url of the source file 
208+  * @param  {string } sourceMappingURL - url of the source map 
209+  * @returns  {object } deserialized source map JSON object 
210+  */ 
189211function  dataFromUrl ( sourceURL ,  sourceMappingURL )  { 
190-   try  { 
191-     const  url  =  new  URL ( sourceMappingURL ) ; 
212+   const  url  =  URLParse ( sourceMappingURL ) ; 
213+ 
214+   if  ( url  !=  null )  { 
192215    switch  ( url . protocol )  { 
193216      case  'data:' :
194217        return  sourceMapFromDataUrl ( sourceURL ,  url . pathname ) ; 
195218      default :
196219        debug ( `unknown protocol ${ url . protocol }  ` ) ; 
197220        return  null ; 
198221    } 
199-   }  catch  ( err )  { 
200-     debug ( err ) ; 
201-     // If no scheme is present, we assume we are dealing with a file path. 
202-     const  mapURL  =  new  URL ( sourceMappingURL ,  sourceURL ) . href ; 
203-     return  sourceMapFromFile ( mapURL ) ; 
204222  } 
223+ 
224+   const  mapURL  =  new  URL ( sourceMappingURL ,  sourceURL ) . href ; 
225+   return  sourceMapFromFile ( mapURL ) ; 
205226} 
206227
207228// Cache the length of each line in the file that a source map was extracted 
@@ -227,7 +248,11 @@ function lineLengths(content) {
227248  return  output ; 
228249} 
229250
230- 
251+ /** 
252+  * Read source map from file. 
253+  * @param  {string } mapURL - file url of the source map 
254+  * @returns  {object } deserialized source map JSON object 
255+  */ 
231256function  sourceMapFromFile ( mapURL )  { 
232257  try  { 
233258    const  fs  =  require ( 'fs' ) ; 
@@ -281,56 +306,44 @@ function sourcesToAbsolute(baseURL, data) {
281306  return  data ; 
282307} 
283308
284- // WARNING: The `sourceMapCacheToObject` and `appendCJSCache` run during  
285- // shutdown. In particular, they  also run  when Workers are terminated, making 
286- // it important that they do  not call out to any user-provided code, including 
287- // built-in prototypes that  might have been tampered with. 
309+ // WARNING: The `sourceMapCacheToObject` runs during shutdown. In particular,  
310+ // it  also runs  when Workers are terminated, making it important that it does  
311+ // not call out to any user-provided code, including built-in prototypes that  
312+ // might have been tampered with. 
288313
289314// Get serialized representation of source-map cache, this is used 
290315// to persist a cache of source-maps to disk when NODE_V8_COVERAGE is enabled. 
291316function  sourceMapCacheToObject ( )  { 
292-   const  obj  =  {  __proto__ : null  } ; 
293- 
294-   for  ( const  {  0 : k ,  1 : v  }  of  esmSourceMapCache )  { 
295-     obj [ k ]  =  v ; 
296-   } 
297- 
298-   appendCJSCache ( obj ) ; 
299- 
300-   if  ( ObjectKeys ( obj ) . length  ===  0 )  { 
317+   const  moduleSourceMapCache  =  getModuleSourceMapCache ( ) ; 
318+   if  ( moduleSourceMapCache . size  ===  0 )  { 
301319    return  undefined ; 
302320  } 
303-   return  obj ; 
304- } 
305321
306- function   appendCJSCache ( obj )   { 
307-   for  ( const  value   of  getCjsSourceMapCache ( ) )  { 
308-     obj [ value . filename ]  =  { 
322+    const   obj   =   {   __proto__ :  null   } ; 
323+   for  ( const  {   0 :  k ,   1 :  v   }   of  moduleSourceMapCache )  { 
324+     obj [ k ]  =  { 
309325      __proto__ : null , 
310-       lineLengths : value . lineLengths , 
311-       data : value . data , 
312-       url : value . url , 
326+       lineLengths : v . lineLengths , 
327+       data : v . data , 
328+       url : v . sourceMapURL , 
313329    } ; 
314330  } 
331+   return  obj ; 
315332} 
316333
334+ /** 
335+  * Find a source map for a given actual source URL or path. 
336+  * @param  {string } sourceURL - actual source URL or path 
337+  * @returns  {import('internal/source_map/source_map').SourceMap | undefined } a source map or undefined if not found 
338+  */ 
317339function  findSourceMap ( sourceURL )  { 
318340  if  ( RegExpPrototypeExec ( kLeadingProtocol ,  sourceURL )  ===  null )  { 
319341    sourceURL  =  pathToFileURL ( sourceURL ) . href ; 
320342  } 
321343  if  ( ! SourceMap )  { 
322344    SourceMap  =  require ( 'internal/source_map/source_map' ) . SourceMap ; 
323345  } 
324-   let  entry  =  esmSourceMapCache . get ( sourceURL )  ??  generatedSourceMapCache . get ( sourceURL ) ; 
325-   if  ( entry  ===  undefined )  { 
326-     for  ( const  value  of  getCjsSourceMapCache ( ) )  { 
327-       const  filename  =  value . filename ; 
328-       const  cachedSourceURL  =  value . sourceURL ; 
329-       if  ( sourceURL  ===  filename  ||  sourceURL  ===  cachedSourceURL )  { 
330-         entry  =  value ; 
331-       } 
332-     } 
333-   } 
346+   const  entry  =  getModuleSourceMapCache ( ) . get ( sourceURL )  ??  generatedSourceMapCache . get ( sourceURL ) ; 
334347  if  ( entry  ===  undefined )  { 
335348    return  undefined ; 
336349  } 
0 commit comments