UNPKG

@difizen/mana-common

Version:

643 lines (619 loc) 27.1 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.URI = void 0; exports.uriToFsPath = uriToFsPath; var _charCode = require("./char-code"); var _platform = require("./platform"); var _encodeTable; function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } 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: \"".concat(ret.authority, "\", path: \"").concat(ret.path, "\", query: \"").concat(ret.query, "\", fragment: \"").concat(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 = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; var _regexpSimple = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?(.*?)$/; /** * 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 = exports.URI = /*#__PURE__*/function () { /** * @internal */ function URI(schemeOrData, authority, path, query, fragment) { var _strict = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false; var options = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : { simpleMode: true }; _classCallCheck(this, URI); /** * scheme is the 'http' part of 'http://www.example.com/some/path?query#fragment'. * The part before the first colon. */ _defineProperty(this, "scheme", void 0); /** * 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. */ _defineProperty(this, "authority", void 0); /** * path is the '/some/path' part of 'http://www.example.com/some/path?query#fragment'. */ _defineProperty(this, "path", void 0); /** * query is the 'query' part of 'http://www.example.com/some/path?query#fragment'. */ _defineProperty(this, "query", void 0); /** * fragment is the 'fragment' part of 'http://www.example.com/some/path?query#fragment'. */ _defineProperty(this, "fragment", void 0); _defineProperty(this, "simpleMode", void 0); 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); } this.simpleMode = options.simpleMode; } // ---- 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). */ _createClass(URI, [{ key: "fsPath", get: function get() { // if (this.scheme !== 'file') { // console.warn(`[UriError] calling fsPath with scheme ${this.scheme}`); // } return uriToFsPath(this, false); } // ---- modify to new ------------------------- }, { key: "with", value: function _with(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.example.com/some/path`, * `file:///usr/home`, or `scheme:with/path`. * * @param value A string which represents an URI (see `URI#toString`). */ }, { key: "toString", value: // ---- 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` */ function toString() { var skipEncoding = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; return _asFormatted(this, skipEncoding); } }, { key: "toJSON", value: function toJSON() { return this; } }], [{ key: "isUri", value: function isUri(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 === 'string' && typeof thing.with === 'function' && typeof thing.toString === 'function'; } }, { key: "parse", value: function parse(value) { var _strict = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : { simpleMode: true }; if (options.simpleMode) { var match = _regexpSimple.exec(value); if (!match) { return new Uri(_empty, _empty, _empty, _empty, _empty); } return new Uri(match[2] || _empty, match[4] || _empty, match[5] || _empty, _empty, _empty, _strict, options); } else { 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, options); } } /** * 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`) */ }, { key: "file", value: function file(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 (_platform.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); } }, { key: "from", value: function from(components) { var result = new Uri(components.scheme, components.authority, components.path, components.query, components.fragment); _validateUri(result, true); return result; } }, { key: "revive", value: function revive(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; }(); var _pathSepMarker = _platform.isWindows ? 1 : undefined; // This class exists so that URI is compatible with vscode.Uri (API). var Uri = /*#__PURE__*/function (_URI) { _inherits(Uri, _URI); var _super = _createSuper(Uri); function Uri() { var _this; _classCallCheck(this, Uri); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _super.call.apply(_super, [this].concat(args)); _defineProperty(_assertThisInitialized(_this), "_formatted", null); _defineProperty(_assertThisInitialized(_this), "_fsPath", null); return _this; } _createClass(Uri, [{ key: "fsPath", get: function get() { if (!this._fsPath) { this._fsPath = uriToFsPath(this, false); } return this._fsPath; } }, { key: "toString", value: function toString() { var skipEncoding = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; if (!skipEncoding) { if (!this._formatted) { this._formatted = _asFormatted(this, false); } return this._formatted; } else { // we don't cache that return _asFormatted(this, true); } } }, { key: "toJSON", value: function toJSON() { 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 = (_encodeTable = {}, _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_encodeTable, _charCode.CharCode.Colon, '%3A'), _charCode.CharCode.Slash, '%2F'), _charCode.CharCode.QuestionMark, '%3F'), _charCode.CharCode.Hash, '%23'), _charCode.CharCode.OpenSquareBracket, '%5B'), _charCode.CharCode.CloseSquareBracket, '%5D'), _charCode.CharCode.AtSign, '%40'), _charCode.CharCode.ExclamationMark, '%21'), _charCode.CharCode.DollarSign, '%24'), _charCode.CharCode.Ampersand, '%26'), _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_encodeTable, _charCode.CharCode.SingleQuote, '%27'), _charCode.CharCode.OpenParen, '%28'), _charCode.CharCode.CloseParen, '%29'), _charCode.CharCode.Asterisk, '%2A'), _charCode.CharCode.Plus, '%2B'), _charCode.CharCode.Comma, '%2C'), _charCode.CharCode.Semicolon, '%3B'), _charCode.CharCode.Equals, '%3D'), _charCode.CharCode.Space, '%20')); function encodeURIComponentFast(uriComponent, isPath, isAuthority) { 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 >= _charCode.CharCode.a && code <= _charCode.CharCode.z || code >= _charCode.CharCode.A && code <= _charCode.CharCode.Z || code >= _charCode.CharCode.Digit0 && code <= _charCode.CharCode.Digit9 || code === _charCode.CharCode.Dash || code === _charCode.CharCode.Period || code === _charCode.CharCode.Underline || code === _charCode.CharCode.Tilde || isPath && code === _charCode.CharCode.Slash || isAuthority && code === _charCode.CharCode.OpenSquareBracket || isAuthority && code === _charCode.CharCode.CloseSquareBracket || isAuthority && code === _charCode.CharCode.Colon) { // 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 === _charCode.CharCode.Hash || code === _charCode.CharCode.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 */ function uriToFsPath(uri, keepDriveLetterCasing) { var value; if (uri.authority && uri.path.length > 1 && uri.scheme === 'file') { // unc path: file://shares/c$/far/boo value = "//".concat(uri.authority).concat(uri.path); } else if (uri.path.charCodeAt(0) === _charCode.CharCode.Slash && (uri.path.charCodeAt(1) >= _charCode.CharCode.A && uri.path.charCodeAt(1) <= _charCode.CharCode.Z || uri.path.charCodeAt(1) >= _charCode.CharCode.a && uri.path.charCodeAt(1) <= _charCode.CharCode.z) && uri.path.charCodeAt(2) === _charCode.CharCode.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 (_platform.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, query = uri.query, fragment = uri.fragment, simpleMode = uri.simpleMode; var authority = uri.authority, path = uri.path; 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.lastIndexOf(':'); if (idx === -1) { res += simpleMode ? userinfo : encoder(userinfo, false, false); } else { // <user>:<pass>@<auth> res += simpleMode ? userinfo.substr(0, idx) : encoder(userinfo.substr(0, idx), false, false); res += ':'; res += simpleMode ? userinfo.substr(idx + 1) : encoder(userinfo.substr(idx + 1), false, true); } res += '@'; } authority = authority.toLowerCase(); idx = authority.lastIndexOf(':'); if (idx === -1) { res += simpleMode ? authority : encoder(authority, false, true); } else { // <auth>:<port> res += simpleMode ? authority.substr(0, idx) : encoder(authority.substr(0, idx), false, true); res += authority.substr(idx); } } if (path) { // lower-case windows drive letters in /C:/fff or C:/fff if (path.length >= 3 && path.charCodeAt(0) === _charCode.CharCode.Slash && path.charCodeAt(2) === _charCode.CharCode.Colon) { var code = path.charCodeAt(1); if (code >= _charCode.CharCode.A && code <= _charCode.CharCode.Z) { path = "/".concat(String.fromCharCode(code + 32), ":").concat(path.substr(3)); // "/c:".length === 3 } } else if (path.length >= 2 && path.charCodeAt(1) === _charCode.CharCode.Colon) { var _code = path.charCodeAt(0); if (_code >= _charCode.CharCode.A && _code <= _charCode.CharCode.Z) { path = "".concat(String.fromCharCode(_code + 32), ":").concat(path.substr(2)); // "/c:".length === 3 } } // encode the rest of the path res += simpleMode ? path : encoder(path, true, false); } if (query) { res += '?'; res += simpleMode ? query : encoder(query, false, false); } if (fragment) { res += '#'; res += !skipEncoding || !simpleMode ? encodeURIComponentFast(fragment, false, false) : fragment; } return res; } // --- decode function decodeURIComponentGraceful(str) { try { return decodeURIComponent(str); } catch (_unused) { 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); }); } /** * Mapped-type that replaces all occurrences of URI with UriComponents */