-
-
Save Yaffle/1088850 to your computer and use it in GitHub Desktop.
/*jslint regexp: true, maxerr: 50, indent: 2 */ | |
(function (global) { | |
"use strict"; | |
function URLUtils(url, baseURL) { | |
var m = String(url).replace(/^\s+|\s+$/g, "").match(/^([^:\/?#]+:)?(?:\/\/(?:([^:@\/?#]*)(?::([^:@\/?#]*))?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/); | |
if (!m) { | |
throw new RangeError(); | |
} | |
var protocol = m[1] || ""; | |
var username = m[2] || ""; | |
var password = m[3] || ""; | |
var host = m[4] || ""; | |
var hostname = m[5] || ""; | |
var port = m[6] || ""; | |
var pathname = m[7] || ""; | |
var search = m[8] || ""; | |
var hash = m[9] || ""; | |
if (baseURL !== undefined) { | |
var base = new URLUtils(baseURL); | |
var flag = protocol === "" && host === "" && username === ""; | |
if (flag && pathname === "" && search === "") { | |
search = base.search; | |
} | |
if (flag && pathname.charAt(0) !== "/") { | |
pathname = (pathname !== "" ? (((base.host !== "" || base.username !== "") && base.pathname === "" ? "/" : "") + base.pathname.slice(0, base.pathname.lastIndexOf("/") + 1) + pathname) : base.pathname); | |
} | |
// dot segments removal | |
var output = []; | |
pathname.replace(/^(\.\.?(\/|$))+/, "") | |
.replace(/\/(\.(\/|$))+/g, "/") | |
.replace(/\/\.\.$/, "/../") | |
.replace(/\/?[^\/]*/g, function (p) { | |
if (p === "/..") { | |
output.pop(); | |
} else { | |
output.push(p); | |
} | |
}); | |
pathname = output.join("").replace(/^\//, pathname.charAt(0) === "/" ? "/" : ""); | |
if (flag) { | |
port = base.port; | |
hostname = base.hostname; | |
host = base.host; | |
password = base.password; | |
username = base.username; | |
} | |
if (protocol === "") { | |
protocol = base.protocol; | |
} | |
} | |
this.origin = protocol + (protocol !== "" || host !== "" ? "//" : "") + host; | |
this.href = protocol + (protocol !== "" || host !== "" ? "//" : "") + (username !== "" ? username + (password !== "" ? ":" + password : "") + "@" : "") + host + pathname + search + hash; | |
this.protocol = protocol; | |
this.username = username; | |
this.password = password; | |
this.host = host; | |
this.hostname = hostname; | |
this.port = port; | |
this.pathname = pathname; | |
this.search = search; | |
this.hash = hash; | |
} | |
global.URLUtils = URLUtils; | |
}(this)); |
of course
p.s.
all tests from here http://skew.org/uri/uri_tests.html passed
You're working too hard. :-) http://stackoverflow.com/a/12965135/1130377
(Unless you're using this in node or similar, where you wouldn't have an url resolver built into the browser DOM already, of course.)
@johan: I don't believe that works in IE, but even more so, crossing the DOM line from JavaScript tends to be slower than a native-JS solution. Requiring a DOM also prevent anyone from creating a cross-environment library.
Forked to fix a small bug: since pathname
is guaranteed to start with /
, adding an extra /
before the leading part of base.pathname
is unnecessary.
The following case breaks, as the @
gets detected as the auth part:
https://service.domain.com/go?email=jim@jam.com
Suggested change is:
var m = String(url).replace(/^\s+|\s+$/g, "").match(/^([^:\/?#]+:)?(?:\/\/(?:([^:@]*)(?::([^:@]*))?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);
to
var m = String(url).replace(/^\s+|\s+$/g, "").match(/^([^:\/?#]+:)?(?:\/\/(?:([^:@\/]*)(?::([^:@\/]*))?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);
I'm not sure this is 100% correct though - better suggestions welcome.
@guybedford,
Thanks, good catch, I have updated my code.
the specification, written by Anne van Kesteren - https://url.spec.whatwg.org/#authority-state - tells, that "/", "", "?", and "#" should not be in "authority".
@Yaffle thanks so much for the quick response.
When updating to this new code in my tests, I've hit two more issues now unfortunately -
new URLUtils('asdf', 'http://example.org/test')
gives an href ofhttp://example.org//asdf
instead ofhttp://example.org/asdf
new URLUtils('asdf', 'file:///example.org/test')
gives an href offile:/example.org/asdf
instead offile:///example.org/asdf
These issues didn't happen in the original code that I'm still using though so will stick with that for now.
@guybedford, Thanks again,
I updated the code to fix those issues too. Possibly, there are other issues, I did not test well.
P.S. URLUtils
tries to match URL
API available in Chrome and Firefox - new URL('asdf', 'file:///example.org/test')
@Yaffle perhaps it is worth considering turning this into a polyfill repo?
@guybedford, there is one - https://github.com/Polymer/URL
A minor performance optimization for line 21 can be useful:
var base = baseURL instanceof URLUtils ? baseURL : new URLUtils(baseURL);
Great job. I'm going to give this a try.
Is this snippet in Public Domain? E.g. like Douglas Crockford's json.js and json2.js? Public domain is great no pressures to litter ones code with disclaimers.