From a8a7ca9740d53e14456ad4417fc2b4cbaa344d8a Mon Sep 17 00:00:00 2001 From: Vitaly Tomilov Date: Fri, 7 Aug 2020 03:57:28 +0100 Subject: [PATCH 1/5] updating the package --- package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 844d186..ca1421b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "connection-string", - "version": "3.4.2", + "version": "4.0.0", "description": "Advanced URL Connection String parser + generator.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -39,15 +39,15 @@ }, "devDependencies": { "@types/chai": "4.2.12", - "@types/mocha": "8.0.0", - "@types/node": "14.0.25", + "@types/mocha": "8.0.1", + "@types/node": "14.0.27", "chai": "4.2.0", "coveralls": "3.1.0", - "mocha": "8.0.1", + "mocha": "8.1.1", "mocha-lcov-reporter": "1.3.0", "nyc": "15.1.0", "ts-node": "8.10.2", - "tslint": "6.1.2", + "tslint": "6.1.3", "typescript": "3.9.7" } } From 743e435adf792bda3574f3bf7fb233699d433e77 Mon Sep 17 00:00:00 2001 From: Vitaly Tomilov Date: Fri, 7 Aug 2020 03:59:28 +0100 Subject: [PATCH 2/5] package update --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index ca1421b..42194e2 100644 --- a/package.json +++ b/package.json @@ -34,8 +34,8 @@ }, "license": "MIT", "engines": { - "node": ">=4.5", - "npm": ">=2.15" + "node": ">=12", + "npm": ">=6" }, "devDependencies": { "@types/chai": "4.2.12", From e2a544e1abc74637765d6f28be32ec98d87ac865 Mon Sep 17 00:00:00 2001 From: Vitaly Tomilov Date: Fri, 7 Aug 2020 05:21:25 +0100 Subject: [PATCH 3/5] implementing #38 --- src/main.ts | 14 +++++--------- src/static.ts | 2 +- test/main.spec.ts | 18 ++++-------------- 3 files changed, 10 insertions(+), 24 deletions(-) diff --git a/src/main.ts b/src/main.ts index 9868df8..948b188 100644 --- a/src/main.ts +++ b/src/main.ts @@ -93,11 +93,10 @@ export class ConnectionString { validateUrl(cs); // will throw, if failed // Extracting the protocol: - let m = cs.match(/^[\w-_.+!*'()$%:]*:\/\//); + let m = cs.match(/^([a-z]+[a-z0-9+-.]*)?:\/\//i); if (m) { - const protocol = m[0].replace(/:\/\//, ''); - if (protocol) { - this.protocol = decode(protocol); + if (m[1]) { + this.protocol = m[1]; } cs = cs.substr(m[0].length); } @@ -180,12 +179,9 @@ export class ConnectionString { * Converts this object into a valid connection string. */ toString(options?: IEncodingOptions): string { - let s = ''; + let s = this.protocol ? `${this.protocol}://` : ``; const opts = options || {}; - if (this.protocol) { - s += encode(this.protocol, opts).replace(/%3A/g, ':') + '://'; - } if (this.user || this.password) { if (this.user) { s += encode(this.user, opts); @@ -239,7 +235,7 @@ export class ConnectionString { } if (!('protocol' in this) && hasText(defaults.protocol)) { - this.protocol = defaults.protocol!.trim(); + this.protocol = defaults.protocol?.trim(); } // Missing default `hosts` are merged with the existing ones: diff --git a/src/static.ts b/src/static.ts index 35d1f78..39e7b2a 100644 --- a/src/static.ts +++ b/src/static.ts @@ -29,7 +29,7 @@ export function hasText(txt?: string): boolean { } export function validateUrl(url: string): void { - const idx = url.search(/[^A-Za-z0-9-._:/?[\]@!$&'()*+,;=%]/); + const idx = url.search(/[^a-z0-9-._:/?[\]@!$&'()*+,;=%]/i); if (idx >= 0) { const s = JSON.stringify(url[idx]).replace(/^"|"$/g, `'`); throw new Error(`Invalid URL character ${s} at position ${idx}`); diff --git a/test/main.spec.ts b/test/main.spec.ts index f988945..427673d 100644 --- a/test/main.spec.ts +++ b/test/main.spec.ts @@ -91,19 +91,13 @@ describe('protocol', () => { it('must recognize standard format', () => { expect(parse('abc://')).to.eql({protocol: 'abc'}); }); - it('must allow sub-protocols', () => { - expect(parse('one:two:three://')).to.eql({protocol: 'one:two:three'}); + it('must allow special symbols', () => { + expect(parse('one+two-three.four://')).to.eql({protocol: 'one+two-three.four'}); }); it('must ignore incomplete format', () => { expect(parse('abc:/')).to.eql({hosts: [{name: 'abc', type: 'domain'}]}); expect(parse('://')).to.eql({}); }); - it('must decode URL-encoded characters', () => { - expect(parse('a%20b%3F://')).to.eql({protocol: 'a b?'}); - }); - it('must support special symbols', () => { - expect(parse('A9z$-_.+!*\'()://')).to.eql({protocol: 'A9z$-_. !*\'()'}); - }); }); describe('hosts', () => { @@ -394,10 +388,6 @@ describe('complex', () => { }); describe('toString', () => { - it('must encode protocol', () => { - expect(create({protocol: 'abc 123?456'})).to.eq('abc%20123%3F456://'); - expect(create({protocol: 'one:two:three'})).to.eq('one:two:three://'); - }); it('must encode user', () => { expect(create({user: 'user 1?2'})).to.eq('user%201%3F2@'); }); @@ -452,8 +442,8 @@ describe('toString', () => { expect(a.toString()).to.eq(''); }); it('must encode dollar symbol when required', () => { - expect(parse('abc%20$://user$:pa$$@host$name.com/seg$?par$=1$2').toString()).to.eq('abc%20$://user$:pa$$@host$name.com/seg$?par$=1$2'); - expect(parse('abc%20$://user$:pa$$@host$name.com/seg$?par$=1$2').toString({encodeDollar: true})).to.eq('abc%20%24://user%24:pa%24%24@host%24name.com/seg%24?par%24=1%242'); + expect(parse('abc://user$:pa$$@host$name.com/seg$?par$=1$2').toString()).to.eq('abc://user$:pa$$@host$name.com/seg$?par$=1$2'); + expect(parse('abc://user$:pa$$@host$name.com/seg$?par$=1$2').toString({encodeDollar: true})).to.eq('abc://user%24:pa%24%24@host%24name.com/seg%24?par%24=1%242'); }); it('must use plus for params when required', () => { expect(parse('?a=+1++2').toString()).to.eq('?a=%201%20%202'); From 2c23cdbda472b3f08b3ada4776c9bf29194d78eb Mon Sep 17 00:00:00 2001 From: Vitaly Tomilov Date: Sat, 8 Aug 2020 20:31:16 +0100 Subject: [PATCH 4/5] fixing typeof warnings --- src/main.ts | 2 +- src/static.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.ts b/src/main.ts index 948b188..d0eeec4 100644 --- a/src/main.ts +++ b/src/main.ts @@ -80,7 +80,7 @@ export class ConnectionString { cs = cs ?? ''; - if (typeof cs !== 'string') { + if (typeof cs as any !== 'string') { throw new TypeError(`Invalid connection string: ${JSON.stringify(cs)}`); } diff --git a/src/static.ts b/src/static.ts index 39e7b2a..a8d6ad1 100644 --- a/src/static.ts +++ b/src/static.ts @@ -38,7 +38,7 @@ export function validateUrl(url: string): void { export function parseHost(host: string, direct?: boolean): IParsedHost | null { if (direct) { - if (typeof host !== 'string') { + if (typeof host as any !== 'string') { throw new TypeError(`Invalid "host" parameter: ${JSON.stringify(host)}`); } host = host.trim(); From 8bf8b6f8560114f840a83ae870f381c2cadd80da Mon Sep 17 00:00:00 2001 From: Vitaly Tomilov Date: Sun, 9 Aug 2020 11:19:46 +0100 Subject: [PATCH 5/5] refactoring protocol --- src/main.ts | 11 ++++++++--- test/main.spec.ts | 18 +++++++++++++++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/main.ts b/src/main.ts index d0eeec4..1839463 100644 --- a/src/main.ts +++ b/src/main.ts @@ -93,10 +93,15 @@ export class ConnectionString { validateUrl(cs); // will throw, if failed // Extracting the protocol: - let m = cs.match(/^([a-z]+[a-z0-9+-.]*)?:\/\//i); + let m = cs.match(/^(.*)?:\/\//); if (m) { - if (m[1]) { - this.protocol = m[1]; + const p = m[1]; // protocol name + if (p) { + const m2 = p.match(/^([a-z]+[a-z0-9+-.]*)/i); + if (p && (!m2 || m2[1] !== p)) { + throw new Error(`Invalid protocol name: ${p}`); + } + this.protocol = p; } cs = cs.substr(m[0].length); } diff --git a/test/main.spec.ts b/test/main.spec.ts index 427673d..ab8fcc4 100644 --- a/test/main.spec.ts +++ b/test/main.spec.ts @@ -89,7 +89,7 @@ describe('constructor', () => { describe('protocol', () => { it('must recognize standard format', () => { - expect(parse('abc://')).to.eql({protocol: 'abc'}); + expect(parse('abc123://')).to.eql({protocol: 'abc123'}); }); it('must allow special symbols', () => { expect(parse('one+two-three.four://')).to.eql({protocol: 'one+two-three.four'}); @@ -98,6 +98,22 @@ describe('protocol', () => { expect(parse('abc:/')).to.eql({hosts: [{name: 'abc', type: 'domain'}]}); expect(parse('://')).to.eql({}); }); + it('must throw on invalid symbols', () => { + expect(() => { + parse('a$b://'); + }).to.throw('Invalid protocol name: a$b'); + expect(() => { + parse('a%://'); + }).to.throw('Invalid protocol name: a%'); + }); + it('must throw on leading digits', () => { + expect(() => { + parse('123://'); + }).to.throw('Invalid protocol name: 123'); + expect(() => { + parse('1a://'); + }).to.throw('Invalid protocol name: 1a'); + }); }); describe('hosts', () => {