Skip to content

Commit 550f73a

Browse files
committed
Incorporate node-querystring functions
Now parses array-style query strings into arrays and objects
1 parent c436dcf commit 550f73a

File tree

2 files changed

+119
-23
lines changed

2 files changed

+119
-23
lines changed

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
(jQuery) URL Parser v2.1
1+
(jQuery) URL Parser v2.2
22
======================
33

4-
A little utility to parse urls and provide easy access to their attributes (such as the protocol, host, port etc), path segments, querystring parameters, fragment parameters and more.
4+
An AMD compatible utility to parse urls and provide easy access to their attributes (such as the protocol, host, port etc), path segments, querystring parameters, fragment parameters and more.
55

6-
The core parser functionality is based on the [Regex URI parser by Steven Levithan](http://blog.stevenlevithan.com/archives/parseuri).
7-
8-
Both the jQuery and non-jQuery of this utility provide AMD compatability.
6+
The core parser functionality is based on the [Regex URI parser by Steven Levithan](http://blog.stevenlevithan.com/archives/parseuri), and the query string parsing is handled by a modified version of [node-querystring](https://github.com/visionmedia/node-querystring).
97

108
**Note this used to have a jQuery dependency - this is now optional. See below for details**
119

@@ -90,6 +88,8 @@ purl('http://allmarkedup.com?sky=blue&grass=green').param(); // returns { 'sky':
9088

9189
Note that the `.param()` method will work on both ampersand-split and semicolon-split querystrings.
9290

91+
*As of version 2.2 the param method now handles array-style query string params.*
92+
9393
URL segments
9494
-----------------------
9595

purl.js

Lines changed: 114 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* JQuery URL Parser plugin, v2.1
2+
* JQuery URL Parser plugin, v2.2
33
* Developed and maintanined by Mark Perkins, mark@allmarkedup.com
44
* Source repository: https://github.com/allmarkedup/jQuery-URL-Parser
55
* Licensed under an MIT-style license. See https://github.com/allmarkedup/jQuery-URL-Parser/blob/master/LICENSE for details.
@@ -41,10 +41,10 @@
4141
strict : /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, //less intuitive, more accurate to the specs
4242
loose : /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ // more intuitive, fails on relative paths and deviates from specs
4343
},
44-
45-
querystring_parser = /(?:^|&|;)([^&=;]*)=?([^&;]*)/g, // supports both ampersand and semicolon-delimted query string key/value pairs
46-
47-
fragment_parser = /(?:^|&|;)([^&=;]*)=?([^&;]*)/g; // supports both ampersand and semicolon-delimted fragment key/value pairs
44+
45+
toString = Object.prototype.toString,
46+
47+
isint = /^[0-9]+$/;
4848

4949
function parseUri( url, strictMode ) {
5050
var str = decodeURI( url ),
@@ -57,19 +57,8 @@
5757
}
5858

5959
// build query and fragment parameters
60-
uri.param['query'] = {};
61-
uri.param['fragment'] = {};
62-
uri.attr['query'].replace( querystring_parser, function ( $0, $1, $2 ){
63-
if ($1) {
64-
uri.param['query'][$1] = $2;
65-
}
66-
});
67-
68-
uri.attr['fragment'].replace( fragment_parser, function ( $0, $1, $2 ){
69-
if ($1) {
70-
uri.param['fragment'][$1] = $2;
71-
}
72-
});
60+
uri.param['query'] = parseString(uri.attr['query']);
61+
uri.param['fragment'] = parseString(uri.attr['fragment']);
7362

7463
// split path and fragement into segments
7564
uri.seg['path'] = uri.attr.path.replace(/^\/+|\/+$/g,'').split('/');
@@ -86,6 +75,113 @@
8675
if ( typeof tn !== 'undefined' ) return tag2attr[tn.toLowerCase()];
8776
return tn;
8877
}
78+
79+
function promote(parent, key) {
80+
if (parent[key].length == 0) return parent[key] = {};
81+
var t = {};
82+
for (var i in parent[key]) t[i] = parent[key][i];
83+
parent[key] = t;
84+
return t;
85+
}
86+
87+
function parse(parts, parent, key, val) {
88+
var part = parts.shift();
89+
// end
90+
if (!part) {
91+
if (Array.isArray(parent[key])) {
92+
parent[key].push(val);
93+
} else if ('object' == typeof parent[key]) {
94+
parent[key] = val;
95+
} else if ('undefined' == typeof parent[key]) {
96+
parent[key] = val;
97+
} else {
98+
parent[key] = [parent[key], val];
99+
}
100+
// array
101+
} else {
102+
var obj = parent[key] = parent[key] || [];
103+
if (']' == part) {
104+
if (Array.isArray(obj)) {
105+
if ('' != val) obj.push(val);
106+
} else if ('object' == typeof obj) {
107+
obj[Object.keys(obj).length] = val;
108+
} else {
109+
obj = parent[key] = [parent[key], val];
110+
}
111+
// prop
112+
} else if (~part.indexOf(']')) {
113+
part = part.substr(0, part.length - 1);
114+
if (!isint.test(part) && Array.isArray(obj)) obj = promote(parent, key);
115+
parse(parts, obj, part, val);
116+
// key
117+
} else {
118+
if (!isint.test(part) && Array.isArray(obj)) obj = promote(parent, key);
119+
parse(parts, obj, part, val);
120+
}
121+
}
122+
}
123+
124+
function merge(parent, key, val) {
125+
if (~key.indexOf(']')) {
126+
var parts = key.split('['),
127+
len = parts.length,
128+
last = len - 1;
129+
parse(parts, parent, 'base', val);
130+
// optimize
131+
} else {
132+
if (!isint.test(key) && Array.isArray(parent.base)) {
133+
var t = {};
134+
for (var k in parent.base) t[k] = parent.base[k];
135+
parent.base = t;
136+
}
137+
set(parent.base, key, val);
138+
}
139+
return parent;
140+
}
141+
142+
function parseString(str) {
143+
return String(str)
144+
.split(/&|;/)
145+
.reduce(function(ret, pair) {
146+
try{
147+
pair = decodeURIComponent(pair.replace(/\+/g, ' '));
148+
} catch(e) {
149+
// ignore
150+
}
151+
152+
var eql = pair.indexOf('='),
153+
brace = lastBraceInKey(pair),
154+
key = pair.substr(0, brace || eql),
155+
val = pair.substr(brace || eql, pair.length),
156+
val = val.substr(val.indexOf('=') + 1, val.length);
157+
158+
if ('' == key) key = pair, val = '';
159+
160+
return merge(ret, key, val);
161+
}, { base: {} }).base;
162+
}
163+
164+
function set(obj, key, val) {
165+
var v = obj[key];
166+
if (undefined === v) {
167+
obj[key] = val;
168+
} else if (Array.isArray(v)) {
169+
v.push(val);
170+
} else {
171+
obj[key] = [v, val];
172+
}
173+
}
174+
175+
function lastBraceInKey(str) {
176+
var len = str.length,
177+
brace, c;
178+
for (var i = 0; i < len; ++i) {
179+
c = str[i];
180+
if (']' == c) brace = false;
181+
if ('[' == c) brace = true;
182+
if ('=' == c && !brace) return i;
183+
}
184+
}
89185

90186
function purl( url, strictMode ) {
91187
if ( arguments.length === 1 && url === true ) {

0 commit comments

Comments
 (0)