connection-string
Version:
Advanced URL Connection String parser + generator.
323 lines (322 loc) • 12.7 kB
JavaScript
;
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConnectionString = void 0;
var types_1 = require("./types");
var static_1 = require("./static");
var inspect_1 = require("./inspect");
var errInvalidDefaults = "Invalid \"defaults\" parameter: ";
var ConnectionString = /** @class */ (function () {
/**
* Constructor.
*
* @param cs - connection string (can be empty).
*
* @param defaults - optional defaults, which can also be set
* explicitly, via method setDefaults.
*/
function ConnectionString(cs, defaults) {
var _this = this;
if (!(this instanceof ConnectionString)) {
throw new TypeError("Class constructor ConnectionString cannot be invoked without 'new'");
}
cs = cs !== null && cs !== void 0 ? cs : '';
if (typeof cs !== 'string') {
throw new TypeError("Invalid connection string: ".concat(JSON.stringify(cs)));
}
if (typeof (defaults !== null && defaults !== void 0 ? defaults : {}) !== 'object') {
throw new TypeError(errInvalidDefaults + JSON.stringify(defaults));
}
cs = cs.trim();
(0, static_1.validateUrl)(cs); // will throw, if failed
// Extracting the protocol:
var m = cs.match(/^(.*)?:\/\//);
if (m) {
var p = m[1]; // protocol name
if (p) {
var m2 = p.match(/^([a-z]+[a-z0-9+-.:]*)/i);
if (p && (!m2 || m2[1] !== p)) {
throw new Error("Invalid protocol name: ".concat(p));
}
this.protocol = p;
}
cs = cs.substring(m[0].length);
}
// Extracting user + password:
m = cs.match(/^([\w-_.+!*'()$%]*):?([\w-_.+!*'()$%~]*)@/);
if (m) {
if (m[1]) {
this.user = (0, static_1.decode)(m[1]);
}
if (m[2]) {
this.password = (0, static_1.decode)(m[2]);
}
cs = cs.substring(m[0].length);
}
// Extracting hosts details:
// (if it starts with `/`, it is the first path segment, i.e. no hosts specified)
if (cs[0] !== '/') {
var endOfHosts = cs.search(/[\/?]/);
var hosts = (endOfHosts === -1 ? cs : cs.substring(0, endOfHosts)).split(',');
hosts.forEach(function (h) {
var host = (0, static_1.parseHost)(h);
if (host) {
if (!_this.hosts) {
_this.hosts = [];
}
_this.hosts.push(host);
}
});
if (endOfHosts >= 0) {
cs = cs.substring(endOfHosts);
}
}
// Extracting the path:
m = cs.match(/\/([\w-_.+!*'()$%]+)/g);
if (m) {
this.path = m.map(function (s) { return (0, static_1.decode)(s.substring(1)); });
}
// Extracting parameters:
var idx = cs.indexOf('?');
if (idx !== -1) {
cs = cs.substring(idx + 1);
m = cs.match(/([\w-_.+!*'()$%]+)=([\w-_.+!*'()$%,]+)/g);
if (m) {
var params_1 = {};
m.forEach(function (s) {
var _a;
var a = s.split('=');
var prop = (0, static_1.decode)(a[0]);
var val = a[1].split(',').map(static_1.decode);
if (prop in params_1) {
if (Array.isArray(params_1[prop])) {
(_a = params_1[prop]).push.apply(_a, val);
}
else {
params_1[prop] = __spreadArray([params_1[prop]], val, true);
}
}
else {
params_1[prop] = val.length > 1 ? val : val[0];
}
});
this.params = params_1;
}
}
if (defaults) {
this.setDefaults(defaults);
}
}
Object.defineProperty(ConnectionString.prototype, "host", {
/**
* Safe read-accessor to the first host's full name (hostname + port).
*/
get: function () {
var _a;
return (_a = this.hosts) === null || _a === void 0 ? void 0 : _a[0].toString();
},
enumerable: false,
configurable: true
});
Object.defineProperty(ConnectionString.prototype, "hostname", {
/**
* Safe read-accessor to the first host's name (without port).
*/
get: function () {
var _a;
return (_a = this.hosts) === null || _a === void 0 ? void 0 : _a[0].name;
},
enumerable: false,
configurable: true
});
Object.defineProperty(ConnectionString.prototype, "port", {
/**
* Safe read-accessor to the first host's port.
*/
get: function () {
var _a;
return (_a = this.hosts) === null || _a === void 0 ? void 0 : _a[0].port;
},
enumerable: false,
configurable: true
});
Object.defineProperty(ConnectionString.prototype, "type", {
/**
* Safe read-accessor to the first host's type.
*/
get: function () {
var _a;
return (_a = this.hosts) === null || _a === void 0 ? void 0 : _a[0].type;
},
enumerable: false,
configurable: true
});
/**
* Parses a host name into an object, which then can be passed into `setDefaults`.
*
* It returns `null` only when no valid host recognized.
*/
ConnectionString.parseHost = function (host) {
return (0, static_1.parseHost)(host, true);
};
/**
* Converts this object into a valid connection string.
*/
ConnectionString.prototype.toString = function (options) {
var s = this.protocol ? "".concat(this.protocol, "://") : "";
var opts = options || {};
if (this.user || this.password) {
if (this.user) {
s += (0, static_1.encode)(this.user, opts);
}
if (this.password) {
s += ':';
var h = opts.passwordHash;
if (h) {
var code = (typeof h === 'string' && h[0]) || '#';
s += code.repeat(this.password.length);
}
else {
s += (0, static_1.encode)(this.password, opts);
}
}
s += '@';
}
if (Array.isArray(this.hosts)) {
s += this.hosts.map(function (h) { return (0, static_1.fullHostName)(h, options); }).join();
}
if (Array.isArray(this.path)) {
this.path.forEach(function (seg) {
s += "/".concat((0, static_1.encode)(seg, opts));
});
}
if (this.params && typeof this.params === 'object') {
var params = [];
for (var a in this.params) {
var value = this.params[a];
value = Array.isArray(value) ? value : [value];
value = value.map(function (v) {
return (0, static_1.encode)(typeof v === 'string' ? v : JSON.stringify(v), opts);
}).join();
if (opts.plusForSpace) {
value = value.replace(/%20/g, '+');
}
params.push("".concat((0, static_1.encode)(a, opts), "=").concat(value));
}
if (params.length) {
s += "?".concat(params.join('&'));
}
}
return s;
};
/**
* Applies default parameters, and returns itself.
*/
ConnectionString.prototype.setDefaults = function (defaults) {
if (!defaults || typeof defaults !== 'object') {
throw new TypeError(errInvalidDefaults + JSON.stringify(defaults));
}
if (!('protocol' in this) && (0, static_1.hasText)(defaults.protocol)) {
this.protocol = defaults.protocol && defaults.protocol.trim();
}
// Missing default `hosts` are merged with the existing ones:
if (Array.isArray(defaults.hosts)) {
var hosts_1 = Array.isArray(this.hosts) ? this.hosts : [];
var dhHosts = defaults.hosts.filter(function (d) { return d && typeof d === 'object'; });
dhHosts.forEach(function (dh) {
var dhName = (0, static_1.hasText)(dh.name) ? dh.name.trim() : undefined;
var h = { name: dhName, port: dh.port, type: dh.type };
var found = false;
for (var i = 0; i < hosts_1.length; i++) {
var thisHost = (0, static_1.fullHostName)(hosts_1[i]), defHost = (0, static_1.fullHostName)(h);
if (thisHost.toLowerCase() === defHost.toLowerCase()) {
found = true;
break;
}
}
if (!found) {
var obj_1 = {};
if (h.name) {
if (h.type && h.type in types_1.HostType) {
obj_1.name = h.name;
obj_1.type = h.type;
}
else {
var t = (0, static_1.parseHost)(h.name, true);
if (t) {
obj_1.name = t.name;
obj_1.type = t.type;
}
}
}
var p = h.port;
if (typeof p === 'number' && p > 0 && p < 65536) {
obj_1.port = p;
}
if (obj_1.name || obj_1.port) {
Object.defineProperty(obj_1, 'toString', {
value: function (options) { return (0, static_1.fullHostName)(obj_1, options); }
});
hosts_1.push(obj_1);
}
}
});
if (hosts_1.length) {
this.hosts = hosts_1;
}
}
if (!('user' in this) && (0, static_1.hasText)(defaults.user)) {
this.user = defaults.user.trim();
}
if (!('password' in this) && (0, static_1.hasText)(defaults.password)) {
this.password = defaults.password.trim();
}
// Since the order of `path` segments is usually important, we set default
// `path` segments as they are, but only when they are missing completely:
if (!('path' in this) && Array.isArray(defaults.path)) {
var s = defaults.path.filter(static_1.hasText);
if (s.length) {
this.path = s;
}
}
// Missing default `params` are merged with the existing ones:
if (defaults.params && typeof defaults.params === 'object') {
var keys = Object.keys(defaults.params);
if (keys.length) {
if (this.params && typeof this.params === 'object') {
for (var a in defaults.params) {
if (!(a in this.params)) {
this.params[a] = defaults.params[a];
}
}
}
else {
this.params = {};
for (var b in defaults.params) {
this.params[b] = defaults.params[b];
}
}
}
}
return this;
};
return ConnectionString;
}());
exports.ConnectionString = ConnectionString;
(function () {
// hiding prototype methods, to keep the type signature clean:
['setDefaults', 'toString'].forEach(function (prop) {
var desc = Object.getOwnPropertyDescriptor(ConnectionString.prototype, prop);
desc.enumerable = false;
Object.defineProperty(ConnectionString.prototype, prop, desc);
});
(0, inspect_1.setupCustomInspect)(ConnectionString);
})();