[Pkg-javascript-commits] [node-url-parse] 01/11: New upstream version 1.2.0
Praveen Arimbrathodiyil
praveen at moszumanska.debian.org
Tue Jan 2 17:20:53 UTC 2018
This is an automated email from the git hooks/post-receive script.
praveen pushed a commit to branch master
in repository node-url-parse.
commit 4fd547d7271e6f70433cd9101a756ce9ba1ab8a5
Author: Pirate Praveen <praveen at debian.org>
Date: Tue Jan 2 21:11:22 2018 +0530
New upstream version 1.2.0
---
.npmignore | 6 -
.travis.yml | 29 ----
.zuul.yml | 21 ---
README.md | 75 ++++++----
dist/url-parse.js | 367 +++++++++++++++++++++++++++++++++++++++++++++
dist/url-parse.min.js | 1 +
fuzzy.js | 124 ---------------
index.js | 306 +++++++++++++++++++++++++++++--------
lolcation.js | 45 ------
package.json | 36 +++--
test.js | 408 --------------------------------------------------
11 files changed, 683 insertions(+), 735 deletions(-)
diff --git a/.npmignore b/.npmignore
deleted file mode 100644
index 63c1316..0000000
--- a/.npmignore
+++ /dev/null
@@ -1,6 +0,0 @@
-node_modules
-coverage
-.tern-port
-browserified.js
-npm-debug.log
-dist
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index d958dcd..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-sudo: false
-language: node_js
-matrix:
- fast_finish: true
- include:
- - node_js: "0.10"
- env: TASK=test-node
- - node_js: "0.12"
- env: TASK=test-node
- - node_js: "iojs"
- env: TASK=test-node
- - node_js: "4"
- env: TASK=test-node
- - node_js: "4"
- env: TASK=test-browser
-env:
- global:
- - secure: edovUXd/s/VAVXTor0CT1XcGqAtBwGgLYN1zYq0JcNiJUgWFiZ5VGKYbKVpb6nKlwm0Fdi1xmByguSa6xLZllcXjtDgfXrkI1cQYmoVncJ63JpXNG+UKyy43BwnF2OqgUrAAOt/ic1YJr9kBe+IaRwDUsMxxIkuJ6Z8c4diX0HE=
- - secure: IF01oyIKSs0C5dARdYRTilKnU1TG4zenjjEPClkQxAWIpUOxl9xcNJWDVEOPxJ/4pVt+pozyT80Rp7efh6ZiREJIQI1tUboBKSqZzSbnD5uViQNSbQ90PaDP0FIUc0IQ5o07W36rijBB0DTmtU1VofzN9PKkJO7XiSSXevI8RcM=
-script:
- - "npm run ${TASK}"
-after_script:
- - 'if [ "${TASK}" == "test-node" ]; then npm i coveralls at 2 && cat coverage/lcov.info | coveralls; fi'
-notifications:
- irc:
- channels:
- - "irc.freenode.org#unshift"
- on_success: change
- on_failure: change
diff --git a/.zuul.yml b/.zuul.yml
deleted file mode 100644
index cdafdf9..0000000
--- a/.zuul.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-ui: mocha-bdd
-browsers:
- - name: android
- version: [oldest, latest]
- - name: chrome
- version: [oldest, latest]
- - name: firefox
- version: [oldest, latest]
- - name: ie
- version: oldest..latest
- - name: iphone
- version: [oldest, latest]
- - name: opera
- version: oldest..latest
- - name: safari
- version: oldest..latest
- - name: microsoftedge
- version: oldest..latest
-capabilities:
- record-screenshots: false
- record-video: false
diff --git a/README.md b/README.md
index b5fdd6d..d9dfd7a 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,6 @@
# url-parse
-[![Made by unshift](https://img.shields.io/badge/made%20by-unshift-00ffcc.svg?style=flat-square)](http://unshift.io)[![Version npm](https://img.shields.io/npm/v/url-parse.svg?style=flat-square)](http://browsenpm.org/package/url-parse)[![Build Status](https://img.shields.io/travis/unshiftio/url-parse/master.svg?style=flat-square)](https://travis-ci.org/unshiftio/url-parse)[![Dependencies](https://img.shields.io/david/unshiftio/url-parse.svg?style=flat-square)](https://david-dm.org/unshift [...]
+
+[![Made by unshift](https://img.shields.io/badge/made%20by-unshift-00ffcc.svg?style=flat-square)](http://unshift.io)[![Version npm](https://img.shields.io/npm/v/url-parse.svg?style=flat-square)](https://www.npmjs.com/package/url-parse)[![Build Status](https://img.shields.io/travis/unshiftio/url-parse/master.svg?style=flat-square)](https://travis-ci.org/unshiftio/url-parse)[![Dependencies](https://img.shields.io/david/unshiftio/url-parse.svg?style=flat-square)](https://david-dm.org/unshif [...]
[![Sauce Test Status](https://saucelabs.com/browser-matrix/url-parse.svg)](https://saucelabs.com/u/url-parse)
@@ -8,21 +9,22 @@ The `url-parse` method exposes two different API interfaces. The
and the new [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL)
interface that is available in the latest browsers.
-Since `0.1` we've moved away from using the DOM's `<a>` element for URL parsing
-and moving to a full Regular Expression solution. The main reason for this
-change is to make the URL parser available in different JavaScript environments
-as you don't always have access to the DOM like `Worker` environments. This
-module still have a really small foot print as this module's main intention is
-to be bundled with client-side code. The only problem however with a RegExp
-based solution is that it required a lot of lookups causing major problems in
-FireFox. So the last and the current solution was a pure string parsing
-solution which chops up the URL in smaller pieces.
+In version `0.1` we moved from a DOM based parsing solution, using the `<a>`
+element, to a full Regular Expression solution. The main reason for this was
+to make the URL parser available in different JavaScript environments as you
+don't always have access to the DOM. An example of such environment is the
+[`Worker`](https://developer.mozilla.org/en/docs/Web/API/Worker) interface.
+The RegExp based solution didn't work well as it required a lot of lookups
+causing major problems in FireFox. In version `1.0.0` we ditched the RegExp
+based solution in favor of a pure string parsing solution which chops up the
+URL into smaller pieces. This module still has a really small footprint as it
+has been designed to be used on the client side.
In addition to URL parsing we also expose the bundled `querystringify` module.
## Installation
-This module is designed to be used using either browserify or node.js it's
+This module is designed to be used using either browserify or Node.js it's
released in the public npm registry and can be installed using:
```
@@ -40,16 +42,28 @@ var URL = require('url-parse');
```
To parse an URL simply call the `URL` method with the URL that needs to be
-transformed in to an object.
+transformed into an object.
```js
var url = new URL('https://github.com/foo/bar');
```
The `new` keyword is optional but it will save you an extra function invocation.
-In the example above we've demonstrated the URL interface, but as said in the
-module description we also support the node.js interface. So you could also use
-the library in this way:
+The constructor takes the following arguments:
+
+- `url` (`String`): A string representing an absolute or relative URL.
+- `baseURL` (`Object` | `String`): An object or string representing
+ the base URL to use in case `url` is a relative URL. This argument is
+ optional and defaults to [`location`](https://developer.mozilla.org/en-US/docs/Web/API/Location)
+ in the browser.
+- `parser` (`Boolean` | `Function`): This argument is optional and specifies
+ how to parse the query string. By default it is `false` so the query string
+ is not parsed. If you pass `true` the query string is parsed using the
+ embedded `querystringify` module. If you pass a function the query string
+ will be parsed using this function.
+
+As said above we also support the Node.js interface so you can also use the
+library in this way:
```js
'use strict';
@@ -60,10 +74,12 @@ var parse = require('url-parse')
The returned `url` instance contains the following properties:
-- `protocol`: Requested protocol without slashes (e.g. `http:`).
+- `protocol`: The protocol scheme of the URL (e.g. `http:`).
+- `slashes`: A boolean which indicates whether the `protocol` is followed by two
+ forward slashes (`//`).
+- `auth`: Authentication information portion (e.g. `username:password`).
- `username`: Username of basic authentication.
- `password`: Password of basic authentication.
-- `auth`: Authentication information portion (e.g. `username:password`).
- `host`: Host name with port number.
- `hostname`: Host name without port number.
- `port`: Optional port number.
@@ -71,6 +87,18 @@ The returned `url` instance contains the following properties:
- `query`: Parsed object containing query string, unless parsing is set to false.
- `hash`: The "fragment" portion of the URL including the pound-sign (`#`).
- `href`: The full URL.
+- `origin`: The origin of the URL.
+
+Note that when `url-parse` is used in a browser environment, it will default to
+using the browser's current window location as the base URL when parsing all
+inputs. To parse an input independently of the browser's current URL (e.g. for
+functionality parity with the library in a Node environment), pass an empty
+location object as the second parameter:
+
+```js
+var parse = require('url-parse');
+parse('hostname', {});
+```
### URL.set(key, value)
@@ -108,14 +136,11 @@ will automatically update.
The testing of this module is done in 3 different ways:
-1. We have unit tests setup which run under Node.js using the normal `npm test`
- command.
-2. Code coverage can be run manually using `npm run coverage`
-3. For browser testing we use `testling` to startup a test server. We do assume
- that you `testling` installed globally, if not please run `npm install -g
- testling` and after that `testling -u` in the root of this repository. When
- you visit the outputted URL all unit tests that were written from the Node
- can now be ran inside browsers.
+1. We have unit tests that run under Node.js. You can run these tests with the
+ `npm test` command.
+2. Code coverage can be run manually using `npm run coverage`.
+3. For browser testing we use Sauce Labs and `zuul`. You can run browser tests
+ using the `npm run test-browser` command.
## License
diff --git a/dist/url-parse.js b/dist/url-parse.js
new file mode 100644
index 0000000..5cca0a4
--- /dev/null
+++ b/dist/url-parse.js
@@ -0,0 +1,367 @@
+!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.URLParse=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot f [...]
+'use strict';
+
+var required = require('requires-port')
+ , lolcation = require('./lolcation')
+ , qs = require('querystringify');
+
+var keys = ',,protocol,username,password,host,hostname,port,pathname,query,hash'.split(',')
+ , inherit = { protocol: 1, host: 1, hostname: 1 }
+ , parts = keys.length;
+
+//
+// Story time children:
+//
+// FireFox 34 has some problems with their Regular Expression engine and
+// executing a RegExp can cause a `too much recursion` error. We initially fixed
+// this by moving the Regular Expression in the URL constructor so it's created
+// every single time. This fixed it for some URL's but the more complex the
+// URL's get the easier it is to trigger. Complexer URL like:
+//
+// https://www.mozilla.org/en-US/firefox/34.0/whatsnew/?oldversion=33.1
+//
+// Still triggered the recursion error. After talking with Chrome and FireFox
+// engineers it seemed to be caused by:
+//
+// https://code.google.com/p/v8/issues/detail?id=430
+//
+// As FireFox started using Chrome's RegExp engine. After testing various of
+// workarounds I finally stumbled upon this gem, use new RegExp as it sometimes
+// behaves different then a RegExp literal.
+//
+// Steps for compiling the new RegExp:
+//
+// 1. Take the regular RegExp as seen below.
+// 2. Escape the RegExp using XRegExp.escape from http://xregexp.com/tests/
+// 3. ??
+// 4. Profit.
+//
+// RegExp source: /^(?:(?:(([^:\/#\?]+:)?(?:(?:\/\/)(?:(?:(?:([^:@\/#\?]+)(?:\:([^:@\/#\?]*))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((?:\/?(?:[^\/\?#]+\/+)*)(?:[^\?#]*)))?(\?[^#]+)?)(#.*)?/
+//
+var regexp = new RegExp('\^\(\?:\(\?:\(\(\[\^:\\/\#\\\?\]\+:\)\?\(\?:\(\?:\\/\\/\)\(\?:\(\?:\(\?:\(\[\^:@\\/\#\\\?\]\+\)\(\?:\\:\(\[\^:@\\/\#\\\?\]\*\)\)\?\)@\)\?\(\(\[\^:\\/\#\\\?\\\]\\\[\]\+\|\\\[\[\^\\/\\\]@\#\?\]\+\\\]\)\(\?:\\:\(\[0\-9\]\+\)\)\?\)\)\?\)\?\)\?\(\(\?:\\/\?\(\?:\[\^\\/\\\?\#\]\+\\/\+\)\*\)\(\?:\[\^\\\?\#\]\*\)\)\)\?\(\\\?\[\^\#\]\+\)\?\)\(\#\.\*\)\?');
+
+function parse(url) {
+ try { return regexp.exec(url); }
+ catch (e) { return url.match(regexp); }
+}
+
+/**
+ * The actual URL instance. Instead of returning an object we've opted-in to
+ * create an actual constructor as it's much more memory efficient and
+ * faster and it pleases my CDO.
+ *
+ * @constructor
+ * @param {String} address URL we want to parse.
+ * @param {Boolean|function} parser Parser for the query string.
+ * @param {Object} location Location defaults for relative paths.
+ * @api public
+ */
+function URL(address, location, parser) {
+ if (!(this instanceof URL)) {
+ return new URL(address, location, parser);
+ }
+
+ var type = typeof location
+ , bits = parse(address)
+ , url = this
+ , i = 0
+ , key;
+
+ //
+ // The following if statements allows this module two have compatibility with
+ // 2 different API:
+ //
+ // 1. Node.js's `url.parse` api which accepts a URL, boolean as arguments
+ // where the boolean indicates that the query string should also be parsed.
+ //
+ // 2. The `URL` interface of the browser which accepts a URL, object as
+ // arguments. The supplied object will be used as default values / fall-back
+ // for relative paths.
+ //
+ if ('object' !== type && 'string' !== type) {
+ parser = location;
+ location = null;
+ }
+
+ if (parser && 'function' !== typeof parser) {
+ parser = qs.parse;
+ }
+
+ location = lolcation(location);
+
+ for (; i < parts; key = keys[++i]) {
+ if (!key) continue;
+
+ url[key] = bits[i] || (key in inherit ? location[key] || '' : '');
+
+ //
+ // The protocol, host, host name should always be lower cased even if they
+ // are supplied in uppercase. This way, when people generate an `origin`
+ // it be correct.
+ //
+ if (i === 2 || i === 5 || i === 6) url[key] = url[key].toLowerCase();
+ }
+
+ //
+ // Also parse the supplied query string in to an object. If we're supplied
+ // with a custom parser as function use that instead of the default build-in
+ // parser.
+ //
+ if (parser) url.query = parser(url.query);
+
+ //
+ // We should not add port numbers if they are already the default port number
+ // for a given protocol. As the host also contains the port number we're going
+ // override it with the hostname which contains no port number.
+ //
+ if (!required(url.port, url.protocol)) {
+ url.host = url.hostname;
+ url.port = '';
+ }
+
+ //
+ // The href is just the compiled result.
+ //
+ url.href = url.toString();
+}
+
+/**
+ * This is convenience method for changing properties in the URL instance to
+ * insure that they all propagate correctly.
+ *
+ * @param {String} prop Property we need to adjust.
+ * @param {Mixed} value The newly assigned value.
+ * @returns {URL}
+ * @api public
+ */
+URL.prototype.set = function set(part, value, fn) {
+ var url = this;
+
+ if ('query' === part) {
+ if ('string' === typeof value) value = (fn || qs.parse)(value);
+ url[part] = value;
+ } else if ('port' === part) {
+ url[part] = value;
+
+ if (!required(value, url.protocol)) {
+ url.host = url.hostname;
+ url[part] = '';
+ } else if (value) {
+ url.host = url.hostname +':'+ value;
+ }
+ } else if ('hostname' === part) {
+ url[part] = value;
+
+ if (url.port) value += ':'+ url.port;
+ url.host = value;
+ } else if ('host' === part) {
+ url[part] = value;
+
+ if (/\:\d+/.test(value)) {
+ value = value.split(':');
+ url.hostname = value[0];
+ url.port = value[1];
+ }
+ } else {
+ url[part] = value;
+ }
+
+ url.href = url.toString();
+ return url;
+};
+
+/**
+ * Transform the properties back in to a valid and full URL string.
+ *
+ * @param {Function} stringify Optional query stringify function.
+ * @returns {String}
+ * @api public
+ */
+URL.prototype.toString = function toString(stringify) {
+ if (!stringify || 'function' !== typeof stringify) stringify = qs.stringify;
+
+ var query
+ , url = this
+ , result = url.protocol +'//';
+
+ if (url.username) result += url.username +':'+ url.password +'@';
+
+ result += url.hostname;
+ if (url.port) result += ':'+ url.port;
+
+ result += url.pathname;
+
+ if (url.query) {
+ if ('object' === typeof url.query) query = stringify(url.query);
+ else query = url.query;
+
+ result += (query.charAt(0) === '?' ? '' : '?') + query;
+ }
+
+ if (url.hash) result += url.hash;
+
+ return result;
+};
+
+//
+// Expose the URL parser and some additional properties that might be useful for
+// others.
+//
+URL.qs = qs;
+URL.location = lolcation;
+module.exports = URL;
+
+},{"./lolcation":2,"querystringify":3,"requires-port":4}],2:[function(require,module,exports){
+(function (global){
+'use strict';
+
+/**
+ * These properties should not be copied or inherited from. This is only needed
+ * for all non blob URL's as the a blob URL does not include a hash, only the
+ * origin.
+ *
+ * @type {Object}
+ * @private
+ */
+var ignore = { hash: 1, query: 1 }
+ , URL;
+
+/**
+ * The location object differs when your code is loaded through a normal page,
+ * Worker or through a worker using a blob. And with the blobble begins the
+ * trouble as the location object will contain the URL of the blob, not the
+ * location of the page where our code is loaded in. The actual origin is
+ * encoded in the `pathname` so we can thankfully generate a good "default"
+ * location from it so we can generate proper relative URL's again.
+ *
+ * @param {Object} loc Optional default location object.
+ * @returns {Object} lolcation object.
+ * @api public
+ */
+module.exports = function lolcation(loc) {
+ loc = loc || global.location || {};
+ URL = URL || require('./');
+
+ var finaldestination = {}
+ , type = typeof loc
+ , key;
+
+ if ('blob:' === loc.protocol) {
+ finaldestination = new URL(unescape(loc.pathname), {});
+ } else if ('string' === type) {
+ finaldestination = new URL(loc, {});
+ for (key in ignore) delete finaldestination[key];
+ } else if ('object' === type) for (key in loc) {
+ if (key in ignore) continue;
+ finaldestination[key] = loc[key];
+ }
+
+ return finaldestination;
+};
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{"./":1}],3:[function(require,module,exports){
+'use strict';
+
+var has = Object.prototype.hasOwnProperty;
+
+/**
+ * Simple query string parser.
+ *
+ * @param {String} query The query string that needs to be parsed.
+ * @returns {Object}
+ * @api public
+ */
+function querystring(query) {
+ var parser = /([^=?&]+)=([^&]*)/g
+ , result = {}
+ , part;
+
+ //
+ // Little nifty parsing hack, leverage the fact that RegExp.exec increments
+ // the lastIndex property so we can continue executing this loop until we've
+ // parsed all results.
+ //
+ for (;
+ part = parser.exec(query);
+ result[decodeURIComponent(part[1])] = decodeURIComponent(part[2])
+ );
+
+ return result;
+}
+
+/**
+ * Transform a query string to an object.
+ *
+ * @param {Object} obj Object that should be transformed.
+ * @param {String} prefix Optional prefix.
+ * @returns {String}
+ * @api public
+ */
+function querystringify(obj, prefix) {
+ prefix = prefix || '';
+
+ var pairs = [];
+
+ //
+ // Optionally prefix with a '?' if needed
+ //
+ if ('string' !== typeof prefix) prefix = '?';
+
+ for (var key in obj) {
+ if (has.call(obj, key)) {
+ pairs.push(encodeURIComponent(key) +'='+ encodeURIComponent(obj[key]));
+ }
+ }
+
+ return prefix + pairs.join('&');
+}
+
+//
+// Expose the module.
+//
+exports.stringify = querystringify;
+exports.parse = querystring;
+
+},{}],4:[function(require,module,exports){
+'use strict';
+
+/**
+ * Check if we're required to add a port number.
+ *
+ * @see https://url.spec.whatwg.org/#default-port
+ * @param {Number|String} port Port number we need to check
+ * @param {String} protocol Protocol we need to check against.
+ * @returns {Boolean} Is it a default port for the given protocol
+ * @api private
+ */
+module.exports = function required(port, protocol) {
+ protocol = protocol.split(':')[0];
+ port = +port;
+
+ if (!port) return false;
+
+ switch (protocol) {
+ case 'http':
+ case 'ws':
+ return port !== 80;
+
+ case 'https':
+ case 'wss':
+ return port !== 443;
+
+ case 'ftp':
+ return port !== 22;
+
+ case 'gopher':
+ return port !== 70;
+
+ case 'file':
+ return false;
+ }
+
+ return port !== 0;
+};
+
+},{}]},{},[1])(1)
+});
\ No newline at end of file
diff --git a/dist/url-parse.min.js b/dist/url-parse.min.js
new file mode 100644
index 0000000..f471b12
--- /dev/null
+++ b/dist/url-parse.min.js
@@ -0,0 +1 @@
+!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).URLParse=e()}}(function(){return function e(t,o,r){function n(a,i){if(!o[a]){if(!t[a]){var p="function"==typeof require&&require;if(!i&&p)return p(a,!0);if(s)return s(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MO [...]
\ No newline at end of file
diff --git a/fuzzy.js b/fuzzy.js
deleted file mode 100644
index c0abe3c..0000000
--- a/fuzzy.js
+++ /dev/null
@@ -1,124 +0,0 @@
-'use strict';
-
-var URL = require('./')
- , url = new URL('');
-
-/**
- * A dictionary with all kind of different options that should generate a valid
- * and parse-able URL.
- *
- * @type {Object}
- * @api private
- */
-var combinations = {};
-
-combinations.protocol = [
- 'http:',
- 'https:',
- 'ws:',
- 'wss:',
- 'blob:'/*,
- ''*/
-];
-combinations.username = ['foo', 'bar'];
-combinations.password = combinations.username;
-combinations.hostname = [
- 'example.com',
- 'www.example.com',
- 'travel.travel',
- 'sub.sub.sub.domain.nl',
- 'xn--n3h.com',
- 'localhost',
- '127.0.0.1',
- '255.255.255.255'/*,
- '3ffe:6a88:85a3:08d3:1319:8a2e:0370:7344',
- '2001:2353::1428:57ab',
- '2001:2353:0::0:1428:57ab',
- '2001:2353:0:0:0:0:1428:57ab',
- '2001:2353:0000:0000:0000::1428:57ab',
- '2001:2353:0000:0000:0000:0000:1428:57ab',
- '2001:2353:02de::0e13',
- '2001:2353:2de::e13'*/
-];
-combinations.port = ['8080', '844', '3340'];
-combinations.pathname = [
- '/',
- '/bar',
- '/bar/',
- '/foo/bar',
- '/foo.bar/foo',
- '/fav.ico',
- '/@3rd-Eden',
- '/a/b/c/d/e/f/g/j/1/d/4/'
-];
-combinations.query = ['foo=bar',
- 'foo[]=bar&foo[]=foo',
- 'email=foo at bar.travel',
- 'q='
-];
-combinations.hash = [
- 'name',
- 'moo-with-longer-name',
- '/what/about/slashes?querystring',
- '?querystring',
- '!/google/urls',
- 'use:foo@',
- 'http://'
-];
-
-/**
- * Get a random item from the given array.
- *
- * @param {String} name Name of the array we want to have a random item returned.
- * @returns {Mixed}
- * @api private
- */
-function get(name) {
- var data = combinations[name];
-
- return data[Math.floor(Math.random() * data.length)];
-}
-
-/**
- * Return a random boolean.
- *
- * @returns {Boolean}
- * @api private
- */
-function yep() {
- return !!Math.round(Math.random() * 1);
-}
-
-/**
- * Generate the actual URL.
- *
- * @returns {Object} specification
- * @api public
- */
-module.exports = function generate() {
- var spec = {}
- , key;
-
- spec.protocol = get('protocol');
- spec.hostname = get('hostname');
- spec.pathname = get('pathname');
-
- if (yep()) spec.port = get('port');
- if (yep()) spec.query = '?'+ get('query');
- if (yep()) spec.hash = '#'+ get('hash');
- if (yep()) {
- spec.username = get('username');
- spec.password = get('password');
- }
-
- for (key in combinations) {
- url[key] = '';
- }
-
- for (key in spec) {
- url[key] = spec[key];
- }
-
- spec.href = url.toString();
- return spec;
-};
diff --git a/index.js b/index.js
index b7c822d..cb0f6e7 100644
--- a/index.js
+++ b/index.js
@@ -1,12 +1,12 @@
'use strict';
var required = require('requires-port')
- , lolcation = require('./lolcation')
, qs = require('querystringify')
- , relativere = /^\/(?!\/)/;
+ , protocolre = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\S\s]*)/i
+ , slashes = /^[A-Za-z][A-Za-z0-9+-.]*:\/\//;
/**
- * These are the parse instructions for the URL parsers, it informs the parser
+ * These are the parse rules for the URL parser, it informs the parser
* about:
*
* 0. The char it Needs to parse, if it's a string it should be done using
@@ -17,26 +17,132 @@ var required = require('requires-port')
* 3. Inherit from location if non existing in the parser.
* 4. `toLowerCase` the resulting value.
*/
-var instructions = [
+var rules = [
['#', 'hash'], // Extract from the back.
['?', 'query'], // Extract from the back.
- ['//', 'protocol', 2, 1, 1], // Extract from the front.
['/', 'pathname'], // Extract from the back.
['@', 'auth', 1], // Extract from the front.
[NaN, 'host', undefined, 1, 1], // Set left over value.
- [/\:(\d+)$/, 'port'], // RegExp the back.
+ [/:(\d+)$/, 'port', undefined, 1], // RegExp the back.
[NaN, 'hostname', undefined, 1, 1] // Set left over.
];
/**
+ * These properties should not be copied or inherited from. This is only needed
+ * for all non blob URL's as a blob URL does not include a hash, only the
+ * origin.
+ *
+ * @type {Object}
+ * @private
+ */
+var ignore = { hash: 1, query: 1 };
+
+/**
+ * The location object differs when your code is loaded through a normal page,
+ * Worker or through a worker using a blob. And with the blobble begins the
+ * trouble as the location object will contain the URL of the blob, not the
+ * location of the page where our code is loaded in. The actual origin is
+ * encoded in the `pathname` so we can thankfully generate a good "default"
+ * location from it so we can generate proper relative URL's again.
+ *
+ * @param {Object|String} loc Optional default location object.
+ * @returns {Object} lolcation object.
+ * @api public
+ */
+function lolcation(loc) {
+ loc = loc || global.location || {};
+
+ var finaldestination = {}
+ , type = typeof loc
+ , key;
+
+ if ('blob:' === loc.protocol) {
+ finaldestination = new URL(unescape(loc.pathname), {});
+ } else if ('string' === type) {
+ finaldestination = new URL(loc, {});
+ for (key in ignore) delete finaldestination[key];
+ } else if ('object' === type) {
+ for (key in loc) {
+ if (key in ignore) continue;
+ finaldestination[key] = loc[key];
+ }
+
+ if (finaldestination.slashes === undefined) {
+ finaldestination.slashes = slashes.test(loc.href);
+ }
+ }
+
+ return finaldestination;
+}
+
+/**
+ * @typedef ProtocolExtract
+ * @type Object
+ * @property {String} protocol Protocol matched in the URL, in lowercase.
+ * @property {Boolean} slashes `true` if protocol is followed by "//", else `false`.
+ * @property {String} rest Rest of the URL that is not part of the protocol.
+ */
+
+/**
+ * Extract protocol information from a URL with/without double slash ("//").
+ *
+ * @param {String} address URL we want to extract from.
+ * @return {ProtocolExtract} Extracted information.
+ * @api private
+ */
+function extractProtocol(address) {
+ var match = protocolre.exec(address);
+
+ return {
+ protocol: match[1] ? match[1].toLowerCase() : '',
+ slashes: !!match[2],
+ rest: match[3]
+ };
+}
+
+/**
+ * Resolve a relative URL pathname against a base URL pathname.
+ *
+ * @param {String} relative Pathname of the relative URL.
+ * @param {String} base Pathname of the base URL.
+ * @return {String} Resolved pathname.
+ * @api private
+ */
+function resolve(relative, base) {
+ var path = (base || '/').split('/').slice(0, -1).concat(relative.split('/'))
+ , i = path.length
+ , last = path[i - 1]
+ , unshift = false
+ , up = 0;
+
+ while (i--) {
+ if (path[i] === '.') {
+ path.splice(i, 1);
+ } else if (path[i] === '..') {
+ path.splice(i, 1);
+ up++;
+ } else if (up) {
+ if (i === 0) unshift = true;
+ path.splice(i, 1);
+ up--;
+ }
+ }
+
+ if (unshift) path.unshift('');
+ if (last === '.' || last === '..') path.push('');
+
+ return path.join('/');
+}
+
+/**
* The actual URL instance. Instead of returning an object we've opted-in to
* create an actual constructor as it's much more memory efficient and
- * faster and it pleases my CDO.
+ * faster and it pleases my OCD.
*
* @constructor
* @param {String} address URL we want to parse.
- * @param {Boolean|function} parser Parser for the query string.
- * @param {Object} location Location defaults for relative paths.
+ * @param {Object|String} location Location defaults for relative paths.
+ * @param {Boolean|Function} parser Parser for the query string.
* @api public
*/
function URL(address, location, parser) {
@@ -44,8 +150,8 @@ function URL(address, location, parser) {
return new URL(address, location, parser);
}
- var relative = relativere.test(address)
- , parse, instruction, index, key
+ var relative, extracted, parse, instruction, index, key
+ , instructions = rules.slice()
, type = typeof location
, url = this
, i = 0;
@@ -66,12 +172,25 @@ function URL(address, location, parser) {
location = null;
}
- if (parser && 'function' !== typeof parser) {
- parser = qs.parse;
- }
+ if (parser && 'function' !== typeof parser) parser = qs.parse;
location = lolcation(location);
+ //
+ // Extract protocol information before running the instructions.
+ //
+ extracted = extractProtocol(address || '');
+ relative = !extracted.protocol && !extracted.slashes;
+ url.slashes = extracted.slashes || relative && location.slashes;
+ url.protocol = extracted.protocol || location.protocol || '';
+ address = extracted.rest;
+
+ //
+ // When the authority component is absent the URL starts with a path
+ // component.
+ //
+ if (!extracted.slashes) instructions[2] = [/(.*)/, 'pathname'];
+
for (; i < instructions.length; i++) {
instruction = instructions[i];
parse = instruction[0];
@@ -89,20 +208,20 @@ function URL(address, location, parser) {
address = address.slice(0, index);
}
}
- } else if (index = parse.exec(address)) {
+ } else if ((index = parse.exec(address))) {
url[key] = index[1];
- address = address.slice(0, address.length - index[0].length);
+ address = address.slice(0, index.index);
}
- url[key] = url[key] || (instruction[3] || ('port' === key && relative) ? location[key] || '' : '');
+ url[key] = url[key] || (
+ relative && instruction[3] ? location[key] || '' : ''
+ );
//
// Hostname, host and protocol should be lowercased so they can be used to
// create a proper `origin`.
//
- if (instruction[4]) {
- url[key] = url[key].toLowerCase();
- }
+ if (instruction[4]) url[key] = url[key].toLowerCase();
}
//
@@ -113,6 +232,18 @@ function URL(address, location, parser) {
if (parser) url.query = parser(url.query);
//
+ // If the URL is relative, resolve the pathname against the base URL.
+ //
+ if (
+ relative
+ && location.slashes
+ && url.pathname.charAt(0) !== '/'
+ && (url.pathname !== '' || location.pathname !== '')
+ ) {
+ url.pathname = resolve(url.pathname, location.pathname);
+ }
+
+ //
// We should not add port numbers if they are already the default port number
// for a given protocol. As the host also contains the port number we're going
// override it with the hostname which contains no port number.
@@ -132,6 +263,10 @@ function URL(address, location, parser) {
url.password = instruction[1] || '';
}
+ url.origin = url.protocol && url.host && url.protocol !== 'file:'
+ ? url.protocol +'//'+ url.host
+ : 'null';
+
//
// The href is just the compiled result.
//
@@ -142,49 +277,93 @@ function URL(address, location, parser) {
* This is convenience method for changing properties in the URL instance to
* insure that they all propagate correctly.
*
- * @param {String} prop Property we need to adjust.
- * @param {Mixed} value The newly assigned value.
+ * @param {String} part Property we need to adjust.
+ * @param {Mixed} value The newly assigned value.
+ * @param {Boolean|Function} fn When setting the query, it will be the function
+ * used to parse the query.
+ * When setting the protocol, double slash will be
+ * removed from the final url if it is true.
* @returns {URL}
* @api public
*/
-URL.prototype.set = function set(part, value, fn) {
+function set(part, value, fn) {
var url = this;
- if ('query' === part) {
- if ('string' === typeof value && value.length) {
- value = (fn || qs.parse)(value);
- }
+ switch (part) {
+ case 'query':
+ if ('string' === typeof value && value.length) {
+ value = (fn || qs.parse)(value);
+ }
- url[part] = value;
- } else if ('port' === part) {
- url[part] = value;
+ url[part] = value;
+ break;
- if (!required(value, url.protocol)) {
- url.host = url.hostname;
- url[part] = '';
- } else if (value) {
- url.host = url.hostname +':'+ value;
- }
- } else if ('hostname' === part) {
- url[part] = value;
-
- if (url.port) value += ':'+ url.port;
- url.host = value;
- } else if ('host' === part) {
- url[part] = value;
-
- if (/\:\d+/.test(value)) {
- value = value.split(':');
- url.hostname = value[0];
- url.port = value[1];
- }
- } else {
- url[part] = value;
+ case 'port':
+ url[part] = value;
+
+ if (!required(value, url.protocol)) {
+ url.host = url.hostname;
+ url[part] = '';
+ } else if (value) {
+ url.host = url.hostname +':'+ value;
+ }
+
+ break;
+
+ case 'hostname':
+ url[part] = value;
+
+ if (url.port) value += ':'+ url.port;
+ url.host = value;
+ break;
+
+ case 'host':
+ url[part] = value;
+
+ if (/:\d+$/.test(value)) {
+ value = value.split(':');
+ url.port = value.pop();
+ url.hostname = value.join(':');
+ } else {
+ url.hostname = value;
+ url.port = '';
+ }
+
+ break;
+
+ case 'protocol':
+ url.protocol = value.toLowerCase();
+ url.slashes = !fn;
+ break;
+
+ case 'pathname':
+ case 'hash':
+ if (value) {
+ var char = part === 'pathname' ? '/' : '#';
+ url[part] = value.charAt(0) !== char ? char + value : value;
+ } else {
+ url[part] = value;
+ }
+ break;
+
+ default:
+ url[part] = value;
}
+ for (var i = 0; i < rules.length; i++) {
+ var ins = rules[i];
+
+ if (ins[4]) url[ins[1]] = url[ins[1]].toLowerCase();
+ }
+
+ url.origin = url.protocol && url.host && url.protocol !== 'file:'
+ ? url.protocol +'//'+ url.host
+ : 'null';
+
url.href = url.toString();
+
return url;
-};
+}
/**
* Transform the properties back in to a valid and full URL string.
@@ -193,12 +372,16 @@ URL.prototype.set = function set(part, value, fn) {
* @returns {String}
* @api public
*/
-URL.prototype.toString = function toString(stringify) {
+function toString(stringify) {
if (!stringify || 'function' !== typeof stringify) stringify = qs.stringify;
var query
, url = this
- , result = url.protocol +'//';
+ , protocol = url.protocol;
+
+ if (protocol && protocol.charAt(protocol.length - 1) !== ':') protocol += ':';
+
+ var result = protocol + (url.slashes ? '//' : '');
if (url.username) {
result += url.username;
@@ -206,10 +389,7 @@ URL.prototype.toString = function toString(stringify) {
result += '@';
}
- result += url.hostname;
- if (url.port) result += ':'+ url.port;
-
- result += url.pathname;
+ result += url.host + url.pathname;
query = 'object' === typeof url.query ? stringify(url.query) : url.query;
if (query) result += '?' !== query.charAt(0) ? '?'+ query : query;
@@ -217,12 +397,16 @@ URL.prototype.toString = function toString(stringify) {
if (url.hash) result += url.hash;
return result;
-};
+}
+
+URL.prototype = { set: set, toString: toString };
//
// Expose the URL parser and some additional properties that might be useful for
-// others.
+// others or testing.
//
-URL.qs = qs;
+URL.extractProtocol = extractProtocol;
URL.location = lolcation;
+URL.qs = qs;
+
module.exports = URL;
diff --git a/lolcation.js b/lolcation.js
deleted file mode 100644
index d251856..0000000
--- a/lolcation.js
+++ /dev/null
@@ -1,45 +0,0 @@
-'use strict';
-
-/**
- * These properties should not be copied or inherited from. This is only needed
- * for all non blob URL's as the a blob URL does not include a hash, only the
- * origin.
- *
- * @type {Object}
- * @private
- */
-var ignore = { hash: 1, query: 1 }
- , URL;
-
-/**
- * The location object differs when your code is loaded through a normal page,
- * Worker or through a worker using a blob. And with the blobble begins the
- * trouble as the location object will contain the URL of the blob, not the
- * location of the page where our code is loaded in. The actual origin is
- * encoded in the `pathname` so we can thankfully generate a good "default"
- * location from it so we can generate proper relative URL's again.
- *
- * @param {Object} loc Optional default location object.
- * @returns {Object} lolcation object.
- * @api public
- */
-module.exports = function lolcation(loc) {
- loc = loc || global.location || {};
- URL = URL || require('./');
-
- var finaldestination = {}
- , type = typeof loc
- , key;
-
- if ('blob:' === loc.protocol) {
- finaldestination = new URL(unescape(loc.pathname), {});
- } else if ('string' === type) {
- finaldestination = new URL(loc, {});
- for (key in ignore) delete finaldestination[key];
- } else if ('object' === type) for (key in loc) {
- if (key in ignore) continue;
- finaldestination[key] = loc[key];
- }
-
- return finaldestination;
-};
diff --git a/package.json b/package.json
index 718b31e..0f2dd24 100644
--- a/package.json
+++ b/package.json
@@ -1,17 +1,19 @@
{
"name": "url-parse",
- "version": "1.0.5",
+ "version": "1.2.0",
"description": "Small footprint URL parser that works seamlessly across Node.js and browser environments",
"main": "index.js",
"scripts": {
- "100%": "istanbul check-coverage --statements 100 --functions 100 --lines 100 --branches 100",
- "browserify": "mkdir -p dist && browserify index.js -s URLParse -o dist/url-parse.js",
- "test-node": "istanbul cover _mocha --report lcovonly -- test.js",
- "coverage": "istanbul cover _mocha -- test.js",
- "test-browser": "zuul -- test.js",
- "watch": "mocha --watch test.js",
- "test": "mocha test.js"
+ "browserify": "mkdir -p dist && browserify index.js -s URLParse | uglifyjs -cm -o dist/url-parse.min.js",
+ "test": "nyc --reporter=html --reporter=text mocha test/test.js",
+ "test-browser": "node test/browser.js",
+ "prepublishOnly": "npm run browserify",
+ "watch": "mocha --watch test/test.js"
},
+ "files": [
+ "index.js",
+ "dist"
+ ],
"repository": {
"type": "git",
"url": "https://github.com/unshiftio/url-parse.git"
@@ -30,15 +32,17 @@
"author": "Arnout Kazemier",
"license": "MIT",
"dependencies": {
- "querystringify": "0.0.x",
- "requires-port": "1.0.x"
+ "querystringify": "~1.0.0",
+ "requires-port": "~1.0.0"
},
"devDependencies": {
- "assume": "1.3.x",
- "browserify": "12.0.x",
- "istanbul": "0.4.x",
- "mocha": "2.3.x",
- "pre-commit": "1.1.x",
- "zuul": "3.7.x"
+ "assume": "~1.5.0",
+ "browserify": "~14.5.0",
+ "mocha": "~4.0.0",
+ "nyc": "~11.3.0",
+ "pre-commit": "~1.2.0",
+ "sauce-browsers": "~1.0.0",
+ "sauce-test": "~1.3.3",
+ "uglify-js": "~3.1.0"
}
}
diff --git a/test.js b/test.js
deleted file mode 100644
index 9770025..0000000
--- a/test.js
+++ /dev/null
@@ -1,408 +0,0 @@
-describe('url-parse', function () {
- 'use strict';
-
- var assume = require('assume')
- , parse = require('./');
-
- it('exposes parse as a function', function () {
- assume(parse).is.a('function');
- });
-
- it('exposes the querystring module', function () {
- assume(parse.qs).equals(require('querystringify'));
- });
-
- it('exposes the location function', function () {
- assume(parse.location).equals(require('./lolcation'));
- });
-
- it('parses the query string into an object', function () {
- var url = 'http://google.com/?foo=bar'
- , data = parse(url, true);
-
- assume(data.query).is.a('object');
- assume(data.query.foo).equals('bar');
-
- url = 'http://google.com/';
- data = parse(url, true);
-
- assume(data.query).is.a('object');
- assume(data.query).is.empty();
- });
-
- it('does not add question mark to href if query string is empty', function () {
- var url = 'http://google.com/'
- , data = parse(url, true);
-
- assume(data.href).equals(url);
- });
-
- it('allows a custom function as parser', function () {
- var url = 'http://google.com/?foo=bar'
- , data = parse(url, function () { return '1337'; });
-
- assume(data.query).equals('1337');
- });
-
- it('allows a custom stringify function', function () {
- var url = 'http://google.com/?foo=bar'
- , data = parse(url, true)
- , str;
-
- str = data.toString(function () { return 'lolcakes'; });
- assume(str).equals('http://google.com/?lolcakes');
- });
-
- it('allows a custom location object', function () {
- var url = '/foo?foo=bar'
- , data = parse(url, parse('http://google.com'));
-
- assume(data.href).equals('http://google.com/foo?foo=bar');
- });
-
- it('is blob: location aware', function () {
- var blob = {
- 'href': 'blob:https%3A//gist.github.com/3f272586-6dac-4e29-92d0-f674f2dde618',
- 'pathname': 'https%3A//gist.github.com/3f272586-6dac-4e29-92d0-f674f2dde618',
- 'origin': 'https://gist.github.com',
- 'protocol': 'blob:',
- 'hostname': '',
- 'search': '',
- 'hash': '',
- 'host': '',
- 'port': ''
- };
-
- var url = '/unshiftio/url-parse'
- , data = parse(url, blob);
-
- assume(data.href).equals('https://gist.github.com/unshiftio/url-parse');
- });
-
- it('converts protocol to lowercase', function () {
- var url = 'HTTP://example.com';
-
- assume(parse(url).protocol).equals('http:');
- });
-
- it('can parse complex urls multiple times without errors', function () {
- var url = 'https://www.mozilla.org/en-US/firefox/34.0/whatsnew/?oldversion=33.1';
-
- for (var i = 0; i < 100; i++) {
- parse(url);
- }
- });
-
- it('converts hostname to lowercase', function () {
- var url = 'HTTP://fOo.eXaMPle.com';
-
- assume(parse(url).hostname).equals('foo.example.com');
- });
-
- it('does not lowercase the path', function () {
- var url = 'HTTP://X.COM/Y/Z';
-
- assume(parse(url).pathname).equals('/Y/Z');
- });
-
- it('removes default port numbers', function () {
- var url = 'http://example.com:80'
- , parsed = parse(url);
-
- assume(parsed.port).equals('');
- assume(parsed.host).equals('example.com');
- assume(parsed.hostname).equals('example.com');
- assume(parsed.href).equals('http://example.com');
- });
-
- it('understands an / as pathname', function () {
- var url = 'http://example.com:80/'
- , parsed = parse(url);
-
- assume(parsed.port).equals('');
- assume(parsed.username).equals('');
- assume(parsed.password).equals('');
- assume(parsed.pathname).equals('/');
- assume(parsed.host).equals('example.com');
- assume(parsed.hostname).equals('example.com');
- assume(parsed.href).equals('http://example.com/');
- });
-
- it('does not care about spaces', function () {
- var url = 'http://x.com/path?that\'s#all, folks'
- , parsed = parse(url);
-
- assume(parsed.port).equals('');
- assume(parsed.username).equals('');
- assume(parsed.password).equals('');
- assume(parsed.pathname).equals('/path');
- assume(parsed.hash).equal('#all, folks');
- assume(parsed.query).equal('?that\'s');
- assume(parsed.host).equals('x.com');
- assume(parsed.hostname).equals('x.com');
- });
-
- it('accepts + in the url', function () {
- var url = 'http://x.y.com+a/b/c'
- , parsed = parse(url);
-
- assume(parsed.protocol).equals('http:');
- assume(parsed.host).equals('x.y.com+a');
- assume(parsed.hostname).equals('x.y.com+a');
- assume(parsed.pathname).equals('/b/c');
- });
-
- describe('ip', function () {
- // coap://
- //
- it('parses ipv6', function () {
- var url = 'http://[1080:0:0:0:8:800:200C:417A]:61616/foo/bar?q=z'
- , parsed = parse(url);
-
- assume(parsed.port).equals('61616');
- assume(parsed.query).equals('?q=z');
- assume(parsed.protocol).equals('http:');
- assume(parsed.hostname).equals('[1080:0:0:0:8:800:200c:417a]');
- assume(parsed.pathname).equals('/foo/bar');
- assume(parsed.href).equals('http://[1080:0:0:0:8:800:200c:417a]:61616/foo/bar?q=z');
- });
-
- it('parses ipv6 with auth', function () {
- var url = 'http://user:password@[3ffe:2a00:100:7031::1]:8080'
- , parsed = parse(url);
-
- assume(parsed.username).equals('user');
- assume(parsed.password).equals('password');
- assume(parsed.host).equals('[3ffe:2a00:100:7031::1]:8080');
- assume(parsed.hostname).equals('[3ffe:2a00:100:7031::1]');
- assume(parsed.href).equals(url);
- });
-
- it('parses ipv4', function () {
- var url = 'http://222.148.142.13:61616/foo/bar?q=z'
- , parsed = parse(url);
-
- assume(parsed.port).equals('61616');
- assume(parsed.query).equals('?q=z');
- assume(parsed.protocol).equals('http:');
- assume(parsed.hostname).equals('222.148.142.13');
- assume(parsed.pathname).equals('/foo/bar');
- assume(parsed.href).equals(url);
- });
- });
-
- describe('auth', function () {
- it('does not lowercase the USER:PASS', function () {
- var url = 'HTTP://USER:PASS@EXAMPLE.COM'
- , parsed = parse(url);
-
- assume(parsed.username).equals('USER');
- assume(parsed.password).equals('PASS');
- assume(parsed.protocol).equals('http:');
- assume(parsed.host).equals('example.com');
- assume(parsed.hostname).equals('example.com');
- });
-
- it('accepts @ in pathnames', function () {
- var url = 'http://mt0.google.com/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s='
- , parsed = parse(url);
-
- assume(parsed.pathname).equals('/vt/lyrs=m at 114&hl=en&src=api&x=2&y=2&z=3&s=');
- assume(parsed.username).equals('');
- assume(parsed.password).equals('');
- });
-
- it('does not require passwords for auth', function () {
- var url = 'http://user@www.example.com/'
- , parsed = parse(url);
-
- assume(parsed.password).equals('');
- assume(parsed.pathname).equals('/');
- assume(parsed.username).equals('user');
- assume(parsed.protocol).equals('http:');
- assume(parsed.hostname).equals('www.example.com');
- assume(parsed.href).equals(url);
- });
- });
-
- it('accepts multiple ???', function () {
- var url = 'http://mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s=';
- assume(parse(url).query).equals('???&hl=en&src=api&x=2&y=2&z=3&s=');
- });
-
- it('accepts a string as source argument', function () {
- var data = parse('/foo', 'http://sub.example.com/bar?foo=bar#hash');
-
- assume(data.port).equals('');
- assume(data.host).equals('sub.example.com');
- assume(data.href).equals('http://sub.example.com/foo');
- });
-
- describe('inheritance', function () {
- it('does not inherit port numbers for non relative urls', function () {
- var data = parse('http://localhost', parse('http://sub.example.com:808/'));
-
- assume(data.port).equals('');
- assume(data.host).equals('localhost');
- assume(data.href).equals('http://localhost');
- });
-
- it('does inherit port numbers from relative urls', function () {
- var data = parse('/foo', parse('http://sub.example.com:808/'));
-
- assume(data.port).equals('808');
- assume(data.hostname).equals('sub.example.com');
- assume(data.host).equals('sub.example.com:808');
- assume(data.href).equals('http://sub.example.com:808/foo');
- });
-
- it('inherits protocol for relative protocols', function () {
- var data = parse('//foo.com/foo', parse('http://sub.example.com:808/'));
-
- assume(data.port).equals('');
- assume(data.host).equals('foo.com');
- assume(data.protocol).equals('http:');
- assume(data.href).equals('http://foo.com/foo');
- });
-
- it('does not inherit pathnames from the source', function () {
- var data = parse('http://localhost', parse('http://foo:bar@sub.example.com/bar?foo=bar#hash'));
-
- assume(data.port).equals('');
- assume(data.host).equals('localhost');
- assume(data.href).equals('http://localhost');
- });
-
- it('does not inherit hashes and query strings from source object', function () {
- var data = parse('/foo', parse('http://sub.example.com/bar?foo=bar#hash'));
-
- assume(data.port).equals('');
- assume(data.host).equals('sub.example.com');
- assume(data.href).equals('http://sub.example.com/foo');
- });
-
- it('does not inherit auth from source object', function () {
- var from = parse('http://foo:bar@sub.example.com')
- , data = parse('/foo', from);
-
- assume(data.port).equals('');
- assume(data.username).equals('');
- assume(data.password).equals('');
- assume(data.host).equals('sub.example.com');
- assume(data.href).equals('http://sub.example.com/foo');
- });
- });
-
- describe('#set', function () {
- it('correctly updates the host when setting port', function () {
- var data = parse('http://google.com/foo');
-
- assume(data.set('port', 8080)).equals(data);
-
- assume(data.host).equals('google.com:8080');
- assume(data.href).equals('http://google.com:8080/foo');
- });
-
- it('removes querystring and hash', function () {
- var data = parse('https://thisanurl.com/?swag=yolo#representing');
-
- data.set('query', '');
- data.set('hash', '');
-
- assume(data.href).equals('https://thisanurl.com/');
- });
-
- it('only sets port when its not default', function () {
- var data = parse('http://google.com/foo');
-
- assume(data.set('port', 80)).equals(data);
-
- assume(data.host).equals('google.com');
- assume(data.href).equals('http://google.com/foo');
-
- assume(data.set('port', 443)).equals(data);
- assume(data.host).equals('google.com:443');
- assume(data.href).equals('http://google.com:443/foo');
- });
-
- it('updates query with object', function () {
- var data = parse('http://google.com/?foo=bar');
-
- assume(data.set('query', { bar: 'foo' })).equals(data);
-
- assume(data.query.foo).equals(undefined);
- assume(data.query.bar).equals('foo');
-
- assume(data.href).equals('http://google.com/?bar=foo');
- });
-
- it('updates query with a string', function () {
- var data = parse('http://google.com/?foo=bar');
-
- assume(data.set('query', 'bar=foo')).equals(data);
-
- assume(data.query.foo).equals(undefined);
- assume(data.query.bar).equals('foo');
-
- assume(data.href).equals('http://google.com/?bar=foo');
-
- assume(data.set('query', '?baz=foo')).equals(data);
-
- assume(data.query.bar).equals(undefined);
- assume(data.query.baz).equals('foo');
-
- assume(data.href).equals('http://google.com/?baz=foo');
- });
-
- it('updates the port when updating host', function () {
- var data = parse('http://google.com/?foo=bar');
-
- assume(data.set('host', 'yahoo.com:808')).equals(data);
-
- assume(data.hostname).equals('yahoo.com');
- assume(data.host).equals('yahoo.com:808');
- assume(data.port).equals('808');
-
- assume(data.href).equals('http://yahoo.com:808/?foo=bar');
- });
-
- it('updates the host when updating hostname', function () {
- var data = parse('http://google.com:808/?foo=bar');
-
- assume(data.set('hostname', 'yahoo.com')).equals(data);
-
- assume(data.hostname).equals('yahoo.com');
- assume(data.host).equals('yahoo.com:808');
- assume(data.port).equals('808');
-
- assume(data.href).equals('http://yahoo.com:808/?foo=bar');
- });
-
- it('updates other values', function () {
- var data = parse('http://google.com/?foo=bar');
-
- assume(data.set('protocol', 'https:')).equals(data);
- assume(data.protocol).equals('https:');
-
- assume(data.href).equals('https://google.com/?foo=bar');
- });
- });
-
- describe('fuzzy', function () {
- var fuzz = require('./fuzzy')
- , times = 10;
-
- for (var i = 0; i < times; i++) {
- (function (spec) {
- it('parses: '+ spec.href, function () {
- var url = parse(spec.href)
- , prop;
-
- for (prop in spec) {
- assume(url[prop]).equals(spec[prop]);
- }
- });
- })(fuzz());
- }
- });
-});
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-url-parse.git
More information about the Pkg-javascript-commits
mailing list