diff options
author | Florian Dold <florian.dold@gmail.com> | 2017-05-03 15:35:00 +0200 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2017-05-03 15:35:00 +0200 |
commit | de98e0b232509d5f40c135d540a70e415272ff85 (patch) | |
tree | a79222a5b58484ab3b80d18efcaaa7ccc4769b33 /node_modules/relateurl | |
parent | e0c9d480a73fa629c1e4a47d3e721f1d2d345406 (diff) | |
download | wallet-core-de98e0b232509d5f40c135d540a70e415272ff85.tar.xz |
node_modules
Diffstat (limited to 'node_modules/relateurl')
21 files changed, 1387 insertions, 0 deletions
diff --git a/node_modules/relateurl/README.md b/node_modules/relateurl/README.md new file mode 100644 index 000000000..fb65fca3d --- /dev/null +++ b/node_modules/relateurl/README.md @@ -0,0 +1,159 @@ +# relateurl [![NPM Version][npm-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Dependency Status][david-image]][david-url] + +> Minify URLs by converting them from absolute to relative. + +If you were to use this library on a website like `http://example.com/dir1/dir1-1/`, you would get results such as: + +| Before | After | +| :------------------------------------------ | :----------------------------------- | +| `http://example.com/dir1/dir1-2/index.html` | `../dir1-2/` | +| `http://example.com/dir2/dir2-1/` | `/dir2/dir2-1/` | +| `http://example.com/dir1/dir1-1/` | ` ` | +| `https://example.com/dir1/dir1-1/` | `https://example.com/dir1/dir1-1/` | +| `http://google.com:80/dir/` | `//google.com/dir/` | +| `../../../../../../../../#anchor` | `/#anchor` | + +**All string parsing.** *No* directory browsing. It is thoroughly tested, very fast and lightweight with zero external dependencies. + +## Getting Started + +This utility requires [Node.js](http://nodejs.org/) `>= 0.10`. To install, type this at the command line: +``` +npm install relateurl --save-dev +``` + +### Options + +#### options.defaultPorts +Type: `Object` +Default value: `{ftp:21, http:80, https:443}` + +Extend the list with any ports you need. Any URLs containing these default ports will have them removed. Example: `http://example.com:80/` will become `http://example.com/`. + +#### options.directoryIndexes +Type: `Array` +Default value: `["index.html"]` + +Extend the list with any resources you need. Works with [`options.removeDirectoryIndexes`](#options.removeDirectoryIndexes). + +#### options.ignore_www +Type: `Boolean` +Default value: `false` + +This will, for example, consider any domains containing `http://www.example.com/` to be related to any that contain `http://example.com/`. + +#### options.output +Type: constant or `String` +Choices: `RelateUrl.ABSOLUTE`,`RelateUrl.PATH_RELATIVE`,`RelateUrl.ROOT_RELATIVE`,`RelateUrl.SHORTEST` +Choices: `"absolute"`,`"pathRelative"`,`"rootRelative"`,`"shortest"` +Default value: `RelateUrl.SHORTEST` + +`RelateUrl.ABSOLUTE` will produce an absolute URL. Overrides [`options.schemeRelative`](#options.schemeRelative) with a value of `false`. +`RelateUrl.PATH_RELATIVE` will produce something like `../child-of-parent/etc/`. +`RelateUrl.ROOT_RELATIVE` will produce something like `/child-of-root/etc/`. +`RelateUrl.SHORTEST` will choose whichever is shortest between root- and path-relative. + +#### options.rejectedSchemes +Type: `Array` +Default value: `["data","javascript","mailto"]` + +Extend the list with any additional schemes. Example: `javascript:something` will not be modified. + +#### options.removeAuth +Type: `Boolean` +Default value: `false` + +Remove user authentication information from the output URL. + +#### options.removeDirectoryIndexes +Type: `Boolean` +Default value: `true` + +Remove any resources that match any found in [`options.directoryIndexes`](#options.directoryIndexes). + +#### options.removeEmptyQueries +Type: `Boolean` +Default value: `false` + +Remove empty query variables. Example: `http://domain.com/?var1&var2=&var3=asdf` will become `http://domain.com/?var3=adsf`. This does not apply to unrelated URLs (with other protocols, auths, hosts and/or ports). + +#### options.removeRootTrailingSlash +Type: `Boolean` +Default value: `true` + +Remove trailing slashes from root paths. Example: `http://domain.com/?var` will become `http://domain.com?var` while `http://domain.com/dir/?var` will not be modified. + +#### options.schemeRelative +Type: `Boolean` +Default value: `true` + +Output URLs relative to the scheme. Example: `http://example.com/` will become `//example.com/`. + +#### options.site +Type: `String` +Default value: `undefined` + +An options-based version of the [`from`](#examples) argument. If both are specified, `from` takes priority. + +#### options.slashesDenoteHost +Type: `Boolean` +Default value: `true` + +Passed to Node's [`url.parse`](http://nodejs.org/api/url.html#url_url_parse_urlstr_parsequerystring_slashesdenotehost). + +### Examples +This library can be used as a [function for single-use](#single-instance) or as a [class for multiple conversions](#reusable-instances). + +Upon successful conversion, a `String` will be returned. If an issue is encountered while parsing `from`, an error will be thrown. + +#### Single Instance +```js +var RelateUrl = require("relateurl"); + +var result = RelateUrl.relate(from, to, options); +``` + +#### Reusable Instances +```js +var RelateUrl = require("relateurl"); + +var instance = new RelateUrl(from, options); + +var result1 = instance.relate(to1); +var result2 = instance.relate(to2, customOptions); +var result3 = instance.relate(to3); +``` + +## FAQ +1. **Why bother writing/using this?** +To aid in further minifying HTML, mainly for the purpose of faster page loads and SEO. It's been integrated into [HTMLMinifier](https://github.com/kangax/html-minifier). + +2. **Why not just use Node's `url.parse`, `url.resolve` and `path.relative`?** +`url.parse` *is* used, but `url.resolve` and `path.relative` are both slower and less powerful than this library. + + +## Release History +* 0.2.7 Node v6 support +* 0.2.6 minor enhancements +* 0.2.5 added `options.removeRootTrailingSlash` +* 0.2.4 added `options.site` +* 0.2.3 added browserify npm-script +* 0.2.2 removed task runner +* 0.2.1 shorten resource- and query-relative URLs, test variations list with other site URLs +* 0.2.0 code cleanup, `options.removeEmptyQueries=true` only applied to unrelated URLs +* 0.1.0 initial release + + +## Roadmap +* 0.2.8 check if queries are the same, regardless of param order +* 0.2.8 possible [scheme exclusions](http://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml) such as `tel:` +* 0.2.8 decipher and return invalid input (special cases) to complete test suite +* 0.3.0 test `options.slashesDenoteHost=false`, add something like `options.externalDirectoryIndexes=[]` for external sites + + +[npm-image]: https://img.shields.io/npm/v/relateurl.svg +[npm-url]: https://npmjs.org/package/relateurl +[travis-image]: https://img.shields.io/travis/stevenvachon/relateurl.svg +[travis-url]: https://travis-ci.org/stevenvachon/relateurl +[david-image]: https://img.shields.io/david/stevenvachon/relateurl.svg +[david-url]: https://david-dm.org/stevenvachon/relateurl diff --git a/node_modules/relateurl/lib/constants.js b/node_modules/relateurl/lib/constants.js new file mode 100644 index 000000000..d4cc8dd69 --- /dev/null +++ b/node_modules/relateurl/lib/constants.js @@ -0,0 +1,10 @@ +"use strict"; + +module.exports = +{ + // Output + ABSOLUTE: "absolute", + PATH_RELATIVE: "pathRelative", + ROOT_RELATIVE: "rootRelative", + SHORTEST: "shortest" +}; diff --git a/node_modules/relateurl/lib/format.js b/node_modules/relateurl/lib/format.js new file mode 100644 index 000000000..4dd5ddc08 --- /dev/null +++ b/node_modules/relateurl/lib/format.js @@ -0,0 +1,174 @@ +"use strict"; + +var constants = require("./constants"); + + + +function formatAuth(urlObj, options) +{ + if (urlObj.auth && !options.removeAuth && (urlObj.extra.relation.maximumHost || options.output===constants.ABSOLUTE)) + { + return urlObj.auth + "@"; + } + + return ""; +} + + + +function formatHash(urlObj, options) +{ + return urlObj.hash ? urlObj.hash : ""; +} + + + +function formatHost(urlObj, options) +{ + if (urlObj.host.full && (urlObj.extra.relation.maximumAuth || options.output===constants.ABSOLUTE)) + { + return urlObj.host.full; + } + + return ""; +} + + + +function formatPath(urlObj, options) +{ + var str = ""; + + var absolutePath = urlObj.path.absolute.string; + var relativePath = urlObj.path.relative.string; + var resource = showResource(urlObj, options); + + if (urlObj.extra.relation.maximumHost || options.output===constants.ABSOLUTE || options.output===constants.ROOT_RELATIVE) + { + str = absolutePath; + } + else if (relativePath.length<=absolutePath.length && options.output===constants.SHORTEST || options.output===constants.PATH_RELATIVE) + { + str = relativePath; + + if (str === "") + { + var query = showQuery(urlObj,options) && !!getQuery(urlObj,options); + + if (urlObj.extra.relation.maximumPath && !resource) + { + str = "./"; + } + else if (urlObj.extra.relation.overridesQuery && !resource && !query) + { + str = "./"; + } + } + } + else + { + str = absolutePath; + } + + if ( str==="/" && !resource && options.removeRootTrailingSlash && (!urlObj.extra.relation.minimumPort || options.output===constants.ABSOLUTE) ) + { + str = ""; + } + + return str; +} + + + +function formatPort(urlObj, options) +{ + if (urlObj.port && !urlObj.extra.portIsDefault && urlObj.extra.relation.maximumHost) + { + return ":" + urlObj.port; + } + + return ""; +} + + + +function formatQuery(urlObj, options) +{ + return showQuery(urlObj,options) ? getQuery(urlObj, options) : ""; +} + + + +function formatResource(urlObj, options) +{ + return showResource(urlObj,options) ? urlObj.resource : ""; +} + + + +function formatScheme(urlObj, options) +{ + var str = ""; + + if (urlObj.extra.relation.maximumHost || options.output===constants.ABSOLUTE) + { + if (!urlObj.extra.relation.minimumScheme || !options.schemeRelative || options.output===constants.ABSOLUTE) + { + str += urlObj.scheme + "://"; + } + else + { + str += "//"; + } + } + + return str; +} + + + +function formatUrl(urlObj, options) +{ + var url = ""; + + url += formatScheme(urlObj, options); + url += formatAuth(urlObj, options); + url += formatHost(urlObj, options); + url += formatPort(urlObj, options); + url += formatPath(urlObj, options); + url += formatResource(urlObj, options); + url += formatQuery(urlObj, options); + url += formatHash(urlObj, options); + + return url; +} + + + +function getQuery(urlObj, options) +{ + var stripQuery = options.removeEmptyQueries && urlObj.extra.relation.minimumPort; + + return urlObj.query.string[ stripQuery ? "stripped" : "full" ]; +} + + + +function showQuery(urlObj, options) +{ + return !urlObj.extra.relation.minimumQuery || options.output===constants.ABSOLUTE || options.output===constants.ROOT_RELATIVE; +} + + + +function showResource(urlObj, options) +{ + var removeIndex = options.removeDirectoryIndexes && urlObj.extra.resourceIsIndex; + var removeMatchingResource = urlObj.extra.relation.minimumResource && options.output!==constants.ABSOLUTE && options.output!==constants.ROOT_RELATIVE; + + return !!urlObj.resource && !removeMatchingResource && !removeIndex; +} + + + +module.exports = formatUrl; diff --git a/node_modules/relateurl/lib/index.js b/node_modules/relateurl/lib/index.js new file mode 100644 index 000000000..714237d59 --- /dev/null +++ b/node_modules/relateurl/lib/index.js @@ -0,0 +1,94 @@ +"use strict"; + +var constants = require("./constants"); +var formatUrl = require("./format"); +var getOptions = require("./options"); +var objUtils = require("./util/object"); +var parseUrl = require("./parse"); +var relateUrl = require("./relate"); + + + +function RelateUrl(from, options) +{ + this.options = getOptions(options, + { + defaultPorts: {ftp:21, http:80, https:443}, + directoryIndexes: ["index.html"], + ignore_www: false, + output: RelateUrl.SHORTEST, + rejectedSchemes: ["data","javascript","mailto"], + removeAuth: false, + removeDirectoryIndexes: true, + removeEmptyQueries: false, + removeRootTrailingSlash: true, + schemeRelative: true, + site: undefined, + slashesDenoteHost: true + }); + + this.from = parseUrl.from(from, this.options, null); +} + + + +/* + Usage: instance=new RelateUrl(); instance.relate(); +*/ +RelateUrl.prototype.relate = function(from, to, options) +{ + // relate(to,options) + if ( objUtils.isPlainObject(to) ) + { + options = to; + to = from; + from = null; + } + // relate(to) + else if (!to) + { + to = from; + from = null; + } + + options = getOptions(options, this.options); + from = from || options.site; + from = parseUrl.from(from, options, this.from); + + if (!from || !from.href) + { + throw new Error("from value not defined."); + } + else if (from.extra.hrefInfo.minimumPathOnly) + { + throw new Error("from value supplied is not absolute: "+from.href); + } + + to = parseUrl.to(to, options); + + if (to.valid===false) return to.href; + + to = relateUrl(from, to, options); + to = formatUrl(to, options); + + return to; +} + + + +/* + Usage: RelateUrl.relate(); +*/ +RelateUrl.relate = function(from, to, options) +{ + return new RelateUrl().relate(from, to, options); +} + + + +// Make constants accessible from API +objUtils.shallowMerge(RelateUrl, constants); + + + +module.exports = RelateUrl; diff --git a/node_modules/relateurl/lib/options.js b/node_modules/relateurl/lib/options.js new file mode 100644 index 000000000..fe8910f71 --- /dev/null +++ b/node_modules/relateurl/lib/options.js @@ -0,0 +1,57 @@ +"use strict"; + +var objUtils = require("./util/object"); + + + +function getOptions(options, defaults) +{ + if ( objUtils.isPlainObject(options) ) + { + var newOptions = {}; + + for (var i in defaults) + { + if ( defaults.hasOwnProperty(i) ) + { + if (options[i] !== undefined) + { + newOptions[i] = mergeOption(options[i], defaults[i]); + } + else + { + newOptions[i] = defaults[i]; + } + } + } + + return newOptions; + } + else + { + return defaults; + } +} + + + +function mergeOption(newValues, defaultValues) +{ + if (defaultValues instanceof Object && newValues instanceof Object) + { + if (defaultValues instanceof Array && newValues instanceof Array) + { + return defaultValues.concat(newValues); + } + else + { + return objUtils.shallowMerge(newValues, defaultValues); + } + } + + return newValues; +} + + + +module.exports = getOptions; diff --git a/node_modules/relateurl/lib/parse/host.js b/node_modules/relateurl/lib/parse/host.js new file mode 100644 index 000000000..21f04ff98 --- /dev/null +++ b/node_modules/relateurl/lib/parse/host.js @@ -0,0 +1,26 @@ +"use strict"; + +function parseHost(urlObj, options) +{ + // TWEAK :: condition only for speed optimization + if (options.ignore_www) + { + var host = urlObj.host.full; + + if (host) + { + var stripped = host; + + if (host.indexOf("www.") === 0) + { + stripped = host.substr(4); + } + + urlObj.host.stripped = stripped; + } + } +} + + + +module.exports = parseHost; diff --git a/node_modules/relateurl/lib/parse/hrefInfo.js b/node_modules/relateurl/lib/parse/hrefInfo.js new file mode 100644 index 000000000..8cac2bd82 --- /dev/null +++ b/node_modules/relateurl/lib/parse/hrefInfo.js @@ -0,0 +1,20 @@ +"use strict"; + +function hrefInfo(urlObj) +{ + var minimumPathOnly = (!urlObj.scheme && !urlObj.auth && !urlObj.host.full && !urlObj.port); + var minimumResourceOnly = (minimumPathOnly && !urlObj.path.absolute.string); + var minimumQueryOnly = (minimumResourceOnly && !urlObj.resource); + var minimumHashOnly = (minimumQueryOnly && !urlObj.query.string.full.length); + var empty = (minimumHashOnly && !urlObj.hash); + + urlObj.extra.hrefInfo.minimumPathOnly = minimumPathOnly; + urlObj.extra.hrefInfo.minimumResourceOnly = minimumResourceOnly; + urlObj.extra.hrefInfo.minimumQueryOnly = minimumQueryOnly; + urlObj.extra.hrefInfo.minimumHashOnly = minimumHashOnly; + urlObj.extra.hrefInfo.empty = empty; +} + + + +module.exports = hrefInfo; diff --git a/node_modules/relateurl/lib/parse/index.js b/node_modules/relateurl/lib/parse/index.js new file mode 100644 index 000000000..9f3677818 --- /dev/null +++ b/node_modules/relateurl/lib/parse/index.js @@ -0,0 +1,58 @@ +"use strict"; + +var hrefInfo = require("./hrefInfo"); +var parseHost = require("./host"); +var parsePath = require("./path"); +var parsePort = require("./port"); +var parseQuery = require("./query"); +var parseUrlString = require("./urlstring"); +var pathUtils = require("../util/path"); + + + +function parseFromUrl(url, options, fallback) +{ + if (url) + { + var urlObj = parseUrl(url, options); + + // Because the following occurs in the relate stage for "to" URLs, + // such had to be mostly duplicated here + + var pathArray = pathUtils.resolveDotSegments(urlObj.path.absolute.array); + + urlObj.path.absolute.array = pathArray; + urlObj.path.absolute.string = "/" + pathUtils.join(pathArray); + + return urlObj; + } + else + { + return fallback; + } +} + + + +function parseUrl(url, options) +{ + var urlObj = parseUrlString(url, options); + + if (urlObj.valid===false) return urlObj; + + parseHost(urlObj, options); + parsePort(urlObj, options); + parsePath(urlObj, options); + parseQuery(urlObj, options); + hrefInfo(urlObj); + + return urlObj; +} + + + +module.exports = +{ + from: parseFromUrl, + to: parseUrl +}; diff --git a/node_modules/relateurl/lib/parse/path.js b/node_modules/relateurl/lib/parse/path.js new file mode 100644 index 000000000..093c00c69 --- /dev/null +++ b/node_modules/relateurl/lib/parse/path.js @@ -0,0 +1,100 @@ +"use strict"; + +function isDirectoryIndex(resource, options) +{ + var verdict = false; + + options.directoryIndexes.every( function(index) + { + if (index === resource) + { + verdict = true; + return false; + } + + return true; + }); + + return verdict; +} + + + +function parsePath(urlObj, options) +{ + var path = urlObj.path.absolute.string; + + if (path) + { + var lastSlash = path.lastIndexOf("/"); + + if (lastSlash > -1) + { + if (++lastSlash < path.length) + { + var resource = path.substr(lastSlash); + + if (resource!=="." && resource!=="..") + { + urlObj.resource = resource; + path = path.substr(0, lastSlash); + } + else + { + path += "/"; + } + } + + urlObj.path.absolute.string = path; + urlObj.path.absolute.array = splitPath(path); + } + else if (path==="." || path==="..") + { + // "..?var", "..#anchor", etc ... not "..index.html" + path += "/"; + + urlObj.path.absolute.string = path; + urlObj.path.absolute.array = splitPath(path); + } + else + { + // Resource-only + urlObj.resource = path; + urlObj.path.absolute.string = null; + } + + urlObj.extra.resourceIsIndex = isDirectoryIndex(urlObj.resource, options); + } + // Else: query/hash-only or empty +} + + + +function splitPath(path) +{ + // TWEAK :: condition only for speed optimization + if (path !== "/") + { + var cleaned = []; + + path.split("/").forEach( function(dir) + { + // Cleanup -- splitting "/dir/" becomes ["","dir",""] + if (dir !== "") + { + cleaned.push(dir); + } + }); + + return cleaned; + } + else + { + // Faster to skip the above block and just create an array + return []; + } +} + + + +module.exports = parsePath; diff --git a/node_modules/relateurl/lib/parse/port.js b/node_modules/relateurl/lib/parse/port.js new file mode 100644 index 000000000..8c4ee2e84 --- /dev/null +++ b/node_modules/relateurl/lib/parse/port.js @@ -0,0 +1,32 @@ +"use strict"; + +function parsePort(urlObj, options) +{ + var defaultPort = -1; + + for (var i in options.defaultPorts) + { + if ( i===urlObj.scheme && options.defaultPorts.hasOwnProperty(i) ) + { + defaultPort = options.defaultPorts[i]; + break; + } + } + + if (defaultPort > -1) + { + // Force same type as urlObj.port + defaultPort = defaultPort.toString(); + + if (urlObj.port === null) + { + urlObj.port = defaultPort; + } + + urlObj.extra.portIsDefault = (urlObj.port === defaultPort); + } +} + + + +module.exports = parsePort; diff --git a/node_modules/relateurl/lib/parse/query.js b/node_modules/relateurl/lib/parse/query.js new file mode 100644 index 000000000..dbb85045c --- /dev/null +++ b/node_modules/relateurl/lib/parse/query.js @@ -0,0 +1,53 @@ +"use strict"; +var hasOwnProperty = Object.prototype.hasOwnProperty; + + + +function parseQuery(urlObj, options) +{ + urlObj.query.string.full = stringify(urlObj.query.object, false); + + // TWEAK :: condition only for speed optimization + if (options.removeEmptyQueries) + { + urlObj.query.string.stripped = stringify(urlObj.query.object, true); + } +} + + + +function stringify(queryObj, removeEmptyQueries) +{ + var count = 0; + var str = ""; + + for (var i in queryObj) + { + if ( i!=="" && hasOwnProperty.call(queryObj, i)===true ) + { + var value = queryObj[i]; + + if (value !== "" || !removeEmptyQueries) + { + str += (++count===1) ? "?" : "&"; + + i = encodeURIComponent(i); + + if (value !== "") + { + str += i +"="+ encodeURIComponent(value).replace(/%20/g,"+"); + } + else + { + str += i; + } + } + } + } + + return str; +} + + + +module.exports = parseQuery; diff --git a/node_modules/relateurl/lib/parse/urlstring.js b/node_modules/relateurl/lib/parse/urlstring.js new file mode 100644 index 000000000..ca4d7d431 --- /dev/null +++ b/node_modules/relateurl/lib/parse/urlstring.js @@ -0,0 +1,146 @@ +"use strict"; + +var _parseUrl = require("url").parse; + + + +/* + Customize the URL object that Node generates + because: + + * necessary data for later + * urlObj.host is useless + * urlObj.hostname is too long + * urlObj.path is useless + * urlObj.pathname is too long + * urlObj.protocol is inaccurate; should be called "scheme" + * urlObj.search is mostly useless +*/ +function clean(urlObj) +{ + var scheme = urlObj.protocol; + + if (scheme) + { + // Remove ":" suffix + if (scheme.indexOf(":") === scheme.length-1) + { + scheme = scheme.substr(0, scheme.length-1); + } + } + + urlObj.host = + { + // TODO :: unescape(encodeURIComponent(s)) ? ... http://ecmanaut.blogspot.ca/2006/07/encoding-decoding-utf8-in-javascript.html + full: urlObj.hostname, + stripped: null + }; + + urlObj.path = + { + absolute: + { + array: null, + string: urlObj.pathname + }, + relative: + { + array: null, + string: null + } + }; + + urlObj.query = + { + object: urlObj.query, + string: + { + full: null, + stripped: null + } + }; + + urlObj.extra = + { + hrefInfo: + { + minimumPathOnly: null, + minimumResourceOnly: null, + minimumQueryOnly: null, + minimumHashOnly: null, + empty: null, + + separatorOnlyQuery: urlObj.search==="?" + }, + portIsDefault: null, + relation: + { + maximumScheme: null, + maximumAuth: null, + maximumHost: null, + maximumPort: null, + maximumPath: null, + maximumResource: null, + maximumQuery: null, + maximumHash: null, + + minimumScheme: null, + minimumAuth: null, + minimumHost: null, + minimumPort: null, + minimumPath: null, + minimumResource: null, + minimumQuery: null, + minimumHash: null, + + overridesQuery: null + }, + resourceIsIndex: null, + slashes: urlObj.slashes + }; + + urlObj.resource = null; + urlObj.scheme = scheme; + delete urlObj.hostname; + delete urlObj.pathname; + delete urlObj.protocol; + delete urlObj.search; + delete urlObj.slashes; + + return urlObj; +} + + + +function validScheme(url, options) +{ + var valid = true; + + options.rejectedSchemes.every( function(rejectedScheme) + { + valid = !(url.indexOf(rejectedScheme+":") === 0); + + // Break loop + return valid; + }); + + return valid; +} + + + +function parseUrlString(url, options) +{ + if ( validScheme(url,options) ) + { + return clean( _parseUrl(url, true, options.slashesDenoteHost) ); + } + else + { + return {href:url, valid:false}; + } +} + + + +module.exports = parseUrlString; diff --git a/node_modules/relateurl/lib/relate/absolutize.js b/node_modules/relateurl/lib/relate/absolutize.js new file mode 100644 index 000000000..2b535a59b --- /dev/null +++ b/node_modules/relateurl/lib/relate/absolutize.js @@ -0,0 +1,89 @@ +"use strict"; + +var findRelation = require("./findRelation"); +var objUtils = require("../util/object"); +var pathUtils = require("../util/path"); + + + +function absolutize(urlObj, siteUrlObj, options) +{ + findRelation.upToPath(urlObj, siteUrlObj, options); + + // Fill in relative URLs + if (urlObj.extra.relation.minimumScheme) urlObj.scheme = siteUrlObj.scheme; + if (urlObj.extra.relation.minimumAuth) urlObj.auth = siteUrlObj.auth; + if (urlObj.extra.relation.minimumHost) urlObj.host = objUtils.clone(siteUrlObj.host); + if (urlObj.extra.relation.minimumPort) copyPort(urlObj, siteUrlObj); + if (urlObj.extra.relation.minimumScheme) copyPath(urlObj, siteUrlObj); + + // Check remaining relativeness now that path has been copied and/or resolved + findRelation.pathOn(urlObj, siteUrlObj, options); + + // Fill in relative URLs + if (urlObj.extra.relation.minimumResource) copyResource(urlObj, siteUrlObj); + if (urlObj.extra.relation.minimumQuery) urlObj.query = objUtils.clone(siteUrlObj.query); + if (urlObj.extra.relation.minimumHash) urlObj.hash = siteUrlObj.hash; +} + + + +/* + Get an absolute path that's relative to site url. +*/ +function copyPath(urlObj, siteUrlObj) +{ + if (urlObj.extra.relation.maximumHost || !urlObj.extra.hrefInfo.minimumResourceOnly) + { + var pathArray = urlObj.path.absolute.array; + var pathString = "/"; + + // If not erroneous URL + if (pathArray) + { + // If is relative path + if (urlObj.extra.hrefInfo.minimumPathOnly && urlObj.path.absolute.string.indexOf("/")!==0) + { + // Append path to site path + pathArray = siteUrlObj.path.absolute.array.concat(pathArray); + } + + pathArray = pathUtils.resolveDotSegments(pathArray); + pathString += pathUtils.join(pathArray); + } + else + { + pathArray = []; + } + + urlObj.path.absolute.array = pathArray; + urlObj.path.absolute.string = pathString; + } + else + { + // Resource-, query- or hash-only or empty + urlObj.path = objUtils.clone(siteUrlObj.path); + } +} + + + +function copyPort(urlObj, siteUrlObj) +{ + urlObj.port = siteUrlObj.port; + + urlObj.extra.portIsDefault = siteUrlObj.extra.portIsDefault; +} + + + +function copyResource(urlObj, siteUrlObj) +{ + urlObj.resource = siteUrlObj.resource; + + urlObj.extra.resourceIsIndex = siteUrlObj.extra.resourceIsIndex; +} + + + +module.exports = absolutize; diff --git a/node_modules/relateurl/lib/relate/findRelation.js b/node_modules/relateurl/lib/relate/findRelation.js new file mode 100644 index 000000000..c5423c3c4 --- /dev/null +++ b/node_modules/relateurl/lib/relate/findRelation.js @@ -0,0 +1,79 @@ +"use strict"; + +function findRelation_upToPath(urlObj, siteUrlObj, options) +{ + // Path- or root-relative URL + var pathOnly = urlObj.extra.hrefInfo.minimumPathOnly; + + // Matching scheme, scheme-relative or path-only + var minimumScheme = (urlObj.scheme===siteUrlObj.scheme || !urlObj.scheme); + + // Matching auth, ignoring auth or path-only + var minimumAuth = minimumScheme && (urlObj.auth===siteUrlObj.auth || options.removeAuth || pathOnly); + + // Matching host or path-only + var www = options.ignore_www ? "stripped" : "full"; + var minimumHost = minimumAuth && (urlObj.host[www]===siteUrlObj.host[www] || pathOnly); + + // Matching port or path-only + var minimumPort = minimumHost && (urlObj.port===siteUrlObj.port || pathOnly); + + urlObj.extra.relation.minimumScheme = minimumScheme; + urlObj.extra.relation.minimumAuth = minimumAuth; + urlObj.extra.relation.minimumHost = minimumHost; + urlObj.extra.relation.minimumPort = minimumPort; + + urlObj.extra.relation.maximumScheme = !minimumScheme || minimumScheme && !minimumAuth; + urlObj.extra.relation.maximumAuth = !minimumScheme || minimumScheme && !minimumHost; + urlObj.extra.relation.maximumHost = !minimumScheme || minimumScheme && !minimumPort; +} + + + +function findRelation_pathOn(urlObj, siteUrlObj, options) +{ + var queryOnly = urlObj.extra.hrefInfo.minimumQueryOnly; + var hashOnly = urlObj.extra.hrefInfo.minimumHashOnly; + var empty = urlObj.extra.hrefInfo.empty; // not required, but self-documenting + + // From upToPath() + var minimumPort = urlObj.extra.relation.minimumPort; + var minimumScheme = urlObj.extra.relation.minimumScheme; + + // Matching port and path + var minimumPath = minimumPort && urlObj.path.absolute.string===siteUrlObj.path.absolute.string; + + // Matching resource or query/hash-only or empty + var matchingResource = (urlObj.resource===siteUrlObj.resource || !urlObj.resource && siteUrlObj.extra.resourceIsIndex) || (options.removeDirectoryIndexes && urlObj.extra.resourceIsIndex && !siteUrlObj.resource); + var minimumResource = minimumPath && (matchingResource || queryOnly || hashOnly || empty); + + // Matching query or hash-only/empty + var query = options.removeEmptyQueries ? "stripped" : "full"; + var urlQuery = urlObj.query.string[query]; + var siteUrlQuery = siteUrlObj.query.string[query]; + var minimumQuery = (minimumResource && !!urlQuery && urlQuery===siteUrlQuery) || ((hashOnly || empty) && !urlObj.extra.hrefInfo.separatorOnlyQuery); + + var minimumHash = minimumQuery && urlObj.hash===siteUrlObj.hash; + + urlObj.extra.relation.minimumPath = minimumPath; + urlObj.extra.relation.minimumResource = minimumResource; + urlObj.extra.relation.minimumQuery = minimumQuery; + urlObj.extra.relation.minimumHash = minimumHash; + + urlObj.extra.relation.maximumPort = !minimumScheme || minimumScheme && !minimumPath; + urlObj.extra.relation.maximumPath = !minimumScheme || minimumScheme && !minimumResource; + urlObj.extra.relation.maximumResource = !minimumScheme || minimumScheme && !minimumQuery; + urlObj.extra.relation.maximumQuery = !minimumScheme || minimumScheme && !minimumHash; + urlObj.extra.relation.maximumHash = !minimumScheme || minimumScheme && !minimumHash; // there's nothing after hash, so it's the same as maximumQuery + + // Matching path and/or resource with existing but non-matching site query + urlObj.extra.relation.overridesQuery = minimumPath && urlObj.extra.relation.maximumResource && !minimumQuery && !!siteUrlQuery; +} + + + +module.exports = +{ + pathOn: findRelation_pathOn, + upToPath: findRelation_upToPath +}; diff --git a/node_modules/relateurl/lib/relate/index.js b/node_modules/relateurl/lib/relate/index.js new file mode 100644 index 000000000..f90838181 --- /dev/null +++ b/node_modules/relateurl/lib/relate/index.js @@ -0,0 +1,18 @@ +"use strict"; + +var absolutize = require("./absolutize"); +var relativize = require("./relativize"); + + + +function relateUrl(siteUrlObj, urlObj, options) +{ + absolutize(urlObj, siteUrlObj, options); + relativize(urlObj, siteUrlObj, options); + + return urlObj; +} + + + +module.exports = relateUrl; diff --git a/node_modules/relateurl/lib/relate/relativize.js b/node_modules/relateurl/lib/relate/relativize.js new file mode 100644 index 000000000..9af9a1017 --- /dev/null +++ b/node_modules/relateurl/lib/relate/relativize.js @@ -0,0 +1,67 @@ +"use strict"; + +var pathUtils = require("../util/path"); + + + +/* + Get a path relative to the site path. +*/ +function relatePath(absolutePath, siteAbsolutePath) +{ + var relativePath = []; + + // At this point, it's related to the host/port + var related = true; + var parentIndex = -1; + + // Find parents + siteAbsolutePath.forEach( function(siteAbsoluteDir, i) + { + if (related) + { + if (absolutePath[i] !== siteAbsoluteDir) + { + related = false; + } + else + { + parentIndex = i; + } + } + + if (!related) + { + // Up one level + relativePath.push(".."); + } + }); + + // Form path + absolutePath.forEach( function(dir, i) + { + if (i > parentIndex) + { + relativePath.push(dir); + } + }); + + return relativePath; +} + + + +function relativize(urlObj, siteUrlObj, options) +{ + if (urlObj.extra.relation.minimumScheme) + { + var pathArray = relatePath(urlObj.path.absolute.array, siteUrlObj.path.absolute.array); + + urlObj.path.relative.array = pathArray; + urlObj.path.relative.string = pathUtils.join(pathArray); + } +} + + + +module.exports = relativize; diff --git a/node_modules/relateurl/lib/util/devlog.js b/node_modules/relateurl/lib/util/devlog.js new file mode 100644 index 000000000..086bdc946 --- /dev/null +++ b/node_modules/relateurl/lib/util/devlog.js @@ -0,0 +1,25 @@ +"use strict"; + +var inspect = require("util").inspect; + + + +function log(data) +{ + console.log( inspect(data, {depth:null, colors:true}) ); +} + + + +function logAll(data) +{ + console.log( inspect(data, {depth:null, showHidden:true, colors:true}) ); +} + + + +module.exports = +{ + log: log, + logAll: logAll +}; diff --git a/node_modules/relateurl/lib/util/object.js b/node_modules/relateurl/lib/util/object.js new file mode 100644 index 000000000..8eab7940e --- /dev/null +++ b/node_modules/relateurl/lib/util/object.js @@ -0,0 +1,64 @@ +"use strict"; + +/* + Deep-clone an object. +*/ +function clone(obj) +{ + if (obj instanceof Object) + { + var clonedObj = (obj instanceof Array) ? [] : {}; + + for (var i in obj) + { + if ( obj.hasOwnProperty(i) ) + { + clonedObj[i] = clone( obj[i] ); + } + } + + return clonedObj; + } + + return obj; +} + + + +/* + https://github.com/jonschlinkert/is-plain-object +*/ +function isPlainObject(obj) +{ + return !!obj && typeof obj==="object" && obj.constructor===Object; +} + + + +/* + Shallow-merge two objects. +*/ +function shallowMerge(target, source) +{ + if (target instanceof Object && source instanceof Object) + { + for (var i in source) + { + if ( source.hasOwnProperty(i) ) + { + target[i] = source[i]; + } + } + } + + return target; +} + + + +module.exports = +{ + clone: clone, + isPlainObject: isPlainObject, + shallowMerge: shallowMerge +}; diff --git a/node_modules/relateurl/lib/util/path.js b/node_modules/relateurl/lib/util/path.js new file mode 100644 index 000000000..f1e9d1193 --- /dev/null +++ b/node_modules/relateurl/lib/util/path.js @@ -0,0 +1,49 @@ +"use strict"; + +function joinPath(pathArray) +{ + if (pathArray.length > 0) + { + return pathArray.join("/") + "/"; + } + else + { + return ""; + } +} + + + +function resolveDotSegments(pathArray) +{ + var pathAbsolute = []; + + pathArray.forEach( function(dir) + { + if (dir !== "..") + { + if (dir !== ".") + { + pathAbsolute.push(dir); + } + } + else + { + // Remove parent + if (pathAbsolute.length > 0) + { + pathAbsolute.splice(pathAbsolute.length-1, 1); + } + } + }); + + return pathAbsolute; +} + + + +module.exports = +{ + join: joinPath, + resolveDotSegments: resolveDotSegments +}; diff --git a/node_modules/relateurl/license b/node_modules/relateurl/license new file mode 100644 index 000000000..b760007ae --- /dev/null +++ b/node_modules/relateurl/license @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Steven Vachon <contact@svachon.com> (svachon.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/node_modules/relateurl/package.json b/node_modules/relateurl/package.json new file mode 100644 index 000000000..f4b236a7e --- /dev/null +++ b/node_modules/relateurl/package.json @@ -0,0 +1,46 @@ +{ + "name": "relateurl", + "description": "Minify URLs by converting them from absolute to relative.", + "version": "0.2.7", + "license": "MIT", + "homepage": "https://github.com/stevenvachon/relateurl", + "author": { + "name": "Steven Vachon", + "email": "contact@svachon.com", + "url": "http://www.svachon.com/" + }, + "main": "lib", + "repository": { + "type": "git", + "url": "git://github.com/stevenvachon/relateurl.git" + }, + "bugs": { + "url": "https://github.com/stevenvachon/relateurl/issues" + }, + "devDependencies": { + "browserify": "^13.0.1", + "chai": "^3.5.0", + "mocha": "^2.5.3", + "uglify-js": "^2.7.0" + }, + "engines": { + "node": ">= 0.10" + }, + "scripts": { + "browserify": "browserify lib/ --standalone RelateUrl | uglifyjs --compress --mangle -o relateurl-browser.js", + "test": "mocha test/ --bail --reporter spec --check-leaks" + }, + "files": [ + "lib", + "license" + ], + "keywords": [ + "uri", + "url", + "minifier", + "minify", + "lint", + "relative", + "absolute" + ] +} |