-
Notifications
You must be signed in to change notification settings - Fork 4
/
normalize.ts
150 lines (142 loc) · 3.96 KB
/
normalize.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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/**
* Lower first letter of the string.
*/
function lowerFirstLetter(name: string) {
if (name.length === 0) return name
return name[0].toLowerCase() + name.slice(1)
}
/**
* Strip `prefix` from the `name` string.
*/
function stripPrefix(name: string, prefix: string | string[]) {
if (typeof prefix === 'string') prefix = [prefix]
for (let p of prefix) {
if (name.startsWith(p)) {
return name.slice(p.length)
}
}
return name
}
/**
* Replace some strings.
*/
function replace(value: string, replaceArray: [string, any][]) {
for (let [search, replace] of replaceArray) {
if (value === search) value = replace
}
return value
}
/**
* Convert string to lower camel case.
*
* @remarks
* This is simplified implementation assuming that input string is already
* partially camel cased. In some edge cases this function produce
* results different from proper implementation.
* However it is stable and faster and sufficient for our use case.
*/
function lowerCamelCase(name: string) {
const words = name.split(/[^a-zA-Z0-9]/)
const camelCaseWords = words.map((word, index) => {
if (index === 0) {
return word.charAt(0).toLowerCase() + word.slice(1)
} else {
return word.charAt(0).toUpperCase() + word.slice(1)
}
})
return camelCaseWords.join('')
}
/**
* Traverse object recursively and apply provided function `fn` to each
* key-value pair. Returns new object.
* @param obj object to traverse
* @param fn function to apply
*/
function morph(
obj: any,
fn: (key: string, value: any) => { key: string; value: any }
): any {
if (typeof obj === 'object' && obj !== null) {
if (Array.isArray(obj)) {
return obj.map((element: any) => morph(element, fn))
} else {
let newObj: Record<string, any> = {}
for (let [key, value] of Object.entries(obj)) {
if (typeof value === 'object') {
newObj[key] = morph(value, fn)
} else {
const updated = fn(key, value)
newObj[updated.key] = updated.value
}
}
return newObj
}
}
}
/**
* Transform object parsed from raw API response to format compatible with
* earlier versions of the API. This function:
* - removes 'praw_' prefix from keys
* - lower first letter of keys
* - replaces empty strings with `undefined`
*
* Note: GUS API returns more prefixed keys than 'praw_'. Removing only this
* prefix was initial partial implementation. This is inconsistent approach and
* thus marked as deprecated, left only for compatibility with legacy code.
*
* @example
* ```js
* import Bir from 'bir1'
* import { legacy } from 'bir1/normalize'
* const bir = new Bir({ normalizeFn: legacy })
* const result = await bir.search('010058960')
* ```
*
* @param obj object to normalize
* @deprecated
*/
export function legacy(obj: any) {
return morph(obj, (key: string, value: any) => {
key = stripPrefix(key, 'praw_')
key = lowerFirstLetter(key)
value = replace(value, [['', undefined]])
return { key, value }
})
}
/**
* Transform object parsed from raw API response to convenient format commonly
* used in modern JavaScript applications. This is subjective and opinionated.
* This function:
* - remove prefixes from keys (e.g. `fiz_`, `praw_`, ...)
* - lower camel case keys
* - unifies some keys (e.g. `regon9` -> `regon`)
* - replaces empty strings with `undefined`
*
* @example
* ```js
* import Bir from 'bir1'
* import { modern } from 'bir1/normalize'
* const bir = new Bir({ normalizeFn: modern })
* const result = await bir.search('010058960')
* ```
*
* @param obj object to normalize
* @beta
*/
export function modern(obj: any) {
return morph(obj, (key: string, value: any) => {
key = stripPrefix(key, [
'fiz_',
'praw_',
'fizC_',
'fizP_',
'lokfiz_',
'lokpraw_',
'wspolsc_',
])
key = lowerCamelCase(key)
key = replace(key, [['regon9', 'regon']])
value = replace(value, [['', undefined]])
return { key, value }
})
}