diff --git a/src/adapter/resourceProvider/basicResourceProvider.ts b/src/adapter/resourceProvider/basicResourceProvider.ts index 318f9b136..64d5a5d2a 100644 --- a/src/adapter/resourceProvider/basicResourceProvider.ts +++ b/src/adapter/resourceProvider/basicResourceProvider.ts @@ -48,7 +48,6 @@ export class BasicResourceProvider implements IResourceProvider { return { ok: false, url, error, statusCode: 200 }; } } - return this.fetchHttp(url, cancellationToken, headers); } /** diff --git a/src/adapter/scriptSkipper/implementation.ts b/src/adapter/scriptSkipper/implementation.ts index 5efb2ab72..86fefb6f6 100644 --- a/src/adapter/scriptSkipper/implementation.ts +++ b/src/adapter/scriptSkipper/implementation.ts @@ -260,6 +260,7 @@ export class ScriptSkipper { if ( !skipped && source.absolutePath && + urlUtils.isAbsolute(source.absolutePath) && this._testSkipAuthored(urlUtils.absolutePathToFileUrl(source.absolutePath)) ) { this.setIsUrlBlackboxSkipped(url, true); diff --git a/src/adapter/sources.ts b/src/adapter/sources.ts index a833f04bb..6b30523da 100644 --- a/src/adapter/sources.ts +++ b/src/adapter/sources.ts @@ -1082,9 +1082,10 @@ export class SourceContainer { const todo: Promise[] = []; for (const url of map.sources) { const absolutePath = await this.sourcePathResolver.urlToAbsolutePath({ url, map }); - const resolvedUrl = absolutePath - ? utils.absolutePathToFileUrl(absolutePath) - : map.computedSourceUrl(url); + const resolvedUrl = + absolutePath && utils.isAbsolute(absolutePath) + ? utils.absolutePathToFileUrl(absolutePath) + : map.computedSourceUrl(url); const existing = this._sourceMapSourcesByUrl.get(resolvedUrl); if (existing) { @@ -1106,7 +1107,6 @@ export class SourceContainer { resolvedUrl, }); - const fileUrl = absolutePath && utils.absolutePathToFileUrl(absolutePath); const smContent = this.sourceMapFactory.guardSourceMapFn( map, () => map.sourceContentFor(url, true), @@ -1129,6 +1129,10 @@ export class SourceContainer { } } + const fileUrl = + absolutePath && utils.isAbsolute(absolutePath) + ? utils.absolutePathToFileUrl(absolutePath) + : absolutePath; const source = new SourceFromMap( this, resolvedUrl, @@ -1146,6 +1150,7 @@ export class SourceContainer { ); source.compiledToSourceUrl.set(compiled, url); compiled.sourceMap.sourceByUrl.set(url, source); + todo.push(this._addSource(source)); } diff --git a/src/adapter/threads.ts b/src/adapter/threads.ts index 0622f3a66..bbac0badd 100644 --- a/src/adapter/threads.ts +++ b/src/adapter/threads.ts @@ -1751,8 +1751,9 @@ export class Thread implements IVariableStoreLocationProvider { } const compiledSource = - this._sourceContainer.getSourceByOriginalUrl(urlUtils.absolutePathToFileUrl(chunk.path)) || - this._sourceContainer.getSourceByOriginalUrl(chunk.path); + this._sourceContainer.getSourceByOriginalUrl( + urlUtils.isAbsolute(chunk.path) ? urlUtils.absolutePathToFileUrl(chunk.path) : chunk.path, + ) || this._sourceContainer.getSourceByOriginalUrl(chunk.path); if (!compiledSource) { todo.push(chunk.toString()); continue; diff --git a/src/common/sourceMaps/sourceMapResolutionUtils.ts b/src/common/sourceMaps/sourceMapResolutionUtils.ts index 3d3023033..1d3991d72 100644 --- a/src/common/sourceMaps/sourceMapResolutionUtils.ts +++ b/src/common/sourceMaps/sourceMapResolutionUtils.ts @@ -20,7 +20,6 @@ export function getFullSourceEntry(sourceRoot: string | undefined, sourcePath: s if (!sourceRoot.endsWith('/')) { sourceRoot += '/'; } - return sourceRoot + sourcePath; } @@ -35,12 +34,13 @@ export async function getComputedSourceRoot( logger: ILogger, ): Promise { generatedPath = utils.fileUrlToAbsolutePath(generatedPath) || generatedPath; - let absSourceRoot: string; if (sourceRoot) { if (utils.isFileUrl(sourceRoot)) { // sourceRoot points to a local path like "file:///c:/project/src", make it an absolute path absSourceRoot = utils.fileUrlToAbsolutePath(sourceRoot); + } else if (utils.isValidUrl(sourceRoot)) { + absSourceRoot = sourceRoot; } else if (utils.isAbsolute(sourceRoot)) { // sourceRoot is like "/src", should be like http://localhost/src, resolve to a local path using pathMaping. // If path mappings do not apply (e.g. node), assume that sourceRoot is actually a local absolute path. @@ -79,9 +79,13 @@ export async function getComputedSourceRoot( ); } - absSourceRoot = utils.stripTrailingSlash(absSourceRoot); - absSourceRoot = fixDriveLetterAndSlashes(absSourceRoot); - + if (!utils.isValidUrl(absSourceRoot)) { + absSourceRoot = utils.stripTrailingSlash(absSourceRoot); + absSourceRoot = fixDriveLetterAndSlashes(absSourceRoot); + } else { + //guarantees one slash in the end for later join with sources files + absSourceRoot = new URL(absSourceRoot).href; + } return absSourceRoot; } diff --git a/src/common/urlUtils.ts b/src/common/urlUtils.ts index 973009292..a33677f6c 100644 --- a/src/common/urlUtils.ts +++ b/src/common/urlUtils.ts @@ -207,6 +207,16 @@ export function isValidUrl(url: string): boolean { } } +export function isValidUrlWithProtocol(url: string): boolean { + try { + const parsed = new URL(url); + + return parsed.protocol.toLowerCase() == 'http:' || parsed.protocol.toLowerCase() == 'https:'; + } catch (e) { + return false; + } +} + export function escapeForRegExp(s: string): string { const chars = '^[]{}()\\.^$*+?|-,'; @@ -301,6 +311,11 @@ export function fileUrlToNetworkPath(urlOrPath: string): string { // TODO: this does not escape/unescape special characters, but it should. export function absolutePathToFileUrl(absolutePath: string): string { + if (!isAbsolute(absolutePath)) { + throw new Error( + `You are using the 'absolutePathToFileUrl()' on a string which is not absolute: ${absolutePath}`, + ); + } if (platform === 'win32') { return 'file:///' + platformPathToUrlPath(absolutePath); } diff --git a/src/targets/browser/browserPathResolver.ts b/src/targets/browser/browserPathResolver.ts index d429551b5..ab925d3ef 100644 --- a/src/targets/browser/browserPathResolver.ts +++ b/src/targets/browser/browserPathResolver.ts @@ -22,7 +22,7 @@ import { } from '../../common/sourceMaps/sourceMapResolutionUtils'; import { IUrlResolution } from '../../common/sourcePathResolver'; import * as utils from '../../common/urlUtils'; -import { urlToRegex } from '../../common/urlUtils'; +import { isValidUrlWithProtocol, urlToRegex } from '../../common/urlUtils'; import { PathMapping } from '../../configuration'; import { ISourcePathResolverOptions, SourcePathResolverBase } from '../sourcePathResolver'; @@ -87,7 +87,6 @@ export class BrowserSourcePathResolver extends SourcePathResolverBase if (queryCharacter !== -1 && url.slice(queryCharacter - 4, queryCharacter) !== '.vue') { url = url.slice(0, queryCharacter); } - return map ? this.sourceMapSourceToAbsolute(url, map) : this.simpleUrlToAbsolute(url); } @@ -170,7 +169,6 @@ export class BrowserSourcePathResolver extends SourcePathResolverBase } url = this.normalizeSourceMapUrl(url); - const { pathMapping } = this.options; const fullSourceEntry = getFullSourceEntry(map.sourceRoot, url); let mappedFullSourceEntry = this.sourceMapOverrides.apply(fullSourceEntry); @@ -200,18 +198,18 @@ export class BrowserSourcePathResolver extends SourcePathResolverBase } if (!path.isAbsolute(url)) { - return properResolve( - await getComputedSourceRoot( - map.sourceRoot, - map.metadata.compiledPath, - pathMapping, - defaultPathMappingResolver, - this.logger, - ), - url, + const computedSourceRoot = await getComputedSourceRoot( + map.sourceRoot, + map.metadata.compiledPath, + pathMapping, + defaultPathMappingResolver, + this.logger, ); + if (isValidUrlWithProtocol(computedSourceRoot)) { + return new URL(url, computedSourceRoot).href; + } + return properResolve(computedSourceRoot, url); } - return fixDriveLetterAndSlashes(url); } diff --git a/src/test/sources/sources-supports-remote-sources-1424.txt b/src/test/sources/sources-supports-remote-sources-1424.txt new file mode 100644 index 000000000..a11d59182 --- /dev/null +++ b/src/test/sources/sources-supports-remote-sources-1424.txt @@ -0,0 +1,23 @@ + +Source event for +{ + reason : new + source : { + name : localhost꞉8001/remote-test/string.ts + path : localhost꞉8001/remote-test/string.ts + sourceReference : + } +} +text/javascript +--------- +let i = 0; +i++; +debugger; +i++; +i++; +i++; +i++; +i++; +console.log(i);//ts file + +--------- diff --git a/src/test/sources/sourcesTest.ts b/src/test/sources/sourcesTest.ts index 503d1e5f9..e04bed112 100644 --- a/src/test/sources/sourcesTest.ts +++ b/src/test/sources/sourcesTest.ts @@ -102,6 +102,16 @@ describe('sources', () => { handle.assertLog({ substring: true }); }); + itIntegrates('supports remote sources (#1424)', async ({ r }) => { + const p = await r.launchUrlAndLoad('index.html'); + p.addScriptTag('remote-test/string.js'); + + const source = await p.waitForSource('string.ts'); + await dumpSource(p, source, ''); + + p.assertLog(); + }); + itIntegrates('works with relative webpack sourcemaps (#479)', async ({ r }) => { const p = await r.launchUrl('webpack/relative-paths.html'); diff --git a/testWorkspace/web/remote-test/string.js b/testWorkspace/web/remote-test/string.js new file mode 100644 index 000000000..0f418f44a --- /dev/null +++ b/testWorkspace/web/remote-test/string.js @@ -0,0 +1,10 @@ +let i = 0; +i++; +debugger; +i++; +i++; +i++; +i++; +i++; +console.log('123'); +//# sourceMappingURL=string.js.map diff --git a/testWorkspace/web/remote-test/string.js.map b/testWorkspace/web/remote-test/string.js.map new file mode 100644 index 000000000..4b92dbc7e --- /dev/null +++ b/testWorkspace/web/remote-test/string.js.map @@ -0,0 +1,10 @@ +{ + "version": 3, + "file": "string.js", + "sourceRoot": "http://localhost:8001/remote-test/", + "sources": [ + "string.ts" + ], + "names": [], + "mappings": ";AAAA,IAAI,CAAC,GAAG,CAAC,CAAC;AACV,CAAC,EAAE,CAAC;AACJ,QAAQ,CAAC;AACT,CAAC,EAAE,CAAC;AACJ,CAAC,EAAE,CAAC;AACJ,CAAC,EAAE,CAAC;AACJ,CAAC,EAAE,CAAC;AACJ,CAAC,EAAE,CAAC;AACJ,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC" +} \ No newline at end of file diff --git a/testWorkspace/web/remote-test/string.ts b/testWorkspace/web/remote-test/string.ts new file mode 100644 index 000000000..9326d9659 --- /dev/null +++ b/testWorkspace/web/remote-test/string.ts @@ -0,0 +1,9 @@ +let i = 0; +i++; +debugger; +i++; +i++; +i++; +i++; +i++; +console.log(i);//ts file