| /*--------------------------------------------------------------------------------------------- |
| * Copyright (c) Microsoft Corporation. All rights reserved. |
| * Licensed under the MIT License. See License.txt in the project root for license information. |
| *--------------------------------------------------------------------------------------------*/ |
| 'use strict'; |
| var __extends = (this && this.__extends) || (function () { |
| var extendStatics = function (d, b) { |
| extendStatics = Object.setPrototypeOf || |
| ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || |
| function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; |
| return extendStatics(d, b); |
| }; |
| return function (d, b) { |
| extendStatics(d, b); |
| function __() { this.constructor = d; } |
| d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); |
| }; |
| })(); |
| var _a; |
| var isWindows; |
| if (typeof process === 'object') { |
| isWindows = process.platform === 'win32'; |
| } |
| else if (typeof navigator === 'object') { |
| var userAgent = navigator.userAgent; |
| isWindows = userAgent.indexOf('Windows') >= 0; |
| } |
| function isHighSurrogate(charCode) { |
| return (0xD800 <= charCode && charCode <= 0xDBFF); |
| } |
| function isLowSurrogate(charCode) { |
| return (0xDC00 <= charCode && charCode <= 0xDFFF); |
| } |
| function isLowerAsciiHex(code) { |
| return code >= 97 /* a */ && code <= 102 /* f */; |
| } |
| function isLowerAsciiLetter(code) { |
| return code >= 97 /* a */ && code <= 122 /* z */; |
| } |
| function isUpperAsciiLetter(code) { |
| return code >= 65 /* A */ && code <= 90 /* Z */; |
| } |
| function isAsciiLetter(code) { |
| return isLowerAsciiLetter(code) || isUpperAsciiLetter(code); |
| } |
| //#endregion |
| var _schemePattern = /^\w[\w\d+.-]*$/; |
| var _singleSlashStart = /^\//; |
| var _doubleSlashStart = /^\/\//; |
| function _validateUri(ret, _strict) { |
| // scheme, must be set |
| if (!ret.scheme && _strict) { |
| throw new Error("[UriError]: Scheme is missing: {scheme: \"\", authority: \"" + ret.authority + "\", path: \"" + ret.path + "\", query: \"" + ret.query + "\", fragment: \"" + ret.fragment + "\"}"); |
| } |
| // scheme, https://tools.ietf.org/html/rfc3986#section-3.1 |
| // ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) |
| if (ret.scheme && !_schemePattern.test(ret.scheme)) { |
| throw new Error('[UriError]: Scheme contains illegal characters.'); |
| } |
| // path, http://tools.ietf.org/html/rfc3986#section-3.3 |
| // If a URI contains an authority component, then the path component |
| // must either be empty or begin with a slash ("/") character. If a URI |
| // does not contain an authority component, then the path cannot begin |
| // with two slash characters ("//"). |
| if (ret.path) { |
| if (ret.authority) { |
| if (!_singleSlashStart.test(ret.path)) { |
| throw new Error('[UriError]: If a URI contains an authority component, then the path component must either be empty or begin with a slash ("/") character'); |
| } |
| } |
| else { |
| if (_doubleSlashStart.test(ret.path)) { |
| throw new Error('[UriError]: If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//")'); |
| } |
| } |
| } |
| } |
| // for a while we allowed uris *without* schemes and this is the migration |
| // for them, e.g. an uri without scheme and without strict-mode warns and falls |
| // back to the file-scheme. that should cause the least carnage and still be a |
| // clear warning |
| function _schemeFix(scheme, _strict) { |
| if (!scheme && !_strict) { |
| return 'file'; |
| } |
| return scheme; |
| } |
| // implements a bit of https://tools.ietf.org/html/rfc3986#section-5 |
| function _referenceResolution(scheme, path) { |
| // the slash-character is our 'default base' as we don't |
| // support constructing URIs relative to other URIs. This |
| // also means that we alter and potentially break paths. |
| // see https://tools.ietf.org/html/rfc3986#section-5.1.4 |
| switch (scheme) { |
| case 'https': |
| case 'http': |
| case 'file': |
| if (!path) { |
| path = _slash; |
| } |
| else if (path[0] !== _slash) { |
| path = _slash + path; |
| } |
| break; |
| } |
| return path; |
| } |
| var _empty = ''; |
| var _slash = '/'; |
| var _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; |
| /** |
| * Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986. |
| * This class is a simple parser which creates the basic component parts |
| * (http://tools.ietf.org/html/rfc3986#section-3) with minimal validation |
| * and encoding. |
| * |
| * ```txt |
| * foo://example.com:8042/over/there?name=ferret#nose |
| * \_/ \______________/\_________/ \_________/ \__/ |
| * | | | | | |
| * scheme authority path query fragment |
| * | _____________________|__ |
| * / \ / \ |
| * urn:example:animal:ferret:nose |
| * ``` |
| */ |
| var URI = /** @class */ (function () { |
| /** |
| * @internal |
| */ |
| function URI(schemeOrData, authority, path, query, fragment, _strict) { |
| if (_strict === void 0) { _strict = false; } |
| if (typeof schemeOrData === 'object') { |
| this.scheme = schemeOrData.scheme || _empty; |
| this.authority = schemeOrData.authority || _empty; |
| this.path = schemeOrData.path || _empty; |
| this.query = schemeOrData.query || _empty; |
| this.fragment = schemeOrData.fragment || _empty; |
| // no validation because it's this URI |
| // that creates uri components. |
| // _validateUri(this); |
| } |
| else { |
| this.scheme = _schemeFix(schemeOrData, _strict); |
| this.authority = authority || _empty; |
| this.path = _referenceResolution(this.scheme, path || _empty); |
| this.query = query || _empty; |
| this.fragment = fragment || _empty; |
| _validateUri(this, _strict); |
| } |
| } |
| URI.isUri = function (thing) { |
| if (thing instanceof URI) { |
| return true; |
| } |
| if (!thing) { |
| return false; |
| } |
| return typeof thing.authority === 'string' |
| && typeof thing.fragment === 'string' |
| && typeof thing.path === 'string' |
| && typeof thing.query === 'string' |
| && typeof thing.scheme === 'string' |
| && typeof thing.fsPath === 'function' |
| && typeof thing.with === 'function' |
| && typeof thing.toString === 'function'; |
| }; |
| Object.defineProperty(URI.prototype, "fsPath", { |
| // ---- filesystem path ----------------------- |
| /** |
| * Returns a string representing the corresponding file system path of this URI. |
| * Will handle UNC paths, normalizes windows drive letters to lower-case, and uses the |
| * platform specific path separator. |
| * |
| * * Will *not* validate the path for invalid characters and semantics. |
| * * Will *not* look at the scheme of this URI. |
| * * The result shall *not* be used for display purposes but for accessing a file on disk. |
| * |
| * |
| * The *difference* to `URI#path` is the use of the platform specific separator and the handling |
| * of UNC paths. See the below sample of a file-uri with an authority (UNC path). |
| * |
| * ```ts |
| const u = URI.parse('file://server/c$/folder/file.txt') |
| u.authority === 'server' |
| u.path === '/shares/c$/file.txt' |
| u.fsPath === '\\server\c$\folder\file.txt' |
| ``` |
| * |
| * Using `URI#path` to read a file (using fs-apis) would not be enough because parts of the path, |
| * namely the server name, would be missing. Therefore `URI#fsPath` exists - it's sugar to ease working |
| * with URIs that represent files on disk (`file` scheme). |
| */ |
| get: function () { |
| // if (this.scheme !== 'file') { |
| // console.warn(`[UriError] calling fsPath with scheme ${this.scheme}`); |
| // } |
| return uriToFsPath(this, false); |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| // ---- modify to new ------------------------- |
| URI.prototype.with = function (change) { |
| if (!change) { |
| return this; |
| } |
| var scheme = change.scheme, authority = change.authority, path = change.path, query = change.query, fragment = change.fragment; |
| if (scheme === undefined) { |
| scheme = this.scheme; |
| } |
| else if (scheme === null) { |
| scheme = _empty; |
| } |
| if (authority === undefined) { |
| authority = this.authority; |
| } |
| else if (authority === null) { |
| authority = _empty; |
| } |
| if (path === undefined) { |
| path = this.path; |
| } |
| else if (path === null) { |
| path = _empty; |
| } |
| if (query === undefined) { |
| query = this.query; |
| } |
| else if (query === null) { |
| query = _empty; |
| } |
| if (fragment === undefined) { |
| fragment = this.fragment; |
| } |
| else if (fragment === null) { |
| fragment = _empty; |
| } |
| if (scheme === this.scheme |
| && authority === this.authority |
| && path === this.path |
| && query === this.query |
| && fragment === this.fragment) { |
| return this; |
| } |
| return new _URI(scheme, authority, path, query, fragment); |
| }; |
| // ---- parse & validate ------------------------ |
| /** |
| * Creates a new URI from a string, e.g. `http://www.msft.com/some/path`, |
| * `file:///usr/home`, or `scheme:with/path`. |
| * |
| * @param value A string which represents an URI (see `URI#toString`). |
| */ |
| URI.parse = function (value, _strict) { |
| if (_strict === void 0) { _strict = false; } |
| var match = _regexp.exec(value); |
| if (!match) { |
| return new _URI(_empty, _empty, _empty, _empty, _empty); |
| } |
| return new _URI(match[2] || _empty, percentDecode(match[4] || _empty), percentDecode(match[5] || _empty), percentDecode(match[7] || _empty), percentDecode(match[9] || _empty), _strict); |
| }; |
| /** |
| * Creates a new URI from a file system path, e.g. `c:\my\files`, |
| * `/usr/home`, or `\\server\share\some\path`. |
| * |
| * The *difference* between `URI#parse` and `URI#file` is that the latter treats the argument |
| * as path, not as stringified-uri. E.g. `URI.file(path)` is **not the same as** |
| * `URI.parse('file://' + path)` because the path might contain characters that are |
| * interpreted (# and ?). See the following sample: |
| * ```ts |
| const good = URI.file('/coding/c#/project1'); |
| good.scheme === 'file'; |
| good.path === '/coding/c#/project1'; |
| good.fragment === ''; |
| const bad = URI.parse('file://' + '/coding/c#/project1'); |
| bad.scheme === 'file'; |
| bad.path === '/coding/c'; // path is now broken |
| bad.fragment === '/project1'; |
| ``` |
| * |
| * @param path A file system path (see `URI#fsPath`) |
| */ |
| URI.file = function (path) { |
| var authority = _empty; |
| // normalize to fwd-slashes on windows, |
| // on other systems bwd-slashes are valid |
| // filename character, eg /f\oo/ba\r.txt |
| if (isWindows) { |
| path = path.replace(/\\/g, _slash); |
| } |
| // check for authority as used in UNC shares |
| // or use the path as given |
| if (path[0] === _slash && path[1] === _slash) { |
| var idx = path.indexOf(_slash, 2); |
| if (idx === -1) { |
| authority = path.substring(2); |
| path = _slash; |
| } |
| else { |
| authority = path.substring(2, idx); |
| path = path.substring(idx) || _slash; |
| } |
| } |
| return new _URI('file', authority, path, _empty, _empty); |
| }; |
| URI.from = function (components) { |
| return new _URI(components.scheme, components.authority, components.path, components.query, components.fragment); |
| }; |
| // /** |
| // * Join a URI path with path fragments and normalizes the resulting path. |
| // * |
| // * @param uri The input URI. |
| // * @param pathFragment The path fragment to add to the URI path. |
| // * @returns The resulting URI. |
| // */ |
| // static joinPath(uri: URI, ...pathFragment: string[]): URI { |
| // if (!uri.path) { |
| // throw new Error(`[UriError]: cannot call joinPaths on URI without path`); |
| // } |
| // let newPath: string; |
| // if (isWindows && uri.scheme === 'file') { |
| // newPath = URI.file(paths.win32.join(uriToFsPath(uri, true), ...pathFragment)).path; |
| // } else { |
| // newPath = paths.posix.join(uri.path, ...pathFragment); |
| // } |
| // return uri.with({ path: newPath }); |
| // } |
| // ---- printing/externalize --------------------------- |
| /** |
| * Creates a string representation for this URI. It's guaranteed that calling |
| * `URI.parse` with the result of this function creates an URI which is equal |
| * to this URI. |
| * |
| * * The result shall *not* be used for display purposes but for externalization or transport. |
| * * The result will be encoded using the percentage encoding and encoding happens mostly |
| * ignore the scheme-specific encoding rules. |
| * |
| * @param skipEncoding Do not encode the result, default is `false` |
| */ |
| URI.prototype.toString = function (skipEncoding) { |
| if (skipEncoding === void 0) { skipEncoding = false; } |
| return _asFormatted(this, skipEncoding); |
| }; |
| URI.prototype.toJSON = function () { |
| return this; |
| }; |
| URI.revive = function (data) { |
| if (!data) { |
| return data; |
| } |
| else if (data instanceof URI) { |
| return data; |
| } |
| else { |
| var result = new _URI(data); |
| result._formatted = data.external; |
| result._fsPath = data._sep === _pathSepMarker ? data.fsPath : null; |
| return result; |
| } |
| }; |
| return URI; |
| }()); |
| export { URI }; |
| var _pathSepMarker = isWindows ? 1 : undefined; |
| // eslint-disable-next-line @typescript-eslint/class-name-casing |
| var _URI = /** @class */ (function (_super) { |
| __extends(_URI, _super); |
| function _URI() { |
| var _this = _super !== null && _super.apply(this, arguments) || this; |
| _this._formatted = null; |
| _this._fsPath = null; |
| return _this; |
| } |
| Object.defineProperty(_URI.prototype, "fsPath", { |
| get: function () { |
| if (!this._fsPath) { |
| this._fsPath = uriToFsPath(this, false); |
| } |
| return this._fsPath; |
| }, |
| enumerable: true, |
| configurable: true |
| }); |
| _URI.prototype.toString = function (skipEncoding) { |
| if (skipEncoding === void 0) { skipEncoding = false; } |
| if (!skipEncoding) { |
| if (!this._formatted) { |
| this._formatted = _asFormatted(this, false); |
| } |
| return this._formatted; |
| } |
| else { |
| // we don't cache that |
| return _asFormatted(this, true); |
| } |
| }; |
| _URI.prototype.toJSON = function () { |
| var res = { |
| $mid: 1 |
| }; |
| // cached state |
| if (this._fsPath) { |
| res.fsPath = this._fsPath; |
| res._sep = _pathSepMarker; |
| } |
| if (this._formatted) { |
| res.external = this._formatted; |
| } |
| // uri components |
| if (this.path) { |
| res.path = this.path; |
| } |
| if (this.scheme) { |
| res.scheme = this.scheme; |
| } |
| if (this.authority) { |
| res.authority = this.authority; |
| } |
| if (this.query) { |
| res.query = this.query; |
| } |
| if (this.fragment) { |
| res.fragment = this.fragment; |
| } |
| return res; |
| }; |
| return _URI; |
| }(URI)); |
| // reserved characters: https://tools.ietf.org/html/rfc3986#section-2.2 |
| var encodeTable = (_a = {}, |
| _a[58 /* Colon */] = '%3A', |
| _a[47 /* Slash */] = '%2F', |
| _a[63 /* QuestionMark */] = '%3F', |
| _a[35 /* Hash */] = '%23', |
| _a[91 /* OpenSquareBracket */] = '%5B', |
| _a[93 /* CloseSquareBracket */] = '%5D', |
| _a[64 /* AtSign */] = '%40', |
| _a[33 /* ExclamationMark */] = '%21', |
| _a[36 /* DollarSign */] = '%24', |
| _a[38 /* Ampersand */] = '%26', |
| _a[39 /* SingleQuote */] = '%27', |
| _a[40 /* OpenParen */] = '%28', |
| _a[41 /* CloseParen */] = '%29', |
| _a[42 /* Asterisk */] = '%2A', |
| _a[43 /* Plus */] = '%2B', |
| _a[44 /* Comma */] = '%2C', |
| _a[59 /* Semicolon */] = '%3B', |
| _a[61 /* Equals */] = '%3D', |
| _a[32 /* Space */] = '%20', |
| _a); |
| function encodeURIComponentFast(uriComponent, allowSlash) { |
| var res = undefined; |
| var nativeEncodePos = -1; |
| for (var pos = 0; pos < uriComponent.length; pos++) { |
| var code = uriComponent.charCodeAt(pos); |
| // unreserved characters: https://tools.ietf.org/html/rfc3986#section-2.3 |
| if ((code >= 97 /* a */ && code <= 122 /* z */) |
| || (code >= 65 /* A */ && code <= 90 /* Z */) |
| || (code >= 48 /* Digit0 */ && code <= 57 /* Digit9 */) |
| || code === 45 /* Dash */ |
| || code === 46 /* Period */ |
| || code === 95 /* Underline */ |
| || code === 126 /* Tilde */ |
| || (allowSlash && code === 47 /* Slash */)) { |
| // check if we are delaying native encode |
| if (nativeEncodePos !== -1) { |
| res += encodeURIComponent(uriComponent.substring(nativeEncodePos, pos)); |
| nativeEncodePos = -1; |
| } |
| // check if we write into a new string (by default we try to return the param) |
| if (res !== undefined) { |
| res += uriComponent.charAt(pos); |
| } |
| } |
| else { |
| // encoding needed, we need to allocate a new string |
| if (res === undefined) { |
| res = uriComponent.substr(0, pos); |
| } |
| // check with default table first |
| var escaped = encodeTable[code]; |
| if (escaped !== undefined) { |
| // check if we are delaying native encode |
| if (nativeEncodePos !== -1) { |
| res += encodeURIComponent(uriComponent.substring(nativeEncodePos, pos)); |
| nativeEncodePos = -1; |
| } |
| // append escaped variant to result |
| res += escaped; |
| } |
| else if (nativeEncodePos === -1) { |
| // use native encode only when needed |
| nativeEncodePos = pos; |
| } |
| } |
| } |
| if (nativeEncodePos !== -1) { |
| res += encodeURIComponent(uriComponent.substring(nativeEncodePos)); |
| } |
| return res !== undefined ? res : uriComponent; |
| } |
| function encodeURIComponentMinimal(path) { |
| var res = undefined; |
| for (var pos = 0; pos < path.length; pos++) { |
| var code = path.charCodeAt(pos); |
| if (code === 35 /* Hash */ || code === 63 /* QuestionMark */) { |
| if (res === undefined) { |
| res = path.substr(0, pos); |
| } |
| res += encodeTable[code]; |
| } |
| else { |
| if (res !== undefined) { |
| res += path[pos]; |
| } |
| } |
| } |
| return res !== undefined ? res : path; |
| } |
| /** |
| * Compute `fsPath` for the given uri |
| */ |
| export function uriToFsPath(uri, keepDriveLetterCasing) { |
| var value; |
| if (uri.authority && uri.path.length > 1 && uri.scheme === 'file') { |
| // unc path: file://shares/c$/far/boo |
| value = "//" + uri.authority + uri.path; |
| } |
| else if (uri.path.charCodeAt(0) === 47 /* Slash */ |
| && (uri.path.charCodeAt(1) >= 65 /* A */ && uri.path.charCodeAt(1) <= 90 /* Z */ || uri.path.charCodeAt(1) >= 97 /* a */ && uri.path.charCodeAt(1) <= 122 /* z */) |
| && uri.path.charCodeAt(2) === 58 /* Colon */) { |
| if (!keepDriveLetterCasing) { |
| // windows drive letter: file:///c:/far/boo |
| value = uri.path[1].toLowerCase() + uri.path.substr(2); |
| } |
| else { |
| value = uri.path.substr(1); |
| } |
| } |
| else { |
| // other path |
| value = uri.path; |
| } |
| if (isWindows) { |
| value = value.replace(/\//g, '\\'); |
| } |
| return value; |
| } |
| /** |
| * Create the external version of a uri |
| */ |
| function _asFormatted(uri, skipEncoding) { |
| var encoder = !skipEncoding |
| ? encodeURIComponentFast |
| : encodeURIComponentMinimal; |
| var res = ''; |
| var scheme = uri.scheme, authority = uri.authority, path = uri.path, query = uri.query, fragment = uri.fragment; |
| if (scheme) { |
| res += scheme; |
| res += ':'; |
| } |
| if (authority || scheme === 'file') { |
| res += _slash; |
| res += _slash; |
| } |
| if (authority) { |
| var idx = authority.indexOf('@'); |
| if (idx !== -1) { |
| // <user>@<auth> |
| var userinfo = authority.substr(0, idx); |
| authority = authority.substr(idx + 1); |
| idx = userinfo.indexOf(':'); |
| if (idx === -1) { |
| res += encoder(userinfo, false); |
| } |
| else { |
| // <user>:<pass>@<auth> |
| res += encoder(userinfo.substr(0, idx), false); |
| res += ':'; |
| res += encoder(userinfo.substr(idx + 1), false); |
| } |
| res += '@'; |
| } |
| authority = authority.toLowerCase(); |
| idx = authority.indexOf(':'); |
| if (idx === -1) { |
| res += encoder(authority, false); |
| } |
| else { |
| // <auth>:<port> |
| res += encoder(authority.substr(0, idx), false); |
| res += authority.substr(idx); |
| } |
| } |
| if (path) { |
| // lower-case windows drive letters in /C:/fff or C:/fff |
| if (path.length >= 3 && path.charCodeAt(0) === 47 /* Slash */ && path.charCodeAt(2) === 58 /* Colon */) { |
| var code = path.charCodeAt(1); |
| if (code >= 65 /* A */ && code <= 90 /* Z */) { |
| path = "/" + String.fromCharCode(code + 32) + ":" + path.substr(3); // "/c:".length === 3 |
| } |
| } |
| else if (path.length >= 2 && path.charCodeAt(1) === 58 /* Colon */) { |
| var code = path.charCodeAt(0); |
| if (code >= 65 /* A */ && code <= 90 /* Z */) { |
| path = String.fromCharCode(code + 32) + ":" + path.substr(2); // "/c:".length === 3 |
| } |
| } |
| // encode the rest of the path |
| res += encoder(path, true); |
| } |
| if (query) { |
| res += '?'; |
| res += encoder(query, false); |
| } |
| if (fragment) { |
| res += '#'; |
| res += !skipEncoding ? encodeURIComponentFast(fragment, false) : fragment; |
| } |
| return res; |
| } |
| // --- decode |
| function decodeURIComponentGraceful(str) { |
| try { |
| return decodeURIComponent(str); |
| } |
| catch (_a) { |
| if (str.length > 3) { |
| return str.substr(0, 3) + decodeURIComponentGraceful(str.substr(3)); |
| } |
| else { |
| return str; |
| } |
| } |
| } |
| var _rEncodedAsHex = /(%[0-9A-Za-z][0-9A-Za-z])+/g; |
| function percentDecode(str) { |
| if (!str.match(_rEncodedAsHex)) { |
| return str; |
| } |
| return str.replace(_rEncodedAsHex, function (match) { return decodeURIComponentGraceful(match); }); |
| } |