/* inspired from https://raw.githubusercontent.com/github/url-polyfill/master/url.js and https://stackoverflow.com/questions/6168260/how-to-parse-a-url */ (function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define(["require", "exports"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); let createIterator; if (Symbol && Symbol.iterator && (typeof ([][Symbol.iterator]) === 'function')) { createIterator = (items) => { return items[Symbol.iterator](); }; } else { createIterator = (items) => { return { next: function () { const value = items.shift(); return { done: value === void 0, value: value }; } }; }; } /** * Encodes a path segment. * RFC 3986 reserves !, ', (, ), and * and the implementation pipes the * output of encodeURIComponent to a hex encoding pass for these special * characters. */ function encodePathSegment(segment) { return encodeURIComponent(segment).replace(/[!'()*]/g, function (c) { return '%' + c.charCodeAt(0).toString(16); }); } class URLSearchParams { constructor(init) { this._entries = {}; if (typeof init === 'string') { if (init !== '') { init = init.replace(/^\?/, ''); const attributes = init.split('&'); let attribute; for (let i = 0; i < attributes.length; i++) { attribute = attributes[i].split('='); this.append(decodeURIComponent(attribute[0]), (attribute.length > 1) ? decodeURIComponent(attribute[1]) : ''); } } } else if (init instanceof URLSearchParams) { init.forEach((value, name) => { this.append(value, name); }); } } append(name, value) { value = value.toString(); if (name in this._entries) { this._entries[name].push(value); } else { this._entries[name] = [value]; } } delete(name) { delete this._entries[name]; } get(name) { return (name in this._entries) ? this._entries[name][0] : null; } getAll(name) { return (name in this._entries) ? this._entries[name].slice(0) : []; } has(name) { return (name in this._entries); } set(name, value) { this._entries[name] = [value.toString()]; } forEach(callback) { let entries; for (let name in this._entries) { if (this._entries.hasOwnProperty(name)) { entries = this._entries[name]; for (let i = 0; i < entries.length; i++) { callback.call(this, entries[i], name, this); } } } } keys() { const items = []; this.forEach((value, name) => { items.push(name); }); return createIterator(items); } values() { const items = []; this.forEach((value) => { items.push(value); }); return createIterator(items); } entries() { const items = []; this.forEach((value, name) => { items.push([value, name]); }); return createIterator(items); } toString() { let searchString = ''; this.forEach((value, name) => { if (searchString.length > 0) searchString += '&'; searchString += encodeURIComponent(name) + '=' + encodeURIComponent(value); }); return searchString; } } exports.URLSearchParams = URLSearchParams; class URL { constructor(url, base) { let baseParts; try { baseParts = URL.parse(base); } catch (e) { throw new Error('Invalid base URL'); } let urlParts = URL.parse(url); if (urlParts.protocol) { this._parts = { ...urlParts }; } else { this._parts = { protocol: baseParts.protocol, username: baseParts.username, password: baseParts.password, hostname: baseParts.hostname, port: baseParts.port, path: urlParts.path || baseParts.path, query: urlParts.query || baseParts.query, hash: urlParts.hash, }; } // console.log(URL.parse(base), URL.parse(url), this._parts); } static init() { this.URLRegExp = new RegExp('^' + this.patterns.protocol + '?' + this.patterns.authority + '?' + this.patterns.path + this.patterns.query + '?' + this.patterns.hash + '?'); this.AuthorityRegExp = new RegExp('^' + this.patterns.authentication + '?' + this.patterns.hostname + this.patterns.port + '?$'); } static parse(url) { const urlMatch = this.URLRegExp.exec(url); if (urlMatch !== null) { const authorityMatch = urlMatch[2] ? this.AuthorityRegExp.exec(urlMatch[2]) : [null, null, null, null, null]; if (authorityMatch !== null) { return { protocol: urlMatch[1] || '', username: authorityMatch[1] || '', password: authorityMatch[2] || '', hostname: authorityMatch[3] || '', port: authorityMatch[4] || '', path: urlMatch[3] || '', query: urlMatch[4] || '', hash: urlMatch[5] || '', }; } } throw new Error('Invalid URL'); } get hash() { return this._parts.hash; } set hash(value) { value = value.toString(); if (value.length === 0) { this._parts.hash = ''; } else { if (value.charAt(0) !== '#') value = '#' + value; this._parts.hash = encodeURIComponent(value); } } get host() { return this.hostname + (this.port ? (':' + this.port) : ''); } set host(value) { value = value.toString(); const url = new URL('http://' + value); this._parts.hostname = url.hostname; this._parts.port = url.port; } get hostname() { return this._parts.hostname; } set hostname(value) { value = value.toString(); this._parts.hostname = encodeURIComponent(value); } get href() { const authentication = (this.username || this.password) ? (this.username + (this.password ? (':' + this.password) : '') + '@') : ''; return this.protocol + '//' + authentication + this.host + this.pathname + this.search + this.hash; } set href(value) { value = value.toString(); const url = new URL(value); this._parts = { ...url._parts }; } get origin() { return this.protocol + '//' + this.host; } get password() { return this._parts.password; } set password(value) { value = value.toString(); this._parts.password = encodeURIComponent(value); } get pathname() { return this._parts.path ? this._parts.path : '/'; } set pathname(value) { let chunks = value.toString().split('/').map(encodePathSegment); if (chunks[0]) { // ensure joined string starts with slash. chunks.unshift(''); } this._parts.path = chunks.join('/'); } get port() { return this._parts.port; } set port(value) { let port = parseInt(value); if (isNaN(port)) { this._parts.port = '0'; } else { this._parts.port = Math.max(0, port % (2 ** 16)).toString(); } } get protocol() { return this._parts.protocol + ':'; } set protocol(value) { value = value.toString(); if (value.length !== 0) { if (value.charAt(value.length - 1) === ':') { value = value.slice(0, -1); } this._parts.protocol = encodeURIComponent(value); } } get search() { return this._parts.query; } set search(value) { value = value.toString(); if (value.charAt(0) !== '?') value = '?' + value; this._parts.query = value; } get username() { return this._parts.username; } set username(value) { value = value.toString(); this._parts.username = encodeURIComponent(value); } get searchParams() { const searchParams = new URLSearchParams(this.search); ['append', 'delete', 'set'].forEach((methodName) => { const method = searchParams[methodName]; searchParams[methodName] = (...args) => { method.apply(searchParams, args); this.search = searchParams.toString(); }; }); return searchParams; } toString() { return this.href; } } // createObjectURL(object: any, options?: ObjectURLOptions): string; // revokeObjectURL(url: string): void; URL.patterns = { protocol: '(?:([^:/?#]+):)', authority: '(?://([^/?#]*))', path: '([^?#]*)', query: '(\\?[^#]*)', hash: '(#.*)', authentication: '(?:([^:]*)(?::([^@]*))?@)', hostname: '([^:]+)', port: '(?::(\\d+))', }; exports.URL = URL; URL.init(); });