Skip to content

Commit

Permalink
Pre-release cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
balazsbotond committed Oct 1, 2020
1 parent f5d2278 commit ad2d694
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 42 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
/dist-test
/.nyc_output
/coverage
.vscode
.vscode
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ function getUserPosts(id, blogId, limit, offset) {
}
~~~

As we can see, this minimal example is already rather hard to read. It is also incorrect:
As you can see, this minimal example is already rather hard to read. It is also incorrect:

- This will lead to URL containing duplicated slashes (`https://api.example.com//users`).
- I forgot that there was a trailing slash at the end of the `API_URL` constant so this resulted in a URL containing duplicate slashes (`https://api.example.com//users`).
- The embedded values need to be escaped using `encodeURIComponent`

I can use the built-in `URL` class to prevent duplicate slashes and `URLSearchParams` to escape the query string. But I still need to escape all path parameters manually.
Expand All @@ -83,7 +83,7 @@ function getUserPosts(id, blogId, limit, offset) {
}
~~~

Such a simple task and yet very hard to read and tedious to write! This is what lead to creation of this tiny library:
Such a simple task and yet very hard to read and tedious to write! This is where this tiny library can help you:

~~~js
const API_URL = 'https://api.example.com/';
Expand Down
11 changes: 4 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,21 +121,18 @@ function path(template: string, params: ParamMap) {
const renderedPath = template.replace(/:\w+/g, p => {
const key = p.slice(1);
if (!params.hasOwnProperty(key)) {
return p;
throw new Error(`Missing value for path parameter ${key}.`);
}
delete remainingParams[key];

if (!allowedTypes.includes(typeof params[key])) {
throw new TypeError(
`Path parameter ${key} cannot be of type ${typeof params[key]}. ` +
`Allowed types are: ${allowedTypes.join(', ')}.`
);
}
if (typeof params[key] === "string" && params[key].trim().length <= 0) {
throw new Error(
`Path parameter ${key} cannot be an empty string.`
);
if (typeof params[key] === "string" && params[key].trim() === '') {
throw new Error(`Path parameter ${key} cannot be an empty string.`);
}
delete remainingParams[key];
return encodeURIComponent(params[key]);
});

Expand Down
30 changes: 11 additions & 19 deletions test/subst.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,6 @@ describe('subst', () => {
expect(actual).to.equal(expected);
});

it('Returns the raw template if it has a param but none are passed', () => {
const expected = '/:p';
const actual = subst('/:p', {});
expect(actual).to.equal(expected);
});

it('Only substitutes params that are present in the object passed', () => {
const expected = '/1/:q';
const actual = subst('/:p/:q', { p: 1 });
expect(actual).to.equal(expected);
});

it('Substitutes all params present in the object passed', () => {
const expected = '/1/a/false';
const actual = subst('/:p/:q/:r', { p: 1, q: 'a', r: false });
Expand All @@ -39,42 +27,46 @@ describe('subst', () => {
expect(actual).to.equal(expected);
});

it('Allowed Type boolean (true) should be rendered', () => {
it('Renders boolean (true) params', () => {
const expected = 'true';
const actual = subst(':p', { p: true });
expect(actual).to.equal(expected);
});

it('Allowed Type boolean (false) should be rendered', () => {
it('Renders boolean (false) params', () => {
const expected = 'false';
const actual = subst(':p', { p: false });
expect(actual).to.equal(expected);
});

it('Allowed Type string should be rendered', () => {
it('Renders string params', () => {
const expected = 'test';
const actual = subst(':p', { p: 'test' });
expect(actual).to.equal(expected);
});

it('Allowed Type Number should be rendered', () => {
it('Renders number params', () => {
const expected = '234';
const actual = subst(':p', { p: 234 });
expect(actual).to.equal(expected);
});

it('Not Allowed Type Array should not be rendered', () => {
it('Throws if a param is an array', () => {
expect(() => subst(':p', { p: [] }))
.to.throw(TypeError, "Path parameter p cannot be of type object. Allowed types are: boolean, string, number.");
});

it('Not Allowed Type Object should not be rendered', () => {
it('Throws if a param is an object', () => {
expect(() => subst(':p', { p: {} }))
.to.throw(TypeError, "Path parameter p cannot be of type object. Allowed types are: boolean, string, number.");
});

it('Not Allowed Type Symbol should not be rendered', () => {
it('Throws if a param is a symbol', () => {
expect(() => subst(':p', { p: Symbol() }))
.to.throw(TypeError, "Path parameter p cannot be of type symbol. Allowed types are: boolean, string, number.");
});

it('Throws if a param is missing', () => {
expect(() => subst(':p', {})).to.throw();
});
});
28 changes: 16 additions & 12 deletions test/urlcat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,58 +103,62 @@ describe('urlcat', () => {
expect(actual).to.equal(expected);
});

it('Can handle allowed Type boolean (true) as param', () => {
it('Renders boolean (true) path params', () => {
const expected = 'http://example.com/path/true';
const actual = urlcat('http://example.com/path/:p', { p: true });
expect(actual).to.equal(expected);
});

it('Can handle allowed Type boolean (false) as param', () => {
it('Renders boolean (false) path params', () => {
const expected = 'http://example.com/path/false';
const actual = urlcat('http://example.com/path/:p', { p: false });
expect(actual).to.equal(expected);
});


it('Can handle allowed Type Number as param', () => {
it('Renders number path params', () => {
const expected = 'http://example.com/path/456';
const actual = urlcat('http://example.com/path/:p', { p: 456 });
expect(actual).to.equal(expected);
});

it('Can handle allowed Type String as param', () => {
it('Renders string path params', () => {
const expected = 'http://example.com/path/test';
const actual = urlcat('http://example.com/path/:p', { p: 'test' });
expect(actual).to.equal(expected);
});

it('Can\'t handle object as param', () => {
it('Throws if a path param is an object', () => {
expect(() => urlcat('http://example.com/path/:p', { p: {} }))
.to.throw(TypeError, "Path parameter p cannot be of type object. Allowed types are: boolean, string, number.");
});

it('Can\'t handle array as param', () => {
it('Throws if a path param is an array', () => {
expect(() => urlcat('http://example.com/path/:p/:q', { p: [] }))
.to.throw(TypeError, "Path parameter p cannot be of type object. Allowed types are: boolean, string, number.");
});

it('Can\'t handle symbol as param', () => {
it('Throws if a path param is a symbol', () => {
expect(() => urlcat('http://example.com/path/:p', { p: Symbol() }))
.to.throw(TypeError, "Path parameter p cannot be of type symbol. Allowed types are: boolean, string, number.");
});

it('Can\'t handle undefined as param', () => {
it('Throws if a path param is undefined', () => {
expect(() => urlcat('http://example.com/path/:p', { p: undefined }))
.to.throw(TypeError, "Path parameter p cannot be of type undefined. Allowed types are: boolean, string, number.");
});

it('Can\'t handle null as param', () => {
it('Throws if a path param is null', () => {
expect(() => urlcat('http://example.com/path/:p', { p: null }))
.to.throw(TypeError, "Path parameter p cannot be of type object. Allowed types are: boolean, string, number.");
});

it('Can\'t handle empty string as param', () => {
expect(() => urlcat('http://example.com/path/:p', { p: " " }))
it('Throws if a path param is an empty string', () => {
expect(() => urlcat('http://example.com/path/:p', { p: "" }))
.to.throw(Error, "Path parameter p cannot be an empty string.");
});

it('Throws if a path param contains only whitespace', () => {
expect(() => urlcat('http://example.com/path/:p', { p: " " }))
.to.throw(Error, "Path parameter p cannot be an empty string.");
});
});

0 comments on commit ad2d694

Please sign in to comment.