-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdata.ts
382 lines (319 loc) · 11.9 KB
/
data.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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
// JAUL: data.ts
import _ = require("lodash")
/** Data Utilities class. */
export class DataUtils {
private static _instance: DataUtils
/** @hidden */
static get Instance() {
return this._instance || (this._instance = new this())
}
/**
* Removes all the specified characters from a string. For example you can cleanup
* a phone number by using removeFromString(phone, [" ", "-", "(", ")", "/"]).
* @param value The original value to be cleaned.
* @param charsToRemove Array of characters or single string to be removed from the original string.
* @returns Value with the characters removed.
*/
removeFromString = (value: string, charsToRemove: any[] | string): string => {
if (!value) {
return value
}
// Make sure value is a valid string.
let result = value.toString()
if (!Array.isArray(charsToRemove)) {
charsToRemove = Array.from(charsToRemove)
}
for (let c of charsToRemove) {
result = result.split(c).join("")
}
return result
}
/**
* Replace tags on the passed text with values from the passed object.
* It follows the TypeScript default format: ${property_name}
* @param text The text with tags to be replaced.
* @param obj Object containing the keys and values for tag replacement.
* @param prefix Optional tag prefix.
* @returns Text with tags replaced by object's values.
*/
replaceTags = (text: string, obj: any, prefix?: String): string => {
if (!text) {
return ""
}
if (!obj) {
return text
}
if (!prefix) {
prefix = ""
}
// State variable.
let keepGoing: boolean = true
// Replace while we have more text to be processed.
do {
let beforeReplace = text
// Replacer function. If a prefix was passed, remove it
// before trying to assign value from object.
const replacer = (wholeMatch, key) => {
if (prefix) {
key = key.replace(prefix, "")
}
let substitution = obj[key.trim()]
return substitution === undefined ? wholeMatch : substitution.toString()
}
text = text.replace(/\${([^}]+)}/g, replacer)
keepGoing = text !== beforeReplace
} while (keepGoing)
return text
}
/**
* Masks the specified string. For eaxmple to mask a phone number but leave the
* last 4 digits visible you could use maskString(phone, "X", 4).
* @param value The original value to be masked.
* @param maskChar Optional character to be used on the masking, default is *.
* @param leaveLast Optional, leave last X positions of the string unmasked, default is 0.
* @returns The masked string.
*/
maskString = (value: string, maskChar?: string, leaveLast?: number): string => {
if (!value) {
return value
}
// Make sure value is a valid string.
value = value.toString()
const separators = [" ", "-", "_", "+", "=", "/"]
if (maskChar == null || maskChar == "") {
maskChar = "*"
}
if (leaveLast == null || leaveLast < 1) {
leaveLast = 0
}
let result = ""
let i = 0
// First split characters, then iterate to replace.
const arr = value.split("")
while (i < arr.length - leaveLast) {
const char = arr[i]
if (separators.indexOf(char) < 0) {
result += maskChar
} else {
result += char
}
i++
}
// Leave last characters?
if (leaveLast > 0) {
result += value.substr(value.length - leaveLast)
}
return result
}
/**
* Minify the passed JSON value. Removes comments, unecessary white spaces etc.
* @param source The JSON string or object to be minified.
* @param asString If true, return as string instead of JSON object, default is false.
* @returns The minified JSON as object or string, depending on asString.
*/
minifyJson = (source: string, asString?: boolean): any => {
if (_.isObject(source)) {
source = JSON.stringify(source, null, 0)
}
let index = 0
const {length} = source
let result = ""
let symbol = undefined
let position = undefined
// Main iterator.
while (index < length) {
symbol = source.charAt(index)
switch (symbol) {
// Ignore whitespace tokens. According to ES 5.1 section 15.12.1.1,
// whitespace tokens include tabs, carriage returns, line feeds, and
// space characters.
/* istanbul ignore next */
case "\t":
/* istanbul ignore next */
case "\r":
case "\n":
case " ":
index += 1
break
// Ignore line and block comments.
case "/":
symbol = source.charAt((index += 1))
switch (symbol) {
// Line comments.
case "/":
position = source.indexOf("\n", index)
// Check for CR-style line endings.
if (position < 0) {
position = source.indexOf("\r", index)
}
index = position > -1 ? position : length
break
// Block comments.
case "*":
position = source.indexOf("*/", index)
if (position > -1) {
// Advance the scanner's position past the end of the comment.
index = position += 2
break
}
throw new Error("Unterminated block comment.")
default:
throw new Error("Invalid comment.")
}
break
// Parse strings separately to ensure that any whitespace characters and
// JavaScript-style comments within them are preserved.
case '"':
position = index
while (index < length) {
symbol = source.charAt((index += 1))
if (symbol === "\\") {
// Skip past escaped characters.
index += 1
} else if (symbol === '"') {
break
}
}
if (source.charAt(index) === '"') {
result += source.slice(position, (index += 1))
break
}
throw new Error("Unterminated string.")
// Preserve all other characters.
default:
result += symbol
index += 1
}
}
// Check if should return as string or JSON.
if (asString) {
return result
} else {
return JSON.parse(result)
}
}
/**
* Strips all the HTML tags from the specified value and returns only the text.
* Tags will be replaced with an empty space by default.
* @param value The HTML string to be converted to only text.
* @param tagReplace Replace tags with that value
*/
stripHtml = (html: string, tagReplace?: string): string => {
if (!html || html == "") {
return ""
}
// Default tagReplace is an empty space.
if (!tagReplace && tagReplace !== "") {
tagReplace = " "
}
// Output will be set here.
let output = ""
// Default symbols.
const PLAINTEXT = Symbol("plaintext")
const HTML = Symbol("html")
const COMMENT = Symbol("comment")
// Initial state variables.
let tagBuffer = ""
let qChar = ""
let depth = 0
let state = PLAINTEXT
// Iterate HTML content to replace tags.
for (let i = 0, length = html.length; i < length; i++) {
let char = html[i]
try {
if (state === PLAINTEXT) {
switch (char) {
case "<":
state = HTML
tagBuffer += char
break
default:
output += char
break
}
} else if (state === HTML) {
switch (char) {
case "<":
if (qChar) {
break
}
depth++
break
case ">":
if (qChar) {
break
}
if (depth) {
depth--
break
}
qChar = ""
state = PLAINTEXT
tagBuffer += ">"
output += tagReplace
tagBuffer = ""
break
case '"':
case "'":
if (char === qChar) {
qChar = ""
} else {
qChar = qChar || char
}
tagBuffer += char
break
case "-":
if (tagBuffer === "<!-") {
state = COMMENT
}
tagBuffer += char
break
case " ":
case "\n":
if (tagBuffer === "<") {
state = PLAINTEXT
output += "< "
tagBuffer = ""
break
}
tagBuffer += char
break
default:
tagBuffer += char
break
}
} else if (state === COMMENT) {
switch (char) {
case ">":
if (tagBuffer.slice(-2) == "--") {
state = PLAINTEXT
}
tagBuffer = ""
break
default:
tagBuffer += char
break
}
}
} catch (ex) {
// Ignore errors
}
}
return output
}
/**
* Generates a RFC4122-compliant unique ID using random numbers.
* @returns A unique ID.
*/
uuid = (): string => {
const baseStr = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
const generator = function (c) {
const r = (Math.random() * 16) | 0
const v = c === "x" ? r : (r & 0x3) | 0x8
return v.toString(16)
}
return baseStr.replace(/[xy]/g, generator)
}
}
// Exports...
export default DataUtils.Instance