grofc_utils 1.0.0
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/generate.exports.js +51 -0
- package/index.js +5 -0
- package/package.json +45 -0
- package/readme.md +4 -0
- package/src/array.js +22 -0
- package/src/guard.js +564 -0
- package/src/missingData.js +65 -0
- package/src/random.js +372 -0
- package/src/string.js +24 -0
- package/tsconfig.json +112 -0
- package/types/index.d.ts +5 -0
- package/types/src/array.d.ts +7 -0
- package/types/src/guard.d.ts +223 -0
- package/types/src/missingData.d.ts +37 -0
- package/types/src/random.d.ts +173 -0
- package/types/src/string.d.ts +9 -0
package/src/guard.js
ADDED
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 获取变量的类型字符串表示
|
|
3
|
+
* @param {*} v - 要检查类型的变量
|
|
4
|
+
* @returns {string} 变量的类型字符串
|
|
5
|
+
*/
|
|
6
|
+
const getType = v => v === null ? "null" : typeof v
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class GuardError extends Error {
|
|
10
|
+
/**
|
|
11
|
+
*
|
|
12
|
+
* @param {string|Error} cause
|
|
13
|
+
*/
|
|
14
|
+
constructor(cause) {
|
|
15
|
+
if (cause instanceof Error) {
|
|
16
|
+
super(`Guard execution failed: ${cause.message}`);
|
|
17
|
+
this.originalError = cause;
|
|
18
|
+
this.stack = cause.stack;
|
|
19
|
+
} else {
|
|
20
|
+
super(`Guard execution failed: ${cause || "Unknown error"}`);
|
|
21
|
+
this.originalError = null;
|
|
22
|
+
}
|
|
23
|
+
this.name = "GuardError";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const safeGuardExecute = (guardFunc, ...args) => {
|
|
27
|
+
try {
|
|
28
|
+
guardFunc(...args)
|
|
29
|
+
} catch (err) {
|
|
30
|
+
throw new GuardError(err);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const throwTypeErrorGiveType = (variable, name = "variable", ...acceptableTypeDescs) => {
|
|
35
|
+
if (acceptableTypeDescs.length === 1) throw TypeError(`Expected ${name} to be ${acceptableTypeDescs}, but got ${getType(variable)}.`)
|
|
36
|
+
else if (acceptableTypeDescs.length > 1) throw TypeError(`Expected ${name} to be ${acceptableTypeDescs.slice(0, -1).join(" ,")} or ${acceptableTypeDescs[acceptableTypeDescs.length - 1]}, but got ${getType(variable)}.`)
|
|
37
|
+
}
|
|
38
|
+
const throwTypeErrorGiveValue = (variable, name = "variable", ...acceptableValueDescs) => {
|
|
39
|
+
if (acceptableValueDescs.length === 1) throw TypeError(`Expected ${name} to be ${acceptableValueDescs}, but got ${variable}.`)
|
|
40
|
+
else if (acceptableValueDescs.length > 1) throw TypeError(`Expected ${name} to be ${acceptableValueDescs.slice(0, -1).join(" ,")} or ${acceptableValueDescs[acceptableValueDescs.length - 1]}, but got ${variable}.`)
|
|
41
|
+
}
|
|
42
|
+
const throwTypeErrorForArray = (name = "variable", acceptableTypeDesc, unexpectedElementDesc) => {
|
|
43
|
+
throw TypeError(`Expected all elements of ${name} to be ${acceptableTypeDesc}, but found ${unexpectedElementDesc}.`)
|
|
44
|
+
}
|
|
45
|
+
const throwRangeErrorGiveValue = (variable, name = "variable", ...acceptableRangeDescs) => {
|
|
46
|
+
if (acceptableRangeDescs.length === 1) throw RangeError(`Expected ${name} to be ${acceptableRangeDescs}, but got ${variable}.`)
|
|
47
|
+
else if (acceptableRangeDescs.length > 1) throw RangeError(`Expected ${name} to be ${acceptableRangeDescs.slice(0, -1).join(" ,")} or ${acceptableRangeDescs[acceptableRangeDescs.length - 1]}, but got ${variable}.`)
|
|
48
|
+
}
|
|
49
|
+
// ------------------------------------------------
|
|
50
|
+
// 值校验守卫函数
|
|
51
|
+
// ------------------------------------------------
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 检查变量是否为空值(不为 null 或 undefined)
|
|
55
|
+
* @param {*} variable - 要检查的变量
|
|
56
|
+
* @param {string} name - 变量名称(用于错误消息)
|
|
57
|
+
* @throws {TypeError} 当变量为 null 或 undefined 时抛出类型错误
|
|
58
|
+
*/
|
|
59
|
+
export function throwIfIsNullishValue(variable, name = "variable") {
|
|
60
|
+
if (variable == null) {
|
|
61
|
+
throwTypeErrorGiveValue(variable, name, "not null or undefined")
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 检查变量是否为真值(truthy)
|
|
67
|
+
* @param {*} variable - 要检查的变量
|
|
68
|
+
* @param {string} name - 变量名称(用于错误消息)
|
|
69
|
+
* @throws {TypeError} 当变量为假值(falsy)时抛出类型错误
|
|
70
|
+
*/
|
|
71
|
+
export function throwIfIsFalsyValue(variable, name = "variable") {
|
|
72
|
+
if (!variable) {
|
|
73
|
+
throwTypeErrorGiveValue(variable, name, "a truthy value")
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ------------------------------------------------
|
|
78
|
+
// 数字类型守卫函数
|
|
79
|
+
// ------------------------------------------------
|
|
80
|
+
/**
|
|
81
|
+
* 检查变量是否为数字类型
|
|
82
|
+
* @param {*} variable - 要检查的变量
|
|
83
|
+
* @param {string} name - 变量名称(用于错误消息)
|
|
84
|
+
* @throws {TypeError} 当变量不是数字类型时抛出类型错误
|
|
85
|
+
*/
|
|
86
|
+
export function throwIfIsNotNumber(variable, name = "variable") {
|
|
87
|
+
if (typeof variable !== "number") {
|
|
88
|
+
throwTypeErrorGiveType(variable, name, "a number")
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 检查数字变量是否为 NaN(非数字)
|
|
93
|
+
* @param {*} variable - 要检查的变量
|
|
94
|
+
* @param {string} name - 变量名称(用于错误消息)
|
|
95
|
+
* @throws {TypeError} 当变量是 NaN 时抛出类型错误
|
|
96
|
+
*/
|
|
97
|
+
export function throwIfIsNotComparableNumber(variable, name = "variable") {
|
|
98
|
+
throwIfIsNotNumber(variable, name)
|
|
99
|
+
if (Number.isNaN(variable)) {
|
|
100
|
+
throwTypeErrorGiveValue(variable, name, "comparable number(not NaN)")
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
export const throwIfIsNotNumberOrIsNaN = throwIfIsNotComparableNumber;
|
|
104
|
+
/**
|
|
105
|
+
* 检查变量是否为有限数字(排除 Infinity 和 -Infinity,但允许 NaN)
|
|
106
|
+
* @param {*} variable - 要检查的变量
|
|
107
|
+
* @param {string} name - 变量名称(用于错误消息)
|
|
108
|
+
* @throws {TypeError} 当变量不是有限数字时抛出类型错误
|
|
109
|
+
*/
|
|
110
|
+
export function throwIfIsNotFiniteNumber(variable, name = "variable") {
|
|
111
|
+
throwIfIsNotNumber(variable, name)
|
|
112
|
+
if (!Number.isFinite(variable)) {
|
|
113
|
+
throwTypeErrorGiveValue(variable, name, "a finite number")
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* 检查变量是否为正有限数
|
|
119
|
+
* @param {*} variable - 要检查的变量
|
|
120
|
+
* @param {string} name - 变量名称(用于错误消息)
|
|
121
|
+
* @throws {RangeError} 当变量不是正有限数时抛出范围错误
|
|
122
|
+
*/
|
|
123
|
+
export function throwIfIsNotPositiveFiniteNumber(variable, name = "variable") {
|
|
124
|
+
throwIfIsNotFiniteNumber(variable, name)
|
|
125
|
+
if (variable <= 0) {
|
|
126
|
+
throwRangeErrorGiveValue(variable, name, "a positive finite number");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* 检查变量是否为负有限数
|
|
132
|
+
* @param {*} variable - 要检查的变量
|
|
133
|
+
* @param {string} name - 变量名称(用于错误消息)
|
|
134
|
+
* @throws {RangeError} 当变量不是负有限数时抛出范围错误
|
|
135
|
+
*/
|
|
136
|
+
export function throwIfIsNotNegativeFiniteNumber(variable, name = "variable") {
|
|
137
|
+
throwIfIsNotFiniteNumber(variable, name)
|
|
138
|
+
if (variable >= 0) {
|
|
139
|
+
throwRangeErrorGiveValue(variable, name, "a negative finite number");
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* 检查变量是否为非负有限数(大于等于0的有限数)
|
|
145
|
+
* @param {*} variable - 要检查的变量
|
|
146
|
+
* @param {string} name - 变量名称(用于错误消息)
|
|
147
|
+
* @throws {RangeError} 当变量不是非负有限数时抛出范围错误
|
|
148
|
+
*/
|
|
149
|
+
export function throwIfIsNotNonNegativeFiniteNumber(variable, name = "variable") {
|
|
150
|
+
throwIfIsNotFiniteNumber(variable, name)
|
|
151
|
+
if (variable < 0) {
|
|
152
|
+
throwRangeErrorGiveValue(variable, name, "a non-negative finite number");
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* 检查变量是否为整数
|
|
158
|
+
* @param {*} variable - 要检查的变量
|
|
159
|
+
* @param {string} name - 变量名称(用于错误消息)
|
|
160
|
+
* @throws {TypeError} 当变量不是整数时抛出类型错误
|
|
161
|
+
*/
|
|
162
|
+
export function throwIfIsNotInteger(variable, name = "variable") {
|
|
163
|
+
throwIfIsNotNumber(variable, name)
|
|
164
|
+
if (!Number.isInteger(variable)) {
|
|
165
|
+
throwTypeErrorGiveValue(variable, name, "an integer");
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* 检查变量是否为正整数
|
|
171
|
+
* @param {*} variable - 要检查的变量
|
|
172
|
+
* @param {string} name - 变量名称(用于错误消息)
|
|
173
|
+
* @throws {RangeError} 当变量不是正整数时抛出范围错误
|
|
174
|
+
*/
|
|
175
|
+
export function throwIfIsNotPositiveInteger(variable, name = "variable") {
|
|
176
|
+
throwIfIsNotInteger(variable, name)
|
|
177
|
+
if (variable <= 0) {
|
|
178
|
+
throwRangeErrorGiveValue(variable, name, "a positive integer");
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* 检查变量是否为负整数
|
|
184
|
+
* @param {*} variable - 要检查的变量
|
|
185
|
+
* @param {string} name - 变量名称(用于错误消息)
|
|
186
|
+
* @throws {RangeError} 当变量不是负整数时抛出范围错误
|
|
187
|
+
*/
|
|
188
|
+
export function throwIfIsNotNegativeInteger(variable, name = "variable") {
|
|
189
|
+
throwIfIsNotInteger(variable, name)
|
|
190
|
+
if (variable >= 0) {
|
|
191
|
+
throwRangeErrorGiveValue(variable, name, "a negative integer");
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* 检查变量是否为非负整数(自然数,包括0)
|
|
197
|
+
* @param {*} variable - 要检查的变量
|
|
198
|
+
* @param {string} name - 变量名称(用于错误消息)
|
|
199
|
+
* @throws {RangeError} 当变量不是非负整数时抛出范围错误
|
|
200
|
+
*/
|
|
201
|
+
export function throwIfIsNotNonNegativeInteger(variable, name = "variable") {
|
|
202
|
+
throwIfIsNotInteger(variable, name)
|
|
203
|
+
if (variable < 0) {
|
|
204
|
+
throwRangeErrorGiveValue(variable, name, "a non-negative integer");
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// ------------------------------------------------
|
|
208
|
+
// 对象类型守卫函数
|
|
209
|
+
// ------------------------------------------------
|
|
210
|
+
/**
|
|
211
|
+
* 检查变量是否为普通对象(非 null,非数组)
|
|
212
|
+
* @param {*} variable - 要检查的变量
|
|
213
|
+
* @param {string} name - 变量名称(用于错误消息)
|
|
214
|
+
* @throws {TypeError} 当变量不是普通对象时抛出类型错误
|
|
215
|
+
*/
|
|
216
|
+
export function throwIfIsNotPlainObject(variable, name = "variable") {
|
|
217
|
+
if (typeof variable !== 'object' || variable === null || Array.isArray(variable)) {
|
|
218
|
+
throwTypeErrorGiveType(variable, name, "a plain object");
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* 检查对象是否缺少所有指定的键
|
|
223
|
+
* @param {*} variable - 要检查的对象
|
|
224
|
+
* @param {string|string[]} keys - 要检查的键名或键名数组
|
|
225
|
+
* @param {string} name - 变量名称(用于错误消息)
|
|
226
|
+
* @throws {TypeError} 当 variable 不是普通对象时抛出类型错误
|
|
227
|
+
* @throws {GuardError} 当 keys 不是字符串或字符串数组时抛出守卫错误
|
|
228
|
+
* @throws {Error} 当对象缺少所有指定键时抛出错误
|
|
229
|
+
*/
|
|
230
|
+
export function throwIfAllKeysMissing(variable, keys, name = "variable") {
|
|
231
|
+
throwIfIsNotPlainObject(variable);
|
|
232
|
+
if (!Array.isArray(keys)) {
|
|
233
|
+
if (typeof keys === "string") keys = [keys];
|
|
234
|
+
else safeGuardExecute(throwTypeErrorGiveType, keys, name, "string", "an array of string");
|
|
235
|
+
}
|
|
236
|
+
if (keys.every(key => !(key in variable))) {
|
|
237
|
+
throw new Error(`Expected ${name} to have at least one attribute of [${keys.map(k => `'${k}'`).join(" ,")}], but cannot find.`)
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* 检查对象是否缺少任意指定的键
|
|
242
|
+
* @param {*} variable - 要检查的对象
|
|
243
|
+
* @param {string|string[]} keys - 要检查的键名或键名数组
|
|
244
|
+
* @param {string} name - 变量名称(用于错误消息)
|
|
245
|
+
* @throws {TypeError} 当 variable 不是普通对象时抛出类型错误
|
|
246
|
+
* @throws {GuardError} 当 keys 不是字符串或字符串数组时抛出守卫错误
|
|
247
|
+
* @throws {Error} 当对象缺少任何一个指定键时抛出错误
|
|
248
|
+
*/
|
|
249
|
+
export function throwIfSomeKeysMissing(variable, keys, name = "variable") {
|
|
250
|
+
throwIfIsNotPlainObject(variable);
|
|
251
|
+
if (!Array.isArray(keys)) {
|
|
252
|
+
if (typeof keys === "string") keys = [keys];
|
|
253
|
+
else safeGuardExecute(throwTypeErrorGiveType, keys, name, "string", "an array of string");
|
|
254
|
+
}
|
|
255
|
+
const l = keys.filter(key => !(key in variable))
|
|
256
|
+
if (l.length) {
|
|
257
|
+
throw new Error(`Expected ${name} to have at all attributes of [${keys.map(k => `'${k}'`).join(" ,")}], but missing [${l.map(k => `'${k}'`).join(" ,")}].`)
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// ------------------------------------------------
|
|
261
|
+
// 函数类型守卫函数
|
|
262
|
+
// ------------------------------------------------
|
|
263
|
+
/**
|
|
264
|
+
* 检查变量是否为函数类型,如果不是则抛出类型错误
|
|
265
|
+
* @param {*} variable - 要检查的变量
|
|
266
|
+
* @param {string} name - 变量名称(用于错误消息),默认值为"variable"
|
|
267
|
+
* @throws {TypeError} 当变量不是函数类型时抛出类型错误
|
|
268
|
+
*/
|
|
269
|
+
export function throwIfIsNotFunction(variable, name = "variable") {
|
|
270
|
+
if (typeof variable !== "function") {
|
|
271
|
+
throwTypeErrorGiveType(variable, name, "a function")
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
// ------------------------------------------------
|
|
275
|
+
// 可迭代守卫函数
|
|
276
|
+
// ------------------------------------------------
|
|
277
|
+
/**
|
|
278
|
+
* 检查变量是否为可迭代对象或字符串
|
|
279
|
+
* @param {*} variable - 要检查的变量
|
|
280
|
+
* @param {string} name - 变量名称(用于错误消息)
|
|
281
|
+
* @throws {TypeError} 当变量不是可迭代对象或字符串时抛出类型错误
|
|
282
|
+
*/
|
|
283
|
+
export function throwIfIsNotIterable(variable, name = "variable") {
|
|
284
|
+
if (variable == null || typeof variable[Symbol.iterator] !== "function") {
|
|
285
|
+
throwTypeErrorGiveType(variable, name, "an iterable");
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* 检查变量是否为可迭代对象,如果不是则抛出类型错误
|
|
290
|
+
* @param {*} variable - 要检查的变量
|
|
291
|
+
* @param {string} name - 变量名称(用于错误消息)
|
|
292
|
+
* @throws {TypeError} 当变量不是可迭代对象时抛出类型错误
|
|
293
|
+
*/
|
|
294
|
+
export function throwIfIsNotIterableObject(variable, name = "") {
|
|
295
|
+
if (typeof variable !== 'object' || variable === null || typeof variable[Symbol.iterator] !== 'function') {
|
|
296
|
+
throwTypeErrorGiveType(variable, name, "an iterable object");
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
//------------------------------------------------
|
|
301
|
+
// 数组类型守卫函数
|
|
302
|
+
// ------------------------------------------------
|
|
303
|
+
export function throwIfIsNotArray(variable, name = "variable") {
|
|
304
|
+
if (!Array.isArray(variable)) {
|
|
305
|
+
throwTypeErrorGiveType(variable, name, "an array");
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
export function throwIfIsNotNonEmptyArray(variable, name = "variable") {
|
|
309
|
+
throwIfIsNotArray(variable, name);
|
|
310
|
+
if (variable.length === 0) {
|
|
311
|
+
throwRangeErrorGiveValue(variable, name, "a non-empty array");
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* 检查变量是否为仅包含非NaN数字的数组,如果不是则抛出类型错误
|
|
316
|
+
*
|
|
317
|
+
* @param {*} variable - 需要检查的变量
|
|
318
|
+
* @param {string} [name="variable"] - 变量名称,用于错误消息显示
|
|
319
|
+
* @param {string} [generalTerm=`all elements of ${name || "array"}`] - 通用术语,用于错误消息显示
|
|
320
|
+
* @throws {TypeError} 当变量不是数组或数组元素不符合要求时抛出错误
|
|
321
|
+
*/
|
|
322
|
+
export function throwIfIsNotComparableNumberArray(variable, name = "variable", generalTerm = `all elements of ${name || "array"}`) {
|
|
323
|
+
throwIfIsNotArray(variable, name);
|
|
324
|
+
const acceptType = "comparable numbers(not NaN)";
|
|
325
|
+
// 验证数组中的每个元素都是非NaN的数字
|
|
326
|
+
for (const e of variable) {
|
|
327
|
+
if (typeof e !== "number") {
|
|
328
|
+
throwTypeErrorForArray(generalTerm, acceptType, `a non-number value of type ${getType(e)}`);
|
|
329
|
+
}
|
|
330
|
+
if (Number.isNaN(e)) {
|
|
331
|
+
throwTypeErrorForArray(generalTerm, acceptType, "NaN");
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export const throwIfIsNumberArrayWithoutNaN = throwIfIsNotComparableNumberArray;
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* 校验变量是否为仅包含有限数(有限 number)的数组。
|
|
340
|
+
* @param {*} variable - 待校验的变量
|
|
341
|
+
* @param {string} [name="variable"] - 变量名称,用于错误消息上下文
|
|
342
|
+
* @param {string} [generalTerm=`all elements of ${name || "array"}`] - 元素合称,用于错误消息上下文
|
|
343
|
+
* @throws {TypeError} 若 variable 不是数组,或包含非数字、NaN、Infinity、-Infinity
|
|
344
|
+
*/
|
|
345
|
+
export function throwIfIsNotFiniteNumberArray(variable, name = "variable", generalTerm = `all elements of ${name || "array"}`) {
|
|
346
|
+
throwIfIsNotArray(variable, name);
|
|
347
|
+
const acceptType = "finite numbers";
|
|
348
|
+
for (const e of variable) {
|
|
349
|
+
if (typeof e !== "number") {
|
|
350
|
+
throwTypeErrorForArray(generalTerm, acceptType, `a non-number value of type ${getType(e)}`);
|
|
351
|
+
}
|
|
352
|
+
if (Number.isNaN(e)) {
|
|
353
|
+
throwTypeErrorForArray(generalTerm, acceptType, "NaN");
|
|
354
|
+
}
|
|
355
|
+
if (!Number.isFinite(e)) {
|
|
356
|
+
const desc = e > 0 ? "Infinity" : "-Infinity";
|
|
357
|
+
throwTypeErrorForArray(generalTerm, acceptType, desc);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* 校验变量是否为仅包含正有限数(> 0 的有限 number)的数组。
|
|
364
|
+
* @param {*} variable - 待校验的变量
|
|
365
|
+
* @param {string} [name="variable"] - 变量名称,用于错误消息上下文
|
|
366
|
+
* @param {string} [generalTerm=`all elements of ${name || "array"}`] - 元素合称,用于错误消息上下文
|
|
367
|
+
* @throws {TypeError} 若 variable 不是数组,或包含非数字、NaN、Infinity、负数、零
|
|
368
|
+
*/
|
|
369
|
+
export function throwIfIsNotPositiveFiniteNumberArray(variable, name = "variable", generalTerm = `all elements of ${name || "array"}`) {
|
|
370
|
+
throwIfIsNotArray(variable, name);
|
|
371
|
+
const acceptType = "positive finite numbers";
|
|
372
|
+
for (const e of variable) {
|
|
373
|
+
if (typeof e !== "number") {
|
|
374
|
+
throwTypeErrorForArray(generalTerm, acceptType, `a non-number value of type ${getType(e)}`);
|
|
375
|
+
}
|
|
376
|
+
if (Number.isNaN(e)) {
|
|
377
|
+
throwTypeErrorForArray(generalTerm, acceptType, "NaN");
|
|
378
|
+
}
|
|
379
|
+
if (!Number.isFinite(e)) {
|
|
380
|
+
const desc = e > 0 ? "Infinity" : "-Infinity";
|
|
381
|
+
throwTypeErrorForArray(generalTerm, acceptType, desc);
|
|
382
|
+
}
|
|
383
|
+
if (e <= 0) {
|
|
384
|
+
const desc = e === 0 ? "zero" : `a negative number (${e})`;
|
|
385
|
+
throwTypeErrorForArray(generalTerm, acceptType, desc);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* 校验变量是否为仅包含非负有限数(>= 0 的有限 number)的数组。
|
|
392
|
+
* @param {*} variable - 待校验的变量
|
|
393
|
+
* @param {string} [name="variable"] - 变量名称,用于错误消息上下文
|
|
394
|
+
* @param {string} [generalTerm=`all elements of ${name || "array"}`] - 元素合称,用于错误消息上下文
|
|
395
|
+
* @throws {TypeError} 若 variable 不是数组,或包含非数字、NaN、Infinity、负数
|
|
396
|
+
*/
|
|
397
|
+
export function throwIfIsNotNonNegativeFiniteNumberArray(variable, name = "variable", generalTerm = `all elements of ${name || "array"}`) {
|
|
398
|
+
throwIfIsNotArray(variable, name);
|
|
399
|
+
const acceptType = "non-negative finite numbers";
|
|
400
|
+
for (const e of variable) {
|
|
401
|
+
if (typeof e !== "number") {
|
|
402
|
+
throwTypeErrorForArray(generalTerm, acceptType, `a non-number value of type ${getType(e)}`);
|
|
403
|
+
}
|
|
404
|
+
if (Number.isNaN(e)) {
|
|
405
|
+
throwTypeErrorForArray(generalTerm, acceptType, "NaN");
|
|
406
|
+
}
|
|
407
|
+
if (!Number.isFinite(e)) {
|
|
408
|
+
const desc = e > 0 ? "Infinity" : "-Infinity";
|
|
409
|
+
throwTypeErrorForArray(generalTerm, acceptType, desc);
|
|
410
|
+
}
|
|
411
|
+
if (e < 0) {
|
|
412
|
+
const desc = `a negative number (${e})`;
|
|
413
|
+
throwTypeErrorForArray(generalTerm, acceptType, desc);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* 校验变量是否为仅包含负有限数(< 0 的有限 number)的数组。
|
|
420
|
+
* @param {*} variable - 待校验的变量
|
|
421
|
+
* @param {string} [name="variable"] - 变量名称,用于错误消息上下文
|
|
422
|
+
* @param {string} [generalTerm=`all elements of ${name || "array"}`] - 元素合称,用于错误消息上下文
|
|
423
|
+
* @throws {TypeError} 若 variable 不是数组,或包含非数字、NaN、Infinity、正数、零
|
|
424
|
+
*/
|
|
425
|
+
export function throwIfIsNotNegativeFiniteNumberArray(variable, name = "variable", generalTerm = `all elements of ${name || "array"}`) {
|
|
426
|
+
throwIfIsNotArray(variable, name);
|
|
427
|
+
const acceptType = "negative finite numbers";
|
|
428
|
+
for (const e of variable) {
|
|
429
|
+
if (typeof e !== "number") {
|
|
430
|
+
throwTypeErrorForArray(generalTerm, acceptType, `a non-number value of type ${getType(e)}`);
|
|
431
|
+
}
|
|
432
|
+
if (Number.isNaN(e)) {
|
|
433
|
+
throwTypeErrorForArray(generalTerm, acceptType, "NaN");
|
|
434
|
+
}
|
|
435
|
+
if (!Number.isFinite(e)) {
|
|
436
|
+
const desc = e > 0 ? "Infinity" : "-Infinity";
|
|
437
|
+
throwTypeErrorForArray(generalTerm, acceptType, desc);
|
|
438
|
+
}
|
|
439
|
+
if (e >= 0) {
|
|
440
|
+
const desc = e === 0 ? "zero" : `a positive number (${e})`;
|
|
441
|
+
throwTypeErrorForArray(generalTerm, acceptType, desc);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* 校验变量是否为仅包含整数的数组。
|
|
448
|
+
* @param {*} variable - 待校验的变量
|
|
449
|
+
* @param {string} [name="variable"] - 变量名称,用于错误消息上下文
|
|
450
|
+
* @param {string} [generalTerm=`all elements of ${name || "array"}`] - 元素合称,用于错误消息上下文
|
|
451
|
+
* @throws {TypeError} 若 variable 不是数组,或包含非数字、NaN、小数
|
|
452
|
+
*/
|
|
453
|
+
export function throwIfIsNotIntegerArray(variable, name = "variable", generalTerm = `all elements of ${name || "array"}`) {
|
|
454
|
+
throwIfIsNotArray(variable, name);
|
|
455
|
+
const acceptType = "integers";
|
|
456
|
+
for (const e of variable) {
|
|
457
|
+
if (typeof e !== "number") {
|
|
458
|
+
throwTypeErrorForArray(generalTerm, acceptType, `a non-number value of type ${getType(e)}`);
|
|
459
|
+
}
|
|
460
|
+
if (Number.isNaN(e)) {
|
|
461
|
+
throwTypeErrorForArray(generalTerm, acceptType, "NaN");
|
|
462
|
+
}
|
|
463
|
+
if (!Number.isFinite(e)) {
|
|
464
|
+
const desc = e > 0 ? "Infinity" : "-Infinity";
|
|
465
|
+
throwTypeErrorForArray(generalTerm, acceptType, desc);
|
|
466
|
+
}
|
|
467
|
+
if (!Number.isInteger(e)) {
|
|
468
|
+
throwTypeErrorForArray(generalTerm, acceptType, `a non-integer value (${e})`);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* 校验变量是否为仅包含正整数(> 0 的整数)的数组。
|
|
475
|
+
* @param {*} variable - 待校验的变量
|
|
476
|
+
* @param {string} [name="variable"] - 变量名称,用于错误消息上下文
|
|
477
|
+
* @param {string} [generalTerm=`all elements of ${name || "array"}`] - 元素合称,用于错误消息上下文
|
|
478
|
+
* @throws {TypeError} 若 variable 不是数组,或包含非数字、NaN、Infinity、负数、零、小数
|
|
479
|
+
*/
|
|
480
|
+
export function throwIfIsNotPositiveIntegerArray(variable, name = "variable", generalTerm = `all elements of ${name || "array"}`) {
|
|
481
|
+
throwIfIsNotArray(variable, name);
|
|
482
|
+
const acceptType = "positive integers";
|
|
483
|
+
for (const e of variable) {
|
|
484
|
+
if (typeof e !== "number") {
|
|
485
|
+
throwTypeErrorForArray(generalTerm, acceptType, `a non-number value of type ${getType(e)}`);
|
|
486
|
+
}
|
|
487
|
+
if (Number.isNaN(e)) {
|
|
488
|
+
throwTypeErrorForArray(generalTerm, acceptType, "NaN");
|
|
489
|
+
}
|
|
490
|
+
if (!Number.isFinite(e)) {
|
|
491
|
+
const desc = e > 0 ? "Infinity" : "-Infinity";
|
|
492
|
+
throwTypeErrorForArray(generalTerm, acceptType, desc);
|
|
493
|
+
}
|
|
494
|
+
if (!Number.isInteger(e)) {
|
|
495
|
+
throwTypeErrorForArray(generalTerm, acceptType, `a non-integer value (${e})`);
|
|
496
|
+
}
|
|
497
|
+
if (e <= 0) {
|
|
498
|
+
const desc = e === 0 ? "zero" : `a negative number (${e})`;
|
|
499
|
+
throwTypeErrorForArray(generalTerm, acceptType, desc);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* 校验变量是否为仅包含非负整数(>= 0 的整数)的数组。
|
|
506
|
+
* @param {*} variable - 待校验的变量
|
|
507
|
+
* @param {string} [name="variable"] - 变量名称,用于错误消息上下文
|
|
508
|
+
* @param {string} [generalTerm=`all elements of ${name || "array"}`] - 元素合称,用于错误消息上下文
|
|
509
|
+
* @throws {TypeError} 若 variable 不是数组,或包含非数字、NaN、Infinity、负数、小数
|
|
510
|
+
*/
|
|
511
|
+
export function throwIfIsNotNonNegativeIntegerArray(variable, name = "variable", generalTerm = `all elements of ${name || "array"}`) {
|
|
512
|
+
throwIfIsNotArray(variable, name);
|
|
513
|
+
const acceptType = "non-negative integers";
|
|
514
|
+
for (const e of variable) {
|
|
515
|
+
if (typeof e !== "number") {
|
|
516
|
+
throwTypeErrorForArray(generalTerm, acceptType, `a non-number value of type ${getType(e)}`);
|
|
517
|
+
}
|
|
518
|
+
if (Number.isNaN(e)) {
|
|
519
|
+
throwTypeErrorForArray(generalTerm, acceptType, "NaN");
|
|
520
|
+
}
|
|
521
|
+
if (!Number.isFinite(e)) {
|
|
522
|
+
const desc = e > 0 ? "Infinity" : "-Infinity";
|
|
523
|
+
throwTypeErrorForArray(generalTerm, acceptType, desc);
|
|
524
|
+
}
|
|
525
|
+
if (!Number.isInteger(e)) {
|
|
526
|
+
throwTypeErrorForArray(generalTerm, acceptType, `a non-integer value (${e})`);
|
|
527
|
+
}
|
|
528
|
+
if (e < 0) {
|
|
529
|
+
const desc = `a negative number (${e})`;
|
|
530
|
+
throwTypeErrorForArray(generalTerm, acceptType, desc);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* 校验变量是否为仅包含负整数(< 0 的整数)的数组。
|
|
537
|
+
* @param {*} variable - 待校验的变量
|
|
538
|
+
* @param {string} [name="variable"] - 变量名称,用于错误消息上下文
|
|
539
|
+
* @param {string} [generalTerm=`all elements of ${name || "array"}`] - 元素合称,用于错误消息上下文
|
|
540
|
+
* @throws {TypeError} 若 variable 不是数组,或包含非数字、NaN、Infinity、正数、零、小数
|
|
541
|
+
*/
|
|
542
|
+
export function throwIfIsNotNegativeIntegerArray(variable, name = "variable", generalTerm = `all elements of ${name || "array"}`) {
|
|
543
|
+
throwIfIsNotArray(variable, name);
|
|
544
|
+
const acceptType = "negative integers";
|
|
545
|
+
for (const e of variable) {
|
|
546
|
+
if (typeof e !== "number") {
|
|
547
|
+
throwTypeErrorForArray(generalTerm, acceptType, `a non-number value of type ${getType(e)}`);
|
|
548
|
+
}
|
|
549
|
+
if (Number.isNaN(e)) {
|
|
550
|
+
throwTypeErrorForArray(generalTerm, acceptType, "NaN");
|
|
551
|
+
}
|
|
552
|
+
if (!Number.isFinite(e)) {
|
|
553
|
+
const desc = e > 0 ? "Infinity" : "-Infinity";
|
|
554
|
+
throwTypeErrorForArray(generalTerm, acceptType, desc);
|
|
555
|
+
}
|
|
556
|
+
if (!Number.isInteger(e)) {
|
|
557
|
+
throwTypeErrorForArray(generalTerm, acceptType, `a non-integer value (${e})`);
|
|
558
|
+
}
|
|
559
|
+
if (e >= 0) {
|
|
560
|
+
const desc = e === 0 ? "zero" : `a positive number (${e})`;
|
|
561
|
+
throwTypeErrorForArray(generalTerm, acceptType, desc);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { throwIfIsNotNonNegativeInteger } from "./guard";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 前向填充(forward-fill)输入数据,向前填充无效值。
|
|
5
|
+
*
|
|
6
|
+
* - 若输入为可迭代对象,将展开为迭代序列;若输入为非可迭代的对象,将包装为一个数组
|
|
7
|
+
* - 函数默认舍弃先导无效值,除非设置了`defaultValue`
|
|
8
|
+
* - 函数将以最近的上一次有效值填充无效值,无效值默认为 `undefined`
|
|
9
|
+
* - 函数默认使用`Object.is`进行判断无效值,因此可传入`NaN`,也请注意区分`-0`和`+0`
|
|
10
|
+
* - 对于传入的对象,函数不会进行拷贝,而是直接引用
|
|
11
|
+
*
|
|
12
|
+
* @template T
|
|
13
|
+
* @param {T | Iterable<T>} inputData - 输入数据(一个值或可迭代对象等)
|
|
14
|
+
* @param {{
|
|
15
|
+
* len?: number,
|
|
16
|
+
* invalidityChecker?: T | T[] | ((value: T) => boolean),
|
|
17
|
+
* defaultValue?: T
|
|
18
|
+
* checkDefaultValue?: boolean
|
|
19
|
+
* }} options
|
|
20
|
+
* @param options.len - 期望输出的元素总数,当 `len` 未提供时,输出长度 = 从第一个有效值开始到输入结束的长度,且不会自动扩展。
|
|
21
|
+
* @param options.invalidityChecker - 用于判断无效值的标准(默认: `undefined`)
|
|
22
|
+
* @param options.defaultValue - 若提供,则用以填充前导无效值,默认开启有效性检查。
|
|
23
|
+
* @param options.checkDefaultValue - 是否对 defaultValue 进行有效性检查(默认: `true`)
|
|
24
|
+
* @returns {T[]} 填充后的结果数组,长度不超过 `len`
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* forwardFill("abc",{len:2}) //=> ["abc", "abc"]
|
|
28
|
+
* forwardFill(new String("abc")) // => ["a", "b", "c"]
|
|
29
|
+
* forwardFill([1, undefined, 3], { len: 5 }) // => [1, 1, 3, 3, 3]
|
|
30
|
+
* forwardFill(null, { len: 2, invalidityChecker: null, defaultValue: 0 }) // => [0, 0]
|
|
31
|
+
* forwardFill(new Map([[1,2],['a',2]])) // => [[1,2],['a',2]]
|
|
32
|
+
* const obj = {};forwardFill(obj,{len:2}) // => [obj, obj]
|
|
33
|
+
*/
|
|
34
|
+
export function forwardFill(inputData, options = { checkDefaultValue: true }) {
|
|
35
|
+
if ("len" in options) {
|
|
36
|
+
throwIfIsNotNonNegativeInteger(options.len, "options.len");
|
|
37
|
+
if (options.len === 0) return [];
|
|
38
|
+
}
|
|
39
|
+
const result = []
|
|
40
|
+
const dataList = typeof inputData === "object"
|
|
41
|
+
&& typeof inputData?.[Symbol.iterator] === 'function' ?
|
|
42
|
+
inputData : [inputData]
|
|
43
|
+
const checkInvalidity = typeof options.invalidityChecker === "function" ? options.invalidityChecker
|
|
44
|
+
: Array.isArray(options.invalidityChecker) ? (v) => options.invalidityChecker.some(w => Object.is(v, w))
|
|
45
|
+
: (v) => Object.is(v, options.invalidityChecker);
|
|
46
|
+
let currentValue, hasValidValue = false;
|
|
47
|
+
if ("defaultValue" in options) {
|
|
48
|
+
currentValue = options.defaultValue;
|
|
49
|
+
hasValidValue = options.checkDefaultValue ? !checkInvalidity(options.defaultValue) : true;
|
|
50
|
+
}
|
|
51
|
+
for (const gottenValue of dataList) {
|
|
52
|
+
if (!checkInvalidity(gottenValue)) {
|
|
53
|
+
currentValue = gottenValue;
|
|
54
|
+
hasValidValue = true;
|
|
55
|
+
}
|
|
56
|
+
if (!hasValidValue) continue;
|
|
57
|
+
result.push(currentValue);
|
|
58
|
+
if (result.length >= options.len) return result;
|
|
59
|
+
}
|
|
60
|
+
if (!hasValidValue) return result;
|
|
61
|
+
while (result.length < options.len) {
|
|
62
|
+
result.push(currentValue);
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
}
|