@@ -9,6 +9,8 @@ import * as Platform from '../platform/platform.js';
99import * as Root from '../root/root.js' ;
1010
1111import type { CallFrame , ScopeChainEntry } from './DebuggerModel.js' ;
12+ import { scopeTreeForScript } from './ScopeTreeCache.js' ;
13+ import type { Script } from './Script.js' ;
1214import { buildOriginalScopes , decodePastaRanges , type NamedFunctionRange } from './SourceMapFunctionRanges.js' ;
1315import { SourceMapScopesInfo } from './SourceMapScopesInfo.js' ;
1416
@@ -131,18 +133,22 @@ export class SourceMap {
131133 readonly #sourceInfos: SourceInfo [ ] = [ ] ;
132134 readonly #sourceInfoByURL = new Map < Platform . DevToolsPath . UrlString , SourceInfo > ( ) ;
133135
136+ readonly #script?: Script ;
134137 #scopesInfo: SourceMapScopesInfo | null = null ;
135138
136139 readonly #debugId?: DebugId ;
137140
141+ scopesFallbackPromiseForTest ?: Promise < unknown > ;
142+
138143 /**
139144 * Implements Source Map V3 model. See https://github.com/google/closure-compiler/wiki/Source-Maps
140145 * for format description.
141146 */
142147 constructor (
143148 compiledURL : Platform . DevToolsPath . UrlString , sourceMappingURL : Platform . DevToolsPath . UrlString ,
144- payload : SourceMapV3 ) {
149+ payload : SourceMapV3 , script ?: Script ) {
145150 this . #json = payload ;
151+ this . #script = script ;
146152 this . #compiledURL = compiledURL ;
147153 this . #sourceMappingURL = sourceMappingURL ;
148154 this . #baseURL = ( Common . ParsedURL . schemeIs ( sourceMappingURL , 'data:' ) ) ? compiledURL : sourceMappingURL ;
@@ -163,7 +169,7 @@ export class SourceMap {
163169 }
164170
165171 augmentWithScopes ( scriptUrl : Platform . DevToolsPath . UrlString , ranges : NamedFunctionRange [ ] ) : void {
166- this . #ensureMappingsProcessed ( ) ;
172+ this . #ensureSourceMapProcessed ( ) ;
167173 if ( this . #json && this . #json. version > 3 ) {
168174 throw new Error ( 'Only support augmenting source maps up to version 3.' ) ;
169175 }
@@ -212,12 +218,12 @@ export class SourceMap {
212218 }
213219
214220 hasScopeInfo ( ) : boolean {
215- this . #ensureMappingsProcessed ( ) ;
216- return this . #scopesInfo !== null ;
221+ this . #ensureSourceMapProcessed ( ) ;
222+ return this . #scopesInfo !== null && ! this . #scopesInfo . isEmpty ( ) ;
217223 }
218224
219225 findEntry ( lineNumber : number , columnNumber : number , inlineFrameIndex ?: number ) : SourceMapEntry | null {
220- this . #ensureMappingsProcessed ( ) ;
226+ this . #ensureSourceMapProcessed ( ) ;
221227 if ( inlineFrameIndex && this . #scopesInfo !== null ) {
222228 // For inlineFrameIndex != 0 we use the callsite info for the corresponding inlining site.
223229 // Note that the callsite for "inlineFrameIndex" is actually in the previous frame.
@@ -372,20 +378,40 @@ export class SourceMap {
372378 }
373379
374380 mappings ( ) : SourceMapEntry [ ] {
375- this . #ensureMappingsProcessed ( ) ;
381+ this . #ensureSourceMapProcessed ( ) ;
376382 return this . #mappings ?? [ ] ;
377383 }
378384
385+ /**
386+ * If the source map does not contain scope information by itself (e.g. "scopes proposal"
387+ * or "pasta" scopes), then we'll use this getter to calculate basic function name information from
388+ * the AST and mappings.
389+ */
390+ async #buildScopesFallback( ) : Promise < SourceMapScopesInfo | null > {
391+ const scopeTreeAndText = this . #script ? await scopeTreeForScript ( this . #script) : null ;
392+ if ( ! scopeTreeAndText ) {
393+ return null ;
394+ }
395+
396+ const { scopeTree, text} = scopeTreeAndText ;
397+ return SourceMapScopesInfo . createFromAst ( this , scopeTree , text ) ;
398+ }
399+
379400 private reversedMappings ( sourceURL : Platform . DevToolsPath . UrlString ) : number [ ] {
380- this . #ensureMappingsProcessed ( ) ;
401+ this . #ensureSourceMapProcessed ( ) ;
381402 return this . #sourceInfoByURL. get ( sourceURL ) ?. reverseMappings ?? [ ] ;
382403 }
383404
384- #ensureMappingsProcessed ( ) : void {
405+ #ensureSourceMapProcessed ( ) : void {
385406 if ( this . #mappings === null ) {
386407 this . #mappings = [ ] ;
387408 try {
388409 this . eachSection ( this . parseMap . bind ( this ) ) ;
410+ if ( ! this . hasScopeInfo ( ) ) {
411+ this . scopesFallbackPromiseForTest = this . #buildScopesFallback( ) . then ( info => {
412+ this . #scopesInfo = info ;
413+ } ) ;
414+ }
389415 } catch ( e ) {
390416 console . error ( 'Failed to parse source map' , e ) ;
391417 this . #mappings = [ ] ;
@@ -728,7 +754,7 @@ export class SourceMap {
728754 }
729755
730756 expandCallFrame ( frame : CallFrame ) : CallFrame [ ] {
731- this . #ensureMappingsProcessed ( ) ;
757+ this . #ensureSourceMapProcessed ( ) ;
732758 if ( this . #scopesInfo === null ) {
733759 return [ frame ] ;
734760 }
@@ -737,7 +763,7 @@ export class SourceMap {
737763 }
738764
739765 resolveScopeChain ( frame : CallFrame ) : ScopeChainEntry [ ] | null {
740- this . #ensureMappingsProcessed ( ) ;
766+ this . #ensureSourceMapProcessed ( ) ;
741767 if ( this . #scopesInfo === null ) {
742768 return null ;
743769 }
@@ -746,7 +772,7 @@ export class SourceMap {
746772 }
747773
748774 findOriginalFunctionName ( position : ScopesCodec . Position ) : string | null {
749- this . #ensureMappingsProcessed ( ) ;
775+ this . #ensureSourceMapProcessed ( ) ;
750776 return this . #scopesInfo?. findOriginalFunctionName ( position ) ?? null ;
751777 }
752778}
0 commit comments