Comparing version 0.2.3 to 1.0.0
'use strict'; | ||
var URL = require('./') | ||
, url = new URL(); | ||
, url = new URL(''); | ||
@@ -6,0 +6,0 @@ /** |
114
index.js
@@ -5,8 +5,27 @@ 'use strict'; | ||
, lolcation = require('./lolcation') | ||
, qs = require('querystringify'); | ||
, qs = require('querystringify') | ||
, relativere = /^\/(?!\/)/; | ||
var keys = ',,protocol,username,password,host,hostname,port,pathname,query,hash'.split(',') | ||
, inherit = { protocol: 1, host: 1, hostname: 1 } | ||
, relativere = /^\/(?!\/)/ | ||
, parts = keys.length; | ||
/** | ||
* These are the parse instructions for the URL parsers, it informs the parser | ||
* about: | ||
* | ||
* 0. The char it Needs to parse, if it's a string it should be done using | ||
* indexOf, RegExp using exec and NaN means set as current value. | ||
* 1. The property we should set when parsing this value. | ||
* 2. Indication if it's backwards or forward parsing, when set as number it's | ||
* the value of extra chars that should be split off. | ||
* 3. Inherit from location if non existing in the parser. | ||
* 4. `toLowerCase` the resulting value. | ||
*/ | ||
var instructions = [ | ||
['#', '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. | ||
[NaN, 'hostname', undefined, 1, 1] // Set left over. | ||
]; | ||
@@ -29,42 +48,7 @@ /** | ||
// | ||
// 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. The biggest problem with this | ||
// FireFox problem is that it's super hard to reproduce as our "normal" test | ||
// suite doesn't catch it. The only way to reproduce it was run the parser in | ||
// jsperf.com (uses the benchmark module from npm) and supply it the URL | ||
// mentioned above as URL to parse. | ||
// | ||
// 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\]\+\)\)\?\)\)\?\)\?\)\?\(\(\?:\\/\?\(\?:\[\^\\/\\\?\#\]\+\\/\+\)\*\)\(\?:\[\^\\\?\#\]\*\)\)\)\?\(\\\?\[\^\#\]\+\)\?\)\(\#\.\*\)\?') | ||
, relative = relativere.test(address) | ||
, bits = regexp.exec(address) | ||
var relative = relativere.test(address) | ||
, parse, instruction, index, key | ||
, type = typeof location | ||
, url = this | ||
, i = 0 | ||
, key; | ||
, i = 0; | ||
@@ -93,13 +77,33 @@ // | ||
for (; i < parts; key = keys[++i]) { | ||
if (!key) continue; | ||
for (; i < instructions.length; i++) { | ||
instruction = instructions[i]; | ||
parse = instruction[0]; | ||
key = instruction[1]; | ||
url[key] = bits[i] || (key in inherit || ('port' === key && relative) ? location[key] || '' : ''); | ||
if (parse !== parse) { | ||
url[key] = address; | ||
} else if ('string' === typeof parse) { | ||
if (~(index = address.indexOf(parse))) { | ||
if ('number' === typeof instruction[2]) { | ||
url[key] = address.slice(0, index); | ||
address = address.slice(index + instruction[2]); | ||
} else { | ||
url[key] = address.slice(index); | ||
address = address.slice(0, index); | ||
} | ||
} | ||
} else if (index = parse.exec(address)) { | ||
url[key] = index[1]; | ||
address = address.slice(0, address.length - index[0].length); | ||
} | ||
url[key] = url[key] || (instruction[3] || ('port' === key && relative) ? 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. | ||
// Hostname, host and protocol should be lowercased so they can be used to | ||
// create a proper `origin`. | ||
// | ||
if (i === 2 || i === 5 || i === 6) url[key] = url[key].toLowerCase(); | ||
if (instruction[4]) { | ||
url[key] = url[key].toLowerCase(); | ||
} | ||
} | ||
@@ -125,2 +129,12 @@ | ||
// | ||
// Parse down the `auth` for the username and password. | ||
// | ||
url.username = url.password = ''; | ||
if (url.auth) { | ||
instruction = url.auth.split(':'); | ||
url.username = instruction[0] || ''; | ||
url.password = instruction[1] || ''; | ||
} | ||
// | ||
// The href is just the compiled result. | ||
@@ -127,0 +141,0 @@ // |
{ | ||
"name": "url-parse", | ||
"version": "0.2.3", | ||
"version": "1.0.0", | ||
"description": "Parse URL in node using the URL module and in the browser using the DOM", | ||
@@ -10,3 +10,3 @@ "main": "index.js", | ||
"test-travis": "istanbul cover node_modules/.bin/_mocha --report lcovonly -- --reporter spec --ui bdd ./test.js", | ||
"browserify": "mkdir dist && browserify index.js -o dist/url-parse.js --standalone URLParse", | ||
"browserify": "mkdir -p dist && browserify index.js -o dist/url-parse.js --standalone URLParse", | ||
"phantomjs": "mochify --reporter spec --ui bdd ./test.js", | ||
@@ -29,6 +29,6 @@ "testling": "testling -u" | ||
"devDependencies": { | ||
"assume": "0.0.x", | ||
"browserify": "7.0.x", | ||
"assume": "1.0.x", | ||
"browserify": "8.1.x", | ||
"istanbul": "0.3.x", | ||
"mocha": "2.0.x", | ||
"mocha": "2.1.x", | ||
"mochify": "2.1.x", | ||
@@ -35,0 +35,0 @@ "pre-commit": "0.0.x", |
@@ -13,3 +13,6 @@ # url-parse | ||
module still have a really small foot print as this module's main intention is | ||
to be bundled with client-side code. | ||
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. | ||
@@ -16,0 +19,0 @@ In addition to URL parsing we also expose the bundled `querystringify` module. |
119
test.js
@@ -78,9 +78,2 @@ describe('url-parse', function () { | ||
it('does not lowercase the USER:PASS', function () { | ||
var url = 'HTTP://USER:PASS@EXAMPLE.COM'; | ||
assume(parse(url).username).equals('USER'); | ||
assume(parse(url).password).equals('PASS'); | ||
}); | ||
it('does not lowercase the path', function () { | ||
@@ -102,8 +95,111 @@ var url = 'HTTP://X.COM/Y/Z'; | ||
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='; | ||
it('understands an / as pathname', function () { | ||
var url = 'http://example.com:80/' | ||
, parsed = parse(url); | ||
assume(parse(url).pathname).equals('/vt/lyrs=m@114&hl=en&src=api&x=2&y=2&z=3&s='); | ||
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@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'); | ||
}); | ||
}); | ||
it('accepts multiple ???', function () { | ||
@@ -166,3 +262,4 @@ var url = 'http://mt0.google.com/vt/lyrs=m@114???&hl=en&src=api&x=2&y=2&z=3&s='; | ||
it('does not inherit auth from source object', function () { | ||
var data = parse('/foo', parse('http://foo:bar@sub.example.com')); | ||
var from = parse('http://foo:bar@sub.example.com') | ||
, data = parse('/foo', from); | ||
@@ -169,0 +266,0 @@ assume(data.port).equals(''); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
29162
588
1
119