Comparing version 1.1.3 to 1.1.4
215
index.js
@@ -6,7 +6,6 @@ 'use strict'; | ||
, qs = require('querystringify') | ||
, relativere = /^\/(?!\/)/ | ||
, protocolre = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\S\s]*)/i; | ||
/** | ||
* 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: | ||
@@ -22,3 +21,3 @@ * | ||
*/ | ||
var instructions = [ | ||
var rules = [ | ||
['#', 'hash'], // Extract from the back. | ||
@@ -29,21 +28,21 @@ ['?', 'query'], // Extract from the back. | ||
[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. | ||
]; | ||
/** | ||
/** | ||
* @typedef ProtocolExtract | ||
* @type Object | ||
* @property {String} protocol Protocol matched in the URL, in lowercase | ||
* @property {Boolean} slashes Indicates whether the protocol is followed by double slash ("//") | ||
* @property {String} rest Rest of the URL that is not part of the protocol | ||
* @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 | ||
*/ | ||
/** | ||
* 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) { | ||
@@ -55,3 +54,3 @@ var match = protocolre.exec(address); | ||
slashes: !!match[2], | ||
rest: match[3] ? match[3] : '' | ||
rest: match[3] | ||
}; | ||
@@ -61,2 +60,36 @@ } | ||
/** | ||
* 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 | ||
@@ -77,7 +110,6 @@ * create an actual constructor as it's much more memory efficient and | ||
var relative = relativere.test(address) | ||
, parse, instruction, index, key | ||
var relative, extracted, parse, instruction, index, key | ||
, instructions = rules.slice() | ||
, type = typeof location | ||
, url = this | ||
, extracted | ||
, i = 0; | ||
@@ -101,5 +133,3 @@ | ||
if (parser && 'function' !== typeof parser) { | ||
parser = qs.parse; | ||
} | ||
if (parser && 'function' !== typeof parser) parser = qs.parse; | ||
@@ -109,9 +139,16 @@ location = lolcation(location); | ||
// | ||
// extract protocol information before running the instructions | ||
// 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 || ''; | ||
url.slashes = extracted.slashes || location.slashes; | ||
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++) { | ||
@@ -136,6 +173,8 @@ instruction = instructions[i]; | ||
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] || '' : '' | ||
); | ||
@@ -146,5 +185,3 @@ // | ||
// | ||
if (instruction[4]) { | ||
url[key] = url[key].toLowerCase(); | ||
} | ||
if (instruction[4]) url[key] = url[key].toLowerCase(); | ||
} | ||
@@ -160,2 +197,14 @@ | ||
// | ||
// 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 | ||
@@ -180,6 +229,9 @@ // for a given protocol. As the host also contains the port number we're going | ||
url.origin = url.protocol && url.host && url.protocol !== 'file:' | ||
? url.protocol +'//'+ url.host | ||
: 'null'; | ||
// | ||
// The href is just the compiled result. | ||
// | ||
url.origin = url.protocol && url.host && url.protocol !== 'file:' ? url.protocol +'//'+ url.host : 'null'; | ||
url.href = url.toString(); | ||
@@ -194,6 +246,6 @@ } | ||
* @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. | ||
* @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} | ||
@@ -204,50 +256,69 @@ * @api public | ||
var url = this; | ||
switch(part) { | ||
case 'query': | ||
if ('string' === typeof value && value.length) { | ||
value = (fn || qs.parse)(value); | ||
} | ||
if ('query' === part) { | ||
if ('string' === typeof value && value.length) { | ||
value = (fn || qs.parse)(value); | ||
} | ||
url[part] = value; | ||
break; | ||
url[part] = value; | ||
} else if ('port' === part) { | ||
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; | ||
} | ||
} else if ('hostname' === part) { | ||
url[part] = value; | ||
if (!required(value, url.protocol)) { | ||
url.host = url.hostname; | ||
url[part] = ''; | ||
} else if (value) { | ||
url.host = url.hostname +':'+ value; | ||
} | ||
if (url.port) value += ':'+ url.port; | ||
url.host = value; | ||
} else if ('host' === part) { | ||
url[part] = value; | ||
break; | ||
if (/:\d+$/.test(value)) { | ||
value = value.split(':'); | ||
url.port = value.pop(); | ||
url.hostname = value.join(':'); | ||
} else { | ||
url.hostname = value; | ||
url.port = ''; | ||
} | ||
} else if ('protocol' === part) { | ||
url.protocol = value.toLowerCase(); | ||
url.slashes = !fn; | ||
} else { | ||
url[part] = value; | ||
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': | ||
url.pathname = value.charAt(0) === '/' ? value : '/' + value; | ||
break; | ||
default: | ||
url[part] = value; | ||
break; | ||
} | ||
for (var i = 0; i < instructions.length; i++) { | ||
var ins = instructions[i]; | ||
for (var i = 0; i < rules.length; i++) { | ||
var ins = rules[i]; | ||
if (ins[4]) { | ||
url[ins[1]] = url[ins[1]].toLowerCase(); | ||
} | ||
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.origin = url.protocol && url.host && url.protocol !== 'file:' | ||
? url.protocol +'//'+ url.host | ||
: 'null'; | ||
url.href = url.toString(); | ||
@@ -254,0 +325,0 @@ |
{ | ||
"name": "url-parse", | ||
"version": "1.1.3", | ||
"version": "1.1.4", | ||
"description": "Small footprint URL parser that works seamlessly across Node.js and browser environments", | ||
@@ -38,8 +38,8 @@ "main": "index.js", | ||
"assume": "1.4.x", | ||
"browserify": "13.0.x", | ||
"browserify": "13.1.x", | ||
"istanbul": "0.4.x", | ||
"mocha": "2.5.x", | ||
"mocha": "3.0.x", | ||
"pre-commit": "1.1.x", | ||
"zuul": "3.10.x" | ||
"zuul": "3.11.x" | ||
} | ||
} |
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
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
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 README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
19559
5
347
0
137
1