diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..646ac51 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +node_modules/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..8d40586 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# URL helper + +A URL helper for use with design systems at The Grid. diff --git a/lib/url-helper.js b/lib/url-helper.js new file mode 100644 index 0000000..92f4649 --- /dev/null +++ b/lib/url-helper.js @@ -0,0 +1,48 @@ +// Generated by CoffeeScript 1.9.3 +(function() { + var URI, url, urlHelper; + + url = require("url"); + + URI = require("URIjs"); + + urlHelper = { + isAbsoluteUrl: function(uri) { + return (new URI(uri)).is("absolute"); + }, + resolveRelativeUrl: function(to, from) { + var uri; + if (module.exports.isAbsoluteUrl(to)) { + return to; + } + uri = new URI("/" + to).relativeTo("/" + from); + if (uri.filename() === "index.html") { + if (uri.directory() === "") { + uri = uri.directory("."); + } + uri = uri.filename(""); + } + return uri.toString(); + }, + validateAbsoluteUrl: function(remoteUrl) { + var protocol; + if (remoteUrl == null) { + return false; + } + protocol = url.parse(remoteUrl).protocol; + return protocol === "http:" || protocol === "https:"; + }, + normalizeUrl: function(uri, pagePath) { + if (urlHelper.isAbsoluteUrl(uri)) { + if (urlHelper.validateAbsoluteUrl(uri)) { + return uri; + } + return null; + } + return urlHelper.resolveRelativeUrl(uri, pagePath); + } + }; + + module.exports = urlHelper; + +}).call(this); diff --git a/package.json b/package.json new file mode 100644 index 0000000..4367f27 --- /dev/null +++ b/package.json @@ -0,0 +1,33 @@ +{ + "name": "url-helper", + "version": "0.1.0", + "description": "A URL helper for use with design systems at The Grid.", + "main": "lib/url-helper.js", + "scripts": { + "test": "grunt test --stack" + }, + "repository": { + "type": "git", + "url": "git://github.com/design-systems/url-helper" + }, + "author": "Paul Young", + "license": "proprietary", + "bugs": { + "url": "https://github.com/design-systems/url-helper/issues" + }, + "homepage": "https://github.com/design-systems/url-helper", + "dependencies": { + "URIjs": "^1.16.0", + "url": "^0.10.3" + }, + "devDependencies": { + "chai": "^3.2.0", + "coffee-script": "^1.9.3", + "mocha": "^2.2.5" + }, + "scripts": { + "build": "npm run clean; ./node_modules/.bin/coffee --compile --output lib/ src/", + "clean": "mkdir -p lib; rm -r lib; mkdir lib", + "test": "npm run build; ./node_modules/.bin/mocha 'spec/**/*.coffee' --compilers coffee:coffee-script/register --reporter spec" + } +} diff --git a/spec/url-helper.coffee b/spec/url-helper.coffee new file mode 100644 index 0000000..d4dadda --- /dev/null +++ b/spec/url-helper.coffee @@ -0,0 +1,93 @@ +chai = require "chai" +{expect} = chai + +urlHelper = require "../lib/url-helper" + +describe "url helper", -> + + describe "relative", -> + + context "absolute URL", -> + it "should pass through unchanged", -> + to = "https://twitter.com/thegrid" + from = "index.html" + resolved = urlHelper.resolveRelativeUrl to, from + expect(resolved).to.equal "https://twitter.com/thegrid" + + + context "URL relative to index", -> + it "should resolve to the correct URL", -> + to = "index.html" + from = "faq/index.html" + resolved = urlHelper.resolveRelativeUrl to, from + expect(resolved).to.equal "../" + + + context "URL relative to named page", -> + it "should resolve to the correct URL", -> + to = "foo.html" + from = "bar/baz.html" + resolved = urlHelper.resolveRelativeUrl to, from + expect(resolved).to.equal "../foo.html" + + + context "URL relative to itself", -> + it "should resolve to the correct URL", -> + to = "faq/index.html" + from = "faq/index.html" + resolved = urlHelper.resolveRelativeUrl to, from + expect(resolved).to.equal "" + + + context "URL relative to another URL", -> + it "should resolve to the correct URL", -> + to = "blog/foo/index.html" + from = "categories/noflo/index.html" + resolved = urlHelper.resolveRelativeUrl to, from + expect(resolved).to.equal "../../blog/foo/" + + + context "Sibling page URL relative to index", -> + it "should resolve to the correct URL", -> + to = "index.html" + from = "index.abcde.html" + resolved = urlHelper.resolveRelativeUrl to, from + expect(resolved).to.equal "./" + + + describe "absolute", -> + + context "without a URL", -> + it "should be invalid", -> + isValid = urlHelper.validateAbsoluteUrl null + expect(isValid).to.equal false + + context "empty URL", -> + it "should be invalid", -> + isValid = urlHelper.validateAbsoluteUrl "" + expect(isValid).to.equal false + + context "relative URL", -> + it "should be invalid", -> + isValid = urlHelper.validateAbsoluteUrl "../index.html" + expect(isValid).to.equal false + + context "protocol-relative URL", -> + it "should be invalid", -> + isValid = urlHelper.validateAbsoluteUrl "//thegrid.io" + expect(isValid).to.equal false + + context "URL with a file:// protocol", -> + it "should be invalid", -> + isValid = urlHelper.validateAbsoluteUrl "file://thegrid.png" + expect(isValid).to.equal false + + context "URL with http:// protocol", -> + it "should be valid", -> + isValid = urlHelper.validateAbsoluteUrl "http://thegrid.io" + expect(isValid).to.equal true + + context "URL with https:// protocol", -> + it "should be valid", -> + isValid = urlHelper.validateAbsoluteUrl "https://thegrid.io" + expect(isValid).to.equal true diff --git a/src/url-helper.coffee b/src/url-helper.coffee new file mode 100644 index 0000000..920eac1 --- /dev/null +++ b/src/url-helper.coffee @@ -0,0 +1,27 @@ +url = require "url" +URI = require "URIjs" + +urlHelper = + isAbsoluteUrl: (uri) -> + (new URI(uri)).is "absolute" + + resolveRelativeUrl: (to, from) -> + return to if module.exports.isAbsoluteUrl to + uri = new URI("/#{to}").relativeTo("/#{from}") + if uri.filename() is "index.html" + uri = uri.directory(".") if uri.directory() is "" + uri = uri.filename("") + uri.toString() + + validateAbsoluteUrl: (remoteUrl) -> + return false unless remoteUrl? + {protocol} = url.parse remoteUrl + protocol is "http:" or protocol is "https:" + + normalizeUrl: (uri, pagePath) -> + if urlHelper.isAbsoluteUrl uri + return uri if urlHelper.validateAbsoluteUrl uri + return null + urlHelper.resolveRelativeUrl uri, pagePath + +module.exports = urlHelper