url-assembler
Version:
Assemble urls from route-like templates (/path/:param)
165 lines (141 loc) • 4.54 kB
JavaScript
var extend = require('extend');
var url = require('url');
var qs = require('qs');
var selectUrlFields = require('./fields-to-keep');
module.exports = function (request) {
function UrlAssembler (baseUrlOrUrlAssembler) {
if(!(this instanceof UrlAssembler)) {
return new UrlAssembler(baseUrlOrUrlAssembler);
}
var query = {};
//For future to keep other configs
this._config = {
qsConfig: {}
};
this._query = addQueryParamTo(query);
this._prefix = '';
this.pathname = '';
this.getParsedQuery = clone.bind(null, query);
Object.defineProperty(this, '_requestModule', { value: request, writable: true });
if (baseUrlOrUrlAssembler instanceof UrlAssembler) {
initWithInstance(this, baseUrlOrUrlAssembler);
} else if (baseUrlOrUrlAssembler) {
initWithBaseUrl(this, baseUrlOrUrlAssembler);
}
}
function initWithBaseUrl (self, baseUrl) {
extend(self, selectUrlFields(url.parse(baseUrl)));
self._prefix = self.pathname;
if(self._prefix === '/') {
self._prefix = '';
self.pathname = '';
}
if(self.search && self.search.length > 1) {
var parsedQuery = qs.parse(self.search.substr(1))
self._query(parsedQuery)
}
}
function initWithInstance (self, instance) {
extend(self, selectUrlFields(instance));
self._prefix = instance._prefix;
self._config = instance._config;
self._query(instance.getParsedQuery());
self._requestModule = instance._requestModule;
}
var methods = UrlAssembler.prototype;
methods._chain = function () {
return new this.constructor(this);
};
methods.template = function (fragment) {
var chainable = this._chain();
chainable.pathname = this._prefix + encodeURI(fragment);
return chainable;
};
methods.qsConfig = function(config) {
var chainable = this._chain();
extend(chainable._config.qsConfig, config);
return chainable;
};
methods.segment = function (segment) {
var chainable = this._chain();
chainable.pathname = this.pathname + encodeURI(segment);
return chainable;
};
methods.toString = function toString () {
return url.format(this);
};
methods.valueOf = methods.toString;
methods.toJSON = methods.toString;
methods.query = function (param, value) {
var chainable = this._chain();
chainable._query(param, value);
return chainable;
};
methods.prefix = function prefix (prefix) {
var chainable = this._chain();
var pathToKeep = this.pathname.substr(this._prefix.length);
chainable._prefix = this._prefix + encodeURI(prefix);
chainable.pathname = chainable._prefix + pathToKeep;
return chainable;
};
methods.param = function param (key, value, strict) {
if (typeof key === 'object') {
return _multiParam(this, key, (value === true));
}
var chainable = this._chain();
var previous = this.pathname;
var symbol = ':' + key;
chainable.pathname = this.pathname.replace(symbol, encodeURIComponent(value));
if (!strict && chainable.pathname === previous) {
return chainable.query(key, value);
}
return chainable;
};
function _multiParam (chainable, hash, strict) {
for (var key in hash) {
chainable = chainable.param(key, hash[key], strict);
}
return chainable;
}
function addQueryParamTo (query) {
return function addQueryParam(key, value) {
if(!value && typeof key === 'object') {
addManyParameters(key);
} else {
addOneParameter(key, value)
}
this.search = qs.stringify(query, this._config.qsConfig);
}
function addManyParameters (hash) {
for (var key in hash) {
if (nullOrUndef(hash[key])) delete hash[key];
}
extend(true, query, hash);
}
function addOneParameter (key, value) {
if (!nullOrUndef(value)) {
query[key] = value;
}
}
}
Object.defineProperty(UrlAssembler.prototype, 'request', {
get: function () {
var request = this._requestModule;
if (request) {
return request.defaults({ uri: this.toString() });
} else {
throw Error('the "request" module was not found. You must have it installed to use this property');
}
},
set: function (newRequest) {
return this._requestModule = newRequest;
}
});
function nullOrUndef (value) {
return value === null || typeof value === 'undefined';
}
function clone (obj) {
return extend(true, {}, obj);
}
return UrlAssembler;
}