-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
115 lines (89 loc) · 2.91 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import querystring, {
ParseOptions as QueryParseOptions,
StringifyOptions as QueryStringifyOptions
} from 'query-string';
type BaseTypes = typeof Boolean | typeof Number | typeof String
type Types = BaseTypes | BaseTypes[]
type IsString<T> = T extends typeof String ? true : T extends string ? true : false;
type IsBoolean<T> = T extends typeof Boolean ? true : false;
type IsNumber<T> = T extends typeof Number ? true : false;
type ParseType<T> =
IsString<T> extends true ? string :
IsBoolean<T> extends true ? boolean :
IsNumber<T> extends true ? number : (string | string[])
export type Parsed<T> = {
[K in keyof T]: ParseType<T[K]>
}
export type Config = Record<string, Types>;
export type ParseOptions = QueryParseOptions;
export type StringifyOptions = QueryStringifyOptions;
export function parse<C extends Config>(query: string, config?: C, options?: ParseOptions): Parsed<C> {
const parsed = querystring.parse(query, options) as Parsed<C>;
const entries = Object.entries(config ?? {})
if (!entries.length) {
return parsed;
}
return entries.reduce((query, [key, type]) => {
const value = parsed[key] as string | string[];
const result = (() => {
if (!Array.isArray(type)) {
return type(value)
}
if (Array.isArray(value) && Array.isArray(type)) {
return value.map(v => type[0](v))
}
return value
})()
return ({
...query,
[key]: result
})
}, {} as Parsed<C>)
}
export function stringify(object: Record<string, any>, options?: StringifyOptions) {
return querystring.stringify(object, options);
}
export function serializeConfig(types: Record<string, Types>) {
const serialized = Object.entries(types).reduce((serialized, [key, type]) => {
const typeConstructor = Array.isArray(type) ? type[0] : type;
const typeString = (() => {
switch (typeConstructor) {
case Number:
return 'Number';
case String:
return 'String';
case Boolean:
return 'Boolean';
}
return 'Unknown'
})();
return {
...serialized,
[key]: Array.isArray(type) ? `[]${typeString}` : typeString
}
}, {});
return JSON.stringify(serialized);
}
export function deserializeConfig(serialized: string): Record<string, Types> {
const json = JSON.parse(serialized) as Record<string, string>;
return Object.entries(json).reduce((deserialized, [key, type]) => {
const isArray = type.startsWith('[]');
const typeString = isArray ? type.substring(2) : type;
const typeConstructor = (() => {
switch (typeString) {
case 'Number':
return Number;
case 'String':
return String;
case 'Boolean':
return Boolean;
}
return undefined
})();
return {
...deserialized,
[key]: isArray ? [typeConstructor] : typeConstructor
}
}, {});
}
export default { parse, stringify }