diff --git a/package.json b/package.json index ce91cf8..2b1a4cd 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vscode-uri", "author": "Microsoft", - "version": "3.0.6", + "version": "3.0.7", "description": "The URI implementation that is used by VS Code and its extensions", "main": "./lib/umd/index.js", "typings": "./lib/umd/index", diff --git a/src/uri.ts b/src/uri.ts index f0183b7..842453f 100644 --- a/src/uri.ts +++ b/src/uri.ts @@ -114,29 +114,29 @@ export class URI implements UriComponents { } /** - * scheme is the 'http' part of 'http://www.msft.com/some/path?query#fragment'. + * scheme is the 'http' part of 'http://www.example.com/some/path?query#fragment'. * The part before the first colon. */ readonly scheme: string; /** - * authority is the 'www.msft.com' part of 'http://www.msft.com/some/path?query#fragment'. + * authority is the 'www.example.com' part of 'http://www.example.com/some/path?query#fragment'. * The part between the first double slashes and the next slash. */ readonly authority: string; /** - * path is the '/some/path' part of 'http://www.msft.com/some/path?query#fragment'. + * path is the '/some/path' part of 'http://www.example.com/some/path?query#fragment'. */ readonly path: string; /** - * query is the 'query' part of 'http://www.msft.com/some/path?query#fragment'. + * query is the 'query' part of 'http://www.example.com/some/path?query#fragment'. */ readonly query: string; /** - * fragment is the 'fragment' part of 'http://www.msft.com/some/path?query#fragment'. + * fragment is the 'fragment' part of 'http://www.example.com/some/path?query#fragment'. */ readonly fragment: string; @@ -258,7 +258,7 @@ export class URI implements UriComponents { // ---- parse & validate ------------------------ /** - * Creates a new URI from a string, e.g. `http://www.msft.com/some/path`, + * Creates a new URI from a string, e.g. `http://www.example.com/some/path`, * `file:///usr/home`, or `scheme:with/path`. * * @param value A string which represents an URI (see `URI#toString`). @@ -327,13 +327,15 @@ export class URI implements UriComponents { } static from(components: { scheme: string; authority?: string; path?: string; query?: string; fragment?: string }): URI { - return new Uri( + const result = new Uri( components.scheme, components.authority, components.path, components.query, components.fragment, ); + _validateUri(result, true); + return result; } // ---- printing/externalize --------------------------- @@ -392,7 +394,7 @@ interface UriState extends UriComponents { const _pathSepMarker = isWindows ? 1 : undefined; -// This class exists so that URI is compatibile with vscode.Uri (API). +// This class exists so that URI is compatible with vscode.Uri (API). class Uri extends URI { _formatted: string | null = null; @@ -474,7 +476,7 @@ const encodeTable: { [ch: number]: string } = { [CharCode.Space]: '%20', }; -function encodeURIComponentFast(uriComponent: string, allowSlash: boolean): string { +function encodeURIComponentFast(uriComponent: string, isPath: boolean, isAuthority: boolean): string { let res: string | undefined = undefined; let nativeEncodePos = -1; @@ -490,7 +492,10 @@ function encodeURIComponentFast(uriComponent: string, allowSlash: boolean): stri || code === CharCode.Period || code === CharCode.Underline || code === CharCode.Tilde - || (allowSlash && code === CharCode.Slash) + || (isPath && code === CharCode.Slash) + || (isAuthority && code === CharCode.OpenSquareBracket) + || (isAuthority && code === CharCode.CloseSquareBracket) + || (isAuthority && code === CharCode.Colon) ) { // check if we are delaying native encode if (nativeEncodePos !== -1) { @@ -608,24 +613,24 @@ function _asFormatted(uri: URI, skipEncoding: boolean): string { // @ const userinfo = authority.substr(0, idx); authority = authority.substr(idx + 1); - idx = userinfo.indexOf(':'); + idx = userinfo.lastIndexOf(':'); if (idx === -1) { - res += encoder(userinfo, false); + res += encoder(userinfo, false, false); } else { // :@ - res += encoder(userinfo.substr(0, idx), false); + res += encoder(userinfo.substr(0, idx), false, false); res += ':'; - res += encoder(userinfo.substr(idx + 1), false); + res += encoder(userinfo.substr(idx + 1), false, true); } res += '@'; } authority = authority.toLowerCase(); - idx = authority.indexOf(':'); + idx = authority.lastIndexOf(':'); if (idx === -1) { - res += encoder(authority, false); + res += encoder(authority, false, true); } else { // : - res += encoder(authority.substr(0, idx), false); + res += encoder(authority.substr(0, idx), false, true); res += authority.substr(idx); } } @@ -643,15 +648,15 @@ function _asFormatted(uri: URI, skipEncoding: boolean): string { } } // encode the rest of the path - res += encoder(path, true); + res += encoder(path, true, false); } if (query) { res += '?'; - res += encoder(query, false); + res += encoder(query, false, false); } if (fragment) { res += '#'; - res += !skipEncoding ? encodeURIComponentFast(fragment, false) : fragment; + res += !skipEncoding ? encodeURIComponentFast(fragment, false, false) : fragment; } return res; } @@ -678,3 +683,10 @@ function percentDecode(str: string): string { } return str.replace(_rEncodedAsHex, (match) => decodeURIComponentGraceful(match)); } + +/** + * Mapped-type that replaces all occurrences of URI with UriComponents + */ +export type UriDto = { [K in keyof T]: T[K] extends URI + ? UriComponents + : UriDto };