Skip to content

Commit

Permalink
refactoring static members
Browse files Browse the repository at this point in the history
  • Loading branch information
vitaly-t committed Aug 29, 2019
1 parent 806d287 commit cde44a6
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 70 deletions.
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export {ConnectionString} from './main';
export {IConnectionDefaults} from './types';
export {IConnectionDefaults, IEncodingOptions, HostType, IHost, IParsedHost} from './types';
134 changes: 67 additions & 67 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export class ConnectionString {
user?: string;
password?: string;
path?: string[];
params?: { [name: string]: string };
params?: { [name: string]: any };

/**
* Virtualized accessor to the first host name.
Expand Down Expand Up @@ -42,7 +42,7 @@ export class ConnectionString {

cs = cs.trim();

ConnectionString.validateUrl(cs);
validateUrl(cs);

// Extracting the protocol:
let m = cs.match(/^[\w-_.+!*'()$%:]*:\/\//);
Expand Down Expand Up @@ -74,7 +74,7 @@ export class ConnectionString {
const hosts = (endOfHosts === -1 ? cs : cs.substr(0, endOfHosts)).split(',');

hosts.forEach(h => {
const host = ConnectionString.parseInnerHost(h);
const host = parseHost(h);
if (host) {
if (!this.hosts) {
this.hosts = [];
Expand Down Expand Up @@ -119,70 +119,8 @@ export class ConnectionString {

}

private static validateUrl(url: string): void {
const idx = url.search(/[^A-Za-z0-9-._~:/?[\]@!$&'()*+,;=%]/);
if (idx >= 0) {
const s = JSON.stringify(url[idx]).replace(/^"|"$/g, '\'');
throw new Error('Invalid URL character ' + s + ' at position ' + idx);
}
}

static parseHost(host: string): IParsedHost | null {
return ConnectionString.parseInnerHost(host, true);
}

private static parseInnerHost(host: string, raw?: boolean): IParsedHost | null {
if (raw) {
if (typeof host !== 'string') {
throw new TypeError('Invalid "host" parameter: ' + JSON.stringify(host));
}
host = host.trim();
}
let m, isIPv6;
if (host[0] === '[') {
// This is IPv6, with [::] being the shortest possible
m = host.match(/((\[[0-9a-z:%]{2,45}])(?::(-?[0-9a-z]+))?)/i);
isIPv6 = true;
} else {
// It is either IPv4 or domain/socket
if (raw) {
m = host.match(/(([a-z0-9.$/-]*)(?::(-?[0-9a-z]+))?)/i);
} else {
m = host.match(/(([a-z0-9.$%-]*)(?::(-?[0-9a-z]+))?)/i);
}
}
if (m) {
const h: IHost = {};
if (m[2]) {
if (isIPv6) {
h.name = m[2];
h.type = HostType.IPv6;
} else {
if (m[2].match(/([0-9]{1,3}\.){3}[0-9]{1,3}/)) {
h.name = m[2];
h.type = HostType.IPv4;
} else {
h.name = raw ? m[2] : decode(m[2]);
h.type = h.name.match(/\/|.*\.sock$/i) ? HostType.socket : HostType.domain;
}
}
}
if (m[3]) {
const p = m[3], port = parseInt(p);
if (port > 0 && port < 65536 && port.toString() === p) {
h.port = port;
} else {
throw new Error('Invalid port number: ' + JSON.stringify(p));
}
}
if (h.name || h.port) {
Object.defineProperty(h, 'toString', {
value: (options: IEncodingOptions) => fullHostName(h, options)
});
return h;
}
}
return null;
return parseHost(host, true);
}

toString(options?: IEncodingOptions): string {
Expand Down Expand Up @@ -269,7 +207,7 @@ export class ConnectionString {
obj.name = h.name;
obj.type = h.type;
} else {
const t = ConnectionString.parseInnerHost(h.name, true);
const t = parseHost(h.name, true);
if (t) {
obj.name = t.name;
obj.type = t.type;
Expand Down Expand Up @@ -332,6 +270,68 @@ export class ConnectionString {
}
}

function validateUrl(url: string): void {
const idx = url.search(/[^A-Za-z0-9-._~:/?[\]@!$&'()*+,;=%]/);
if (idx >= 0) {
const s = JSON.stringify(url[idx]).replace(/^"|"$/g, '\'');
throw new Error('Invalid URL character ' + s + ' at position ' + idx);
}
}

function parseHost(host: string, raw?: boolean): IParsedHost | null {
if (raw) {
if (typeof host !== 'string') {
throw new TypeError('Invalid "host" parameter: ' + JSON.stringify(host));
}
host = host.trim();
}
let m, isIPv6;
if (host[0] === '[') {
// This is IPv6, with [::] being the shortest possible
m = host.match(/((\[[0-9a-z:%]{2,45}])(?::(-?[0-9a-z]+))?)/i);
isIPv6 = true;
} else {
// It is either IPv4 or domain/socket
if (raw) {
m = host.match(/(([a-z0-9.$/-]*)(?::(-?[0-9a-z]+))?)/i);
} else {
m = host.match(/(([a-z0-9.$%-]*)(?::(-?[0-9a-z]+))?)/i);
}
}
if (m) {
const h: IHost = {};
if (m[2]) {
if (isIPv6) {
h.name = m[2];
h.type = HostType.IPv6;
} else {
if (m[2].match(/([0-9]{1,3}\.){3}[0-9]{1,3}/)) {
h.name = m[2];
h.type = HostType.IPv4;
} else {
h.name = raw ? m[2] : decode(m[2]);
h.type = h.name.match(/\/|.*\.sock$/i) ? HostType.socket : HostType.domain;
}
}
}
if (m[3]) {
const p = m[3], port = parseInt(p);
if (port > 0 && port < 65536 && port.toString() === p) {
h.port = port;
} else {
throw new Error('Invalid port number: ' + JSON.stringify(p));
}
}
if (h.name || h.port) {
Object.defineProperty(h, 'toString', {
value: (options: IEncodingOptions) => fullHostName(h, options)
});
return h;
}
}
return null;
}

(function () {
// hiding prototype members:
['setDefaults', 'toString', 'hostname', 'port'].forEach(prop => {
Expand Down
3 changes: 1 addition & 2 deletions test/main.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {expect} from './header';
import {ConnectionString, IConnectionDefaults} from '../src';
import {HostType, IHost, IParsedHost} from '../src/types';
import {ConnectionString, IConnectionDefaults, HostType, IHost, IParsedHost} from '../src';

function parse(cs: string, defaults?: IConnectionDefaults): ConnectionString {
return new ConnectionString(cs, defaults);
Expand Down

0 comments on commit cde44a6

Please sign in to comment.