setup-php/node_modules/urlgrey/index.js
2019-09-20 21:54:46 +05:30

444 lines
11 KiB
JavaScript

var urlParse = require('url').parse;
var querystring = require('querystring');
var isBrowser = (typeof window !== "undefined");
var getDefaults = function(){
var defaultUrl = "http://localhost:80";
if (isBrowser){
defaultUrl = window.location.href.toString();
}
var defaults = urlParse(defaultUrl);
return defaults;
};
if (!Array.isArray) {
Array.isArray = function (arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
var objectEach = function(obj, cb){
for (var k in obj){
if (Object.prototype.hasOwnProperty.call(obj, k)) {
cb(obj[k], k);
}
}
};
var argsArray = function(obj){
if (!obj) { return []; }
if (Array.isArray(obj)) { return obj.slice() ; }
var args = [];
objectEach(obj, function(v, k){
args[k] = v;
});
return args;
};
var arrLast = function(arr){
return arr[arr.length-1];
};
var arrFlatten = function(input, output) {
if (!output) { output = []; }
for (var i = 0; i < input.length; i++){
var value = input[i];
if (Array.isArray(value)) {
arrFlatten(value, output);
} else {
output.push(value);
}
}
return output;
};
var UrlGrey = function(url){
if (!url && isBrowser){
url = window.location.href.toString();
}
this.url = url;
this._parsed = null;
};
UrlGrey.prototype.parsed = function(){
if (!this._parsed){
this._parsed = urlParse(this.url);
var defaults = getDefaults();
var p = this._parsed;
p.protocol = p.protocol || defaults.protocol;
p.protocol = p.protocol.slice(0,-1);
if (p.hash){
p.hash = p.hash.substring(1);
}
p.username = '';
p.password = '';
if (p.protocol !== 'file'){
p.port = parseInt(p.port, 10);
if (p.auth){
var auth = p.auth.split(':');
p.username = auth[0];
p.password = auth[1];
}
}
if (isBrowser){
p.hostname = p.hostname || defaults.hostname;
}
}
// enforce only returning these properties
this._parsed = {
protocol : this._parsed.protocol,
auth: this._parsed.auth,
host: this._parsed.host,
port: this._parsed.port,
hostname: this._parsed.hostname,
hash: this._parsed.hash,
search: this._parsed.search,
query: this._parsed.query,
pathname: this._parsed.pathname,
path: this._parsed.path,
href: this._parsed.href,
username: this._parsed.username,
password: this._parsed.password
};
return this._parsed;
};
UrlGrey.prototype.extendedPath = function(url){
if (url){
var p = urlParse(url);
var obj = new UrlGrey(this.toString());
if (p.hash){
p.hash = p.hash.substring(1);
}
obj.parsed().hash = p.hash;
obj.parsed().query = p.query;
obj = obj.path(p.pathname);
return obj;
} else {
var href = this.path();
href += this.queryString() ? '?' + this.queryString() : '';
href += this.hash() ? '#' + this.hash() : '';
return href;
}
};
UrlGrey.prototype.port = function(num){
var hostname = this.parsed().hostname;
// setter
if (num){
if (this.protocol() === 'file'){
throw new Error("file urls don't have ports");
}
var obj = new UrlGrey(this.toString());
obj.parsed().port = parseInt(num, 10);
return obj;
}
// getter
var output = this._parsed.port;
if (!output){
switch(this.protocol()){
case 'http' : return 80;
case 'https' : return 443;
default : return null;
}
}
return parseInt(output, 10);
};
UrlGrey.prototype.query = function(mergeObject){
if (arguments.length === 0) {
return querystring.parse(this.queryString());
} else if (mergeObject === null || mergeObject === false){
return this.queryString('');
} else {
// read the object out
var oldQuery = querystring.parse(this.queryString());
objectEach(mergeObject, function(v, k){
if (v === null || v === false){
delete oldQuery[k];
} else {
oldQuery[k] = v;
}
});
var newString = querystring.stringify(oldQuery);
var ret = this.queryString(newString);
return ret;
}
};
UrlGrey.prototype.rawQuery = function(mergeObject){
if (arguments.length === 0) {
if (this.queryString().length === 0) { return {}; }
return this.queryString().split("&").reduce(function(obj, pair) {
pair = pair.split("=");
var key = pair[0];
var val = pair[1];
obj[key] = val;
return obj;
}, {});
} else if (mergeObject === null || mergeObject === false){
return this.queryString('');
} else {
// read the object out
var oldQuery = querystring.parse(this.queryString());
objectEach(mergeObject, function(v, k){
if (v === null){
delete oldQuery[k];
} else {
oldQuery[k] = v;
}
});
var pairs = [];
objectEach(oldQuery, function(v, k){
pairs.push(k + '=' + v);
});
var newString = pairs.join('&');
return this.queryString(newString);
}
};
addPropertyGetterSetter('protocol');
addPropertyGetterSetter('username');
addPropertyGetterSetter('password');
addPropertyGetterSetter('hostname');
addPropertyGetterSetter('hash');
// add a method called queryString that manipulates 'query'
addPropertyGetterSetter('query', 'queryString');
addPropertyGetterSetter('pathname', 'path');
UrlGrey.prototype.path = function(){
var args = arrFlatten(argsArray(arguments));
if (args.length !== 0){
var obj = new UrlGrey(this.toString());
var str = args.join('/');
str = str.replace(/\/+/g, '/'); // remove double slashes
str = str.replace(/\/$/, ''); // remove all trailing slashes
args = str.split('/');
for(var i = 0; i < args.length; i++){
args[i] = this.encode(args[i]);
}
str = args.join('/');
if (str[0] !== '/'){ str = '/' + str; }
obj.parsed().pathname = str;
return obj;
}
return this.parsed().pathname;
};
UrlGrey.prototype.rawPath = function(){
var args = arrFlatten(argsArray(arguments));
if (args.length !== 0){
var obj = new UrlGrey(this.toString());
var str = args.join('/');
str = str.replace(/\/+/g, '/'); // remove double slashes
str = str.replace(/\/$/, ''); // remove all trailing slashes
if (str[0] !== '/'){ str = '/' + str; }
obj.parsed().pathname = str;
return obj;
}
return this.parsed().pathname;
};
UrlGrey.prototype.encode = function(str){
try {
return encodeURIComponent(str);
} catch (ex) {
return querystring.escape(str);
}
};
UrlGrey.prototype.decode = function(str){
return decode(str);
};
UrlGrey.prototype.parent = function(){
// read-only. (can't SET parent)
var pieces = this.path().split("/");
var popped = pieces.pop();
if (popped === ''){ // ignore trailing slash
popped = pieces.pop();
}
if (!popped){
throw new Error("The current path has no parent path");
}
return this.query(false).hash('').path(pieces.join("/"));
};
UrlGrey.prototype.rawChild = function(suffixes){
if (suffixes){
suffixes = argsArray(arguments);
return this.query(false).hash('').rawPath(this.path(), suffixes);
} else {
// if no suffix, return the child
var pieces = this.path().split("/");
var last = arrLast(pieces);
if ((pieces.length > 1) && (last === '')){
// ignore trailing slashes
pieces.pop();
last = arrLast(pieces);
}
return last;
}
};
UrlGrey.prototype.child = function(suffixes){
suffixes = argsArray(arguments);
if (suffixes.length > 0){
return this.query(false).hash('').path(this.path(), suffixes);
}
// if no suffix, return the child
var pieces = pathPieces(this.path());
var last = arrLast(pieces);
if ((pieces.length > 1) && (last === '')){
// ignore trailing slashes
pieces.pop();
last = arrLast(pieces);
}
return last;
};
UrlGrey.prototype.toJSON = function(){
return this.toString();
};
UrlGrey.prototype.toString = function(){
var p = this.parsed();
var retval = this.protocol() + '://';
if (this.protocol() !== 'file'){
var userinfo = p.username + ':' + p.password;
if (userinfo !== ':'){
retval += userinfo + '@';
}
retval += p.hostname;
var port = portString(this);
if (port !== ''){
retval += ':' + port;
}
}
retval += this.path() === '/' ? '' : this.path();
var qs = this.queryString();
if (qs){
retval += '?' + qs;
}
if (p.hash){
retval += '#' + p.hash;
}
return retval;
};
var pathPieces = function(path){
var pieces = path.split('/');
for(var i = 0; i < pieces.length; i++){
pieces[i] = decode(pieces[i]);
}
return pieces;
};
var decode = function(str){
try {
return decodeURIComponent(str);
} catch (ex) {
return querystring.unescape(str);
}
};
var portString = function(o){
if (o.protocol() === 'https'){
if (o.port() === 443){
return '';
}
}
if (o.protocol() === 'http'){
if (o.port() === 80){
return '';
}
}
return '' + o.port();
};
/*
UrlGrey.prototype.absolute = function(path){
if (path[0] == '/'){
path = path.substring(1);
}
var parsed = urlParse(path);
if (!!parsed.protocol){ // if it's already absolute, just return it
return path;
}
return this._protocol + "://" + this._host + '/' + path;
};
// TODO make this interpolate vars into the url. both sinatra style and url-tempates
// TODO name this:
UrlGrey.prototype.get = function(nameOrPath, varDict){
if (!!nameOrPath){
if (!!varDict){
return this.absolute(this._router.getUrl(nameOrPath, varDict));
}
return this.absolute(this._router.getUrl(nameOrPath));
}
return this.url;
};*/
/*
// TODO needs to take a template as an input
UrlGrey.prototype.param = function(key, defaultValue){
var value = this.params()[key];
if (!!value) {
return value;
}
return defaultValue;
};
// TODO extract params, given a template?
// TODO needs to take a template as an input
UrlGrey.prototype.params = function(inUrl){
if (!!inUrl){
return this._router.pathVariables(inUrl);
}
if (!!this._params){
return this._params;
}
return this._router.pathVariables(this.url);
};
*/
// TODO relative() // takes an absolutepath and returns a relative one
// TODO absolute() // takes a relative path and returns an absolute one.
module.exports = function(url){ return new UrlGrey(url); };
function addPropertyGetterSetter(propertyName, methodName){
if (!methodName){
methodName = propertyName;
}
UrlGrey.prototype[methodName] = function(str){
if (!str && str !== "") {
return this.parsed()[propertyName];
} else {
var obj = new UrlGrey(this.toString());
obj.parsed()[propertyName] = str;
return obj;
}
};
}