Skip to content

Commit 267de54

Browse files
committed
Added common localization actors and routing function
1 parent 1327f61 commit 267de54

6 files changed

Lines changed: 141 additions & 0 deletions

File tree

package-lock.json

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"jest": "25.5.4",
2525
"jest-extended": "0.11.5",
2626
"prettier": "1.19.1",
27+
"query-string": "6.13.1",
2728
"rimraf": "2.6.2",
2829
"rosie": "2.0.1",
2930
"ts-jest": "25.5.1",

src/interfaces/culture-params.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* Request parameters for digesting localization related culture information
3+
*/
4+
export default interface CultureParams {
5+
/**
6+
* RFC-4646 language code
7+
*/
8+
culture: string;
9+
}

src/interfaces/culture.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* Localization culture information and related nested resources
3+
*/
4+
export default interface Culture<TResources> {
5+
/**
6+
* RFC-4646 language code
7+
*/
8+
code: string;
9+
10+
/**
11+
* Key/value pairs of translations
12+
*/
13+
resources: TResources;
14+
}

src/utilities/route-utils.test.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,78 @@ describe("RouteUtils", () => {
210210

211211
//#endregion isAbsoluteUrl
212212

213+
// -----------------------------------------------------------------------------------------
214+
// #region queryStringToObject
215+
// -----------------------------------------------------------------------------------------
216+
217+
describe("queryStringToObject", () => {
218+
test.each`
219+
inputString
220+
${null}
221+
${undefined}
222+
${""}
223+
${" "}
224+
`(
225+
"given queryString is $inputString, returns empty object",
226+
({ inputString }) => {
227+
// Arrange & Act
228+
const result = RouteUtils.queryStringToObject<any>(inputString);
229+
230+
// Assert
231+
expect(result).not.toBeNull();
232+
expect(typeof result).toBe("object");
233+
}
234+
);
235+
236+
test("given queryString contains matching properties, returns typed object", () => {
237+
// Arrange
238+
interface TestStub {
239+
testProp1: string;
240+
testProp2: string;
241+
}
242+
const expectedValue1 = "testValue1";
243+
const expectedValue2 = "testValue2";
244+
245+
const queryString = `testProp1=${expectedValue1}&testProp2=${expectedValue2}`;
246+
247+
// Act
248+
const result = RouteUtils.queryStringToObject<TestStub>(
249+
queryString
250+
);
251+
252+
// Assert
253+
expect(result).not.toBeNull();
254+
expect(result.testProp1).toBe(expectedValue1);
255+
expect(result.testProp2).toBe(expectedValue2);
256+
});
257+
258+
test("given queryString contains unmatching properties, returns typed object with unmatched properties", () => {
259+
// Arrange
260+
interface TestStub {
261+
testProp1: string;
262+
}
263+
const expectedTypedValue1 = "testValue1";
264+
const expectedUntypedProperty2 = "testProp2";
265+
const expectedUntypedValue2 = "testValue2";
266+
267+
const queryString = `testProp1=${expectedTypedValue1}&${expectedUntypedProperty2}=${expectedUntypedValue2}`;
268+
269+
// Act
270+
const result = RouteUtils.queryStringToObject<TestStub>(
271+
queryString
272+
);
273+
274+
// Assert
275+
expect(result).not.toBeNull();
276+
expect(result.testProp1).toBe(expectedTypedValue1);
277+
expect(result[expectedUntypedProperty2]).toBe(
278+
expectedUntypedValue2
279+
);
280+
});
281+
});
282+
283+
//#endregion queryStringToObject
284+
213285
// -----------------------------------------------------------------------------------------
214286
// #region replacePathParams
215287
// -----------------------------------------------------------------------------------------

src/utilities/route-utils.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import QueryString from "query-string";
2+
13
// -----------------------------------------------------------------------------------------
24
// #region Constants
35
// -----------------------------------------------------------------------------------------
@@ -72,6 +74,25 @@ const getUrlFromPath = (path: string, pathParams?: any, queryParams?: any) => {
7274
const isAbsoluteUrl = (url: string): boolean =>
7375
new RegExp("^(?:[a-z]+:)?//", "i").test(url);
7476

77+
/**
78+
* Parse a query string and return an object of type T
79+
* @param queryString current query string
80+
* @param arrayFormat format to parse arrays from
81+
* @param parseNumbers convert numbers to number type from string
82+
* @param parseBooleans convert booleans to boolean type from string
83+
*/
84+
const queryStringToObject = <T>(
85+
queryString: string,
86+
arrayFormat: "bracket" | "index" | "comma" = "index",
87+
parseNumbers: boolean = true,
88+
parseBooleans: boolean = true
89+
): T =>
90+
(QueryString.parse(queryString, {
91+
arrayFormat,
92+
parseNumbers,
93+
parseBooleans,
94+
}) as any) as T;
95+
7596
/**
7697
* Replace routing components in supplied path with keys and values
7798
* of supplied pathParams.
@@ -110,6 +131,7 @@ export const RouteUtils = {
110131
getUrl,
111132
getUrlFromPath,
112133
isAbsoluteUrl,
134+
queryStringToObject,
113135
replacePathParams,
114136
};
115137

0 commit comments

Comments
 (0)