@etsoo/shared 1.2.51 → 1.2.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/main.yml +6 -5
- package/README.md +1 -1
- package/lib/cjs/ActionResult.d.ts +1 -1
- package/lib/cjs/ActionResult.js +3 -3
- package/lib/cjs/ArrayUtils.d.ts +1 -1
- package/lib/cjs/ArrayUtils.js +4 -4
- package/lib/cjs/ColorUtils.d.ts +1 -1
- package/lib/cjs/ColorUtils.js +2 -2
- package/lib/cjs/DataTypes.d.ts +6 -6
- package/lib/cjs/DataTypes.js +50 -51
- package/lib/cjs/DateUtils.d.ts +1 -1
- package/lib/cjs/DateUtils.js +27 -28
- package/lib/cjs/DomUtils.d.ts +3 -3
- package/lib/cjs/DomUtils.js +64 -73
- package/lib/cjs/ExtendUtils.d.ts +1 -1
- package/lib/cjs/ExtendUtils.js +6 -6
- package/lib/cjs/IActionResult.d.ts +15 -2
- package/lib/cjs/NumberUtils.d.ts +1 -1
- package/lib/cjs/NumberUtils.js +9 -9
- package/lib/cjs/StorageUtils.js +2 -2
- package/lib/cjs/Utils.d.ts +4 -4
- package/lib/cjs/Utils.js +58 -62
- package/lib/cjs/index.d.ts +22 -22
- package/lib/cjs/storage/WindowStorage.d.ts +1 -1
- package/lib/cjs/types/ContentDisposition.d.ts +2 -2
- package/lib/cjs/types/ContentDisposition.js +11 -13
- package/lib/cjs/types/EColor.js +5 -7
- package/lib/cjs/types/EHistory.d.ts +3 -3
- package/lib/cjs/types/EHistory.js +4 -4
- package/lib/cjs/types/ErrorData.d.ts +1 -1
- package/lib/cjs/types/EventClass.js +1 -1
- package/lib/mjs/ActionResult.d.ts +1 -1
- package/lib/mjs/ActionResult.js +3 -3
- package/lib/mjs/ArrayUtils.d.ts +1 -1
- package/lib/mjs/ArrayUtils.js +5 -5
- package/lib/mjs/ColorUtils.d.ts +1 -1
- package/lib/mjs/ColorUtils.js +3 -3
- package/lib/mjs/DataTypes.d.ts +6 -6
- package/lib/mjs/DataTypes.js +50 -51
- package/lib/mjs/DateUtils.d.ts +1 -1
- package/lib/mjs/DateUtils.js +27 -28
- package/lib/mjs/DomUtils.d.ts +3 -3
- package/lib/mjs/DomUtils.js +67 -76
- package/lib/mjs/ExtendUtils.d.ts +1 -1
- package/lib/mjs/ExtendUtils.js +6 -6
- package/lib/mjs/IActionResult.d.ts +15 -2
- package/lib/mjs/NumberUtils.d.ts +1 -1
- package/lib/mjs/NumberUtils.js +9 -9
- package/lib/mjs/StorageUtils.js +4 -4
- package/lib/mjs/Utils.d.ts +4 -4
- package/lib/mjs/Utils.js +61 -65
- package/lib/mjs/index.d.ts +22 -22
- package/lib/mjs/index.js +22 -22
- package/lib/mjs/storage/WindowStorage.d.ts +1 -1
- package/lib/mjs/storage/WindowStorage.js +2 -2
- package/lib/mjs/types/ContentDisposition.d.ts +2 -2
- package/lib/mjs/types/ContentDisposition.js +12 -14
- package/lib/mjs/types/EColor.js +5 -7
- package/lib/mjs/types/EHistory.d.ts +3 -3
- package/lib/mjs/types/EHistory.js +5 -5
- package/lib/mjs/types/ErrorData.d.ts +1 -1
- package/lib/mjs/types/EventClass.js +1 -1
- package/package.json +61 -63
- package/src/ActionResult.ts +23 -23
- package/src/ArrayUtils.ts +164 -172
- package/src/ColorUtils.ts +80 -82
- package/src/DataTypes.ts +745 -754
- package/src/DateUtils.ts +266 -268
- package/src/DomUtils.ts +806 -831
- package/src/ExtendUtils.ts +191 -191
- package/src/IActionResult.ts +55 -40
- package/src/Keyboard.ts +258 -258
- package/src/NumberUtils.ts +135 -135
- package/src/StorageUtils.ts +117 -117
- package/src/Utils.ts +908 -930
- package/src/index.ts +22 -22
- package/src/node/Storage.ts +53 -53
- package/src/storage/IStorage.ts +62 -62
- package/src/storage/WindowStorage.ts +140 -140
- package/src/types/ContentDisposition.ts +59 -63
- package/src/types/DataError.ts +15 -15
- package/src/types/DelayedExecutorType.ts +15 -15
- package/src/types/EColor.ts +241 -248
- package/src/types/EHistory.ts +151 -151
- package/src/types/ErrorData.ts +11 -11
- package/src/types/EventClass.ts +220 -220
- package/src/types/FormData.ts +25 -25
- package/src/types/ParsedPath.ts +5 -5
- package/tsconfig.cjs.json +16 -16
- package/tsconfig.json +16 -16
- package/.eslintignore +0 -3
- package/.eslintrc.json +0 -29
- package/.prettierignore +0 -5
- package/.prettierrc +0 -6
package/src/Utils.ts
CHANGED
|
@@ -1,1021 +1,999 @@
|
|
|
1
|
-
import { DataTypes, IdType } from
|
|
2
|
-
import isEqual from
|
|
3
|
-
import { DateUtils } from
|
|
4
|
-
import { ParsedPath } from
|
|
1
|
+
import { DataTypes, IdType } from "./DataTypes";
|
|
2
|
+
import isEqual from "lodash.isequal";
|
|
3
|
+
import { DateUtils } from "./DateUtils";
|
|
4
|
+
import { ParsedPath } from "./types/ParsedPath";
|
|
5
5
|
|
|
6
6
|
declare global {
|
|
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
|
-
|
|
7
|
+
interface String {
|
|
8
|
+
/**
|
|
9
|
+
* Add parameter to URL
|
|
10
|
+
* @param this URL to add parameter
|
|
11
|
+
* @param name Parameter name
|
|
12
|
+
* @param value Parameter value
|
|
13
|
+
* @param arrayFormat Array format to array style or not to multiple fields
|
|
14
|
+
* @returns New URL
|
|
15
|
+
*/
|
|
16
|
+
addUrlParam(
|
|
17
|
+
this: string,
|
|
18
|
+
name: string,
|
|
19
|
+
value: DataTypes.Simple,
|
|
20
|
+
arrayFormat?: boolean | string
|
|
21
|
+
): string;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Add parameters to URL
|
|
25
|
+
* @param this URL to add parameters
|
|
26
|
+
* @param data Parameters
|
|
27
|
+
* @param arrayFormat Array format to array style or not to multiple fields
|
|
28
|
+
* @returns New URL
|
|
29
|
+
*/
|
|
30
|
+
addUrlParams(
|
|
31
|
+
this: string,
|
|
32
|
+
data: DataTypes.SimpleObject,
|
|
33
|
+
arrayFormat?: boolean | string
|
|
34
|
+
): string;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Add parameters to URL
|
|
38
|
+
* @param this URL to add parameters
|
|
39
|
+
* @param params Parameters string
|
|
40
|
+
* @returns New URL
|
|
41
|
+
*/
|
|
42
|
+
addUrlParams(this: string, params: string): string;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Check the input string contains Chinese character or not
|
|
46
|
+
* @param this Input
|
|
47
|
+
* @param test Test string
|
|
48
|
+
*/
|
|
49
|
+
containChinese(this: string): boolean;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Check the input string contains Korean character or not
|
|
53
|
+
* @param this Input
|
|
54
|
+
* @param test Test string
|
|
55
|
+
*/
|
|
56
|
+
containKorean(this: string): boolean;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Check the input string contains Japanese character or not
|
|
60
|
+
* @param this Input
|
|
61
|
+
* @param test Test string
|
|
62
|
+
*/
|
|
63
|
+
containJapanese(this: string): boolean;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Format string with parameters
|
|
67
|
+
* @param this Input template
|
|
68
|
+
* @param parameters Parameters to fill the template
|
|
69
|
+
*/
|
|
70
|
+
format(this: string, ...parameters: string[]): string;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Format inital character to lower case or upper case
|
|
74
|
+
* @param this Input string
|
|
75
|
+
* @param upperCase To upper case or lower case
|
|
76
|
+
*/
|
|
77
|
+
formatInitial(this: string, upperCase: boolean): string;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Hide data
|
|
81
|
+
* @param this Input string
|
|
82
|
+
* @param endChar End char
|
|
83
|
+
*/
|
|
84
|
+
hideData(this: string, endChar?: string): string;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Hide email data
|
|
88
|
+
* @param this Input email
|
|
89
|
+
*/
|
|
90
|
+
hideEmail(this: string): string;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Is digits string
|
|
94
|
+
* @param this Input string
|
|
95
|
+
* @param minLength Minimum length
|
|
96
|
+
*/
|
|
97
|
+
isDigits(this: string, minLength?: number): boolean;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Is email string
|
|
101
|
+
* @param this Input string
|
|
102
|
+
*/
|
|
103
|
+
isEmail(this: string): boolean;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Remove non letters (0-9, a-z, A-Z)
|
|
107
|
+
* @param this Input string
|
|
108
|
+
*/
|
|
109
|
+
removeNonLetters(this: string): string;
|
|
110
|
+
}
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
String.prototype.addUrlParam = function (
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
this: string,
|
|
115
|
+
name: string,
|
|
116
|
+
value: DataTypes.Simple,
|
|
117
|
+
arrayFormat?: boolean | string
|
|
118
118
|
) {
|
|
119
|
-
|
|
119
|
+
return this.addUrlParams({ [name]: value }, arrayFormat);
|
|
120
120
|
};
|
|
121
121
|
|
|
122
122
|
String.prototype.addUrlParams = function (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
123
|
+
this: string,
|
|
124
|
+
data: DataTypes.SimpleObject | string,
|
|
125
|
+
arrayFormat?: boolean | string
|
|
126
126
|
) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
127
|
+
if (typeof data === "string") {
|
|
128
|
+
let url = this;
|
|
129
|
+
if (url.includes("?")) {
|
|
130
|
+
url += "&";
|
|
131
|
+
} else {
|
|
132
|
+
if (!url.endsWith("/")) url = url + "/";
|
|
133
|
+
url += "?";
|
|
134
|
+
}
|
|
135
|
+
return url + data;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Simple check
|
|
139
|
+
if (typeof URL === "undefined" || !this.includes("://")) {
|
|
140
|
+
const params = Object.entries(data)
|
|
141
|
+
.map(([key, value]) => {
|
|
142
|
+
let v: string;
|
|
143
|
+
if (Array.isArray(value)) {
|
|
144
|
+
if (arrayFormat == null || arrayFormat === false) {
|
|
145
|
+
return value
|
|
146
|
+
.map((item) => `${key}=${encodeURIComponent(`${item}`)}`)
|
|
147
|
+
.join("&");
|
|
148
|
+
} else {
|
|
149
|
+
v = value.join(arrayFormat ? "," : arrayFormat);
|
|
150
|
+
}
|
|
151
|
+
} else if (value instanceof Date) {
|
|
152
|
+
v = value.toJSON();
|
|
131
153
|
} else {
|
|
132
|
-
|
|
133
|
-
url += '?';
|
|
154
|
+
v = value == null ? "" : `${value}`;
|
|
134
155
|
}
|
|
135
|
-
return url + data;
|
|
136
|
-
}
|
|
137
156
|
|
|
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
|
-
} else {
|
|
166
|
-
const urlObj = new URL(this);
|
|
167
|
-
Object.entries(data).forEach(([key, value]) => {
|
|
168
|
-
if (Array.isArray(value)) {
|
|
169
|
-
if (arrayFormat == null || arrayFormat === false) {
|
|
170
|
-
value.forEach((item) => {
|
|
171
|
-
urlObj.searchParams.append(key, `${item}`);
|
|
172
|
-
});
|
|
173
|
-
} else {
|
|
174
|
-
urlObj.searchParams.append(
|
|
175
|
-
key,
|
|
176
|
-
value.join(arrayFormat ? ',' : arrayFormat)
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
} else if (value instanceof Date) {
|
|
180
|
-
urlObj.searchParams.append(key, value.toJSON());
|
|
181
|
-
} else {
|
|
182
|
-
urlObj.searchParams.append(
|
|
183
|
-
key,
|
|
184
|
-
`${value == null ? '' : value}`
|
|
185
|
-
);
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
return urlObj.toString();
|
|
189
|
-
}
|
|
157
|
+
return `${key}=${encodeURIComponent(v)}`;
|
|
158
|
+
})
|
|
159
|
+
.join("&");
|
|
160
|
+
|
|
161
|
+
return this.addUrlParams(params);
|
|
162
|
+
} else {
|
|
163
|
+
const urlObj = new URL(this);
|
|
164
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
165
|
+
if (Array.isArray(value)) {
|
|
166
|
+
if (arrayFormat == null || arrayFormat === false) {
|
|
167
|
+
value.forEach((item) => {
|
|
168
|
+
urlObj.searchParams.append(key, `${item}`);
|
|
169
|
+
});
|
|
170
|
+
} else {
|
|
171
|
+
urlObj.searchParams.append(
|
|
172
|
+
key,
|
|
173
|
+
value.join(arrayFormat ? "," : arrayFormat)
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
} else if (value instanceof Date) {
|
|
177
|
+
urlObj.searchParams.append(key, value.toJSON());
|
|
178
|
+
} else {
|
|
179
|
+
urlObj.searchParams.append(key, `${value == null ? "" : value}`);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
return urlObj.toString();
|
|
183
|
+
}
|
|
190
184
|
};
|
|
191
185
|
|
|
192
186
|
String.prototype.containChinese = function (this: string): boolean {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
187
|
+
const regExp =
|
|
188
|
+
/[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uff66-\uff9f]/g;
|
|
189
|
+
return regExp.test(this);
|
|
196
190
|
};
|
|
197
191
|
|
|
198
192
|
String.prototype.containKorean = function (this: string): boolean {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
193
|
+
const regExp =
|
|
194
|
+
/[\uac00-\ud7af\u1100-\u11ff\u3130-\u318f\ua960-\ua97f\ud7b0-\ud7ff\u3400-\u4dbf]/g;
|
|
195
|
+
return regExp.test(this);
|
|
202
196
|
};
|
|
203
197
|
|
|
204
198
|
String.prototype.containJapanese = function (this: string): boolean {
|
|
205
|
-
|
|
206
|
-
|
|
199
|
+
const regExp = /[\u3040-\u309f\u30a0-\u30ff\uff00-\uff9f\u4e00-\u9faf]/g;
|
|
200
|
+
return regExp.test(this);
|
|
207
201
|
};
|
|
208
202
|
|
|
209
203
|
String.prototype.format = function (
|
|
210
|
-
|
|
211
|
-
|
|
204
|
+
this: string,
|
|
205
|
+
...parameters: string[]
|
|
212
206
|
): string {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
207
|
+
let template = this;
|
|
208
|
+
parameters.forEach((value, index) => {
|
|
209
|
+
template = template.replace(new RegExp(`\\{${index}\\}`, "g"), value);
|
|
210
|
+
});
|
|
211
|
+
return template;
|
|
218
212
|
};
|
|
219
213
|
|
|
220
214
|
String.prototype.formatInitial = function (
|
|
221
|
-
|
|
222
|
-
|
|
215
|
+
this: string,
|
|
216
|
+
upperCase: boolean = false
|
|
223
217
|
) {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
);
|
|
218
|
+
const initial = this.charAt(0);
|
|
219
|
+
return (
|
|
220
|
+
(upperCase ? initial.toUpperCase() : initial.toLowerCase()) + this.slice(1)
|
|
221
|
+
);
|
|
229
222
|
};
|
|
230
223
|
|
|
231
224
|
String.prototype.hideData = function (this: string, endChar?: string) {
|
|
232
|
-
|
|
225
|
+
if (this.length === 0) return this;
|
|
233
226
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
227
|
+
if (endChar != null) {
|
|
228
|
+
const index = this.indexOf(endChar);
|
|
229
|
+
if (index === -1) return this.hideData();
|
|
230
|
+
return this.substring(0, index).hideData() + this.substring(index);
|
|
231
|
+
}
|
|
239
232
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
233
|
+
var len = this.length;
|
|
234
|
+
if (len < 4) return this.substring(0, 1) + "***";
|
|
235
|
+
if (len < 6) return this.substring(0, 2) + "***";
|
|
236
|
+
if (len < 8) return this.substring(0, 2) + "***" + this.slice(-2);
|
|
237
|
+
if (len < 12) return this.substring(0, 3) + "***" + this.slice(-3);
|
|
245
238
|
|
|
246
|
-
|
|
239
|
+
return this.substring(0, 4) + "***" + this.slice(-4);
|
|
247
240
|
};
|
|
248
241
|
|
|
249
242
|
String.prototype.hideEmail = function (this: string) {
|
|
250
|
-
|
|
243
|
+
return this.hideData("@");
|
|
251
244
|
};
|
|
252
245
|
|
|
253
246
|
String.prototype.isDigits = function (this: string, minLength?: number) {
|
|
254
|
-
|
|
247
|
+
return this.length >= (minLength ?? 0) && /^\d+$/.test(this);
|
|
255
248
|
};
|
|
256
249
|
|
|
257
250
|
String.prototype.isEmail = function (this: string) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
251
|
+
const re =
|
|
252
|
+
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
|
253
|
+
return re.test(this.toLowerCase());
|
|
261
254
|
};
|
|
262
255
|
|
|
263
256
|
String.prototype.removeNonLetters = function (this: string) {
|
|
264
|
-
|
|
257
|
+
return this.replace(/[^a-zA-Z0-9]/g, "");
|
|
265
258
|
};
|
|
266
259
|
|
|
267
260
|
/**
|
|
268
261
|
* Utilities
|
|
269
262
|
*/
|
|
270
263
|
export namespace Utils {
|
|
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
|
-
return options;
|
|
264
|
+
/**
|
|
265
|
+
* Add blank item to collection
|
|
266
|
+
* @param options Options
|
|
267
|
+
* @param idField Id field, default is id
|
|
268
|
+
* @param labelField Label field, default is label
|
|
269
|
+
* @param blankLabel Blank label, default is ---
|
|
270
|
+
*/
|
|
271
|
+
export function addBlankItem<T extends object>(
|
|
272
|
+
options: T[],
|
|
273
|
+
idField?: string | keyof T,
|
|
274
|
+
labelField?: unknown,
|
|
275
|
+
blankLabel?: string
|
|
276
|
+
) {
|
|
277
|
+
// Avoid duplicate blank items
|
|
278
|
+
idField ??= "id";
|
|
279
|
+
if (options.length === 0 || Reflect.get(options[0], idField) !== "") {
|
|
280
|
+
const blankItem: any = {
|
|
281
|
+
[idField]: "",
|
|
282
|
+
[typeof labelField === "string" ? labelField : "label"]:
|
|
283
|
+
blankLabel ?? "---"
|
|
284
|
+
};
|
|
285
|
+
options.unshift(blankItem);
|
|
296
286
|
}
|
|
297
287
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
288
|
+
return options;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Base64 chars to number
|
|
293
|
+
* @param base64Chars Base64 chars
|
|
294
|
+
* @returns Number
|
|
295
|
+
*/
|
|
296
|
+
export function charsToNumber(base64Chars: string) {
|
|
297
|
+
const chars =
|
|
298
|
+
typeof Buffer === "undefined"
|
|
299
|
+
? [...atob(base64Chars)].map((char) => char.charCodeAt(0))
|
|
300
|
+
: [...Buffer.from(base64Chars, "base64")];
|
|
301
|
+
|
|
302
|
+
return chars.reduce((previousValue, currentValue, currentIndex) => {
|
|
303
|
+
return previousValue + currentValue * Math.pow(128, currentIndex);
|
|
304
|
+
}, 0);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Correct object's property value type
|
|
309
|
+
* @param input Input object
|
|
310
|
+
* @param fields Fields to correct
|
|
311
|
+
*/
|
|
312
|
+
export function correctTypes<
|
|
313
|
+
T extends object,
|
|
314
|
+
F extends { [P in keyof T]?: DataTypes.BasicNames }
|
|
315
|
+
>(input: T, fields: F) {
|
|
316
|
+
for (const field in fields) {
|
|
317
|
+
const type = fields[field];
|
|
318
|
+
if (type == null) continue;
|
|
319
|
+
const value = Reflect.get(input, field);
|
|
320
|
+
const newValue = DataTypes.convertByType(value, type);
|
|
321
|
+
if (newValue !== value) {
|
|
322
|
+
Reflect.set(input, field, newValue);
|
|
323
|
+
}
|
|
312
324
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
const value = Reflect.get(input, field);
|
|
327
|
-
const newValue = DataTypes.convertByType(value, type);
|
|
328
|
-
if (newValue !== value) {
|
|
329
|
-
Reflect.set(input, field, newValue);
|
|
330
|
-
}
|
|
331
|
-
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Two values equal
|
|
329
|
+
* @param v1 Value 1
|
|
330
|
+
* @param v2 Value 2
|
|
331
|
+
* @param strict Strict level, 0 with ==, 1 === but null equal undefined, 2 ===
|
|
332
|
+
*/
|
|
333
|
+
export function equals(v1: unknown, v2: unknown, strict = 1) {
|
|
334
|
+
// Null and undefined case
|
|
335
|
+
if (v1 == null || v2 == null) {
|
|
336
|
+
if (strict <= 1 && v1 == v2) return true;
|
|
337
|
+
return v1 === v2;
|
|
332
338
|
}
|
|
333
339
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
340
|
+
// For date, array and object
|
|
341
|
+
if (typeof v1 === "object") return isEqual(v1, v2);
|
|
342
|
+
|
|
343
|
+
// 1 and '1' case
|
|
344
|
+
if (strict === 0) return v1 == v2;
|
|
345
|
+
|
|
346
|
+
// Strict equal
|
|
347
|
+
return v1 === v2;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Exclude specific items
|
|
352
|
+
* @param items Items
|
|
353
|
+
* @param field Filter field
|
|
354
|
+
* @param excludedValues Excluded values
|
|
355
|
+
* @returns Result
|
|
356
|
+
*/
|
|
357
|
+
export function exclude<
|
|
358
|
+
T extends { [P in D]: IdType },
|
|
359
|
+
D extends string = "id"
|
|
360
|
+
>(items: T[], field: D, ...excludedValues: T[D][]) {
|
|
361
|
+
return items.filter((item) => !excludedValues.includes(item[field]));
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Async exclude specific items
|
|
366
|
+
* @param items Items
|
|
367
|
+
* @param field Filter field
|
|
368
|
+
* @param excludedValues Excluded values
|
|
369
|
+
* @returns Result
|
|
370
|
+
*/
|
|
371
|
+
export async function excludeAsync<
|
|
372
|
+
T extends { [P in D]: IdType },
|
|
373
|
+
D extends string = "id"
|
|
374
|
+
>(items: Promise<T[] | undefined>, field: D, ...excludedValues: T[D][]) {
|
|
375
|
+
const result = await items;
|
|
376
|
+
if (result == null) return result;
|
|
377
|
+
return exclude(result, field, ...excludedValues);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Format inital character to lower case or upper case
|
|
382
|
+
* @param input Input string
|
|
383
|
+
* @param upperCase To upper case or lower case
|
|
384
|
+
*/
|
|
385
|
+
export function formatInitial(input: string, upperCase: boolean = false) {
|
|
386
|
+
return input.formatInitial(upperCase);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Format string with parameters
|
|
391
|
+
* @param template Template with {0}, {1}, ...
|
|
392
|
+
* @param parameters Parameters to fill the template
|
|
393
|
+
* @returns Result
|
|
394
|
+
*/
|
|
395
|
+
export function formatString(template: string, ...parameters: string[]) {
|
|
396
|
+
return template.format(...parameters);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Get data changed fields with input data updated
|
|
401
|
+
* @param input Input data
|
|
402
|
+
* @param initData Initial data
|
|
403
|
+
* @param ignoreFields Ignore fields
|
|
404
|
+
* @returns
|
|
405
|
+
*/
|
|
406
|
+
export function getDataChanges(
|
|
407
|
+
input: object,
|
|
408
|
+
initData: object,
|
|
409
|
+
ignoreFields: string[] = ["id"]
|
|
410
|
+
): string[] {
|
|
411
|
+
// Changed fields
|
|
412
|
+
const changes: string[] = [];
|
|
413
|
+
|
|
414
|
+
Object.entries(input).forEach(([key, value]) => {
|
|
415
|
+
// Ignore fields, no process
|
|
416
|
+
if (ignoreFields.includes(key)) return;
|
|
417
|
+
|
|
418
|
+
// Compare with init value
|
|
419
|
+
const initValue = Reflect.get(initData, key);
|
|
420
|
+
|
|
421
|
+
if (value == null && initValue == null) {
|
|
422
|
+
// Both are null, it's equal
|
|
423
|
+
Reflect.deleteProperty(input, key);
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (initValue != null) {
|
|
428
|
+
// Date when meets string
|
|
429
|
+
if (value instanceof Date) {
|
|
430
|
+
if (value.valueOf() === DateUtils.parse(initValue)?.valueOf()) {
|
|
431
|
+
Reflect.deleteProperty(input, key);
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
changes.push(key);
|
|
435
|
+
return;
|
|
345
436
|
}
|
|
346
437
|
|
|
347
|
-
|
|
348
|
-
if (
|
|
438
|
+
const newValue = DataTypes.convert(value, initValue);
|
|
439
|
+
if (Utils.equals(newValue, initValue)) {
|
|
440
|
+
Reflect.deleteProperty(input, key);
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
349
443
|
|
|
350
|
-
//
|
|
351
|
-
|
|
444
|
+
// Update
|
|
445
|
+
Reflect.set(input, key, newValue);
|
|
446
|
+
}
|
|
352
447
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
448
|
+
// Remove empty property
|
|
449
|
+
if (value == null || value === "") {
|
|
450
|
+
Reflect.deleteProperty(input, key);
|
|
451
|
+
}
|
|
356
452
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
* @param field Filter field
|
|
361
|
-
* @param excludedValues Excluded values
|
|
362
|
-
* @returns Result
|
|
363
|
-
*/
|
|
364
|
-
export function exclude<
|
|
365
|
-
T extends { [P in D]: IdType },
|
|
366
|
-
D extends string = 'id'
|
|
367
|
-
>(items: T[], field: D, ...excludedValues: T[D][]) {
|
|
368
|
-
return items.filter((item) => !excludedValues.includes(item[field]));
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
* Async exclude specific items
|
|
373
|
-
* @param items Items
|
|
374
|
-
* @param field Filter field
|
|
375
|
-
* @param excludedValues Excluded values
|
|
376
|
-
* @returns Result
|
|
377
|
-
*/
|
|
378
|
-
export async function excludeAsync<
|
|
379
|
-
T extends { [P in D]: IdType },
|
|
380
|
-
D extends string = 'id'
|
|
381
|
-
>(items: Promise<T[] | undefined>, field: D, ...excludedValues: T[D][]) {
|
|
382
|
-
const result = await items;
|
|
383
|
-
if (result == null) return result;
|
|
384
|
-
return exclude(result, field, ...excludedValues);
|
|
385
|
-
}
|
|
453
|
+
// Hold the key
|
|
454
|
+
changes.push(key);
|
|
455
|
+
});
|
|
386
456
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
457
|
+
return changes;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Get nested value from object
|
|
462
|
+
* @param data Data
|
|
463
|
+
* @param name Field name, support property chain like 'jsonData.logSize'
|
|
464
|
+
* @returns Result
|
|
465
|
+
*/
|
|
466
|
+
export function getNestedValue(data: object, name: string) {
|
|
467
|
+
const properties = name.split(".");
|
|
468
|
+
const len = properties.length;
|
|
469
|
+
if (len === 1) {
|
|
470
|
+
return Reflect.get(data, name);
|
|
471
|
+
} else {
|
|
472
|
+
let curr = data;
|
|
473
|
+
for (let i = 0; i < len; i++) {
|
|
474
|
+
const property = properties[i];
|
|
395
475
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
return template.format(...parameters);
|
|
404
|
-
}
|
|
476
|
+
if (i + 1 === len) {
|
|
477
|
+
return Reflect.get(curr, property);
|
|
478
|
+
} else {
|
|
479
|
+
let p = Reflect.get(curr, property);
|
|
480
|
+
if (p == null) {
|
|
481
|
+
return undefined;
|
|
482
|
+
}
|
|
405
483
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
* @param initData Initial data
|
|
410
|
-
* @param ignoreFields Ignore fields
|
|
411
|
-
* @returns
|
|
412
|
-
*/
|
|
413
|
-
export function getDataChanges(
|
|
414
|
-
input: object,
|
|
415
|
-
initData: object,
|
|
416
|
-
ignoreFields: string[] = ['id']
|
|
417
|
-
): string[] {
|
|
418
|
-
// Changed fields
|
|
419
|
-
const changes: string[] = [];
|
|
420
|
-
|
|
421
|
-
Object.entries(input).forEach(([key, value]) => {
|
|
422
|
-
// Ignore fields, no process
|
|
423
|
-
if (ignoreFields.includes(key)) return;
|
|
424
|
-
|
|
425
|
-
// Compare with init value
|
|
426
|
-
const initValue = Reflect.get(initData, key);
|
|
427
|
-
|
|
428
|
-
if (value == null && initValue == null) {
|
|
429
|
-
// Both are null, it's equal
|
|
430
|
-
Reflect.deleteProperty(input, key);
|
|
431
|
-
return;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
if (initValue != null) {
|
|
435
|
-
// Date when meets string
|
|
436
|
-
if (value instanceof Date) {
|
|
437
|
-
if (
|
|
438
|
-
value.valueOf() ===
|
|
439
|
-
DateUtils.parse(initValue)?.valueOf()
|
|
440
|
-
) {
|
|
441
|
-
Reflect.deleteProperty(input, key);
|
|
442
|
-
return;
|
|
443
|
-
}
|
|
444
|
-
changes.push(key);
|
|
445
|
-
return;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
const newValue = DataTypes.convert(value, initValue);
|
|
449
|
-
if (Utils.equals(newValue, initValue)) {
|
|
450
|
-
Reflect.deleteProperty(input, key);
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
// Update
|
|
455
|
-
Reflect.set(input, key, newValue);
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// Remove empty property
|
|
459
|
-
if (value == null || value === '') {
|
|
460
|
-
Reflect.deleteProperty(input, key);
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
// Hold the key
|
|
464
|
-
changes.push(key);
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
return changes;
|
|
484
|
+
curr = p;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
468
487
|
}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Get input function or value result
|
|
492
|
+
* @param input Input function or value
|
|
493
|
+
* @param args Arguments
|
|
494
|
+
* @returns Result
|
|
495
|
+
*/
|
|
496
|
+
export const getResult = <R, T = DataTypes.Func<R> | R>(
|
|
497
|
+
input: T,
|
|
498
|
+
...args: T extends DataTypes.Func<R> ? Parameters<typeof input> : never | []
|
|
499
|
+
): T extends DataTypes.Func<R> ? ReturnType<T> : T => {
|
|
500
|
+
return typeof input === "function" ? input(...args) : input;
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Get time zone
|
|
505
|
+
* @returns Timezone
|
|
506
|
+
*/
|
|
507
|
+
export const getTimeZone = () => {
|
|
508
|
+
// If Intl supported
|
|
509
|
+
if (typeof Intl === "object" && typeof Intl.DateTimeFormat === "function")
|
|
510
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
511
|
+
};
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Is digits string
|
|
515
|
+
* @param input Input string
|
|
516
|
+
* @param minLength Minimum length
|
|
517
|
+
* @returns Result
|
|
518
|
+
*/
|
|
519
|
+
export const isDigits = (input?: string, minLength?: number) => {
|
|
520
|
+
if (input == null) return false;
|
|
521
|
+
return input.isDigits(minLength);
|
|
522
|
+
};
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Is email string
|
|
526
|
+
* @param input Input string
|
|
527
|
+
* @returns Result
|
|
528
|
+
*/
|
|
529
|
+
export const isEmail = (input?: string) => {
|
|
530
|
+
if (input == null) return false;
|
|
531
|
+
return input.isEmail();
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Join items as a string
|
|
536
|
+
* @param items Items
|
|
537
|
+
* @param joinPart Join string
|
|
538
|
+
*/
|
|
539
|
+
export const joinItems = (
|
|
540
|
+
items: (string | undefined)[],
|
|
541
|
+
joinPart: string = ", "
|
|
542
|
+
) =>
|
|
543
|
+
items
|
|
544
|
+
.reduce((items, item) => {
|
|
545
|
+
if (item) {
|
|
546
|
+
const newItem = item.trim();
|
|
547
|
+
if (newItem) items.push(newItem);
|
|
497
548
|
}
|
|
549
|
+
return items;
|
|
550
|
+
}, [] as string[])
|
|
551
|
+
.join(joinPart);
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Merge class names
|
|
555
|
+
* @param classNames Class names
|
|
556
|
+
*/
|
|
557
|
+
export const mergeClasses = (...classNames: (string | undefined)[]) =>
|
|
558
|
+
joinItems(classNames, " ");
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Create a GUID
|
|
562
|
+
*/
|
|
563
|
+
export function newGUID() {
|
|
564
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
565
|
+
const r = (Math.random() * 16) | 0,
|
|
566
|
+
v = c === "x" ? r : (r & 0x3) | 0x8;
|
|
567
|
+
return v.toString(16);
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* Number to base64 chars
|
|
573
|
+
* @param num Input number
|
|
574
|
+
* @returns Result
|
|
575
|
+
*/
|
|
576
|
+
export function numberToChars(num: number) {
|
|
577
|
+
const codes = [];
|
|
578
|
+
while (num > 0) {
|
|
579
|
+
const code = num % 128;
|
|
580
|
+
codes.push(code);
|
|
581
|
+
num = (num - code) / 128;
|
|
498
582
|
}
|
|
499
583
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
*/
|
|
506
|
-
export const getResult = <R, T = DataTypes.Func<R> | R>(
|
|
507
|
-
input: T,
|
|
508
|
-
...args: T extends DataTypes.Func<R>
|
|
509
|
-
? Parameters<typeof input>
|
|
510
|
-
: never | []
|
|
511
|
-
): T extends DataTypes.Func<R> ? ReturnType<T> : T => {
|
|
512
|
-
return typeof input === 'function' ? input(...args) : input;
|
|
513
|
-
};
|
|
514
|
-
|
|
515
|
-
/**
|
|
516
|
-
* Get time zone
|
|
517
|
-
* @returns Timezone
|
|
518
|
-
*/
|
|
519
|
-
export const getTimeZone = () => {
|
|
520
|
-
// If Intl supported
|
|
521
|
-
if (
|
|
522
|
-
typeof Intl === 'object' &&
|
|
523
|
-
typeof Intl.DateTimeFormat === 'function'
|
|
524
|
-
)
|
|
525
|
-
return Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
526
|
-
};
|
|
527
|
-
|
|
528
|
-
/**
|
|
529
|
-
* Is digits string
|
|
530
|
-
* @param input Input string
|
|
531
|
-
* @param minLength Minimum length
|
|
532
|
-
* @returns Result
|
|
533
|
-
*/
|
|
534
|
-
export const isDigits = (input?: string, minLength?: number) => {
|
|
535
|
-
if (input == null) return false;
|
|
536
|
-
return input.isDigits(minLength);
|
|
537
|
-
};
|
|
538
|
-
|
|
539
|
-
/**
|
|
540
|
-
* Is email string
|
|
541
|
-
* @param input Input string
|
|
542
|
-
* @returns Result
|
|
543
|
-
*/
|
|
544
|
-
export const isEmail = (input?: string) => {
|
|
545
|
-
if (input == null) return false;
|
|
546
|
-
return input.isEmail();
|
|
547
|
-
};
|
|
548
|
-
|
|
549
|
-
/**
|
|
550
|
-
* Join items as a string
|
|
551
|
-
* @param items Items
|
|
552
|
-
* @param joinPart Join string
|
|
553
|
-
*/
|
|
554
|
-
export const joinItems = (
|
|
555
|
-
items: (string | undefined)[],
|
|
556
|
-
joinPart: string = ', '
|
|
557
|
-
) =>
|
|
558
|
-
items
|
|
559
|
-
.reduce((items, item) => {
|
|
560
|
-
if (item) {
|
|
561
|
-
const newItem = item.trim();
|
|
562
|
-
if (newItem) items.push(newItem);
|
|
563
|
-
}
|
|
564
|
-
return items;
|
|
565
|
-
}, [] as string[])
|
|
566
|
-
.join(joinPart);
|
|
567
|
-
|
|
568
|
-
/**
|
|
569
|
-
* Merge class names
|
|
570
|
-
* @param classNames Class names
|
|
571
|
-
*/
|
|
572
|
-
export const mergeClasses = (...classNames: (string | undefined)[]) =>
|
|
573
|
-
joinItems(classNames, ' ');
|
|
574
|
-
|
|
575
|
-
/**
|
|
576
|
-
* Create a GUID
|
|
577
|
-
*/
|
|
578
|
-
export function newGUID() {
|
|
579
|
-
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
580
|
-
const r = (Math.random() * 16) | 0,
|
|
581
|
-
v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
582
|
-
return v.toString(16);
|
|
583
|
-
});
|
|
584
|
+
if (typeof Buffer === "undefined") {
|
|
585
|
+
return btoa(String.fromCharCode(...codes));
|
|
586
|
+
} else {
|
|
587
|
+
const buffer = Buffer.from(codes);
|
|
588
|
+
return buffer.toString("base64");
|
|
584
589
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Test two objects are equal or not
|
|
594
|
+
* @param obj1 Object 1
|
|
595
|
+
* @param obj2 Object 2
|
|
596
|
+
* @param ignoreFields Ignored fields
|
|
597
|
+
* @param strict Strict level, 0 with ==, 1 === but null equal undefined, 2 ===
|
|
598
|
+
* @returns Result
|
|
599
|
+
*/
|
|
600
|
+
export function objectEqual(
|
|
601
|
+
obj1: object,
|
|
602
|
+
obj2: object,
|
|
603
|
+
ignoreFields: string[] = [],
|
|
604
|
+
strict = 1
|
|
605
|
+
) {
|
|
606
|
+
// Unique keys
|
|
607
|
+
const keys = Utils.objectKeys(obj1, obj2, ignoreFields);
|
|
608
|
+
|
|
609
|
+
for (const key of keys) {
|
|
610
|
+
// Values
|
|
611
|
+
const v1 = Reflect.get(obj1, key);
|
|
612
|
+
const v2 = Reflect.get(obj2, key);
|
|
613
|
+
|
|
614
|
+
if (!Utils.equals(v1, v2, strict)) return false;
|
|
605
615
|
}
|
|
606
616
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
const v1 = Reflect.get(obj1, key);
|
|
627
|
-
const v2 = Reflect.get(obj2, key);
|
|
628
|
-
|
|
629
|
-
if (!Utils.equals(v1, v2, strict)) return false;
|
|
630
|
-
}
|
|
617
|
+
return true;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* Get two object's unqiue properties
|
|
622
|
+
* @param obj1 Object 1
|
|
623
|
+
* @param obj2 Object 2
|
|
624
|
+
* @param ignoreFields Ignored fields
|
|
625
|
+
* @returns Unique properties
|
|
626
|
+
*/
|
|
627
|
+
export function objectKeys(
|
|
628
|
+
obj1: object,
|
|
629
|
+
obj2: object,
|
|
630
|
+
ignoreFields: string[] = []
|
|
631
|
+
) {
|
|
632
|
+
// All keys
|
|
633
|
+
const allKeys = [...Object.keys(obj1), ...Object.keys(obj2)].filter(
|
|
634
|
+
(item) => !ignoreFields.includes(item)
|
|
635
|
+
);
|
|
631
636
|
|
|
632
|
-
|
|
637
|
+
// Unique keys
|
|
638
|
+
return new Set(allKeys);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
/**
|
|
642
|
+
* Get the new object's updated fields contrast to the previous object
|
|
643
|
+
* @param objNew New object
|
|
644
|
+
* @param objPre Previous object
|
|
645
|
+
* @param ignoreFields Ignored fields
|
|
646
|
+
* @param strict Strict level, 0 with ==, 1 === but null equal undefined, 2 ===
|
|
647
|
+
* @returns Updated fields
|
|
648
|
+
*/
|
|
649
|
+
export function objectUpdated(
|
|
650
|
+
objNew: object,
|
|
651
|
+
objPrev: object,
|
|
652
|
+
ignoreFields: string[] = [],
|
|
653
|
+
strict = 1
|
|
654
|
+
) {
|
|
655
|
+
// Fields
|
|
656
|
+
const fields: string[] = [];
|
|
657
|
+
|
|
658
|
+
// Unique keys
|
|
659
|
+
const keys = Utils.objectKeys(objNew, objPrev, ignoreFields);
|
|
660
|
+
|
|
661
|
+
for (const key of keys) {
|
|
662
|
+
// Values
|
|
663
|
+
const vNew = Reflect.get(objNew, key);
|
|
664
|
+
const vPrev = Reflect.get(objPrev, key);
|
|
665
|
+
|
|
666
|
+
if (!Utils.equals(vNew, vPrev, strict)) {
|
|
667
|
+
fields.push(key);
|
|
668
|
+
}
|
|
633
669
|
}
|
|
634
670
|
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
671
|
+
return fields;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* Try to parse JSON input to array
|
|
676
|
+
* @param input JSON input
|
|
677
|
+
* @param checkValue Type check value
|
|
678
|
+
* @returns Result
|
|
679
|
+
*/
|
|
680
|
+
export function parseJsonArray<T>(
|
|
681
|
+
input: string,
|
|
682
|
+
checkValue?: T
|
|
683
|
+
): T[] | undefined {
|
|
684
|
+
try {
|
|
685
|
+
if (!input.startsWith("[")) input = `[${input}]`;
|
|
686
|
+
const array = JSON.parse(input);
|
|
687
|
+
const type = typeof checkValue;
|
|
688
|
+
if (
|
|
689
|
+
Array.isArray(array) &&
|
|
690
|
+
(checkValue == null || !array.some((item) => typeof item !== type))
|
|
691
|
+
) {
|
|
692
|
+
return array;
|
|
693
|
+
}
|
|
694
|
+
} catch (e) {
|
|
695
|
+
console.error(`Utils.parseJsonArray ${input} with error`, e);
|
|
654
696
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* Parse string (JSON) to specific type, no type conversion
|
|
702
|
+
* For type conversion, please use DataTypes.convert
|
|
703
|
+
* @param input Input string
|
|
704
|
+
* @returns Parsed value
|
|
705
|
+
*/
|
|
706
|
+
export function parseString<T>(
|
|
707
|
+
input: string | undefined | null
|
|
708
|
+
): T | undefined;
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* Parse string (JSON) to specific type, no type conversion
|
|
712
|
+
* For type conversion, please use DataTypes.convert
|
|
713
|
+
* @param input Input string
|
|
714
|
+
* @param defaultValue Default value
|
|
715
|
+
* @returns Parsed value
|
|
716
|
+
*/
|
|
717
|
+
export function parseString<T>(
|
|
718
|
+
input: string | undefined | null,
|
|
719
|
+
defaultValue: T
|
|
720
|
+
): T;
|
|
721
|
+
|
|
722
|
+
/**
|
|
723
|
+
* Parse string (JSON) to specific type, no type conversion
|
|
724
|
+
* When return type depends on parameter value, uses function overloading, otherwise uses conditional type
|
|
725
|
+
* For type conversion, please use DataTypes.convert
|
|
726
|
+
* @param input Input string
|
|
727
|
+
* @param defaultValue Default value
|
|
728
|
+
* @returns Parsed value
|
|
729
|
+
*/
|
|
730
|
+
export function parseString<T>(
|
|
731
|
+
input: string | undefined | null,
|
|
732
|
+
defaultValue?: T
|
|
733
|
+
): T | undefined {
|
|
734
|
+
// Undefined and empty case, return default value
|
|
735
|
+
if (input == null || input === "") return <T>defaultValue;
|
|
736
|
+
|
|
737
|
+
// String
|
|
738
|
+
if (typeof defaultValue === "string") return <any>input;
|
|
739
|
+
|
|
740
|
+
try {
|
|
741
|
+
// Date
|
|
742
|
+
if (defaultValue instanceof Date) {
|
|
743
|
+
const date = new Date(input);
|
|
744
|
+
if (date == null) return <any>defaultValue;
|
|
745
|
+
return <any>date;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// JSON
|
|
749
|
+
const json = JSON.parse(input);
|
|
750
|
+
|
|
751
|
+
// Return
|
|
752
|
+
return <T>json;
|
|
753
|
+
} catch {
|
|
754
|
+
if (defaultValue == null) return <any>input;
|
|
755
|
+
return <T>defaultValue;
|
|
687
756
|
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* Remove empty values (null, undefined, '') from the input object
|
|
761
|
+
* @param input Input object
|
|
762
|
+
*/
|
|
763
|
+
export function removeEmptyValues(input: object) {
|
|
764
|
+
Object.keys(input).forEach((key) => {
|
|
765
|
+
const value = Reflect.get(input, key);
|
|
766
|
+
if (value == null || value === "") {
|
|
767
|
+
Reflect.deleteProperty(input, key);
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* Remove non letters
|
|
774
|
+
* @param input Input string
|
|
775
|
+
* @returns Result
|
|
776
|
+
*/
|
|
777
|
+
export const removeNonLetters = (input?: string) => {
|
|
778
|
+
return input?.removeNonLetters();
|
|
779
|
+
};
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* Replace null or empty with default value
|
|
783
|
+
* @param input Input string
|
|
784
|
+
* @param defaultValue Default value
|
|
785
|
+
* @returns Result
|
|
786
|
+
*/
|
|
787
|
+
export const replaceNullOrEmpty = (
|
|
788
|
+
input: string | null | undefined,
|
|
789
|
+
defaultValue: string
|
|
790
|
+
) => {
|
|
791
|
+
if (input == null || input.trim() === "") return defaultValue;
|
|
792
|
+
return input;
|
|
793
|
+
};
|
|
794
|
+
|
|
795
|
+
/**
|
|
796
|
+
* Set source with new labels
|
|
797
|
+
* @param source Source
|
|
798
|
+
* @param labels Labels
|
|
799
|
+
* @param reference Key reference dictionary
|
|
800
|
+
*/
|
|
801
|
+
export const setLabels = (
|
|
802
|
+
source: DataTypes.StringRecord,
|
|
803
|
+
labels: DataTypes.StringRecord,
|
|
804
|
+
reference?: Readonly<DataTypes.StringDictionary>
|
|
805
|
+
) => {
|
|
806
|
+
Object.keys(source).forEach((key) => {
|
|
807
|
+
// Reference key
|
|
808
|
+
const labelKey = reference == null ? key : reference[key] ?? key;
|
|
809
|
+
|
|
810
|
+
// Label
|
|
811
|
+
const label = labels[labelKey];
|
|
812
|
+
|
|
813
|
+
if (label != null) {
|
|
814
|
+
// If found, update
|
|
815
|
+
Reflect.set(source, key, label);
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
};
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* Snake name to works, 'snake_name' to 'Snake Name'
|
|
822
|
+
* @param name Name text
|
|
823
|
+
* @param firstOnly Only convert the first word to upper case
|
|
824
|
+
*/
|
|
825
|
+
export const snakeNameToWord = (name: string, firstOnly: boolean = false) => {
|
|
826
|
+
const items = name.split("_");
|
|
827
|
+
if (firstOnly) {
|
|
828
|
+
items[0] = items[0].formatInitial(true);
|
|
829
|
+
return items.join(" ");
|
|
714
830
|
}
|
|
715
831
|
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
832
|
+
return items.map((part) => part.formatInitial(true)).join(" ");
|
|
833
|
+
};
|
|
834
|
+
|
|
835
|
+
function getSortValue(n1: number, n2: number) {
|
|
836
|
+
if (n1 === n2) return 0;
|
|
837
|
+
if (n1 === -1) return 1;
|
|
838
|
+
if (n2 === -1) return -1;
|
|
839
|
+
return n1 - n2;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
/**
|
|
843
|
+
* Set nested value to object
|
|
844
|
+
* @param data Data
|
|
845
|
+
* @param name Field name, support property chain like 'jsonData.logSize'
|
|
846
|
+
* @param value Value
|
|
847
|
+
* @param keepNull Keep null value or not
|
|
848
|
+
*/
|
|
849
|
+
export function setNestedValue(
|
|
850
|
+
data: object,
|
|
851
|
+
name: string,
|
|
852
|
+
value: unknown,
|
|
853
|
+
keepNull?: boolean
|
|
854
|
+
) {
|
|
855
|
+
const properties = name.split(".");
|
|
856
|
+
const len = properties.length;
|
|
857
|
+
if (len === 1) {
|
|
858
|
+
if (value == null && keepNull !== true) {
|
|
859
|
+
Reflect.deleteProperty(data, name);
|
|
860
|
+
} else {
|
|
861
|
+
Reflect.set(data, name, value);
|
|
862
|
+
}
|
|
863
|
+
} else {
|
|
864
|
+
let curr = data;
|
|
865
|
+
for (let i = 0; i < len; i++) {
|
|
866
|
+
const property = properties[i];
|
|
725
867
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
defaultValue: T
|
|
736
|
-
): T;
|
|
868
|
+
if (i + 1 === len) {
|
|
869
|
+
setNestedValue(curr, property, value, keepNull);
|
|
870
|
+
// Reflect.set(curr, property, value);
|
|
871
|
+
} else {
|
|
872
|
+
let p = Reflect.get(curr, property);
|
|
873
|
+
if (p == null) {
|
|
874
|
+
p = {};
|
|
875
|
+
Reflect.set(curr, property, p);
|
|
876
|
+
}
|
|
737
877
|
|
|
738
|
-
|
|
739
|
-
* Parse string (JSON) to specific type, no type conversion
|
|
740
|
-
* When return type depends on parameter value, uses function overloading, otherwise uses conditional type
|
|
741
|
-
* For type conversion, please use DataTypes.convert
|
|
742
|
-
* @param input Input string
|
|
743
|
-
* @param defaultValue Default value
|
|
744
|
-
* @returns Parsed value
|
|
745
|
-
*/
|
|
746
|
-
export function parseString<T>(
|
|
747
|
-
input: string | undefined | null,
|
|
748
|
-
defaultValue?: T
|
|
749
|
-
): T | undefined {
|
|
750
|
-
// Undefined and empty case, return default value
|
|
751
|
-
if (input == null || input === '') return <T>defaultValue;
|
|
752
|
-
|
|
753
|
-
// String
|
|
754
|
-
if (typeof defaultValue === 'string') return <any>input;
|
|
755
|
-
|
|
756
|
-
try {
|
|
757
|
-
// Date
|
|
758
|
-
if (defaultValue instanceof Date) {
|
|
759
|
-
const date = new Date(input);
|
|
760
|
-
if (date == null) return <any>defaultValue;
|
|
761
|
-
return <any>date;
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
// JSON
|
|
765
|
-
const json = JSON.parse(input);
|
|
766
|
-
|
|
767
|
-
// Return
|
|
768
|
-
return <T>json;
|
|
769
|
-
} catch {
|
|
770
|
-
if (defaultValue == null) return <any>input;
|
|
771
|
-
return <T>defaultValue;
|
|
878
|
+
curr = p;
|
|
772
879
|
}
|
|
880
|
+
}
|
|
773
881
|
}
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/**
|
|
885
|
+
* Parse path similar with node.js path.parse
|
|
886
|
+
* @param path Input path
|
|
887
|
+
*/
|
|
888
|
+
export const parsePath = (path: string): ParsedPath => {
|
|
889
|
+
// Two formats or mixed
|
|
890
|
+
// /home/user/dir/file.txt
|
|
891
|
+
// C:\\path\\dir\\file.txt
|
|
892
|
+
const lastIndex = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
|
|
893
|
+
|
|
894
|
+
let root = "",
|
|
895
|
+
dir = "",
|
|
896
|
+
base: string,
|
|
897
|
+
ext: string,
|
|
898
|
+
name: string;
|
|
899
|
+
|
|
900
|
+
if (lastIndex === -1) {
|
|
901
|
+
base = path;
|
|
902
|
+
} else {
|
|
903
|
+
base = path.substring(lastIndex + 1);
|
|
904
|
+
const index1 = path.indexOf("/");
|
|
905
|
+
const index2 = path.indexOf("\\");
|
|
906
|
+
const index =
|
|
907
|
+
index1 === -1
|
|
908
|
+
? index2
|
|
909
|
+
: index2 === -1
|
|
910
|
+
? index1
|
|
911
|
+
: Math.min(index1, index2);
|
|
912
|
+
root = path.substring(0, index + 1);
|
|
913
|
+
dir = path.substring(0, lastIndex);
|
|
914
|
+
if (dir === "") dir = root;
|
|
786
915
|
}
|
|
787
916
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
};
|
|
796
|
-
|
|
797
|
-
/**
|
|
798
|
-
* Replace null or empty with default value
|
|
799
|
-
* @param input Input string
|
|
800
|
-
* @param defaultValue Default value
|
|
801
|
-
* @returns Result
|
|
802
|
-
*/
|
|
803
|
-
export const replaceNullOrEmpty = (
|
|
804
|
-
input: string | null | undefined,
|
|
805
|
-
defaultValue: string
|
|
806
|
-
) => {
|
|
807
|
-
if (input == null || input.trim() === '') return defaultValue;
|
|
808
|
-
return input;
|
|
809
|
-
};
|
|
810
|
-
|
|
811
|
-
/**
|
|
812
|
-
* Set source with new labels
|
|
813
|
-
* @param source Source
|
|
814
|
-
* @param labels Labels
|
|
815
|
-
* @param reference Key reference dictionary
|
|
816
|
-
*/
|
|
817
|
-
export const setLabels = (
|
|
818
|
-
source: DataTypes.StringRecord,
|
|
819
|
-
labels: DataTypes.StringRecord,
|
|
820
|
-
reference?: Readonly<DataTypes.StringDictionary>
|
|
821
|
-
) => {
|
|
822
|
-
Object.keys(source).forEach((key) => {
|
|
823
|
-
// Reference key
|
|
824
|
-
const labelKey = reference == null ? key : reference[key] ?? key;
|
|
825
|
-
|
|
826
|
-
// Label
|
|
827
|
-
const label = labels[labelKey];
|
|
828
|
-
|
|
829
|
-
if (label != null) {
|
|
830
|
-
// If found, update
|
|
831
|
-
Reflect.set(source, key, label);
|
|
832
|
-
}
|
|
833
|
-
});
|
|
834
|
-
};
|
|
835
|
-
|
|
836
|
-
/**
|
|
837
|
-
* Snake name to works, 'snake_name' to 'Snake Name'
|
|
838
|
-
* @param name Name text
|
|
839
|
-
* @param firstOnly Only convert the first word to upper case
|
|
840
|
-
*/
|
|
841
|
-
export const snakeNameToWord = (
|
|
842
|
-
name: string,
|
|
843
|
-
firstOnly: boolean = false
|
|
844
|
-
) => {
|
|
845
|
-
const items = name.split('_');
|
|
846
|
-
if (firstOnly) {
|
|
847
|
-
items[0] = items[0].formatInitial(true);
|
|
848
|
-
return items.join(' ');
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
return items.map((part) => part.formatInitial(true)).join(' ');
|
|
852
|
-
};
|
|
853
|
-
|
|
854
|
-
function getSortValue(n1: number, n2: number) {
|
|
855
|
-
if (n1 === n2) return 0;
|
|
856
|
-
if (n1 === -1) return 1;
|
|
857
|
-
if (n2 === -1) return -1;
|
|
858
|
-
return n1 - n2;
|
|
917
|
+
const extIndex = base.lastIndexOf(".");
|
|
918
|
+
if (extIndex === -1) {
|
|
919
|
+
name = base;
|
|
920
|
+
ext = "";
|
|
921
|
+
} else {
|
|
922
|
+
name = base.substring(0, extIndex);
|
|
923
|
+
ext = base.substring(extIndex);
|
|
859
924
|
}
|
|
860
925
|
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
926
|
+
return { root, dir, base, ext, name };
|
|
927
|
+
};
|
|
928
|
+
|
|
929
|
+
/**
|
|
930
|
+
* Sort array by favored values
|
|
931
|
+
* @param items Items
|
|
932
|
+
* @param favored Favored values
|
|
933
|
+
* @returns Sorted array
|
|
934
|
+
*/
|
|
935
|
+
export const sortByFavor = <T>(items: T[], favored: T[]) => {
|
|
936
|
+
return items.sort((r1, r2) => {
|
|
937
|
+
const n1 = favored.indexOf(r1);
|
|
938
|
+
const n2 = favored.indexOf(r2);
|
|
939
|
+
return getSortValue(n1, n2);
|
|
940
|
+
});
|
|
941
|
+
};
|
|
942
|
+
|
|
943
|
+
/**
|
|
944
|
+
* Sort array by favored field values
|
|
945
|
+
* @param items Items
|
|
946
|
+
* @param field Field to sort
|
|
947
|
+
* @param favored Favored field values
|
|
948
|
+
* @returns Sorted array
|
|
949
|
+
*/
|
|
950
|
+
export const sortByFieldFavor = <T, F extends keyof T>(
|
|
951
|
+
items: T[],
|
|
952
|
+
field: F,
|
|
953
|
+
favored: T[F][]
|
|
954
|
+
) => {
|
|
955
|
+
return items.sort((r1, r2) => {
|
|
956
|
+
const n1 = favored.indexOf(r1[field]);
|
|
957
|
+
const n2 = favored.indexOf(r2[field]);
|
|
958
|
+
return getSortValue(n1, n2);
|
|
959
|
+
});
|
|
960
|
+
};
|
|
961
|
+
|
|
962
|
+
/**
|
|
963
|
+
* Trim chars
|
|
964
|
+
* @param input Input string
|
|
965
|
+
* @param chars Trim chars
|
|
966
|
+
* @returns Result
|
|
967
|
+
*/
|
|
968
|
+
export const trim = (input: string, ...chars: string[]) => {
|
|
969
|
+
return trimEnd(trimStart(input, ...chars), ...chars);
|
|
970
|
+
};
|
|
971
|
+
|
|
972
|
+
/**
|
|
973
|
+
* Trim end chars
|
|
974
|
+
* @param input Input string
|
|
975
|
+
* @param chars Trim chars
|
|
976
|
+
* @returns Result
|
|
977
|
+
*/
|
|
978
|
+
export const trimEnd = (input: string, ...chars: string[]) => {
|
|
979
|
+
let char: string | undefined;
|
|
980
|
+
while ((char = chars.find((char) => input.endsWith(char))) != null) {
|
|
981
|
+
input = input.substring(0, input.length - char.length);
|
|
901
982
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
base: string,
|
|
919
|
-
ext: string,
|
|
920
|
-
name: string;
|
|
921
|
-
|
|
922
|
-
if (lastIndex === -1) {
|
|
923
|
-
base = path;
|
|
924
|
-
} else {
|
|
925
|
-
base = path.substring(lastIndex + 1);
|
|
926
|
-
const index1 = path.indexOf('/');
|
|
927
|
-
const index2 = path.indexOf('\\');
|
|
928
|
-
const index =
|
|
929
|
-
index1 === -1
|
|
930
|
-
? index2
|
|
931
|
-
: index2 === -1
|
|
932
|
-
? index1
|
|
933
|
-
: Math.min(index1, index2);
|
|
934
|
-
root = path.substring(0, index + 1);
|
|
935
|
-
dir = path.substring(0, lastIndex);
|
|
936
|
-
if (dir === '') dir = root;
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
const extIndex = base.lastIndexOf('.');
|
|
940
|
-
if (extIndex === -1) {
|
|
941
|
-
name = base;
|
|
942
|
-
ext = '';
|
|
943
|
-
} else {
|
|
944
|
-
name = base.substring(0, extIndex);
|
|
945
|
-
ext = base.substring(extIndex);
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
return { root, dir, base, ext, name };
|
|
949
|
-
};
|
|
950
|
-
|
|
951
|
-
/**
|
|
952
|
-
* Sort array by favored values
|
|
953
|
-
* @param items Items
|
|
954
|
-
* @param favored Favored values
|
|
955
|
-
* @returns Sorted array
|
|
956
|
-
*/
|
|
957
|
-
export const sortByFavor = <T>(items: T[], favored: T[]) => {
|
|
958
|
-
return items.sort((r1, r2) => {
|
|
959
|
-
const n1 = favored.indexOf(r1);
|
|
960
|
-
const n2 = favored.indexOf(r2);
|
|
961
|
-
return getSortValue(n1, n2);
|
|
962
|
-
});
|
|
963
|
-
};
|
|
964
|
-
|
|
965
|
-
/**
|
|
966
|
-
* Sort array by favored field values
|
|
967
|
-
* @param items Items
|
|
968
|
-
* @param field Field to sort
|
|
969
|
-
* @param favored Favored field values
|
|
970
|
-
* @returns Sorted array
|
|
971
|
-
*/
|
|
972
|
-
export const sortByFieldFavor = <T, F extends keyof T>(
|
|
973
|
-
items: T[],
|
|
974
|
-
field: F,
|
|
975
|
-
favored: T[F][]
|
|
976
|
-
) => {
|
|
977
|
-
return items.sort((r1, r2) => {
|
|
978
|
-
const n1 = favored.indexOf(r1[field]);
|
|
979
|
-
const n2 = favored.indexOf(r2[field]);
|
|
980
|
-
return getSortValue(n1, n2);
|
|
981
|
-
});
|
|
982
|
-
};
|
|
983
|
-
|
|
984
|
-
/**
|
|
985
|
-
* Trim chars
|
|
986
|
-
* @param input Input string
|
|
987
|
-
* @param chars Trim chars
|
|
988
|
-
* @returns Result
|
|
989
|
-
*/
|
|
990
|
-
export const trim = (input: string, ...chars: string[]) => {
|
|
991
|
-
return trimEnd(trimStart(input, ...chars), ...chars);
|
|
992
|
-
};
|
|
993
|
-
|
|
994
|
-
/**
|
|
995
|
-
* Trim end chars
|
|
996
|
-
* @param input Input string
|
|
997
|
-
* @param chars Trim chars
|
|
998
|
-
* @returns Result
|
|
999
|
-
*/
|
|
1000
|
-
export const trimEnd = (input: string, ...chars: string[]) => {
|
|
1001
|
-
let char: string | undefined;
|
|
1002
|
-
while ((char = chars.find((char) => input.endsWith(char))) != null) {
|
|
1003
|
-
input = input.substring(0, input.length - char.length);
|
|
1004
|
-
}
|
|
1005
|
-
return input;
|
|
1006
|
-
};
|
|
1007
|
-
|
|
1008
|
-
/**
|
|
1009
|
-
* Trim start chars
|
|
1010
|
-
* @param input Input string
|
|
1011
|
-
* @param chars Trim chars
|
|
1012
|
-
* @returns Result
|
|
1013
|
-
*/
|
|
1014
|
-
export const trimStart = (input: string, ...chars: string[]) => {
|
|
1015
|
-
let char: string | undefined;
|
|
1016
|
-
while ((char = chars.find((char) => input.startsWith(char))) != null) {
|
|
1017
|
-
input = input.substring(char.length);
|
|
1018
|
-
}
|
|
1019
|
-
return input;
|
|
1020
|
-
};
|
|
983
|
+
return input;
|
|
984
|
+
};
|
|
985
|
+
|
|
986
|
+
/**
|
|
987
|
+
* Trim start chars
|
|
988
|
+
* @param input Input string
|
|
989
|
+
* @param chars Trim chars
|
|
990
|
+
* @returns Result
|
|
991
|
+
*/
|
|
992
|
+
export const trimStart = (input: string, ...chars: string[]) => {
|
|
993
|
+
let char: string | undefined;
|
|
994
|
+
while ((char = chars.find((char) => input.startsWith(char))) != null) {
|
|
995
|
+
input = input.substring(char.length);
|
|
996
|
+
}
|
|
997
|
+
return input;
|
|
998
|
+
};
|
|
1021
999
|
}
|