import * as path from 'path' ; import * as url from 'url' ; import { logger } from 'vscode-debugadapter' ; import * as chromeUtils from '../chrome/chromeUtils' ; import * as utils from '../utils' ; import { ISourceMapPathOverrides , IPathMapping } from '../debugAdapterInterfaces' ; /**
 * Resolves a relative path in terms of another file
 */ export function resolveRelativeToFile ( absPath , relPath ) { return utils . properResolve ( path . dirname ( absPath ) , relPath ) ; } /**
 * Determine an absolute path for the sourceRoot.
 */ export function getComputedSourceRoot ( sourceRoot , generatedPath , pathMapping = { } ) { generatedPath = utils . fileUrlToPath ( generatedPath ) ; let absSourceRoot ; if ( sourceRoot ) { if ( sourceRoot . startsWith ( 'file:///' ) ) { absSourceRoot = utils . canonicalizeUrl ( sourceRoot ) ; } else if ( utils . isAbsolute ( sourceRoot ) ) { absSourceRoot = chromeUtils . applyPathMappingsToTargetUrlPath ( sourceRoot , pathMapping ) || sourceRoot ; } else if ( path . isAbsolute ( generatedPath ) ) { absSourceRoot = resolveRelativeToFile ( generatedPath , sourceRoot ) ; } else { const generatedUrlPath = url . parse ( generatedPath ) . pathname ; const mappedPath = chromeUtils . applyPathMappingsToTargetUrlPath ( generatedUrlPath , pathMapping ) ; const mappedDirname = path . dirname ( mappedPath ) ; absSourceRoot = utils . properJoin ( mappedDirname , sourceRoot ) ; } logger . log ( `SourceMap: resolved sourceRoot ${ sourceRoot } -> ${ absSourceRoot }` ) ; } else if ( path . isAbsolute ( generatedPath ) ) { absSourceRoot = path . dirname ( generatedPath ) ; logger . log ( `SourceMap: no sourceRoot specified, using script dirname: ${ absSourceRoot }` ) ; } else { const urlPathname = url . parse ( generatedPath ) . pathname || '/placeholder.js' ; const mappedPath = chromeUtils . applyPathMappingsToTargetUrlPath ( urlPathname , pathMapping ) ; const scriptPathDirname = mappedPath ? path . dirname ( mappedPath ) : '' ; absSourceRoot = scriptPathDirname ; logger . log ( `SourceMap: no sourceRoot specified, using webRoot + script path dirname: ${ absSourceRoot }` ) ; } absSourceRoot = utils . stripTrailingSlash ( absSourceRoot ) ; absSourceRoot = utils . fixDriveLetterAndSlashes ( absSourceRoot ) ; return absSourceRoot ; } let aspNetFallbackCount = 0 ; export function getAspNetFallbackCount ( ) { return aspNetFallbackCount ; } /**
 * Applies a set of path pattern mappings to the given path. See tests for examples.
 * Returns something validated to be an absolute path.
 */ export function applySourceMapPathOverrides ( sourcePath , sourceMapPathOverrides , isVSClient = false ) { const forwardSlashSourcePath = sourcePath . replace ( /\\/g , '/' ) ; const sortedOverrideKeys = Object . keys ( sourceMapPathOverrides ) . sort ( ( a , b ) => b . length - a . length ) ; for ( let leftPattern of sortedOverrideKeys ) { const rightPattern = sourceMapPathOverrides [ leftPattern ] ; const entryStr = `"${ leftPattern }": "${ rightPattern }"` ; const asterisks = leftPattern . match ( /\*/g ) || [ ] ; if ( asterisks . length > 1 ) { logger . log ( `Warning: only one asterisk allowed in a sourceMapPathOverrides entry - ${ entryStr }` ) ; continue ; } const replacePatternAsterisks = rightPattern . match ( /\*/g ) || [ ] ; if ( replacePatternAsterisks . length > asterisks . length ) { logger . log ( `Warning: the right side of a sourceMapPathOverrides entry must have 0 or 1 asterisks - ${ entryStr }}` ) ; continue ; } const escapedLeftPattern = utils . escapeRegexSpecialChars ( leftPattern , '/*' ) ; const leftRegexSegment = escapedLeftPattern . replace ( /\*/g , '(.*)' ) . replace ( /\\\\/g , '/' ) ; const leftRegex = new RegExp ( `^${ leftRegexSegment }$` , 'i' ) ; const overridePatternMatches = forwardSlashSourcePath . match ( leftRegex ) ; if ( ! overridePatternMatches ) continue ; const wildcardValue = overridePatternMatches [ 1 ] ; let mappedPath = rightPattern . replace ( /\*/g , wildcardValue ) ; mappedPath = utils . properJoin ( mappedPath ) ; if ( isVSClient && leftPattern === 'webpack:///./*' && ! utils . existsSync ( mappedPath ) ) { const pathFixingASPNETBug = path . join ( rightPattern . replace ( /\*/g , path . join ( '../ClientApp' , wildcardValue ) ) ) ; if ( utils . existsSync ( pathFixingASPNETBug ) ) { ++ aspNetFallbackCount ; mappedPath = pathFixingASPNETBug ; } } logger . log ( `SourceMap: mapping ${ sourcePath } => ${ mappedPath }, via sourceMapPathOverrides entry - ${ entryStr }` ) ; return mappedPath ; } return sourcePath ; } export function resolveMapPath ( pathToGenerated , mapPath , pathMapping ) { if ( ! utils . isURL ( mapPath ) ) { if ( utils . isURL ( pathToGenerated ) ) { const scriptUrl = url . parse ( pathToGenerated ) ; const scriptPath = scriptUrl . pathname ; if ( ! scriptPath ) { return null ; } const mapUrlPathSegment = utils . isAbsolute ( mapPath ) ? mapPath : path . posix . join ( path . dirname ( scriptPath ) , mapPath ) ; mapPath = `${ scriptUrl . protocol }//${ scriptUrl . host }${ mapUrlPathSegment }` ; } else if ( utils . isAbsolute ( mapPath ) ) { mapPath = chromeUtils . applyPathMappingsToTargetUrlPath ( mapPath , pathMapping ) || mapPath ; } else if ( path . isAbsolute ( pathToGenerated ) ) { mapPath = resolveRelativeToFile ( pathToGenerated , mapPath ) ; } } return mapPath ; } export function getFullSourceEntry ( sourceRoot , sourcePath ) { if ( ! sourceRoot ) { return sourcePath ; } if ( ! sourceRoot . endsWith ( '/' ) ) { sourceRoot += '/' ; } return sourceRoot + sourcePath ; }