add lisp packages

This commit is contained in:
2020-12-05 21:29:49 +01:00
parent 85e20365ae
commit a6e2395755
7272 changed files with 1363243 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
The MIT License
Copyright (c) 2017 Valentin Richard
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,48 @@
### Polyfill URL and URLSearchParams to match last WHATWG specifications
Compliant in most of the use cases but not at 100% (like unicode chars, punycodes, etc...)
Tested on IE 10+
#### Install
```
npm i url-polyfill --save
```
#### Currently supported
##### window.URL
Documentation: https://developer.mozilla.org/en-US/docs/Web/API/URL
Supported : 'hash', 'host', 'hostname', 'href', 'port', 'protocol', 'search', 'toString', 'pathname', 'origin', 'searchParams'
Example:
```js
const url = new URL('https://www.example.com:8080/?fr=yset_ie_syc_oracle&type=orcl_hpset#page0');
```
- hash: `"page0"`
- host: `"www.example.com:8080"`
- hostname: `"www.example.com"`
- href: `"https://www.example.com:8080/?fr=yset_ie_syc_oracle&type=orcl_hpset#page0"`
- origin: `"https://www.example.com:8080"`
- pathname: `"/"`
- port: `"8080"`
- protocol: `"https:"`
- search: `"?fr=yset_ie_syc_oracle&type=orcl_hpset"`
- searchParams: URLSearchParams (see next)
##### window.URLSearchParams
Documentation: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
Supported : 'append', 'delete', 'get', 'getAll', 'has', 'set', 'forEach', 'keys', 'values', 'entries', 'toString', 'Symbol.iterator'
Example:
```js
const url = new URL('https://www.example.com/?fr=yset_ie_syc_oracle&type=orcl_hpset#page0');
url.searchParams.append('page', 0);
console.log(url.toString()); // print: "https://www.example.com/?fr=yset_ie_syc_oracle&type=orcl_hpset&page=0#page0"
```

View File

@@ -0,0 +1,304 @@
/*
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();
});

View File

@@ -0,0 +1,54 @@
{
"_from": "url-polyfill@^1.1.8",
"_id": "url-polyfill@1.1.8",
"_inBundle": false,
"_integrity": "sha512-Ey61F4FEqhcu1vHSOMmjl0Vd/RPRLEjMj402qszD/dhMBrVfoUsnIj8KSZo2yj+eIlxJGKFdnm6ES+7UzMgZ3Q==",
"_location": "/url-polyfill",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "url-polyfill@^1.1.8",
"name": "url-polyfill",
"escapedName": "url-polyfill",
"rawSpec": "^1.1.8",
"saveSpec": null,
"fetchSpec": "^1.1.8"
},
"_requiredBy": [
"/plyr"
],
"_resolved": "https://registry.npmjs.org/url-polyfill/-/url-polyfill-1.1.8.tgz",
"_shasum": "21eb58ad61192f52b77dcac8ab5293ae7bc67060",
"_spec": "url-polyfill@^1.1.8",
"_where": "/home/andy/plyr/node_modules/plyr",
"author": {
"name": "valentin"
},
"bugs": {
"url": "https://github.com/lifaon74/url-polyfill/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "Polyfill URL and URLSearchParams",
"devDependencies": {
"@types/node": "^10.12.18",
"http-server": "^0.11.1",
"selenium-webdriver": "^4.0.0-alpha.1",
"uglify-js": "^3.4.9"
},
"homepage": "https://github.com/lifaon74/url-polyfill#readme",
"license": "MIT",
"main": "url-polyfill.js",
"name": "url-polyfill",
"repository": {
"type": "git",
"url": "git+https://github.com/lifaon74/url-polyfill.git"
},
"scripts": {
"serve": "http-server ./ -p9876",
"start": "uglifyjs url-polyfill.js --stats -m -o url-polyfill.min.js",
"test": "node ./tests/test.js"
},
"version": "1.1.8"
}

View File

@@ -0,0 +1,15 @@
## Tests
```
npm run serve
```
Open : http://localhost:8080/tests/index.html
Replace params in `config.json`.
```
npm test
```
To clear IE cache: `RunDll32.exe InetCpl.cpl,ClearMyTracksByProcess 255`

View File

@@ -0,0 +1,35 @@
(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 });
class Async {
static $delay(timeout) {
return new Promise((resolve) => {
setTimeout(resolve, timeout);
});
}
static $yield() {
return new Promise((resolve) => {
// process.nextTick(resolve);
// setTimeout(resolve, 0);
setImmediate(resolve);
});
}
static async $await(callback, timeout = 0) {
const startTime = Date.now();
while (!callback()) {
await this.$yield();
if ((timeout > 0) && (Date.now() - startTime > timeout))
throw new Error('Timeout reached');
}
}
}
exports.Async = Async;
});

View File

@@ -0,0 +1,141 @@
(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", "selenium-webdriver"], factory);
}
})(function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const $webdriver = require("selenium-webdriver");
class Driver {
static get CHROME() {
return 'chrome';
}
;
static get FIREFOX() {
return 'firefox';
}
;
static get OPERA() {
return 'opera';
}
;
static get IE() {
return 'ie';
}
;
static get EDGE() {
return 'edge';
}
;
static create(browserName, remoteUrl) {
let capabilities = null;
switch (browserName) {
case this.CHROME:
capabilities = $webdriver.Capabilities.chrome();
break;
case this.IE:
capabilities = $webdriver.Capabilities.ie();
break;
case this.FIREFOX:
capabilities = $webdriver.Capabilities.firefox();
break;
case this.OPERA:
capabilities = $webdriver.Capabilities.opera();
break;
case this.EDGE:
capabilities = $webdriver.Capabilities.edge();
break;
default:
throw new Error(`Can't find browswer name ${browserName}`);
}
let builder = new $webdriver.Builder();
if (remoteUrl !== void 0) {
builder = builder.usingServer(remoteUrl);
}
return new Driver(builder
.withCapabilities(capabilities)
.build());
}
constructor(driver) {
this.driver = driver;
}
/**
* Executes an async script in the browser. Provides 2 function:
* - resolve
* - reject
* @param {string} script
* @return {Promise<void>}
*/
executeAsyncScript(script) {
// return this.driver.executeAsyncScript('arguments[arguments.length - 1]()');
return this.driver.executeAsyncScript(`
var __done = arguments[arguments.length - 1];
var resolve = function(data) {
if(__done) __done({ success : true, data: data });
__done = null;
};
var reject = function(error) {
if(error instanceof Error) {
var type = error.constructor.name || (/^\\s*function\\s+([^\\(\\s]*)\\s*/).exec(error.constructor.toString())[1]
error = { type: type, name: error.name || '', message: error.message || '', stack: error.stack || '' };
}
if(__done) __done({ success : false, _error: error });
__done = null;
};
try {
${script}
} catch(error) {
reject(error);
}
`).then((data) => {
if (data.success) {
return data.data;
}
else {
let error = data._error;
if (typeof error === 'object') {
const type = (error.type in global) ? global[error.type] : Error;
const _error = new type(error.message || '');
if (error.name && (error.name !== _error.name))
_error.name = error.name;
// if(error.stack) _error.stack = error.stack;
_error.stack = error.stack || `${error.name}: ${error.message}\n\tempty stack`;
error = _error;
}
throw error;
}
});
}
/**
* Executes a script in the browser.
* Can return a value with 'return'
* @param {string} script
* @return {Promise<void>}
*/
executeScript(script) {
return this.executeAsyncScript(`resolve(
(function() {
${script}
})()
);`);
}
navigate(url) {
return this.driver.navigate().to(url);
}
ngNavigate(path) {
return this.driver.executeScript(`return window.router.navigate(${JSON.stringify(path)});`);
}
quit() {
return this.driver.quit();
}
}
exports.Driver = Driver;
});

View File

@@ -0,0 +1,56 @@
(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", "./Driver"], factory);
}
})(function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const Driver_1 = require("./Driver");
class Tester {
constructor(remoteUrl) {
this.remoteUrl = remoteUrl;
}
runForMany(browsers, callback) {
return Promise.all(browsers.map((browser) => this.runFor(browser, callback))).then(() => {
});
}
runFor(browser, callback) {
const driver = Driver_1.Driver.create(browser, this.remoteUrl);
return new Promise((resolve) => {
resolve(callback(driver));
})
.then(() => {
return driver.quit();
}, (error) => {
return Promise.race([
driver.quit(),
new Promise((resolve) => setTimeout(resolve, 2000))
]).then(() => Promise.reject(error));
});
}
test(testName, callback) {
return new Promise((resolve, reject) => {
this.log(`Starting test '${testName}'`, 33);
resolve(callback());
})
.then(() => {
this.log(`test '${testName}' succeed`, 32);
}, (error) => {
this.log(`test '${testName}' failed`, 31);
console.log(error);
throw error;
});
}
log(content, color) {
console.log(this.colorString(content, color));
}
colorString(content, color = 0) {
return `\x1b[${color}m${content}\x1b[0m`;
}
}
exports.Tester = Tester;
});

View File

@@ -0,0 +1,4 @@
{
"testServer": "http://192.168.0.128:4444/wd/hub",
"testHost": "http://192.168.0.130:9876/tests/"
}

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Tests</title>
<script type="text/javascript">
['url-polyfill'].forEach(function(fileName) {
var script = document.createElement('script');
script.src = '../' + fileName + '.js?timeout=' + Math.random().toString();
document.head.appendChild(script);
});
</script>
</head>
<body>
Test executing...
</body>
</html>

View File

@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Tests</title>
<!--<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.3/require.min.js"></script>-->
<script type="text/javascript">
var script = document.createElement('script');
exports = {};
script.src = 'url-class-test.js?timeout=' + Math.random().toString();
document.head.appendChild(script);
</script>
</head>
<body>
Test executing...
</body>
</html>

View File

@@ -0,0 +1,35 @@
(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", "../do-not-use/url"], factory);
}
})(function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const originalURL = window.URL;
const url_1 = require("../do-not-use/url");
const test = () => {
let a = new originalURL('?fr=yset_ie_syc_oracle&type=orcl_hpset#page0', 'https://username:password@www.yahoo.com:80/path');
let b = new url_1.URL('?fr=yset_ie_syc_oracle&type=orcl_hpset#page0', 'https://username:password@www.yahoo.com:80/path');
// let b = new URL('https://username:password@www.yahoo.com:80/path?fr=yset_ie_syc_oracle&type=orcl_hpset#page0', '');
window.a = a;
window.b = b;
// 'a+"*ç%&/()=?±“#Ç[]|{}≠b'
for (let key in a) {
let value = a[key];
switch (typeof value) {
case 'boolean':
case 'number':
case 'string':
if (value !== b[key]) {
throw new Error('Values mismatch for key "' + key + '" : \n' + value + '\n' + b[key]);
}
break;
}
}
};
test();
});

View File

@@ -0,0 +1,157 @@
(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", "./classes/Driver", "./classes/Async", "./classes/Tester"], factory);
}
})(function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const Driver_1 = require("./classes/Driver");
const Async_1 = require("./classes/Async");
const Tester_1 = require("./classes/Tester");
(function example() {
const config = require('./config.json');
const tester = new Tester_1.Tester(config.testServer);
return tester.runForMany([
Driver_1.Driver.EDGE,
Driver_1.Driver.CHROME,
// Driver.FIREFOX,
// Driver.OPERA,
Driver_1.Driver.IE
], async (driver) => {
await driver.driver.manage().setTimeouts({
pageLoad: 300000,
script: 300000,
});
await driver.navigate(config.testHost);
await Async_1.Async.$delay(500);
await tester.test('Test URL', () => {
return driver.executeScript(`
var url = new URL('https://www.yahoo.com:80/?fr=yset_ie_syc_oracle&type=orcl_hpset#page0');
if(url.hash !== '#page0') throw new Error('Invalid hash : ' + url.hash);
if(url.host !== 'www.yahoo.com:80') throw new Error('Invalid host : ' + url.host);
if(url.hostname !== 'www.yahoo.com') throw new Error('Invalid hostname : ' + url.hostname);
if(url.href !== 'https://www.yahoo.com:80/?fr=yset_ie_syc_oracle&type=orcl_hpset#page0') throw new Error('Invalid href : ' + url.href);
if(url.origin !== 'https://www.yahoo.com:80') throw new Error('Invalid origin : ' + url.origin);
if(url.pathname !== '/') throw new Error('Invalid pathname : ' + url.pathname);
if(url.port !== '80') throw new Error('Invalid port : ' + url.port);
if(url.protocol !== 'https:') throw new Error('Invalid protocol : ' + url.protocol);
if(url.search !== '?fr=yset_ie_syc_oracle&type=orcl_hpset') throw new Error('Invalid search : ' + url.search);
url.searchParams.append('page', 1);
if(url.search !== '?fr=yset_ie_syc_oracle&type=orcl_hpset&page=1') throw new Error('Invalid search (append page 1) : ' + url.search);
url.searchParams.delete('type');
if(url.search !== '?fr=yset_ie_syc_oracle&page=1') throw new Error('Invalid search (delete type) : ' + url.search);
return url;
`);
});
await tester.test('Test URLSearchParams', () => {
return driver.executeScript(`
var url = new URL('http://localhost/?a=b');
if(url.searchParams !== url.searchParams) throw new Error('Expects url.searchParams === url.searchParams');
url.search = 'c=b';
if(url.searchParams.toString() !== 'c=b') throw new Error('Expects url.searchParams.toString() === c=b');
url.searchParams.append('d', 'e');
if(url.search !== '?c=b&d=e') throw new Error('Expects url.search === ?c=b&d=e');
return url;
`);
});
await tester.test('Test URLSearchParams special char encoding/decoding', () => {
return driver.executeScript(`
if(new URLSearchParams('a=2018-12-19T09:14:35%2B09:00').get('a') !== '2018-12-19T09:14:35+09:00') {
throw new Error('a=2018-12-19T09:14:35%2B09:00 failed');
}
if(new URLSearchParams('a=one+two').get('a') !== 'one two') {
throw new Error('a=one+two failed');
}
`);
});
await tester.test('Test URLSearchParams constructor', () => {
return driver.executeScript(`
var a = new URLSearchParams('b=1&a=2&c=3');
if(a.toString() !== 'b=1&a=2&c=3') throw new Error('Invalid constructor with new URLSearchParams(\\'b=1&a=2&c=3\\')');
var b = new URLSearchParams(a);
if(b.toString() !== 'b=1&a=2&c=3') throw new Error('Invalid constructor with new URLSearchParams(new URLSearchParams(\\'b=1&a=2&c=3\\'))');
var c = new URLSearchParams([['b', 1], ['a', 2], ['c', 3]]);
if(c.toString() !== 'b=1&a=2&c=3') throw new Error('Invalid constructor with new URLSearchParams([[\\'b\\', 1], [\\'a\\', 2], [\\'c\\', 3]])');
var d = new URLSearchParams({ 'b': 1, 'a': 2, 'c': 3 });
if(d.toString() !== 'b=1&a=2&c=3') throw new Error('Invalid constructor with new URLSearchParams({ \\'b\\': 1, \\'a\\': 2, \\'c\\': 3 })');
`);
});
await tester.test('Test URLSearchParams.sort', () => {
return driver.executeScript(`
var a = new URLSearchParams('b=1&a=2&c=3');
a.sort();
if(a.toString() !== 'a=2&b=1&c=3') throw new Error('Expects searchParams.sort().toString() === a=2&b=1&c=3');
`);
});
await tester.test('Test URL with base', () => {
return driver.executeScript(`
var url = new URL('test', 'http://www.example.com/base');
if(url.host !== 'www.example.com') throw new Error('Invalid host : ' + url.host);
if(url.hostname !== 'www.example.com') throw new Error('Invalid hostname : ' + url.hostname);
if(url.href !== 'http://www.example.com/test') throw new Error('Invalid href : ' + url.href);
if(url.pathname !== '/test') throw new Error('Invalid pathname : ' + url.pathname);
if(url.protocol !== 'http:') throw new Error('Invalid protocol : ' + url.protocol);
if(url.search !== '') throw new Error('Invalid search : ' + url.search);
return url;
`);
});
await tester.test('Test pathname variations', () => {
return driver.executeScript(`
var url = new URL('test/long/path.html', 'http://www.example.com');
if(url.pathname !== '/test/long/path.html') throw new Error('Invalid pathname : ' + url.pathname);
url.pathname = 'a/b 1'
if(url.pathname !== '/a/b%201') throw new Error('Invalid pathname : ' + url.pathname);
return url;
`);
});
await tester.test('Ensure url.href does\'nt finish with ? if url.search is empty', () => {
return driver.executeScript(`
var url = new URL('https://www.example.com/');
url.searchParams.delete('foo');
if(url.toString() !== 'https://www.example.com/') throw new Error('Invalid url : ' + url.toString());
`);
});
await tester.test('URL SearchParams should have spaces encoded as "+"', () => {
return driver.executeScript(`
var url = new URL('https://www.example.com/');
url.searchParams.set('foo', 'value with spaces');
if(url.toString() !== 'https://www.example.com/?foo=value+with+spaces') throw new Error('Invalid url : ' + url.toString());
var url = new URL('https://www.example.com/?foo=another+value+with+spaces');
var fooParam = url.searchParams.get('foo');
if(fooParam !== 'another value with spaces') throw new Error('Invalid "foo" param value : ' + fooParam);
`);
});
await tester.test('Url Protocol should control the visibility of port in origin', () => {
return driver.executeScript(`
var url = new URL('https://www.example.com:443'); // No port for https on 443
var url2 = new URL('http://www.example.com:8080'); // Port for http on 8080
var url3 = new URL('https://www.example.com:80'); // port for https on 80
if (url.origin !== 'https://www.example.com') throw new Error('Origin value is not correct ' + url.origin);
if (url2.origin !== 'http://www.example.com:8080') throw new Error('Origin value is not correct ' + url2.origin);
if (url3.origin !== 'https://www.example.com:80') throw new Error('Origin value is not correct ' + url3.origin);
`);
});
});
})().catch(_ => console.log('ERROR: ', _));
});

View File

@@ -0,0 +1,618 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
(function(scope) {
'use strict';
// feature detect for URL constructor
var hasWorkingUrl = false;
if (!scope.forceJURL) {
try {
var u = new URL('b', 'http://a');
u.pathname = 'c%20d';
hasWorkingUrl = u.href === 'http://a/c%20d';
} catch(e) {}
}
if (hasWorkingUrl)
return;
var relative = Object.create(null);
relative['ftp'] = 21;
relative['file'] = 0;
relative['gopher'] = 70;
relative['http'] = 80;
relative['https'] = 443;
relative['ws'] = 80;
relative['wss'] = 443;
var relativePathDotMapping = Object.create(null);
relativePathDotMapping['%2e'] = '.';
relativePathDotMapping['.%2e'] = '..';
relativePathDotMapping['%2e.'] = '..';
relativePathDotMapping['%2e%2e'] = '..';
function isRelativeScheme(scheme) {
return relative[scheme] !== undefined;
}
function invalid() {
clear.call(this);
this._isInvalid = true;
}
function IDNAToASCII(h) {
if ('' == h) {
invalid.call(this)
}
// XXX
return h.toLowerCase()
}
function percentEscape(c) {
var unicode = c.charCodeAt(0);
if (unicode > 0x20 &&
unicode < 0x7F &&
// " # < > ? `
[0x22, 0x23, 0x3C, 0x3E, 0x3F, 0x60].indexOf(unicode) == -1
) {
return c;
}
return encodeURIComponent(c);
}
function percentEscapeQuery(c) {
// XXX This actually needs to encode c using encoding and then
// convert the bytes one-by-one.
var unicode = c.charCodeAt(0);
if (unicode > 0x20 &&
unicode < 0x7F &&
// " # < > ` (do not escape '?')
[0x22, 0x23, 0x3C, 0x3E, 0x60].indexOf(unicode) == -1
) {
return c;
}
return encodeURIComponent(c);
}
var EOF = undefined,
ALPHA = /[a-zA-Z]/,
ALPHANUMERIC = /[a-zA-Z0-9\+\-\.]/;
function parse(input, stateOverride, base) {
function err(message) {
errors.push(message)
}
var state = stateOverride || 'scheme start',
cursor = 0,
buffer = '',
seenAt = false,
seenBracket = false,
errors = [];
loop: while ((input[cursor - 1] != EOF || cursor == 0) && !this._isInvalid) {
var c = input[cursor];
switch (state) {
case 'scheme start':
if (c && ALPHA.test(c)) {
buffer += c.toLowerCase(); // ASCII-safe
state = 'scheme';
} else if (!stateOverride) {
buffer = '';
state = 'no scheme';
continue;
} else {
err('Invalid scheme.');
break loop;
}
break;
case 'scheme':
if (c && ALPHANUMERIC.test(c)) {
buffer += c.toLowerCase(); // ASCII-safe
} else if (':' == c) {
this._scheme = buffer;
buffer = '';
if (stateOverride) {
break loop;
}
if (isRelativeScheme(this._scheme)) {
this._isRelative = true;
}
if ('file' == this._scheme) {
state = 'relative';
} else if (this._isRelative && base && base._scheme == this._scheme) {
state = 'relative or authority';
} else if (this._isRelative) {
state = 'authority first slash';
} else {
state = 'scheme data';
}
} else if (!stateOverride) {
buffer = '';
cursor = 0;
state = 'no scheme';
continue;
} else if (EOF == c) {
break loop;
} else {
err('Code point not allowed in scheme: ' + c)
break loop;
}
break;
case 'scheme data':
if ('?' == c) {
query = '?';
state = 'query';
} else if ('#' == c) {
this._fragment = '#';
state = 'fragment';
} else {
// XXX error handling
if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
this._schemeData += percentEscape(c);
}
}
break;
case 'no scheme':
if (!base || !(isRelativeScheme(base._scheme))) {
err('Missing scheme.');
invalid.call(this);
} else {
state = 'relative';
continue;
}
break;
case 'relative or authority':
if ('/' == c && '/' == input[cursor+1]) {
state = 'authority ignore slashes';
} else {
err('Expected /, got: ' + c);
state = 'relative';
continue
}
break;
case 'relative':
this._isRelative = true;
if ('file' != this._scheme)
this._scheme = base._scheme;
if (EOF == c) {
this._host = base._host;
this._port = base._port;
this._path = base._path.slice();
this._query = base._query;
this._username = base._username;
this._password = base._password;
break loop;
} else if ('/' == c || '\\' == c) {
if ('\\' == c)
err('\\ is an invalid code point.');
state = 'relative slash';
} else if ('?' == c) {
this._host = base._host;
this._port = base._port;
this._path = base._path.slice();
this._query = '?';
this._username = base._username;
this._password = base._password;
state = 'query';
} else if ('#' == c) {
this._host = base._host;
this._port = base._port;
this._path = base._path.slice();
this._query = base._query;
this._fragment = '#';
this._username = base._username;
this._password = base._password;
state = 'fragment';
} else {
var nextC = input[cursor+1]
var nextNextC = input[cursor+2]
if (
'file' != this._scheme || !ALPHA.test(c) ||
(nextC != ':' && nextC != '|') ||
(EOF != nextNextC && '/' != nextNextC && '\\' != nextNextC && '?' != nextNextC && '#' != nextNextC)) {
this._host = base._host;
this._port = base._port;
this._username = base._username;
this._password = base._password;
this._path = base._path.slice();
this._path.pop();
}
state = 'relative path';
continue;
}
break;
case 'relative slash':
if ('/' == c || '\\' == c) {
if ('\\' == c) {
err('\\ is an invalid code point.');
}
if ('file' == this._scheme) {
state = 'file host';
} else {
state = 'authority ignore slashes';
}
} else {
if ('file' != this._scheme) {
this._host = base._host;
this._port = base._port;
this._username = base._username;
this._password = base._password;
}
state = 'relative path';
continue;
}
break;
case 'authority first slash':
if ('/' == c) {
state = 'authority second slash';
} else {
err("Expected '/', got: " + c);
state = 'authority ignore slashes';
continue;
}
break;
case 'authority second slash':
state = 'authority ignore slashes';
if ('/' != c) {
err("Expected '/', got: " + c);
continue;
}
break;
case 'authority ignore slashes':
if ('/' != c && '\\' != c) {
state = 'authority';
continue;
} else {
err('Expected authority, got: ' + c);
}
break;
case 'authority':
if ('@' == c) {
if (seenAt) {
err('@ already seen.');
buffer += '%40';
}
seenAt = true;
for (var i = 0; i < buffer.length; i++) {
var cp = buffer[i];
if ('\t' == cp || '\n' == cp || '\r' == cp) {
err('Invalid whitespace in authority.');
continue;
}
// XXX check URL code points
if (':' == cp && null === this._password) {
this._password = '';
continue;
}
var tempC = percentEscape(cp);
(null !== this._password) ? this._password += tempC : this._username += tempC;
}
buffer = '';
} else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
cursor -= buffer.length;
buffer = '';
state = 'host';
continue;
} else {
buffer += c;
}
break;
case 'file host':
if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
if (buffer.length == 2 && ALPHA.test(buffer[0]) && (buffer[1] == ':' || buffer[1] == '|')) {
state = 'relative path';
} else if (buffer.length == 0) {
state = 'relative path start';
} else {
this._host = IDNAToASCII.call(this, buffer);
buffer = '';
state = 'relative path start';
}
continue;
} else if ('\t' == c || '\n' == c || '\r' == c) {
err('Invalid whitespace in file host.');
} else {
buffer += c;
}
break;
case 'host':
case 'hostname':
if (':' == c && !seenBracket) {
// XXX host parsing
this._host = IDNAToASCII.call(this, buffer);
buffer = '';
state = 'port';
if ('hostname' == stateOverride) {
break loop;
}
} else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c) {
this._host = IDNAToASCII.call(this, buffer);
buffer = '';
state = 'relative path start';
if (stateOverride) {
break loop;
}
continue;
} else if ('\t' != c && '\n' != c && '\r' != c) {
if ('[' == c) {
seenBracket = true;
} else if (']' == c) {
seenBracket = false;
}
buffer += c;
} else {
err('Invalid code point in host/hostname: ' + c);
}
break;
case 'port':
if (/[0-9]/.test(c)) {
buffer += c;
} else if (EOF == c || '/' == c || '\\' == c || '?' == c || '#' == c || stateOverride) {
if ('' != buffer) {
var temp = parseInt(buffer, 10);
if (temp != relative[this._scheme]) {
this._port = temp + '';
}
buffer = '';
}
if (stateOverride) {
break loop;
}
state = 'relative path start';
continue;
} else if ('\t' == c || '\n' == c || '\r' == c) {
err('Invalid code point in port: ' + c);
} else {
invalid.call(this);
}
break;
case 'relative path start':
if ('\\' == c)
err("'\\' not allowed in path.");
state = 'relative path';
if ('/' != c && '\\' != c) {
continue;
}
break;
case 'relative path':
if (EOF == c || '/' == c || '\\' == c || (!stateOverride && ('?' == c || '#' == c))) {
if ('\\' == c) {
err('\\ not allowed in relative path.');
}
var tmp;
if (tmp = relativePathDotMapping[buffer.toLowerCase()]) {
buffer = tmp;
}
if ('..' == buffer) {
this._path.pop();
if ('/' != c && '\\' != c) {
this._path.push('');
}
} else if ('.' == buffer && '/' != c && '\\' != c) {
this._path.push('');
} else if ('.' != buffer) {
if ('file' == this._scheme && this._path.length == 0 && buffer.length == 2 && ALPHA.test(buffer[0]) && buffer[1] == '|') {
buffer = buffer[0] + ':';
}
this._path.push(buffer);
}
buffer = '';
if ('?' == c) {
this._query = '?';
state = 'query';
} else if ('#' == c) {
this._fragment = '#';
state = 'fragment';
}
} else if ('\t' != c && '\n' != c && '\r' != c) {
buffer += percentEscape(c);
}
break;
case 'query':
if (!stateOverride && '#' == c) {
this._fragment = '#';
state = 'fragment';
} else if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
this._query += percentEscapeQuery(c);
}
break;
case 'fragment':
if (EOF != c && '\t' != c && '\n' != c && '\r' != c) {
this._fragment += c;
}
break;
}
cursor++;
}
}
function clear() {
this._scheme = '';
this._schemeData = '';
this._username = '';
this._password = null;
this._host = '';
this._port = '';
this._path = [];
this._query = '';
this._fragment = '';
this._isInvalid = false;
this._isRelative = false;
}
// Does not process domain names or IP addresses.
// Does not handle encoding for the query parameter.
function jURL(url, base /* , encoding */) {
if (base !== undefined && !(base instanceof jURL))
base = new jURL(String(base));
url = String(url)
this._url = url
clear.call(this);
var input = url.replace(/^[ \t\r\n\f]+|[ \t\r\n\f]+$/g, '');
// encoding = encoding || 'utf-8'
parse.call(this, input, null, base);
}
jURL.prototype = {
toString: function() {
return this.href;
},
get href() {
if (this._isInvalid)
return this._url;
var authority = '';
if ('' != this._username || null != this._password) {
authority = this._username +
(null != this._password ? ':' + this._password : '') + '@';
}
return this.protocol +
(this._isRelative ? '//' + authority + this.host : '') +
this.pathname + this._query + this._fragment;
},
set href(href) {
clear.call(this);
parse.call(this, href);
},
get protocol() {
return this._scheme + ':';
},
set protocol(protocol) {
if (this._isInvalid)
return;
parse.call(this, protocol + ':', 'scheme start');
},
get host() {
return this._isInvalid ? '' : this._port ?
this._host + ':' + this._port : this._host;
},
set host(host) {
if (this._isInvalid || !this._isRelative)
return;
parse.call(this, host, 'host');
},
get hostname() {
return this._host;
},
set hostname(hostname) {
if (this._isInvalid || !this._isRelative)
return;
parse.call(this, hostname, 'hostname');
},
get port() {
return this._port;
},
set port(port) {
if (this._isInvalid || !this._isRelative)
return;
parse.call(this, port, 'port');
},
get pathname() {
return this._isInvalid ? '' : this._isRelative ?
'/' + this._path.join('/') : this._schemeData;
},
set pathname(pathname) {
if (this._isInvalid || !this._isRelative)
return;
this._path = [];
parse.call(this, pathname, 'relative path start');
},
get search() {
return this._isInvalid || !this._query || '?' == this._query ?
'' : this._query;
},
set search(search) {
if (this._isInvalid || !this._isRelative)
return;
this._query = '?';
if ('?' == search[0])
search = search.slice(1);
parse.call(this, search, 'query');
},
get hash() {
return this._isInvalid || !this._fragment || '#' == this._fragment ?
'' : this._fragment;
},
set hash(hash) {
if (this._isInvalid)
return;
this._fragment = '#';
if ('#' == hash[0])
hash = hash.slice(1);
parse.call(this, hash, 'fragment');
},
get origin() {
var host;
if (this._isInvalid || !this._scheme) {
return '';
}
// javascript: Gecko returns String(""), WebKit/Blink String("null")
// Gecko throws error for "data://"
// data: Gecko returns "", Blink returns "data://", WebKit returns "null"
// Gecko returns String("") for file: mailto:
// WebKit/Blink returns String("SCHEME://") for file: mailto:
switch (this._scheme) {
case 'data':
case 'file':
case 'javascript':
case 'mailto':
return 'null';
}
host = this.host;
if (!host) {
return '';
}
return this._scheme + '://' + host;
}
};
// Copy over the static methods
var OriginalURL = scope.URL;
if (OriginalURL) {
jURL.createObjectURL = function(blob) {
// IE extension allows a second optional options argument.
// http://msdn.microsoft.com/en-us/library/ie/hh772302(v=vs.85).aspx
return OriginalURL.createObjectURL.apply(OriginalURL, arguments);
};
jURL.revokeObjectURL = function(url) {
OriginalURL.revokeObjectURL(url);
};
}
scope.URL = jURL;
})(this);

View File

@@ -0,0 +1,483 @@
(function(global) {
/**
* Polyfill URLSearchParams
*
* Inspired from : https://github.com/WebReflection/url-search-params/blob/master/src/url-search-params.js
*/
var checkIfIteratorIsSupported = function() {
try {
return !!Symbol.iterator;
} catch (error) {
return false;
}
};
var iteratorSupported = checkIfIteratorIsSupported();
var createIterator = function(items) {
var iterator = {
next: function() {
var value = items.shift();
return { done: value === void 0, value: value };
}
};
if (iteratorSupported) {
iterator[Symbol.iterator] = function() {
return iterator;
};
}
return iterator;
};
/**
* Search param name and values should be encoded according to https://url.spec.whatwg.org/#urlencoded-serializing
* encodeURIComponent() produces the same result except encoding spaces as `%20` instead of `+`.
*/
var serializeParam = function(value) {
return encodeURIComponent(value).replace(/%20/g, '+');
};
var deserializeParam = function(value) {
return decodeURIComponent(String(value).replace(/\+/g, ' '));
};
var polyfillURLSearchParams = function() {
var URLSearchParams = function(searchString) {
Object.defineProperty(this, '_entries', { writable: true, value: {} });
var typeofSearchString = typeof searchString;
if (typeofSearchString === 'undefined') {
// do nothing
} else if (typeofSearchString === 'string') {
if (searchString !== '') {
this._fromString(searchString);
}
} else if (searchString instanceof URLSearchParams) {
var _this = this;
searchString.forEach(function(value, name) {
_this.append(name, value);
});
} else if ((searchString !== null) && (typeofSearchString === 'object')) {
if (Object.prototype.toString.call(searchString) === '[object Array]') {
for (var i = 0; i < searchString.length; i++) {
var entry = searchString[i];
if ((Object.prototype.toString.call(entry) === '[object Array]') || (entry.length !== 2)) {
this.append(entry[0], entry[1]);
} else {
throw new TypeError('Expected [string, any] as entry at index ' + i + ' of URLSearchParams\'s input');
}
}
} else {
for (var key in searchString) {
if (searchString.hasOwnProperty(key)) {
this.append(key, searchString[key]);
}
}
}
} else {
throw new TypeError('Unsupported input\'s type for URLSearchParams');
}
};
var proto = URLSearchParams.prototype;
proto.append = function(name, value) {
if (name in this._entries) {
this._entries[name].push(String(value));
} else {
this._entries[name] = [String(value)];
}
};
proto.delete = function(name) {
delete this._entries[name];
};
proto.get = function(name) {
return (name in this._entries) ? this._entries[name][0] : null;
};
proto.getAll = function(name) {
return (name in this._entries) ? this._entries[name].slice(0) : [];
};
proto.has = function(name) {
return (name in this._entries);
};
proto.set = function(name, value) {
this._entries[name] = [String(value)];
};
proto.forEach = function(callback, thisArg) {
var entries;
for (var name in this._entries) {
if (this._entries.hasOwnProperty(name)) {
entries = this._entries[name];
for (var i = 0; i < entries.length; i++) {
callback.call(thisArg, entries[i], name, this);
}
}
}
};
proto.keys = function() {
var items = [];
this.forEach(function(value, name) {
items.push(name);
});
return createIterator(items);
};
proto.values = function() {
var items = [];
this.forEach(function(value) {
items.push(value);
});
return createIterator(items);
};
proto.entries = function() {
var items = [];
this.forEach(function(value, name) {
items.push([name, value]);
});
return createIterator(items);
};
if (iteratorSupported) {
proto[Symbol.iterator] = proto.entries;
}
proto.toString = function() {
var searchArray = [];
this.forEach(function(value, name) {
searchArray.push(serializeParam(name) + '=' + serializeParam(value));
});
return searchArray.join('&');
};
global.URLSearchParams = URLSearchParams;
};
var checkIfURLSearchParamsSupported = function() {
try {
var URLSearchParams = global.URLSearchParams;
return (new URLSearchParams('?a=1').toString() === 'a=1') && (typeof URLSearchParams.prototype.set === 'function');
} catch (e) {
return false;
}
};
if (!checkIfURLSearchParamsSupported()) {
polyfillURLSearchParams();
}
var proto = global.URLSearchParams.prototype;
if (typeof proto.sort !== 'function') {
proto.sort = function() {
var _this = this;
var items = [];
this.forEach(function(value, name) {
items.push([name, value]);
if (!_this._entries) {
_this.delete(name);
}
});
items.sort(function(a, b) {
if (a[0] < b[0]) {
return -1;
} else if (a[0] > b[0]) {
return +1;
} else {
return 0;
}
});
if (_this._entries) { // force reset because IE keeps keys index
_this._entries = {};
}
for (var i = 0; i < items.length; i++) {
this.append(items[i][0], items[i][1]);
}
};
}
if (typeof proto._fromString !== 'function') {
Object.defineProperty(proto, '_fromString', {
enumerable: false,
configurable: false,
writable: false,
value: function(searchString) {
if (this._entries) {
this._entries = {};
} else {
var keys = [];
this.forEach(function(value, name) {
keys.push(name);
});
for (var i = 0; i < keys.length; i++) {
this.delete(keys[i]);
}
}
searchString = searchString.replace(/^\?/, '');
var attributes = searchString.split('&');
var attribute;
for (var i = 0; i < attributes.length; i++) {
attribute = attributes[i].split('=');
this.append(
deserializeParam(attribute[0]),
(attribute.length > 1) ? deserializeParam(attribute[1]) : ''
);
}
}
});
}
// HTMLAnchorElement
})(
(typeof global !== 'undefined') ? global
: ((typeof window !== 'undefined') ? window
: ((typeof self !== 'undefined') ? self : this))
);
(function(global) {
/**
* Polyfill URL
*
* Inspired from : https://github.com/arv/DOM-URL-Polyfill/blob/master/src/url.js
*/
var checkIfURLIsSupported = function() {
try {
var u = new global.URL('b', 'http://a');
u.pathname = 'c d';
return (u.href === 'http://a/c%20d') && u.searchParams;
} catch (e) {
return false;
}
};
var polyfillURL = function() {
var _URL = global.URL;
var URL = function(url, base) {
if (typeof url !== 'string') url = String(url);
// Only create another document if the base is different from current location.
var doc = document, baseElement;
if (base && (global.location === void 0 || base !== global.location.href)) {
doc = document.implementation.createHTMLDocument('');
baseElement = doc.createElement('base');
baseElement.href = base;
doc.head.appendChild(baseElement);
try {
if (baseElement.href.indexOf(base) !== 0) throw new Error(baseElement.href);
} catch (err) {
throw new Error('URL unable to set base ' + base + ' due to ' + err);
}
}
var anchorElement = doc.createElement('a');
anchorElement.href = url;
if (baseElement) {
doc.body.appendChild(anchorElement);
anchorElement.href = anchorElement.href; // force href to refresh
}
if (anchorElement.protocol === ':' || !/:/.test(anchorElement.href)) {
throw new TypeError('Invalid URL');
}
Object.defineProperty(this, '_anchorElement', {
value: anchorElement
});
// create a linked searchParams which reflect its changes on URL
var searchParams = new global.URLSearchParams(this.search);
var enableSearchUpdate = true;
var enableSearchParamsUpdate = true;
var _this = this;
['append', 'delete', 'set'].forEach(function(methodName) {
var method = searchParams[methodName];
searchParams[methodName] = function() {
method.apply(searchParams, arguments);
if (enableSearchUpdate) {
enableSearchParamsUpdate = false;
_this.search = searchParams.toString();
enableSearchParamsUpdate = true;
}
};
});
Object.defineProperty(this, 'searchParams', {
value: searchParams,
enumerable: true
});
var search = void 0;
Object.defineProperty(this, '_updateSearchParams', {
enumerable: false,
configurable: false,
writable: false,
value: function() {
if (this.search !== search) {
search = this.search;
if (enableSearchParamsUpdate) {
enableSearchUpdate = false;
this.searchParams._fromString(this.search);
enableSearchUpdate = true;
}
}
}
});
};
var proto = URL.prototype;
var linkURLWithAnchorAttribute = function(attributeName) {
Object.defineProperty(proto, attributeName, {
get: function() {
return this._anchorElement[attributeName];
},
set: function(value) {
this._anchorElement[attributeName] = value;
},
enumerable: true
});
};
['hash', 'host', 'hostname', 'port', 'protocol']
.forEach(function(attributeName) {
linkURLWithAnchorAttribute(attributeName);
});
Object.defineProperty(proto, 'search', {
get: function() {
return this._anchorElement['search'];
},
set: function(value) {
this._anchorElement['search'] = value;
this._updateSearchParams();
},
enumerable: true
});
Object.defineProperties(proto, {
'toString': {
get: function() {
var _this = this;
return function() {
return _this.href;
};
}
},
'href': {
get: function() {
return this._anchorElement.href.replace(/\?$/, '');
},
set: function(value) {
this._anchorElement.href = value;
this._updateSearchParams();
},
enumerable: true
},
'pathname': {
get: function() {
return this._anchorElement.pathname.replace(/(^\/?)/, '/');
},
set: function(value) {
this._anchorElement.pathname = value;
},
enumerable: true
},
'origin': {
get: function() {
// get expected port from protocol
var expectedPort = { 'http:': 80, 'https:': 443, 'ftp:': 21 }[this._anchorElement.protocol];
// add port to origin if, expected port is different than actual port
// and it is not empty f.e http://foo:8080
// 8080 != 80 && 8080 != ''
var addPortToOrigin = this._anchorElement.port != expectedPort &&
this._anchorElement.port !== '';
return this._anchorElement.protocol +
'//' +
this._anchorElement.hostname +
(addPortToOrigin ? (':' + this._anchorElement.port) : '');
},
enumerable: true
},
'password': { // TODO
get: function() {
return '';
},
set: function(value) {
},
enumerable: true
},
'username': { // TODO
get: function() {
return '';
},
set: function(value) {
},
enumerable: true
},
});
URL.createObjectURL = function(blob) {
return _URL.createObjectURL.apply(_URL, arguments);
};
URL.revokeObjectURL = function(url) {
return _URL.revokeObjectURL.apply(_URL, arguments);
};
global.URL = URL;
};
if (!checkIfURLIsSupported()) {
polyfillURL();
}
if ((global.location !== void 0) && !('origin' in global.location)) {
var getOrigin = function() {
return global.location.protocol + '//' + global.location.hostname + (global.location.port ? (':' + global.location.port) : '');
};
try {
Object.defineProperty(global.location, 'origin', {
get: getOrigin,
enumerable: true
});
} catch (e) {
setInterval(function() {
global.location.origin = getOrigin();
}, 100);
}
}
})(
(typeof global !== 'undefined') ? global
: ((typeof window !== 'undefined') ? window
: ((typeof self !== 'undefined') ? self : this))
);

File diff suppressed because one or more lines are too long