mirror of
https://github.com/shivammathur/setup-php.git
synced 2024-11-26 13:23:05 +07:00
444 lines
11 KiB
JavaScript
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;
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|