Skip to content
This repository was archived by the owner on May 1, 2021. It is now read-only.

Commit a7b605d

Browse files
authored
Merge pull request #22 from pbeshai/stringify-opts
Add support for stringify options
2 parents bac5bbd + 21be36a commit a7b605d

File tree

3 files changed

+90
-6
lines changed

3 files changed

+90
-6
lines changed

src/__tests__/updateLocation-test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,31 @@ describe('updateLocation', () => {
4848
'?foo=xxx'
4949
);
5050
});
51+
52+
it('handles stringify options', () => {
53+
const location = makeMockLocation({
54+
foo: 'one two',
55+
bar: '[({1,2:3:4,5})]',
56+
});
57+
const newLocation = updateLocation(
58+
{ foo: 'o t h', bar: '[({1,2:3:6,5})]' },
59+
location,
60+
{
61+
encode: false,
62+
}
63+
);
64+
expect(newLocation.search).toBe('?bar=[({1,2:3:6,5})]&foo=o t h');
65+
66+
const newLocation2 = updateLocation(
67+
{ foo: 'o t h', bar: '[({1,2:6:4,5})]' },
68+
location,
69+
{
70+
encode: false,
71+
transformSearchString: (str) => str.replace(/ /g, '%20'),
72+
}
73+
);
74+
expect(newLocation2.search).toBe('?bar=[({1,2:6:4,5})]&foo=o%20t%20h');
75+
});
5176
});
5277

5378
describe('updateInLocation', () => {
@@ -82,4 +107,21 @@ describe('updateInLocation', () => {
82107
'?foo=xxx'
83108
);
84109
});
110+
111+
it('handles stringify options', () => {
112+
const location = makeMockLocation({
113+
foo: 'one two',
114+
bar: '[({1,2:3:4,5})]',
115+
});
116+
const newLocation = updateInLocation({ foo: 'o t h' }, location, {
117+
encode: false,
118+
});
119+
expect(newLocation.search).toBe('?bar=[({1,2:3:4,5})]&foo=o t h');
120+
121+
const newLocation2 = updateInLocation({ foo: 'o t h' }, location, {
122+
encode: false,
123+
transformSearchString: (str) => str.replace(/ /g, '%20'),
124+
});
125+
expect(newLocation2.search).toBe('?bar=[({1,2:3:4,5})]&foo=o%20t%20h');
126+
});
85127
});

src/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ export {
4848
EncodedValueMap,
4949
} from './types';
5050

51-
export { updateLocation, updateInLocation } from './updateLocation';
51+
export {
52+
updateLocation,
53+
updateInLocation,
54+
ExtendedStringifyOptions,
55+
transformSearchStringJsonSafe,
56+
} from './updateLocation';
5257
export { encodeQueryParams } from './encodeQueryParams';
5358
export { decodeQueryParams } from './decodeQueryParams';

src/updateLocation.ts

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,51 @@
1-
import { stringify, parse as parseQueryString, parseUrl } from 'query-string';
1+
import {
2+
stringify,
3+
StringifyOptions,
4+
parse as parseQueryString,
5+
parseUrl,
6+
} from 'query-string';
27
import { EncodedQuery } from './types';
38

9+
/**
10+
* options passed to query-string stringify plus an
11+
* addition of transformSearchString: a function that takes
12+
* the result of stringify and runs a transformation on it.
13+
* (e.g. replacing all instances of character x with y)
14+
*/
15+
export type ExtendedStringifyOptions = StringifyOptions & {
16+
transformSearchString?: (searchString: string) => string;
17+
};
18+
19+
/**
20+
* An example of a transformSearchString function that undoes encoding of
21+
* common JSON characters that are technically allowed in URLs.
22+
*/
23+
const JSON_SAFE_CHARS = `{}[],":`
24+
.split('')
25+
.map((d) => [d, encodeURIComponent(d)]);
26+
export function transformSearchStringJsonSafe(searchString: string): string {
27+
let str = searchString;
28+
for (let [char, code] of JSON_SAFE_CHARS) {
29+
str = str.replace(new RegExp('\\' + code, 'g'), char);
30+
}
31+
return str;
32+
}
33+
434
/**
535
* Update a location, wiping out parameters not included in encodedQuery
636
* If a param is set to undefined it will be removed from the URL.
737
*/
838
export function updateLocation(
939
encodedQuery: EncodedQuery,
10-
location: Location
40+
location: Location,
41+
stringifyOptions?: ExtendedStringifyOptions
1142
): Location {
12-
const encodedSearchString = stringify(encodedQuery);
43+
let encodedSearchString = stringify(encodedQuery, stringifyOptions);
44+
if (stringifyOptions && stringifyOptions.transformSearchString) {
45+
encodedSearchString = stringifyOptions.transformSearchString(
46+
encodedSearchString
47+
);
48+
}
1349
const search = encodedSearchString.length ? `?${encodedSearchString}` : '';
1450
const href = parseUrl(location.href || '').url + search;
1551

@@ -33,7 +69,8 @@ export function updateLocation(
3369
*/
3470
export function updateInLocation(
3571
encodedQueryReplacements: EncodedQuery,
36-
location: Location
72+
location: Location,
73+
stringifyOptions?: ExtendedStringifyOptions
3774
): Location {
3875
// if a query is there, use it, otherwise parse the search string
3976
const currQuery =
@@ -44,5 +81,5 @@ export function updateInLocation(
4481
...encodedQueryReplacements,
4582
};
4683

47-
return updateLocation(newQuery, location);
84+
return updateLocation(newQuery, location, stringifyOptions);
4885
}

0 commit comments

Comments
 (0)