From ee05e79cb5ccddabe2149d44e1b88d68236fe533 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Sat, 20 Feb 2016 14:43:38 +0100 Subject: [PATCH] Remove network.URL --- src/vs/base/common/network.ts | 421 +----------------- src/vs/base/test/common/network.test.ts | 128 ------ src/vs/languages/html/common/htmlWorker.ts | 36 +- .../html/test/common/html-worker.test.ts | 8 +- 4 files changed, 24 insertions(+), 569 deletions(-) diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts index 7d90eb9a800..93f3a9d46cc 100644 --- a/src/vs/base/common/network.ts +++ b/src/vs/base/common/network.ts @@ -4,425 +4,6 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import assert = require('vs/base/common/assert'); -import objects = require('vs/base/common/objects'); -import strings = require('vs/base/common/strings'); -import hash = require('vs/base/common/hash'); -import paths = require('vs/base/common/paths'); -import URI from 'vs/base/common/uri'; - -var _colon = ':'.charCodeAt(0), - _slash = '/'.charCodeAt(0), - _questionMark = '?'.charCodeAt(0), - _hash = '#'.charCodeAt(0); - -export class ParsedUrl { - - private spec:string; - private specLength:number; - private schemeStart:number; - private domainStart:number; - private portStart:number; - private pathStart:number; - private queryStringStart:number; - private fragmentIdStart:number; - - constructor(spec:string) { - this.spec = spec || strings.empty; - this.specLength = this.spec.length; - - - - this.parse(); - } - - private forwardSubstring(startIndex:number, endIndex:number): string { - if (startIndex < endIndex) { - return this.spec.substring(startIndex, endIndex); - } - return strings.empty; - } - - /** - * http for http://www.test.com:8000/this/that/theother.html?query=foo#hash - */ - public getScheme(): string { - return this.forwardSubstring(this.schemeStart, this.domainStart - 1); - } - - /** - * http: for http://www.test.com:8000/this/that/theother.html?query=foo#hash - */ - public getProtocol(): string { - return this.forwardSubstring(this.schemeStart, this.domainStart); - } - - /** - * www.test.com for http://www.test.com:8000/this/that/theother.html?query=foo#hash - */ - public getDomain(): string { - return this.forwardSubstring(this.domainStart + 2, this.portStart); - } - - /** - * 8000 for http://www.test.com:8000/this/that/theother.html?query=foo#hash - */ - public getPort(): string { - return this.forwardSubstring(this.portStart + 1, this.pathStart); - } - - /** - * www.test.com:8000 for http://www.test.com:8000/this/that/theother.html?query=foo#hash - */ - public getHost(): string { - return this.forwardSubstring(this.domainStart + 2, this.pathStart); - } - - /** - * /this/that/theother.html for http://www.test.com:8000/this/that/theother.html?query=foo#hash - */ - public getPath(): string { - return this.forwardSubstring(this.pathStart, this.queryStringStart); - } - - /** - * query=foo for http://www.test.com:8000/this/that/theother.html?query=foo#hash - */ - public getQueryString(): string { - return this.forwardSubstring(this.queryStringStart + 1, this.fragmentIdStart); - } - - /** - * hash for http://www.test.com:8000/this/that/theother.html?query=foo#hash - */ - public getFragmentId(): string { - return this.forwardSubstring(this.fragmentIdStart + 1, this.specLength); - } - - /** - * http://www.test.com:8000 for http://www.test.com:8000/this/that/theother.html?query=foo#hash - */ - public getAllBeforePath(): string { - return this.forwardSubstring(0, this.pathStart); - } - /** - * http://www.test.com:8000/this/that/theother.html?query=foo for http://www.test.com:8000/this/that/theother.html?query=foo#hash - */ - public getAllBeforeFragmentId(): string { - return this.forwardSubstring(0, this.fragmentIdStart); - } - - - /** - * Combine with a relative url, returns absolute url - * e.g. - * http://www.test.com/this/that/theother.html?query=foo#hash=hash - * combined with ../test.js?query=foo#hash - * results in http://www.test.com/this/test.js?query=foo#hash - */ - public combine(relativeUrl:string):string { - var questionMarkIndex = relativeUrl.indexOf('?'); - var hashIndex = relativeUrl.indexOf('#'); - var suffixIndex = relativeUrl.length; - if (questionMarkIndex !== -1 && questionMarkIndex < suffixIndex) { - suffixIndex = questionMarkIndex; - } - if (hashIndex !== -1 && hashIndex < suffixIndex) { - suffixIndex = hashIndex; - } - - var relativeUrlPath = relativeUrl.substring(0, suffixIndex); - var relativeUrlSuffix = relativeUrl.substring(suffixIndex); - - - relativeUrlPath = relativeUrlPath.replace('\\', '/'); - - var resultPath: string; - if (strings.startsWith(relativeUrlPath, '/')) { - // Looks like an absolute URL - resultPath = paths.join(relativeUrlPath); - } else { - resultPath = paths.join(paths.dirname(this.getPath()), relativeUrlPath); - } - - while (resultPath.charAt(0) === '/') { - resultPath = resultPath.substr(1); - } - - while (resultPath.indexOf('../') === 0) { - resultPath = resultPath.substr(3); - } - - return this.getAllBeforePath() + '/' + resultPath + relativeUrlSuffix; - } - - // scheme://domain:port/path?query_string#fragment_id - private parse(): void { - var IN_SCHEME = 0, - IN_DOMAIN = 1, - IN_PORT = 2, - IN_PATH = 3, - IN_QUERY_STRING = 4, - state = IN_SCHEME, - spec = this.spec, - length = this.specLength, - i:number, - prevChCode:number = -1, - prevPrevChCode:number = -1, - chCode:number; - - this.schemeStart = 0; - this.domainStart = this.specLength; - this.portStart = this.specLength; - this.pathStart = this.specLength; - this.queryStringStart = this.specLength; - this.fragmentIdStart = this.specLength; - - for (i = 0; i < length; i++) { - chCode = spec.charCodeAt(i); - - switch (state) { - case IN_SCHEME: - if (prevChCode === _slash && chCode === _slash) { - // going into the domain - state = IN_DOMAIN; - this.domainStart = i - 1; - } - break; - - case IN_DOMAIN: - if (chCode === _colon) { - // going into the port - state = IN_PORT; - this.portStart = i; - } else if (chCode === _slash) { - // skipping the port, going straight to the path - state = IN_PATH; - this.portStart = i; - this.pathStart = i; - } else if (chCode === _hash) { - // skipping the port, path & query string, going straight to the fragment, we can halt now - this.portStart = i; - this.pathStart = i; - this.queryStringStart = i; - this.fragmentIdStart = i; - i = length; - } - break; - - case IN_PORT: - if (chCode === _slash) { - // going into the path - state = IN_PATH; - this.pathStart = i; - } else if (chCode === _hash) { - // skipping the path & query string, going straight to the fragment, we can halt now - this.pathStart = i; - this.queryStringStart = i; - this.fragmentIdStart = i; - i = length; - } - break; - - case IN_PATH: - if (chCode === _questionMark) { - // going in to the query string - state = IN_QUERY_STRING; - this.queryStringStart = i; - } else if (chCode === _hash) { - // skipping the query string, going straight to the fragment, we can halt now - this.queryStringStart = i; - this.fragmentIdStart = i; - i = length; - } - break; - - case IN_QUERY_STRING: - if (chCode === _hash) { - // going into the hash, we can halt now - this.fragmentIdStart = i; - i = length; - } - break; - } - - prevPrevChCode = prevChCode; - prevChCode = chCode; - } - - if (state === IN_SCHEME) { - // Looks like we had a very bad url - this.schemeStart = this.specLength; - } - } -} - - -export class URL extends URI implements objects.IEqualable { - - /** - * Creates a new URL from the provided value - * by decoding it first. - * @param value An encoded url value. - */ - public static fromEncoded(value:string):URL { - return new URL(decodeURIComponent(value)); - } - - public static fromValue(value:string):URL { - return new URL(value); - } - - public static fromUri(value: URI): URL { - if (!value) { - return value; - } else if (value instanceof URL) { - return value; - } else { - return new URL(value); - } - } - - private _spec:string; - private _uri: URI; - private _parsed:ParsedUrl; - - constructor(spec: string); - constructor(spec: URI); - constructor(stringOrURI: string|URI) { - super(); - assert.ok(!!stringOrURI, 'spec must not be null'); - if(typeof stringOrURI === 'string') { - this._uri = URI.parse(stringOrURI); - } else { - this._uri = stringOrURI; - } - this._spec = this._uri.toString(); // make sure spec is normalized - this._parsed = null; - } - - public equals(other:any):boolean { - if (this.toString() !== String(other)) { - return false; - } - - return (other instanceof URL || other instanceof URI); - } - - public hashCode():number { - return hash.computeMurmur2StringHashCode(this._spec); - } - - public isInMemory(): boolean { - return this.scheme === schemas.inMemory; - } - - /** - * http for http://www.test.com:8000/this/that/theother.html?query=foo#hash - */ - public getScheme():string { - this._ensureParsedUrl(); - return this._parsed.getScheme(); - } - - /** - * /this/that/theother.html for http://www.test.com:8000/this/that/theother.html?query=foo#hash - */ - public getPath():string { - this._ensureParsedUrl(); - return this._parsed.getPath(); - } - - /** - * Strips out the hash part of the URL. - * http://www.test.com:8000/this/that/theother.html?query=foo for http://www.test.com:8000/this/that/theother.html?query=foo#hash - */ - public toUnique():string { - this._ensureParsedUrl(); - return this._parsed.getAllBeforeFragmentId(); - } - - public startsWith(other:URL):boolean { - return strings.startsWith(this._spec, other._spec); - } - - /** - * Combine with a relative url, returns absolute url - * e.g. - * http://www.test.com/this/that/theother.html?query=foo#hash=hash - * combined with ../test.js?query=foo#hash - * results in http://www.test.com/this/test.js?query=foo#hash - */ - public combine(relativeUrl:string):URL { - this._ensureParsedUrl(); - return new URL(this._parsed.combine(relativeUrl)); - } - - private _ensureParsedUrl(): void { - if(this._parsed === null) { - this._parsed = new ParsedUrl(this._spec); - } - } - - // ----- URI implementation ------------------------- - - public get scheme(): string { - return this._uri.scheme; - } - - public get authority(): string { - return this._uri.authority; - } - - public get path(): string { - return this._uri.path; - } - - public get fsPath(): string { - return this._uri.fsPath; - } - - public get query(): string { - return this._uri.query; - } - - public get fragment(): string { - return this._uri.fragment; - } - - public withScheme(value: string): URI { - return URI.create(value, this.authority, this.fsPath, this.query, this.fragment); - } - - public withAuthority(value: string): URI { - return URI.create(this.scheme, value, this.fsPath, this.query, this.fragment); - } - - public withPath(value: string): URI { - return URI.create(this.scheme, this.authority, value, this.query, this.fragment); - } - - public withQuery(value: string): URI { - return URI.create(this.scheme, this.authority, this.fsPath, value, this.fragment); - } - - public withFragment(value: string): URI { - return URI.create(this.scheme, this.authority, this.fsPath, this.query, value); - } - - public with(scheme: string, authority: string, path: string, query: string, fragment: string): URI { - return URI.create(scheme, authority, path, query, fragment); - } - - public toString():string { - return this._spec; - } - - public toJSON(): any { - return this.toString(); - } -} - export namespace schemas { /** @@ -436,4 +17,4 @@ export namespace schemas { export var https:string = 'https'; export var file:string = 'file'; -} \ No newline at end of file +} diff --git a/src/vs/base/test/common/network.test.ts b/src/vs/base/test/common/network.test.ts index 8bbb8dbb3e4..3dfb17aff2f 100644 --- a/src/vs/base/test/common/network.test.ts +++ b/src/vs/base/test/common/network.test.ts @@ -6,21 +6,8 @@ import * as assert from 'assert'; import URI from 'vs/base/common/uri'; -import { URL, ParsedUrl } from 'vs/base/common/network'; function assertUrl(raw:string, scheme:string, domain:string, port:string, path:string, queryString:string, fragmentId:string): void { - var url = new ParsedUrl(raw); - assert.equal(url.getScheme(), scheme, 'getScheme ok for ' + raw); - var protocol = scheme ? scheme + ':' : scheme; - assert.equal(url.getProtocol(), protocol, 'getProtocol ok for ' + raw); - assert.equal(url.getDomain(), domain, 'getDomain ok for ' + raw); - assert.equal(url.getPort(), port, 'getPort ok for ' + raw); - var host = domain + (port ? ':' + port : ''); - assert.equal(url.getHost(), host, 'getHost ok for ' + raw); - assert.equal(url.getPath(), path, 'getPath ok for ' + raw); - assert.equal(url.getQueryString(), queryString, 'getQueryString ok for ' + raw); - assert.equal(url.getFragmentId(), fragmentId, 'getFragmentId ok for ' + raw); - // check for equivalent behaviour var uri = URI.parse(raw); assert.equal(uri.scheme, scheme); @@ -30,12 +17,6 @@ function assertUrl(raw:string, scheme:string, domain:string, port:string, path:s assert.equal(uri.fragment, fragmentId); } -function assertCombine(base:string, relativeUrl:string, expectedUrl:string): void { - var url = new ParsedUrl(base); - var result = url.combine(relativeUrl); - assert.equal(result, expectedUrl, 'combine ok for ' + base + ' and ' + relativeUrl); -} - suite('Network', () => { test('urls', () => { assertUrl('http://www.test.com:8000/this/that/theother.html?query=foo#hash', @@ -107,114 +88,5 @@ suite('Network', () => { ); assertUrl('file:///c/far/boo/file.cs', 'file', '', '', '/c/far/boo/file.cs', '', ''); - - assertCombine( - 'http://www.test.com:8000/this/that/theother.html?query=foo#hash', '\\test.js', - 'http://www.test.com:8000/test.js' - ); - assertCombine( - 'http://www.test.com:8000/this/that/theother.html?query=foo#hash', '/test.js', - 'http://www.test.com:8000/test.js' - ); - assertCombine( - 'http://www.test.com:8000/this/that/theother.html?query=foo#hash', '////test.js', - 'http://www.test.com:8000/test.js' - ); - assertCombine( - 'http://www.test.com:8000/this/that/theother.html?query=foo#hash', '\\test.js?token=123', - 'http://www.test.com:8000/test.js?token=123' - ); - assertCombine( - 'http://www.test.com:8000/this/that/theother.html?query=foo#hash', '\\test.js?query=foo#hash', - 'http://www.test.com:8000/test.js?query=foo#hash' - ); - assertCombine( - 'http://www.test.com:8000/this/that/theother.html?query=foo#hash', '\\test.js#hash', - 'http://www.test.com:8000/test.js#hash' - ); - - assertCombine( - 'http://www.test.com:8000/this/that/theother.html?query=foo#hash', 'test.js', - 'http://www.test.com:8000/this/that/test.js' - ); - assertCombine( - 'http://www.test.com:8000/this/that/theother.html?query=foo#hash', '../test.js', - 'http://www.test.com:8000/this/test.js' - ); - assertCombine( - 'http://www.test.com:8000/this/that/theother.html?query=foo#hash', '..\\test.js', - 'http://www.test.com:8000/this/test.js' - ); - assertCombine( - 'http://www.test.com:8000/this/that/theother.html?query=foo#hash', '..\\test.js?token=123', - 'http://www.test.com:8000/this/test.js?token=123' - ); - assertCombine( - 'http://www.test.com:8000/this/that/theother.html?query=foo#hash', '..\\test.js?query=foo#hash', - 'http://www.test.com:8000/this/test.js?query=foo#hash' - ); - assertCombine( - 'http://www.test.com:8000/this/that/theother.html?query=foo#hash', '..\\test.js#hash', - 'http://www.test.com:8000/this/test.js#hash' - ); - - assertCombine( - 'http://www.test.com:8000/this/that/', 'test.js', - 'http://www.test.com:8000/this/that/test.js' - ); - assertCombine( - 'http://www.test.com:8000/this/that/', './test.js', - 'http://www.test.com:8000/this/that/test.js' - ); - - assertCombine( - 'http://www.test.com:8000/', './test.js', - 'http://www.test.com:8000/test.js' - ); - assertCombine( - 'http://www.test.com:8000/', './././test.js', - 'http://www.test.com:8000/test.js' - ); - - assertCombine( - 'http://www.test.com:8000', './././test.js', - 'http://www.test.com:8000/test.js' - ); - assertCombine( - 'http://www.test.com:8000', 'test.js', - 'http://www.test.com:8000/test.js' - ); - assertCombine( - 'http://www.test.com', '../test.js', - 'http://www.test.com/test.js' - ); - assertCombine( - 'http://www.test.com', 'a/b/../../../test.js', - 'http://www.test.com/test.js' - ); - assertCombine( - 'http://www.test.com/a/b', 'a/b/../../../../../test.js', - 'http://www.test.com/test.js' - ); - assertCombine( - 'http://www.test.com', 'test.js', - 'http://www.test.com/test.js' - ); - assertCombine( - 'http://www.test.com', 'a/b/test.js', - 'http://www.test.com/a/b/test.js' - ); - assertCombine( - 'http://www.test.com', './a/b/test.js', - 'http://www.test.com/a/b/test.js' - ); - assertCombine( - 'http://www.test.com/index.html', './a/b/test.js', - 'http://www.test.com/a/b/test.js' - ); - - var url = new URL('inmemory://model/1#css'); - assert.equal(url.toUnique(), 'inmemory://model/1'); }); - }); diff --git a/src/vs/languages/html/common/htmlWorker.ts b/src/vs/languages/html/common/htmlWorker.ts index a39811f62da..fde008cf4c3 100644 --- a/src/vs/languages/html/common/htmlWorker.ts +++ b/src/vs/languages/html/common/htmlWorker.ts @@ -20,6 +20,7 @@ import {getScanner, IHTMLScanner} from 'vs/languages/html/common/htmlScanner'; import {isTag, DELIM_END, DELIM_START, DELIM_ASSIGN, ATTRIB_NAME, ATTRIB_VALUE} from 'vs/languages/html/common/htmlTokenTypes'; import {isEmptyElement} from 'vs/languages/html/common/htmlEmptyTagsShared'; import {filterSuggestions} from 'vs/editor/common/modes/supports/suggestSupport'; +import paths = require('vs/base/common/paths'); enum LinkDetectionState { LOOKING_FOR_HREF_OR_SRC = 1, @@ -516,11 +517,8 @@ export class HTMLWorker { } public static _getWorkspaceUrl(modelAbsoluteUri: URI, rootAbsoluteUri: URI, tokenContent: string): string { - var modelAbsoluteUrl = network.URL.fromUri(modelAbsoluteUri); - var rootAbsoluteUrl = network.URL.fromUri(rootAbsoluteUri); tokenContent = HTMLWorker._stripQuotes(tokenContent); - if (/^\s*javascript\:/i.test(tokenContent) || /^\s*\#/i.test(tokenContent)) { return null; } @@ -532,27 +530,29 @@ export class HTMLWorker { if (/^\s*\/\//i.test(tokenContent)) { // Absolute link (that does not name the protocol) - var modelScheme = modelAbsoluteUrl.getScheme(); - var pickedScheme = 'http'; - if (modelScheme === network.schemas.https) { + let pickedScheme = network.schemas.http; + if (modelAbsoluteUri.scheme === network.schemas.https) { pickedScheme = network.schemas.https; } return pickedScheme + ':' + tokenContent.replace(/^\s*/g, ''); } - try { - var potentialResult = modelAbsoluteUrl.combine(tokenContent).toString(); - } catch (err) { - // invalid URL - return null; + let modelPath = paths.dirname(modelAbsoluteUri.path); + let alternativeResultPath: string = null; + if (tokenContent.length > 0 && tokenContent.charAt(0) === '/') { + alternativeResultPath = tokenContent; + } else { + alternativeResultPath = paths.join(modelPath, tokenContent); + alternativeResultPath = alternativeResultPath.replace(/^(\/\.\.)+/, ''); } + let potentialResult = modelAbsoluteUri.withPath(alternativeResultPath).toString(); - if (rootAbsoluteUrl && modelAbsoluteUrl.startsWith(rootAbsoluteUrl)) { + let rootAbsoluteUrlStr = (rootAbsoluteUri ? rootAbsoluteUri.toString() : null); + if (rootAbsoluteUrlStr && strings.startsWith(modelAbsoluteUri.toString(), rootAbsoluteUrlStr)) { // The `rootAbsoluteUrl` is set and matches our current model // We need to ensure that this `potentialResult` does not escape `rootAbsoluteUrl` - var rootAbsoluteUrlStr = rootAbsoluteUrl.toString(); - var commonPrefixLength = strings.commonPrefixLength(rootAbsoluteUrlStr, potentialResult); + let commonPrefixLength = strings.commonPrefixLength(rootAbsoluteUrlStr, potentialResult); if (strings.endsWith(rootAbsoluteUrlStr, '/')) { commonPrefixLength = potentialResult.lastIndexOf('/', commonPrefixLength) + 1; } @@ -562,7 +562,7 @@ export class HTMLWorker { return potentialResult; } - private createLink(modelAbsoluteUrl: URI, rootAbsoluteUrl: network.URL, tokenContent: string, lineNumber: number, startColumn: number, endColumn: number): Modes.ILink { + private createLink(modelAbsoluteUrl: URI, rootAbsoluteUrl: URI, tokenContent: string, lineNumber: number, startColumn: number, endColumn: number): Modes.ILink { var workspaceUrl = HTMLWorker._getWorkspaceUrl(modelAbsoluteUrl, rootAbsoluteUrl, tokenContent); if (!workspaceUrl) { return null; @@ -596,15 +596,15 @@ export class HTMLWorker { tokenContent: string, link: Modes.ILink; - let rootAbsoluteUrl: network.URL = null; + let rootAbsoluteUrl: URI = null; let workspace = this._contextService.getWorkspace(); if (workspace) { // The workspace can be null in the no folder opened case let strRootAbsoluteUrl = String(workspace.resource); if (strRootAbsoluteUrl.charAt(strRootAbsoluteUrl.length - 1) === '/') { - rootAbsoluteUrl = new network.URL(strRootAbsoluteUrl); + rootAbsoluteUrl = URI.parse(strRootAbsoluteUrl); } else { - rootAbsoluteUrl = new network.URL(strRootAbsoluteUrl + '/'); + rootAbsoluteUrl = URI.parse(strRootAbsoluteUrl + '/'); } } diff --git a/src/vs/languages/html/test/common/html-worker.test.ts b/src/vs/languages/html/test/common/html-worker.test.ts index 8acae3a5098..54724f90035 100644 --- a/src/vs/languages/html/test/common/html-worker.test.ts +++ b/src/vs/languages/html/test/common/html-worker.test.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import assert = require('assert') +import 'vs/languages/html/common/html.contribution'; +import assert = require('assert'); import mm = require('vs/editor/common/model/mirrorModel'); import htmlWorker = require('vs/languages/html/common/htmlWorker'); import URI from 'vs/base/common/uri'; @@ -61,7 +62,7 @@ suite('HTML - worker', () => { var proposalsFound = completion.suggestions.filter(function(suggestion: Modes.ISuggestion) { return suggestion.label === label && (!type || suggestion.type === type) && (!codeSnippet || suggestion.codeSnippet === codeSnippet); }); - if (proposalsFound.length != 1) { + if (proposalsFound.length !== 1) { assert.fail('Suggestion not found: ' + label + ', has ' + completion.suggestions.map(s => s.label).join(', ')); } }; @@ -364,6 +365,7 @@ suite('HTML - worker', () => { testLinkCreation('file:///C:/Alex/src/path/to/file.txt', null, 'file:///C:\\Alex\\src\\path\\to\\file.txt', 'file:///C:\\Alex\\src\\path\\to\\file.txt'); testLinkCreation('file:///C:/Alex/src/path/to/file.txt', 'file:///C:/Alex/src/', 'http://www.microsoft.com/', 'http://www.microsoft.com/'); testLinkCreation('file:///C:/Alex/src/path/to/file.txt', 'file:///C:/Alex/src/', 'https://www.microsoft.com/', 'https://www.microsoft.com/'); + testLinkCreation('file:///C:/Alex/src/path/to/file.txt', 'file:///C:/Alex/src/', 'https://www.microsoft.com/?q=1#h', 'https://www.microsoft.com/?q=1#h'); testLinkCreation('file:///C:/Alex/src/path/to/file.txt', 'file:///C:/Alex/src/', ' //www.microsoft.com/', 'http://www.microsoft.com/'); testLinkCreation('file:///C:/Alex/src/path/to/file.txt', 'file:///C:/Alex/src/', 'a.js', 'file:///C:/Alex/src/path/to/a.js'); testLinkCreation('file:///C:/Alex/src/path/to/file.txt', 'file:///C:/Alex/src/', '/a.js', 'file:///C:/Alex/src/a.js'); @@ -373,7 +375,7 @@ suite('HTML - worker', () => { testLinkCreation('https://www.test.com/path/to/file.txt', 'https://www.test.com', '//www.microsoft.com/', 'https://www.microsoft.com/'); // invalid uris don't throw - testLinkCreation('https://www.test.com/path/to/file.txt', 'https://www.test.com', '%', null); + testLinkCreation('https://www.test.com/path/to/file.txt', 'https://www.test.com', '%', 'https://www.test.com/path/to/%25'); // Bug #18314: Ctrl + Click does not open existing file if folder's name starts with 'c' character testLinkCreation('file:///c:/Alex/working_dir/18314-link-detection/test.html', 'file:///c:/Alex/working_dir/18314-link-detection/', '/class/class.js', 'file:///c:/Alex/working_dir/18314-link-detection/class/class.js');