diff --git a/packages/utils/src/path.ts b/packages/utils/src/path.ts index a790b57970..cfd4d79fba 100644 --- a/packages/utils/src/path.ts +++ b/packages/utils/src/path.ts @@ -8,6 +8,13 @@ function assertPath(path: string) } } +function removeUrlParams(url: string): string +{ + const re = url.split('?')[0]; + + return re.split('#')[0]; +} + function escapeRegExp(string: string) { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string @@ -209,8 +216,8 @@ export const path: Path = { { if (this.isDataUrl(url)) return url; - const baseUrl = this.toPosix(customBaseUrl ?? settings.ADAPTER.getBaseUrl()); - const rootUrl = this.toPosix(customRootUrl ?? this.rootname(baseUrl)); + const baseUrl = removeUrlParams(this.toPosix(customBaseUrl ?? settings.ADAPTER.getBaseUrl())); + const rootUrl = removeUrlParams(this.toPosix(customRootUrl ?? this.rootname(baseUrl))); assertPath(url); url = this.toPosix(url); @@ -291,7 +298,19 @@ export const path: Path = { if (arg.length > 0) { if (joined === undefined) joined = arg; - else joined += `/${arg}`; + else + { + const prevArg = segments[i - 1] ?? ''; + + if (this.extname(prevArg)) + { + joined += `/../${arg}`; + } + else + { + joined += `/${arg}`; + } + } } } if (joined === undefined) { return '.'; } diff --git a/packages/utils/test/path.tests.ts b/packages/utils/test/path.tests.ts index 12c428997a..38f2e1fa3b 100644 --- a/packages/utils/test/path.tests.ts +++ b/packages/utils/test/path.tests.ts @@ -91,6 +91,14 @@ describe('Paths', () => it('should join paths', () => { + expect(path.join('http://foo.com/index.html', '../bar/baz/file')).toBe('http://foo.com/bar/baz/file'); + expect(path.join('http://foo.com/bar/index.html', '../baz/file')).toBe('http://foo.com/baz/file'); + expect(path.join('http://foo.com/bar/index.html', './baz/file')).toBe('http://foo.com/bar/baz/file'); + expect(path.join('http://foo.com/bar/index.html', 'baz/file')).toBe('http://foo.com/bar/baz/file'); + expect(path.join('http://foo.com/bar/index.html?var=a', '../baz/file')).toBe('http://foo.com/baz/file'); + expect(path.join('http://foo.com/bar/index.html?var=a#hash', '../baz/file')).toBe('http://foo.com/baz/file'); + expect(path.join('http://foo.com/bar/index.html#hash', '../baz/file')).toBe('http://foo.com/baz/file'); + expect(path.join('http://foo.com', '../bar/baz/file')).toBe('http://foo.com/bar/baz/file'); expect(path.join('https://foo.com', '../bar/baz/file')).toBe('https://foo.com/bar/baz/file'); expect(path.join('file:///foo', '../bar/baz/file')).toBe('file:///bar/baz/file'); @@ -211,17 +219,46 @@ describe('Paths', () => it('should create absolute urls', () => { - expect(path.toAbsolute('browser.png', 'http://example.com/page-1/')) - .toEqual(`http://example.com/page-1/browser.png`); + // relative paths + expect(path.toAbsolute('./img/browser.png', 'http://example.com/page-1/')) + .toEqual(`http://example.com/page-1/img/browser.png`); + expect(path.toAbsolute('./img/browser.png', 'http://example.com/page-1/')) + .toEqual(`http://example.com/page-1/img/browser.png`); expect(path.toAbsolute('browser.png', 'http://example.com/page-1')).toEqual(`http://example.com/page-1/browser.png`); - expect(path.toAbsolute('/browser.png', undefined, 'http://example.com/')).toEqual(`http://example.com/browser.png`); - expect(path.toAbsolute('/browser.png', undefined, 'http://example.com')).toEqual(`http://example.com/browser.png`); - + expect(path.toAbsolute('img/browser.png', 'http://example.com/page-1/')) + .toEqual(`http://example.com/page-1/img/browser.png`); expect(path.toAbsolute('windows.png', 'C:/foo/bar/')).toEqual(`C:/foo/bar/windows.png`); expect(path.toAbsolute('windows.png', 'C:/foo/bar')).toEqual(`C:/foo/bar/windows.png`); expect(path.toAbsolute('windows.png', 'C:\\foo\\bar\\')).toEqual(`C:/foo/bar/windows.png`); expect(path.toAbsolute('mac.png', '/foo/bar/')).toEqual(`/foo/bar/mac.png`); expect(path.toAbsolute('mac.png', '/foo/bar')).toEqual(`/foo/bar/mac.png`); + + // paths with extensions + expect(path.toAbsolute('./browser.png', 'http://example.com/page-1/index.html')) + .toEqual(`http://example.com/page-1/browser.png`); + expect(path.toAbsolute('./img/browser.png', 'http://example.com/page-1/index.html')) + .toEqual(`http://example.com/page-1/img/browser.png`); + expect(path.toAbsolute('img/browser.png', 'http://example.com/page-1/index.html')) + .toEqual(`http://example.com/page-1/img/browser.png`); + expect(path.toAbsolute('windows.png', 'C:/foo/bar/index.html')).toEqual(`C:/foo/bar/windows.png`); + expect(path.toAbsolute('mac.png', '/foo/bar/index.html')).toEqual(`/foo/bar/mac.png`); + + // path with query string + expect(path.toAbsolute('./browser.png', 'http://example.com/page-1/index.html?var=a#hash')) + .toEqual(`http://example.com/page-1/browser.png`); + expect(path.toAbsolute('./img/browser.png', 'http://example.com/page-1/index.html?var=a#hash')) + .toEqual(`http://example.com/page-1/img/browser.png`); + expect(path.toAbsolute('img/browser.png', 'http://example.com/page-1/index.html?var=a#hash')) + .toEqual(`http://example.com/page-1/img/browser.png`); + expect(path.toAbsolute('img/browser.png', 'http://example.com/page-1?var=a#hash')) + .toEqual(`http://example.com/page-1/img/browser.png`); + expect(path.toAbsolute('img/browser.png', 'http://example.com/page-1/?var=a#hash')) + .toEqual(`http://example.com/page-1/img/browser.png`); + + // root relative paths + expect(path.toAbsolute('/browser.png', undefined, 'http://example.com/')).toEqual(`http://example.com/browser.png`); + expect(path.toAbsolute('/browser.png', undefined, 'http://example.com')).toEqual(`http://example.com/browser.png`); + expect(path.toAbsolute('/windows.png', undefined, 'C:/foo/')).toEqual(`C:/foo/windows.png`); expect(path.toAbsolute('/windows.png', undefined, 'C:/foo')).toEqual(`C:/foo/windows.png`); expect(path.toAbsolute('/windows.png', undefined, 'C:\\foo\\')).toEqual(`C:/foo/windows.png`); @@ -234,7 +271,7 @@ describe('Paths', () => expect(path.toAbsolute('C:\\windows.png')).toEqual(`C:/windows.png`); }); - it.only('should detect if path is a data url', () => + it('should detect if path is a data url', () => { /* eslint-disable max-len */ const valid = [