foreslash 0.3.1 → 0.3.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Change Log
2
2
 
3
+ ## Version 0.3.2 - 2025-09-23
4
+
5
+ Unstable version
6
+
7
+ - Feat 🥥 Functions added: `chunk` `decimalNotation` `round` `format` `isPlainObject` `cartesianProduct` **and** so forth
8
+ - Feat 🥥 Type Utils: `Not` `IsNegative` `IsZero` `IsPositive` `Stringify`
9
+ - Fix 🥕 Document: Added version tags to 19 methods
10
+ - Other fixes and improvements
11
+
12
+ 不稳定版本
13
+
14
+ - 功能 🥥 添加函数: `chunk` `decimalNotation` `round` `format` `isPlainObject` `cartesianProduct` 等
15
+ - 功能 🥥 类型工具: `Not` `IsNegative` `IsZero` `IsPositive` `Stringify`
16
+ - 修复 🥕 文档: 补充 19 个方法的版本标签
17
+ - 其他修复与优化
18
+
3
19
  ## Version 0.3.1 - 2025-08-14
4
20
 
5
21
  Unstable version
package/lib/index.cmn.cjs CHANGED
@@ -11,6 +11,53 @@ See the Mulan PSL v2 for more details.
11
11
  */
12
12
  'use strict';
13
13
 
14
+ function cartesianProduct(...arrList) {
15
+ const arrLen = arrList.length;
16
+ const pList = Array(arrLen).fill(0);
17
+ const lastIndex = arrLen - 1;
18
+ const res = [];
19
+ for (let i = 0; i < arrLen; i++) {
20
+ if (!arrList[i].length)
21
+ return [];
22
+ }
23
+ while (1) {
24
+ const temp = [];
25
+ for (let i = 0; i < arrLen; i++) {
26
+ temp.push(arrList[i][pList[i]]);
27
+ }
28
+ res.push(temp);
29
+ pList[lastIndex] += 1;
30
+ for (let i = lastIndex; i >= 0; i--) {
31
+ if (pList[i] >= arrList[i].length) {
32
+ if (i > 0) {
33
+ pList[i] = 0;
34
+ pList[i - 1] += 1;
35
+ }
36
+ else
37
+ break;
38
+ }
39
+ else
40
+ break;
41
+ }
42
+ if (pList[0] >= arrList[0].length)
43
+ break;
44
+ }
45
+ return res;
46
+ }
47
+
48
+ function chunk(array, size = 2) {
49
+ const res = [];
50
+ if (size < 1 || isNaN(size))
51
+ return res;
52
+ let start = 0, end = size;
53
+ while (start < array.length) {
54
+ res.push(Array.prototype.slice.call(array, start, end));
55
+ start = end;
56
+ end += size;
57
+ }
58
+ return res;
59
+ }
60
+
14
61
  function range(start, end, stepOrOptions) {
15
62
  if (!isFinite(start))
16
63
  throw new Error('start must be finite');
@@ -202,6 +249,22 @@ function isNumber(value) {
202
249
  return typeof value === 'number';
203
250
  }
204
251
 
252
+ const fnToString = Function.prototype.toString;
253
+ const objProtoContString = fnToString.call(Object.prototype.constructor);
254
+ function isPlainObject(value) {
255
+ if (typeof value !== 'object' || value === null)
256
+ return false;
257
+ const prototype = Object.getPrototypeOf(value);
258
+ if (prototype === null)
259
+ return true;
260
+ if (!Object.prototype.hasOwnProperty.call(prototype, "constructor"))
261
+ return false;
262
+ const constructorFn = prototype.constructor;
263
+ if (!isFunction(constructorFn) || fnToString.call(constructorFn) !== objProtoContString)
264
+ return false;
265
+ return (Object.getPrototypeOf(prototype) === null);
266
+ }
267
+
205
268
  function isPrimitive(value) {
206
269
  return value === undefined || value === null || (typeof value !== 'object' && typeof value !== 'function');
207
270
  }
@@ -374,6 +437,178 @@ function clamp(num, min, max, options) {
374
437
  return num < min ? defaultMin : num > max ? defaultMax : num;
375
438
  }
376
439
 
440
+ function decimalNotation(num) {
441
+ const n = isNumber(num) ? num : Number(num);
442
+ if (!isFinite(n))
443
+ return String(n);
444
+ let str = String(n);
445
+ if (!/e/i.test(str))
446
+ return str;
447
+ const match = str.match(/^(-?)(\d+)\.?(\d*)e([+-]?)(\d+)$/);
448
+ const [_, sign, mantissaI, mantissaF, expSign, _exponent] = match;
449
+ const exponent = Number(_exponent);
450
+ let mantissa = mantissaI + mantissaF;
451
+ let dotPos = mantissaI.length;
452
+ if (expSign === '-') {
453
+ const zeroCount = exponent - dotPos + 1;
454
+ if (zeroCount > 0)
455
+ mantissa = '0'.repeat(zeroCount) + mantissa;
456
+ return sign + mantissa[0] + '.' + mantissa.substring(1);
457
+ }
458
+ else {
459
+ const zeroCount = exponent + dotPos - mantissa.length;
460
+ if (zeroCount > 0)
461
+ mantissa = mantissa + '0'.repeat(zeroCount);
462
+ return sign + mantissa.substring(0, exponent + dotPos);
463
+ }
464
+ }
465
+
466
+ function isOdd(num) {
467
+ return !!(num & 1);
468
+ }
469
+ function isEven(num) {
470
+ return !(num & 1);
471
+ }
472
+
473
+ function round(num, precision, type) {
474
+ const str = decimalNotation(num);
475
+ if (/NaN|Inf/.test(str))
476
+ return str;
477
+ let [_integer, _fractional] = str.split('.');
478
+ let sign = '';
479
+ if (/^-/.test(_integer)) {
480
+ _integer = _integer.substring(1);
481
+ sign = '-';
482
+ }
483
+ _fractional = _fractional !== null && _fractional !== void 0 ? _fractional : '';
484
+ const roundMap = { round: roundBase, banker: roundBank, floor: roundFloor, ceil: roundCeil };
485
+ const [integer, fractional] = (roundMap[type || 'round'] || roundBase)(_integer, _fractional, precision, !!sign);
486
+ if (precision > 0)
487
+ return sign + integer + '.' + fractional;
488
+ else
489
+ return sign + integer;
490
+ }
491
+ function roundBase(integer, fractional, precision) {
492
+ if (fractional.length > precision) {
493
+ const splitF = fractional.substring(0, precision);
494
+ if (Number(fractional[precision]) > 4)
495
+ return increase(integer, splitF);
496
+ return [integer, splitF];
497
+ }
498
+ if (fractional.length < precision) {
499
+ fractional += '0'.repeat(precision - fractional.length);
500
+ }
501
+ return [integer, fractional];
502
+ }
503
+ function roundBank(integer, fractional, precision) {
504
+ if (fractional.length > precision) {
505
+ const splitF = fractional.substring(0, precision);
506
+ const rightNumber = Number(fractional[precision]);
507
+ if (rightNumber < 5)
508
+ return [integer, splitF];
509
+ if (rightNumber > 5)
510
+ return increase(integer, splitF);
511
+ const rightNumbers = fractional.substring(precision);
512
+ if (!/^50*$/.test(rightNumbers))
513
+ return increase(integer, splitF);
514
+ const leftNumber = Number(precision ? fractional[precision - 1] : integer[integer.length - 1]);
515
+ if (isEven(leftNumber))
516
+ return [integer, splitF];
517
+ else
518
+ return increase(integer, splitF);
519
+ }
520
+ if (fractional.length < precision) {
521
+ fractional += '0'.repeat(precision - fractional.length);
522
+ }
523
+ return [integer, fractional];
524
+ }
525
+ function roundFloor(integer, fractional, precision, isNegative) {
526
+ if (fractional.length > precision) {
527
+ const splitF = fractional.substring(0, precision);
528
+ if (isNegative)
529
+ return increase(integer, splitF);
530
+ return [integer, splitF];
531
+ }
532
+ if (fractional.length < precision) {
533
+ fractional += '0'.repeat(precision - fractional.length);
534
+ }
535
+ return [integer, fractional];
536
+ }
537
+ function roundCeil(integer, fractional, precision, isNegative) {
538
+ if (fractional.length > precision) {
539
+ const splitF = fractional.substring(0, precision);
540
+ if (!isNegative)
541
+ return increase(integer, splitF);
542
+ return [integer, splitF];
543
+ }
544
+ if (fractional.length < precision) {
545
+ fractional += '0'.repeat(precision - fractional.length);
546
+ }
547
+ return [integer, fractional];
548
+ }
549
+ function increase(integer, fractional) {
550
+ if (fractional) {
551
+ const _fractional = _increase(fractional);
552
+ if (_fractional.length > fractional.length) {
553
+ return [_increase(integer), _fractional.substring(1)];
554
+ }
555
+ return [integer, _fractional];
556
+ }
557
+ return [_increase(integer), ''];
558
+ }
559
+ function _increase(num) {
560
+ const numList = num.split('').map(Number).reverse();
561
+ numList[0] += 1;
562
+ numList.push(0);
563
+ for (let i = 0; i < numList.length; i++) {
564
+ if (numList[i] > 9) {
565
+ numList[i] -= 10;
566
+ numList[i + 1] += 1;
567
+ }
568
+ else
569
+ break;
570
+ }
571
+ if (numList[numList.length - 1] === 0)
572
+ numList.pop();
573
+ return numList.reverse().map(String).join('');
574
+ }
575
+
576
+ function format(num, options) {
577
+ var _a;
578
+ const str = decimalNotation(num);
579
+ if (/NaN|Inf/.test(str))
580
+ return str;
581
+ const separator = (options || {}).separator || ',';
582
+ const separate = clamp((options || {}).separate || 3, 1, Infinity);
583
+ const decimal = (options || {}).decimal || '.';
584
+ const precision = clamp((_a = (options || {}).precision) !== null && _a !== void 0 ? _a : 2, 0, Infinity);
585
+ const round = (options || {}).round || 'round';
586
+ let [integer, fractional] = str.split('.');
587
+ let sign = '';
588
+ if (/^-/.test(integer)) {
589
+ integer = integer.substring(1);
590
+ sign = '-';
591
+ }
592
+ fractional = fractional !== null && fractional !== void 0 ? fractional : '';
593
+ if (fractional.length > precision) {
594
+ const roundMap = { round: roundBase, banker: roundBank, floor: roundFloor, ceil: roundCeil };
595
+ [integer, fractional] = (roundMap[round] || roundBase)(integer, fractional, precision, !!sign);
596
+ }
597
+ else if (fractional.length < precision) {
598
+ fractional += '0'.repeat(precision - fractional.length);
599
+ }
600
+ if (integer.length > separate) {
601
+ integer = chunk(Array.from(integer).reverse(), separate)
602
+ .map((part) => part.join(''))
603
+ .join(separator);
604
+ integer = Array.from(integer).reverse().join('');
605
+ }
606
+ if (precision > 0)
607
+ return sign + integer + decimal + fractional;
608
+ else
609
+ return sign + integer;
610
+ }
611
+
377
612
  function parallel(args, fn, options) {
378
613
  return __awaiter(this, void 0, void 0, function* () {
379
614
  if (!args.length)
@@ -2048,20 +2283,24 @@ exports.acceptableFileName = acceptableFileName;
2048
2283
  exports.acceptableFileType = acceptableFileType;
2049
2284
  exports.camelCase = camelCase;
2050
2285
  exports.capitalize = capitalize;
2286
+ exports.cartesianProduct = cartesianProduct;
2051
2287
  exports.caseCamel = caseCamel;
2052
2288
  exports.caseConvert = caseConvert;
2053
2289
  exports.caseKebab = caseKebab;
2054
2290
  exports.casePascal = casePascal;
2055
2291
  exports.caseSnake = caseSnake;
2292
+ exports.chunk = chunk;
2056
2293
  exports.clamp = clamp;
2057
2294
  exports.compose = compose;
2058
2295
  exports.curry = _curryMore;
2059
2296
  exports.debounce = debounce;
2297
+ exports.decimalNotation = decimalNotation;
2060
2298
  exports.dedent = dedent;
2061
2299
  exports.deepClone = deepClone;
2062
2300
  exports.deepMerge = deepMerge;
2063
2301
  exports.defer = defer;
2064
2302
  exports.fastClone = fastClone;
2303
+ exports.format = format;
2065
2304
  exports.getAcceptableExtByMIME = getAcceptableExtByMIME;
2066
2305
  exports.getAcceptableMIMEByExt = getAcceptableMIMEByExt;
2067
2306
  exports.getGlobalThis = getGlobalThis;
@@ -2079,6 +2318,7 @@ exports.isBuffer = isBuffer;
2079
2318
  exports.isDataView = isDataView;
2080
2319
  exports.isDate = isDate;
2081
2320
  exports.isEmpty = isEmpty;
2321
+ exports.isEven = isEven;
2082
2322
  exports.isFile = isFile;
2083
2323
  exports.isFloat32Array = isFloat32Array;
2084
2324
  exports.isFloat64Array = isFloat64Array;
@@ -2095,7 +2335,9 @@ exports.isNil = isNil;
2095
2335
  exports.isNull = isNull;
2096
2336
  exports.isNumber = isNumber;
2097
2337
  exports.isObject = isObject;
2338
+ exports.isOdd = isOdd;
2098
2339
  exports.isPlaceholder = isPlaceholder;
2340
+ exports.isPlainObject = isPlainObject;
2099
2341
  exports.isPrimitive = isPrimitive;
2100
2342
  exports.isPromise = isPromise;
2101
2343
  exports.isPromiseLike = isPromiseLike;
@@ -2135,6 +2377,11 @@ exports.randomString = randomString;
2135
2377
  exports.range = range;
2136
2378
  exports.remove = remove;
2137
2379
  exports.retry = retry;
2380
+ exports.round = round;
2381
+ exports.roundBank = roundBank;
2382
+ exports.roundBase = roundBase;
2383
+ exports.roundCeil = roundCeil;
2384
+ exports.roundFloor = roundFloor;
2138
2385
  exports.shuffle = shuffle;
2139
2386
  exports.sleep = sleep;
2140
2387
  exports.snakeCase = snakeCase;
package/lib/index.d.ts CHANGED
@@ -1,5 +1,61 @@
1
1
  import { A, F } from 'ts-toolbelt';
2
2
 
3
+ /**
4
+ * 将多个数组或类数组对象以笛卡尔积的形式拼接为一个新的二维数组
5
+ * @returns 笛卡尔积
6
+ * @example
7
+ * ```js
8
+ * cartesianProduct([1, 2, 3, 4, 5]) // [[1], [2], [3], [4], [5]]
9
+ * cartesianProduct([1, 2], '12') // [[1, '1'], [1, '2'], [2, '1'], [2, '2']]
10
+ * cartesianProduct([1, 2], '12', [3, 4])
11
+ * // [[1, '1', 3], [1, '1', 4], [1, '2', 3], [1, '2', 4]
12
+ * // [2, '1', 3], [2, '1', 4], [2, '2', 3], [2, '2', 4]]
13
+ * cartesianProduct([1, 2, 3, 4, 5], '12345', []) // [] 空集与其他集合的笛卡尔积是空集
14
+ * ```
15
+ * @version 0.3.2
16
+ */
17
+ declare function cartesianProduct<T>(arr1: ArrayLike<T>): [T][];
18
+ declare function cartesianProduct<T1, T2>(arr1: ArrayLike<T1>, arr2: ArrayLike<T2>): [T1, T2][];
19
+ declare function cartesianProduct<T1, T2, T3>(arr1: ArrayLike<T1>, arr2: ArrayLike<T2>, arr3: ArrayLike<T3>): [T1, T2, T3][];
20
+ declare function cartesianProduct<T1, T2, T3, T4>(arr1: ArrayLike<T1>, arr2: ArrayLike<T2>, arr3: ArrayLike<T3>, arr4: ArrayLike<T4>): [T1, T2, T3, T4][];
21
+ declare function cartesianProduct<T1, T2, T3, T4, T5>(arr1: ArrayLike<T1>, arr2: ArrayLike<T2>, arr3: ArrayLike<T3>, arr4: ArrayLike<T4>, arr5: ArrayLike<T5>): [T1, T2, T3, T4, T5][];
22
+ declare function cartesianProduct<T1, T2, T3, T4, T5, T6>(arr1: ArrayLike<T1>, arr2: ArrayLike<T2>, arr3: ArrayLike<T3>, arr4: ArrayLike<T4>, arr5: ArrayLike<T5>, arr6: ArrayLike<T6>): [T1, T2, T3, T4, T5, T6][];
23
+ declare function cartesianProduct<T1, T2, T3, T4, T5, T6, T7>(arr1: ArrayLike<T1>, arr2: ArrayLike<T2>, arr3: ArrayLike<T3>, arr4: ArrayLike<T4>, arr5: ArrayLike<T5>, arr6: ArrayLike<T6>, arr7: ArrayLike<T7>): [T1, T2, T3, T4, T5, T6, T7][];
24
+ declare function cartesianProduct<T1, T2, T3, T4, T5, T6, T7, T8>(arr1: ArrayLike<T1>, arr2: ArrayLike<T2>, arr3: ArrayLike<T3>, arr4: ArrayLike<T4>, arr5: ArrayLike<T5>, arr6: ArrayLike<T6>, arr7: ArrayLike<T7>, arr8: ArrayLike<T8>): [T1, T2, T3, T4, T5, T6, T7, T8][];
25
+ declare function cartesianProduct(...arrList: ArrayLike<any>[]): any[][];
26
+
27
+ type Not<T> = T extends false | 0 | '' | null | undefined ? true : false;
28
+
29
+ type Stringify<T extends string | number | boolean | bigint | null | undefined> = `${T}`;
30
+
31
+ /** 检查输入的数字是否为 `0` 或 `0n` */
32
+ type IsZero<T> = T extends 0 | 0n ? true : false;
33
+ /** 检查输入的数字是否为负数 */
34
+ type IsNegative<T> = T extends number | bigint ? (Stringify<T> extends `-${infer R}` ? true : false) : false;
35
+ /** 检查输入的数字是否为正数 */
36
+ type IsPositive<T> = T extends number | bigint ? (IsZero<T> extends true ? false : Not<IsNegative<T>>) : false;
37
+
38
+ /**
39
+ * 将一个数组或类数组对象分割成多个指定大小的小块\
40
+ * 类似 Lodash 的 `chunk` 或是 Radash 的 `cluster`\
41
+ * 可以填入 `size` 以自定义每个小块的大小
42
+ * @param array 需要分块的数组
43
+ * @param size 每块大小, 不能小于 1, 默认为 `2`
44
+ * @returns 分块后的数组
45
+ * @example
46
+ * ```js
47
+ * chunk([1, 2, 3, 4, 5], 2) // [[1, 2], [3, 4], [5]]
48
+ * chunk('12345', 3) // [['1', '2', '3'], ['4', '5']]
49
+ * chunk({0: 1, 1: 2, 2: 3, length: 3}, 2) // [[1, 2], [3]]
50
+ * // 如果传入了不正常的 size 则返回空数组(类型为 `never[]`)
51
+ * chunk([1, 2, 3, 4, 5], 0) // []
52
+ * chunk([1, 2, 3, 4, 5], NaN) // []
53
+ * ```
54
+ * @version 0.3.2
55
+ */
56
+ declare function chunk<T, Size extends number = 2>(array: ArrayLike<T>, size?: Size): Chunked<T, Size>;
57
+ type Chunked<T, Size extends number> = Size extends 1 ? [T][] : Size extends 2 ? [T, T][] : Size extends 3 ? [T, T, T][] : Size extends 4 ? [T, T, T, T][] : Size extends 5 ? [T, T, T, T, T][] : Size extends 6 ? [T, T, T, T, T, T][] : Size extends 7 ? [T, T, T, T, T, T, T][] : Size extends 8 ? [T, T, T, T, T, T, T, T][] : Size extends 9 ? [T, T, T, T, T, T, T, T, T][] : IsNegative<Size> extends true ? never[] : Size extends 0 ? never[] : T[][];
58
+
3
59
  type RangeOptions<T> = {
4
60
  step?: number;
5
61
  value?: T;
@@ -539,6 +595,21 @@ declare function isNumber(value: unknown): value is number;
539
595
  */
540
596
  declare function isObject(value: unknown): value is object;
541
597
 
598
+ /**
599
+ * 类型守卫,判断给定的值是否为普通对象(不是 `Date`、数组等特殊对象)
600
+ * - 注意,与 lodash 的同名方法不同,不会将函数视为对象
601
+ * @param value 要判断的值
602
+ * @example
603
+ * ```js
604
+ * isObject({}) // true
605
+ * isObject(Object.create(null)) // true
606
+ * isObject([]) // false
607
+ * isObject(Object(123)) // false
608
+ * isObject(null) // false
609
+ * ```
610
+ */
611
+ declare function isPlainObject(value: unknown): value is object;
612
+
542
613
  /**
543
614
  * 类型守卫,判断给定的值是否为原始类型(如字符串数字等 JS 内置的类型)
544
615
  * - 包括 `undefined` 和 `null`
@@ -876,6 +947,165 @@ declare function clamp(num: number, min: number, max: number, options?: {
876
947
  defaultMax?: number;
877
948
  }): number;
878
949
 
950
+ /**
951
+ * 将一个数字转换为正常的十进制计数法
952
+ * @param num 需要转换的数字
953
+ * @returns 返回一个十进制计数法表示的数字
954
+ * @example
955
+ * ```js
956
+ * decimalNotation(1e12) // 1000000000000
957
+ * decimalNotation(-2.33e8) // -233000000
958
+ * decimalNotation(1.234e-6) // 0.000001234
959
+ * decimalNotation(-4.321e-8) // -0.00000004321
960
+ * ```
961
+ * @version 0.3.2
962
+ */
963
+ declare function decimalNotation(num: string | number): string;
964
+
965
+ /**
966
+ * 将一个数字转换为指定的格式(如千分位逗号分隔)
967
+ * @param num 需要格式化的数字
968
+ * @param options 格式化配置\
969
+ * - `separator` 分割符, 默认为 `','`
970
+ * - `separate` 按位分割, 默认为 `3`
971
+ * - `decimal` 小数点, 默认为 `'.'`
972
+ * - `precision` 小数精度, 默认为 `2`
973
+ * - `round` 数值修约规则
974
+ * - `'round'` 四舍五入
975
+ * - `'banker'` 四舍六入五成双
976
+ * - `'floor'` 向下取整
977
+ * - `'ceil'` 向上取整
978
+ * @returns 返回一个指定格式的十进制数字
979
+ * @version 0.3.2
980
+ */
981
+ declare function format(num: number | string, options?: {
982
+ separator?: string;
983
+ separate?: number;
984
+ decimal?: string;
985
+ precision?: number;
986
+ round?: 'round' | 'banker' | 'floor' | 'ceil';
987
+ }): string;
988
+
989
+ /**
990
+ * 检查一个数字是否为奇数
991
+ * @param num 需要检查的数字
992
+ * @returns 如果是奇数则返回 true 否则返回 false
993
+ * @version 0.3.2
994
+ */
995
+ declare function isOdd(num: number): boolean;
996
+ /**
997
+ * 检查一个数字是否为偶数
998
+ * @param num 需要检查的数字
999
+ * @returns 如果是偶数则返回 true 否则返回 false
1000
+ * @version 0.3.2
1001
+ */
1002
+ declare function isEven(num: number): boolean;
1003
+
1004
+ /**
1005
+ * 数值修约, 可以使用 4 种修约方法, 默认使用四舍五入
1006
+ * - 四舍五入: 修约位置的后一位如果是 5 则进位, 否则不进位
1007
+ * - 四舍六入五成双: 修约位置的后一位如果是 5 且前一位是偶数则进位, 否则不进位
1008
+ * - 向下取整
1009
+ * - 向上取整
1010
+ * @param num 需要修约的数字
1011
+ * @param precision 精度, 小数点后几位
1012
+ * @param type 修约方法, 默认使用四舍五入
1013
+ * @example
1014
+ * ```js
1015
+ * // 四舍五入
1016
+ * round(1.95, 1) // '2.0'
1017
+ * round('1.95', 1) // '2.0'
1018
+ * // 四舍六入五成双
1019
+ * round('1.85', 1, 'banker') // '1.8'
1020
+ * round('1.95', 1, 'banker') // '2.0'
1021
+ * // 向下取整
1022
+ * round('1.95', 1, 'floor') // '1.9'
1023
+ * round(-1.95, 1, 'floor') // '-2.0'
1024
+ * // 向上取整
1025
+ * round('1.95', 1, 'ceil') // '2.0'
1026
+ * round(-1.95, 1, 'ceil') // '-1.9'
1027
+ * ```
1028
+ * @version 0.3.2
1029
+ */
1030
+ declare function round(num: string | number, precision: number, type?: 'round' | 'banker' | 'floor' | 'ceil'): string;
1031
+ /**
1032
+ * 四舍五入, 由于 JS 的 toFixed 有浮点误差所以不能使用
1033
+ * @example
1034
+ * ```js
1035
+ * // 四舍五入
1036
+ * roundBase('1', '34', 1, false) // ['1', '3']
1037
+ * roundBase('1', '35', 1, false) // ['1', '4']
1038
+ * roundBase('1', '36', 1, false) // ['1', '4']
1039
+ * // 与符号无关
1040
+ * roundBase('1', '34', 1, true) // ['1', '3']
1041
+ * roundBase('1', '35', 1, true) // ['1', '4']
1042
+ * roundBase('1', '36', 1, true) // ['1', '4']
1043
+ * ```
1044
+ * @version 0.3.2
1045
+ */
1046
+ declare function roundBase(integer: string, fractional: string, precision: number): [integer: string, fractional: string];
1047
+ /**
1048
+ * 四舍六入五成双
1049
+ * @example
1050
+ * ```js
1051
+ * // 四舍六入, 如果后一位是 5(000...) 则看前一位, 凑偶数
1052
+ * roundBank('1', '34', 1, false) // ['1', '3']
1053
+ * roundBank('1', '35', 1, false) // ['1', '4'] 五成双
1054
+ * roundBank('1', '36', 1, false) // ['1', '4']
1055
+ * roundBank('1', '44', 1, false) // ['1', '4']
1056
+ * roundBank('1', '45', 1, false) // ['1', '4'] 五成双
1057
+ * roundBank('1', '450001', 1, false) // ['1', '5'] 后一位比 5(000...) 多所以仍然进位
1058
+ * roundBank('1', '46', 1, false) // ['1', '5']
1059
+ * // 向整数进位也是如此
1060
+ * roundBank('1', '4', 0, false) // ['1', '']
1061
+ * roundBank('1', '5', 0, false) // ['2', ''] 五成双
1062
+ * roundBank('1', '6', 0, false) // ['2', '']
1063
+ * roundBank('2', '4', 0, false) // ['2', '']
1064
+ * roundBank('2', '5', 0, false) // ['2', ''] 五成双
1065
+ * roundBank('2', '6', 0, false) // ['3', '']
1066
+ * // 与符号无关
1067
+ * roundBank('1', '34', 1, true) // ['1', '3']
1068
+ * roundBank('1', '35', 1, true) // ['1', '4'] 五成双
1069
+ * roundBank('1', '36', 1, true) // ['1', '4']
1070
+ * roundBank('1', '44', 1, true) // ['1', '4']
1071
+ * roundBank('1', '45', 1, true) // ['1', '4'] 五成双
1072
+ * roundBank('1', '450001', 1, true) // ['1', '5']
1073
+ * roundBank('1', '46', 1, true) // ['1', '5']
1074
+ * ```
1075
+ * @version 0.3.2
1076
+ */
1077
+ declare function roundBank(integer: string, fractional: string, precision: number): [integer: string, fractional: string];
1078
+ /** 向下取整
1079
+ * @example
1080
+ * ```js
1081
+ * // 忽略后面的数字向下取整
1082
+ * roundFloor('1', '34', 1, false) // ['1', '3']
1083
+ * roundFloor('1', '36', 1, false) // ['1', '3']
1084
+ * roundFloor('1', '39', 1, false) // ['1', '3']
1085
+ * // 与符号有关 向更小的数字进位
1086
+ * roundFloor('1', '34', 1, true) // ['1', '4']
1087
+ * roundFloor('1', '35', 1, true) // ['1', '4']
1088
+ * roundFloor('1', '36', 1, true) // ['1', '4']
1089
+ * ```
1090
+ * @version 0.3.2
1091
+ */
1092
+ declare function roundFloor(integer: string, fractional: string, precision: number, isNegative: boolean): [integer: string, fractional: string];
1093
+ /** 向上取整
1094
+ * @example
1095
+ * ```js
1096
+ * // 忽略后面的数字向上取整
1097
+ * roundCeil('1', '34', 1, false) // ['1', '4']
1098
+ * roundCeil('1', '35', 1, false) // ['1', '4']
1099
+ * roundCeil('1', '36', 1, false) // ['1', '4']
1100
+ * // 与符号有关 向更大的数字进位
1101
+ * roundCeil('1', '34', 1, true) // ['1', '3']
1102
+ * roundCeil('1', '35', 1, true) // ['1', '3']
1103
+ * roundCeil('1', '36', 1, true) // ['1', '3']
1104
+ * ```
1105
+ * @version 0.3.2
1106
+ */
1107
+ declare function roundCeil(integer: string, fractional: string, precision: number, isNegative: boolean): [integer: string, fractional: string];
1108
+
879
1109
  /**
880
1110
  * 根据文件名称判断是否匹配支持的文件类型,需要注意 `.C` 与 `.c` 的区别
881
1111
  * - `text/x-c++src` 对应 `.C`
@@ -1986,5 +2216,5 @@ declare function throttle<T extends any[]>(fn: (...args: T) => any, delay: numbe
1986
2216
  reset: () => void;
1987
2217
  };
1988
2218
 
1989
- export { $$Empty, _, acceptableFileName, acceptableFileType, camelCase, capitalize, caseCamel, caseConvert, caseKebab, casePascal, caseSnake, clamp, compose, _curryMore as curry, debounce, dedent, deepClone, deepMerge, defer, fastClone, getAcceptableExtByMIME, getAcceptableMIMEByExt, getGlobalThis, getTag, indent, isArray, isArrayBuffer, isArrayLike, isBigInt, isBigInt64Array, isBigUint64Array, isBlob, isBoolean, isBuffer, isDataView, isDate, isEmpty, isFile, isFloat32Array, isFloat64Array, isFormData, isFunction, isInt16Array, isInt32Array, isInt8Array, isInteger, isIterable, isMap, isMergeEmptyPlaceholder, isNil, isNull, isNumber, isObject, isPlaceholder, isPrimitive, isPromise, isPromiseLike, isRegExp, isSet, isString, isSymbol, isTypedArray, isUint16Array, isUint32Array, isUint8Array, isUint8ClampedArray, isUndefined, isWeakMap, isWeakSet, isWrapperBigInt, isWrapperBoolean, isWrapperNumber, isWrapperObject, isWrapperString, isWrapperSymbol, kebabCase, memo, noop, not, parallel, pascalCase, pass, passWith, pipe, randomBase32String, randomChoice, randomHexString, randomInt, randomIntFloor, randomString, range, remove, retry, shuffle, sleep, snakeCase, splitWords, throttle, titleCase, tryit, ulid, uncapitalize, uuidNil, uuidV4, withResolvers };
1990
- export type { BaseMargeType, CloneOptions, CustomCloner, MergeOption, MergeStrategy, MergeStrategyFunction, MergeType, MergeTypeStrategy, RangeOptions, SourceMergeType, TargetMergeType, TypedArray };
2219
+ export { $$Empty, _, acceptableFileName, acceptableFileType, camelCase, capitalize, cartesianProduct, caseCamel, caseConvert, caseKebab, casePascal, caseSnake, chunk, clamp, compose, _curryMore as curry, debounce, decimalNotation, dedent, deepClone, deepMerge, defer, fastClone, format, getAcceptableExtByMIME, getAcceptableMIMEByExt, getGlobalThis, getTag, indent, isArray, isArrayBuffer, isArrayLike, isBigInt, isBigInt64Array, isBigUint64Array, isBlob, isBoolean, isBuffer, isDataView, isDate, isEmpty, isEven, isFile, isFloat32Array, isFloat64Array, isFormData, isFunction, isInt16Array, isInt32Array, isInt8Array, isInteger, isIterable, isMap, isMergeEmptyPlaceholder, isNil, isNull, isNumber, isObject, isOdd, isPlaceholder, isPlainObject, isPrimitive, isPromise, isPromiseLike, isRegExp, isSet, isString, isSymbol, isTypedArray, isUint16Array, isUint32Array, isUint8Array, isUint8ClampedArray, isUndefined, isWeakMap, isWeakSet, isWrapperBigInt, isWrapperBoolean, isWrapperNumber, isWrapperObject, isWrapperString, isWrapperSymbol, kebabCase, memo, noop, not, parallel, pascalCase, pass, passWith, pipe, randomBase32String, randomChoice, randomHexString, randomInt, randomIntFloor, randomString, range, remove, retry, round, roundBank, roundBase, roundCeil, roundFloor, shuffle, sleep, snakeCase, splitWords, throttle, titleCase, tryit, ulid, uncapitalize, uuidNil, uuidV4, withResolvers };
2220
+ export type { BaseMargeType, Chunked, CloneOptions, CustomCloner, IsNegative, IsPositive, IsZero, MergeOption, MergeStrategy, MergeStrategyFunction, MergeType, MergeTypeStrategy, Not, RangeOptions, SourceMergeType, Stringify, TargetMergeType, TypedArray };
package/lib/index.mjs CHANGED
@@ -9,6 +9,53 @@ EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
9
9
  MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
10
10
  See the Mulan PSL v2 for more details.
11
11
  */
12
+ function cartesianProduct(...arrList) {
13
+ const arrLen = arrList.length;
14
+ const pList = Array(arrLen).fill(0);
15
+ const lastIndex = arrLen - 1;
16
+ const res = [];
17
+ for (let i = 0; i < arrLen; i++) {
18
+ if (!arrList[i].length)
19
+ return [];
20
+ }
21
+ while (1) {
22
+ const temp = [];
23
+ for (let i = 0; i < arrLen; i++) {
24
+ temp.push(arrList[i][pList[i]]);
25
+ }
26
+ res.push(temp);
27
+ pList[lastIndex] += 1;
28
+ for (let i = lastIndex; i >= 0; i--) {
29
+ if (pList[i] >= arrList[i].length) {
30
+ if (i > 0) {
31
+ pList[i] = 0;
32
+ pList[i - 1] += 1;
33
+ }
34
+ else
35
+ break;
36
+ }
37
+ else
38
+ break;
39
+ }
40
+ if (pList[0] >= arrList[0].length)
41
+ break;
42
+ }
43
+ return res;
44
+ }
45
+
46
+ function chunk(array, size = 2) {
47
+ const res = [];
48
+ if (size < 1 || isNaN(size))
49
+ return res;
50
+ let start = 0, end = size;
51
+ while (start < array.length) {
52
+ res.push(Array.prototype.slice.call(array, start, end));
53
+ start = end;
54
+ end += size;
55
+ }
56
+ return res;
57
+ }
58
+
12
59
  function range(start, end, stepOrOptions) {
13
60
  if (!isFinite(start))
14
61
  throw new Error('start must be finite');
@@ -200,6 +247,22 @@ function isNumber(value) {
200
247
  return typeof value === 'number';
201
248
  }
202
249
 
250
+ const fnToString = Function.prototype.toString;
251
+ const objProtoContString = fnToString.call(Object.prototype.constructor);
252
+ function isPlainObject(value) {
253
+ if (typeof value !== 'object' || value === null)
254
+ return false;
255
+ const prototype = Object.getPrototypeOf(value);
256
+ if (prototype === null)
257
+ return true;
258
+ if (!Object.prototype.hasOwnProperty.call(prototype, "constructor"))
259
+ return false;
260
+ const constructorFn = prototype.constructor;
261
+ if (!isFunction(constructorFn) || fnToString.call(constructorFn) !== objProtoContString)
262
+ return false;
263
+ return (Object.getPrototypeOf(prototype) === null);
264
+ }
265
+
203
266
  function isPrimitive(value) {
204
267
  return value === undefined || value === null || (typeof value !== 'object' && typeof value !== 'function');
205
268
  }
@@ -372,6 +435,178 @@ function clamp(num, min, max, options) {
372
435
  return num < min ? defaultMin : num > max ? defaultMax : num;
373
436
  }
374
437
 
438
+ function decimalNotation(num) {
439
+ const n = isNumber(num) ? num : Number(num);
440
+ if (!isFinite(n))
441
+ return String(n);
442
+ let str = String(n);
443
+ if (!/e/i.test(str))
444
+ return str;
445
+ const match = str.match(/^(-?)(\d+)\.?(\d*)e([+-]?)(\d+)$/);
446
+ const [_, sign, mantissaI, mantissaF, expSign, _exponent] = match;
447
+ const exponent = Number(_exponent);
448
+ let mantissa = mantissaI + mantissaF;
449
+ let dotPos = mantissaI.length;
450
+ if (expSign === '-') {
451
+ const zeroCount = exponent - dotPos + 1;
452
+ if (zeroCount > 0)
453
+ mantissa = '0'.repeat(zeroCount) + mantissa;
454
+ return sign + mantissa[0] + '.' + mantissa.substring(1);
455
+ }
456
+ else {
457
+ const zeroCount = exponent + dotPos - mantissa.length;
458
+ if (zeroCount > 0)
459
+ mantissa = mantissa + '0'.repeat(zeroCount);
460
+ return sign + mantissa.substring(0, exponent + dotPos);
461
+ }
462
+ }
463
+
464
+ function isOdd(num) {
465
+ return !!(num & 1);
466
+ }
467
+ function isEven(num) {
468
+ return !(num & 1);
469
+ }
470
+
471
+ function round(num, precision, type) {
472
+ const str = decimalNotation(num);
473
+ if (/NaN|Inf/.test(str))
474
+ return str;
475
+ let [_integer, _fractional] = str.split('.');
476
+ let sign = '';
477
+ if (/^-/.test(_integer)) {
478
+ _integer = _integer.substring(1);
479
+ sign = '-';
480
+ }
481
+ _fractional = _fractional !== null && _fractional !== void 0 ? _fractional : '';
482
+ const roundMap = { round: roundBase, banker: roundBank, floor: roundFloor, ceil: roundCeil };
483
+ const [integer, fractional] = (roundMap[type || 'round'] || roundBase)(_integer, _fractional, precision, !!sign);
484
+ if (precision > 0)
485
+ return sign + integer + '.' + fractional;
486
+ else
487
+ return sign + integer;
488
+ }
489
+ function roundBase(integer, fractional, precision) {
490
+ if (fractional.length > precision) {
491
+ const splitF = fractional.substring(0, precision);
492
+ if (Number(fractional[precision]) > 4)
493
+ return increase(integer, splitF);
494
+ return [integer, splitF];
495
+ }
496
+ if (fractional.length < precision) {
497
+ fractional += '0'.repeat(precision - fractional.length);
498
+ }
499
+ return [integer, fractional];
500
+ }
501
+ function roundBank(integer, fractional, precision) {
502
+ if (fractional.length > precision) {
503
+ const splitF = fractional.substring(0, precision);
504
+ const rightNumber = Number(fractional[precision]);
505
+ if (rightNumber < 5)
506
+ return [integer, splitF];
507
+ if (rightNumber > 5)
508
+ return increase(integer, splitF);
509
+ const rightNumbers = fractional.substring(precision);
510
+ if (!/^50*$/.test(rightNumbers))
511
+ return increase(integer, splitF);
512
+ const leftNumber = Number(precision ? fractional[precision - 1] : integer[integer.length - 1]);
513
+ if (isEven(leftNumber))
514
+ return [integer, splitF];
515
+ else
516
+ return increase(integer, splitF);
517
+ }
518
+ if (fractional.length < precision) {
519
+ fractional += '0'.repeat(precision - fractional.length);
520
+ }
521
+ return [integer, fractional];
522
+ }
523
+ function roundFloor(integer, fractional, precision, isNegative) {
524
+ if (fractional.length > precision) {
525
+ const splitF = fractional.substring(0, precision);
526
+ if (isNegative)
527
+ return increase(integer, splitF);
528
+ return [integer, splitF];
529
+ }
530
+ if (fractional.length < precision) {
531
+ fractional += '0'.repeat(precision - fractional.length);
532
+ }
533
+ return [integer, fractional];
534
+ }
535
+ function roundCeil(integer, fractional, precision, isNegative) {
536
+ if (fractional.length > precision) {
537
+ const splitF = fractional.substring(0, precision);
538
+ if (!isNegative)
539
+ return increase(integer, splitF);
540
+ return [integer, splitF];
541
+ }
542
+ if (fractional.length < precision) {
543
+ fractional += '0'.repeat(precision - fractional.length);
544
+ }
545
+ return [integer, fractional];
546
+ }
547
+ function increase(integer, fractional) {
548
+ if (fractional) {
549
+ const _fractional = _increase(fractional);
550
+ if (_fractional.length > fractional.length) {
551
+ return [_increase(integer), _fractional.substring(1)];
552
+ }
553
+ return [integer, _fractional];
554
+ }
555
+ return [_increase(integer), ''];
556
+ }
557
+ function _increase(num) {
558
+ const numList = num.split('').map(Number).reverse();
559
+ numList[0] += 1;
560
+ numList.push(0);
561
+ for (let i = 0; i < numList.length; i++) {
562
+ if (numList[i] > 9) {
563
+ numList[i] -= 10;
564
+ numList[i + 1] += 1;
565
+ }
566
+ else
567
+ break;
568
+ }
569
+ if (numList[numList.length - 1] === 0)
570
+ numList.pop();
571
+ return numList.reverse().map(String).join('');
572
+ }
573
+
574
+ function format(num, options) {
575
+ var _a;
576
+ const str = decimalNotation(num);
577
+ if (/NaN|Inf/.test(str))
578
+ return str;
579
+ const separator = (options || {}).separator || ',';
580
+ const separate = clamp((options || {}).separate || 3, 1, Infinity);
581
+ const decimal = (options || {}).decimal || '.';
582
+ const precision = clamp((_a = (options || {}).precision) !== null && _a !== void 0 ? _a : 2, 0, Infinity);
583
+ const round = (options || {}).round || 'round';
584
+ let [integer, fractional] = str.split('.');
585
+ let sign = '';
586
+ if (/^-/.test(integer)) {
587
+ integer = integer.substring(1);
588
+ sign = '-';
589
+ }
590
+ fractional = fractional !== null && fractional !== void 0 ? fractional : '';
591
+ if (fractional.length > precision) {
592
+ const roundMap = { round: roundBase, banker: roundBank, floor: roundFloor, ceil: roundCeil };
593
+ [integer, fractional] = (roundMap[round] || roundBase)(integer, fractional, precision, !!sign);
594
+ }
595
+ else if (fractional.length < precision) {
596
+ fractional += '0'.repeat(precision - fractional.length);
597
+ }
598
+ if (integer.length > separate) {
599
+ integer = chunk(Array.from(integer).reverse(), separate)
600
+ .map((part) => part.join(''))
601
+ .join(separator);
602
+ integer = Array.from(integer).reverse().join('');
603
+ }
604
+ if (precision > 0)
605
+ return sign + integer + decimal + fractional;
606
+ else
607
+ return sign + integer;
608
+ }
609
+
375
610
  function parallel(args, fn, options) {
376
611
  return __awaiter(this, void 0, void 0, function* () {
377
612
  if (!args.length)
@@ -2040,4 +2275,4 @@ function throttle(fn, delay, options) {
2040
2275
  return _throttle(fn, delay, Object.assign({ trailing: false, leading: true }, options));
2041
2276
  }
2042
2277
 
2043
- export { $$Empty, _, acceptableFileName, acceptableFileType, camelCase, capitalize, caseCamel, caseConvert, caseKebab, casePascal, caseSnake, clamp, compose, _curryMore as curry, debounce, dedent, deepClone, deepMerge, defer, fastClone, getAcceptableExtByMIME, getAcceptableMIMEByExt, getGlobalThis, getTag, indent, isArray, isArrayBuffer, isArrayLike, isBigInt, isBigInt64Array, isBigUint64Array, isBlob, isBoolean, isBuffer, isDataView, isDate, isEmpty, isFile, isFloat32Array, isFloat64Array, isFormData, isFunction, isInt16Array, isInt32Array, isInt8Array, isInteger, isIterable, isMap, isMergeEmptyPlaceholder, isNil, isNull, isNumber, isObject, isPlaceholder, isPrimitive, isPromise, isPromiseLike, isRegExp, isSet, isString, isSymbol, isTypedArray, isUint16Array, isUint32Array, isUint8Array, isUint8ClampedArray, isUndefined, isWeakMap, isWeakSet, isWrapperBigInt, isWrapperBoolean, isWrapperNumber, isWrapperObject, isWrapperString, isWrapperSymbol, kebabCase, memo, noop, not, parallel, pascalCase, pass, passWith, pipe, randomBase32String, randomChoice, randomHexString, randomInt, randomIntFloor, randomString, range, remove, retry, shuffle, sleep, snakeCase, splitWords, throttle, titleCase, tryit, ulid, uncapitalize, uuidNil, uuidV4, withResolvers };
2278
+ export { $$Empty, _, acceptableFileName, acceptableFileType, camelCase, capitalize, cartesianProduct, caseCamel, caseConvert, caseKebab, casePascal, caseSnake, chunk, clamp, compose, _curryMore as curry, debounce, decimalNotation, dedent, deepClone, deepMerge, defer, fastClone, format, getAcceptableExtByMIME, getAcceptableMIMEByExt, getGlobalThis, getTag, indent, isArray, isArrayBuffer, isArrayLike, isBigInt, isBigInt64Array, isBigUint64Array, isBlob, isBoolean, isBuffer, isDataView, isDate, isEmpty, isEven, isFile, isFloat32Array, isFloat64Array, isFormData, isFunction, isInt16Array, isInt32Array, isInt8Array, isInteger, isIterable, isMap, isMergeEmptyPlaceholder, isNil, isNull, isNumber, isObject, isOdd, isPlaceholder, isPlainObject, isPrimitive, isPromise, isPromiseLike, isRegExp, isSet, isString, isSymbol, isTypedArray, isUint16Array, isUint32Array, isUint8Array, isUint8ClampedArray, isUndefined, isWeakMap, isWeakSet, isWrapperBigInt, isWrapperBoolean, isWrapperNumber, isWrapperObject, isWrapperString, isWrapperSymbol, kebabCase, memo, noop, not, parallel, pascalCase, pass, passWith, pipe, randomBase32String, randomChoice, randomHexString, randomInt, randomIntFloor, randomString, range, remove, retry, round, roundBank, roundBase, roundCeil, roundFloor, shuffle, sleep, snakeCase, splitWords, throttle, titleCase, tryit, ulid, uncapitalize, uuidNil, uuidV4, withResolvers };
package/lib/index.umd.js CHANGED
@@ -15,6 +15,53 @@ See the Mulan PSL v2 for more details.
15
15
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.foreslash = {}));
16
16
  })(this, (function (exports) { 'use strict';
17
17
 
18
+ function cartesianProduct(...arrList) {
19
+ const arrLen = arrList.length;
20
+ const pList = Array(arrLen).fill(0);
21
+ const lastIndex = arrLen - 1;
22
+ const res = [];
23
+ for (let i = 0; i < arrLen; i++) {
24
+ if (!arrList[i].length)
25
+ return [];
26
+ }
27
+ while (1) {
28
+ const temp = [];
29
+ for (let i = 0; i < arrLen; i++) {
30
+ temp.push(arrList[i][pList[i]]);
31
+ }
32
+ res.push(temp);
33
+ pList[lastIndex] += 1;
34
+ for (let i = lastIndex; i >= 0; i--) {
35
+ if (pList[i] >= arrList[i].length) {
36
+ if (i > 0) {
37
+ pList[i] = 0;
38
+ pList[i - 1] += 1;
39
+ }
40
+ else
41
+ break;
42
+ }
43
+ else
44
+ break;
45
+ }
46
+ if (pList[0] >= arrList[0].length)
47
+ break;
48
+ }
49
+ return res;
50
+ }
51
+
52
+ function chunk(array, size = 2) {
53
+ const res = [];
54
+ if (size < 1 || isNaN(size))
55
+ return res;
56
+ let start = 0, end = size;
57
+ while (start < array.length) {
58
+ res.push(Array.prototype.slice.call(array, start, end));
59
+ start = end;
60
+ end += size;
61
+ }
62
+ return res;
63
+ }
64
+
18
65
  function range(start, end, stepOrOptions) {
19
66
  if (!isFinite(start))
20
67
  throw new Error('start must be finite');
@@ -206,6 +253,22 @@ See the Mulan PSL v2 for more details.
206
253
  return typeof value === 'number';
207
254
  }
208
255
 
256
+ const fnToString = Function.prototype.toString;
257
+ const objProtoContString = fnToString.call(Object.prototype.constructor);
258
+ function isPlainObject(value) {
259
+ if (typeof value !== 'object' || value === null)
260
+ return false;
261
+ const prototype = Object.getPrototypeOf(value);
262
+ if (prototype === null)
263
+ return true;
264
+ if (!Object.prototype.hasOwnProperty.call(prototype, "constructor"))
265
+ return false;
266
+ const constructorFn = prototype.constructor;
267
+ if (!isFunction(constructorFn) || fnToString.call(constructorFn) !== objProtoContString)
268
+ return false;
269
+ return (Object.getPrototypeOf(prototype) === null);
270
+ }
271
+
209
272
  function isPrimitive(value) {
210
273
  return value === undefined || value === null || (typeof value !== 'object' && typeof value !== 'function');
211
274
  }
@@ -378,6 +441,178 @@ See the Mulan PSL v2 for more details.
378
441
  return num < min ? defaultMin : num > max ? defaultMax : num;
379
442
  }
380
443
 
444
+ function decimalNotation(num) {
445
+ const n = isNumber(num) ? num : Number(num);
446
+ if (!isFinite(n))
447
+ return String(n);
448
+ let str = String(n);
449
+ if (!/e/i.test(str))
450
+ return str;
451
+ const match = str.match(/^(-?)(\d+)\.?(\d*)e([+-]?)(\d+)$/);
452
+ const [_, sign, mantissaI, mantissaF, expSign, _exponent] = match;
453
+ const exponent = Number(_exponent);
454
+ let mantissa = mantissaI + mantissaF;
455
+ let dotPos = mantissaI.length;
456
+ if (expSign === '-') {
457
+ const zeroCount = exponent - dotPos + 1;
458
+ if (zeroCount > 0)
459
+ mantissa = '0'.repeat(zeroCount) + mantissa;
460
+ return sign + mantissa[0] + '.' + mantissa.substring(1);
461
+ }
462
+ else {
463
+ const zeroCount = exponent + dotPos - mantissa.length;
464
+ if (zeroCount > 0)
465
+ mantissa = mantissa + '0'.repeat(zeroCount);
466
+ return sign + mantissa.substring(0, exponent + dotPos);
467
+ }
468
+ }
469
+
470
+ function isOdd(num) {
471
+ return !!(num & 1);
472
+ }
473
+ function isEven(num) {
474
+ return !(num & 1);
475
+ }
476
+
477
+ function round(num, precision, type) {
478
+ const str = decimalNotation(num);
479
+ if (/NaN|Inf/.test(str))
480
+ return str;
481
+ let [_integer, _fractional] = str.split('.');
482
+ let sign = '';
483
+ if (/^-/.test(_integer)) {
484
+ _integer = _integer.substring(1);
485
+ sign = '-';
486
+ }
487
+ _fractional = _fractional !== null && _fractional !== void 0 ? _fractional : '';
488
+ const roundMap = { round: roundBase, banker: roundBank, floor: roundFloor, ceil: roundCeil };
489
+ const [integer, fractional] = (roundMap[type || 'round'] || roundBase)(_integer, _fractional, precision, !!sign);
490
+ if (precision > 0)
491
+ return sign + integer + '.' + fractional;
492
+ else
493
+ return sign + integer;
494
+ }
495
+ function roundBase(integer, fractional, precision) {
496
+ if (fractional.length > precision) {
497
+ const splitF = fractional.substring(0, precision);
498
+ if (Number(fractional[precision]) > 4)
499
+ return increase(integer, splitF);
500
+ return [integer, splitF];
501
+ }
502
+ if (fractional.length < precision) {
503
+ fractional += '0'.repeat(precision - fractional.length);
504
+ }
505
+ return [integer, fractional];
506
+ }
507
+ function roundBank(integer, fractional, precision) {
508
+ if (fractional.length > precision) {
509
+ const splitF = fractional.substring(0, precision);
510
+ const rightNumber = Number(fractional[precision]);
511
+ if (rightNumber < 5)
512
+ return [integer, splitF];
513
+ if (rightNumber > 5)
514
+ return increase(integer, splitF);
515
+ const rightNumbers = fractional.substring(precision);
516
+ if (!/^50*$/.test(rightNumbers))
517
+ return increase(integer, splitF);
518
+ const leftNumber = Number(precision ? fractional[precision - 1] : integer[integer.length - 1]);
519
+ if (isEven(leftNumber))
520
+ return [integer, splitF];
521
+ else
522
+ return increase(integer, splitF);
523
+ }
524
+ if (fractional.length < precision) {
525
+ fractional += '0'.repeat(precision - fractional.length);
526
+ }
527
+ return [integer, fractional];
528
+ }
529
+ function roundFloor(integer, fractional, precision, isNegative) {
530
+ if (fractional.length > precision) {
531
+ const splitF = fractional.substring(0, precision);
532
+ if (isNegative)
533
+ return increase(integer, splitF);
534
+ return [integer, splitF];
535
+ }
536
+ if (fractional.length < precision) {
537
+ fractional += '0'.repeat(precision - fractional.length);
538
+ }
539
+ return [integer, fractional];
540
+ }
541
+ function roundCeil(integer, fractional, precision, isNegative) {
542
+ if (fractional.length > precision) {
543
+ const splitF = fractional.substring(0, precision);
544
+ if (!isNegative)
545
+ return increase(integer, splitF);
546
+ return [integer, splitF];
547
+ }
548
+ if (fractional.length < precision) {
549
+ fractional += '0'.repeat(precision - fractional.length);
550
+ }
551
+ return [integer, fractional];
552
+ }
553
+ function increase(integer, fractional) {
554
+ if (fractional) {
555
+ const _fractional = _increase(fractional);
556
+ if (_fractional.length > fractional.length) {
557
+ return [_increase(integer), _fractional.substring(1)];
558
+ }
559
+ return [integer, _fractional];
560
+ }
561
+ return [_increase(integer), ''];
562
+ }
563
+ function _increase(num) {
564
+ const numList = num.split('').map(Number).reverse();
565
+ numList[0] += 1;
566
+ numList.push(0);
567
+ for (let i = 0; i < numList.length; i++) {
568
+ if (numList[i] > 9) {
569
+ numList[i] -= 10;
570
+ numList[i + 1] += 1;
571
+ }
572
+ else
573
+ break;
574
+ }
575
+ if (numList[numList.length - 1] === 0)
576
+ numList.pop();
577
+ return numList.reverse().map(String).join('');
578
+ }
579
+
580
+ function format(num, options) {
581
+ var _a;
582
+ const str = decimalNotation(num);
583
+ if (/NaN|Inf/.test(str))
584
+ return str;
585
+ const separator = (options || {}).separator || ',';
586
+ const separate = clamp((options || {}).separate || 3, 1, Infinity);
587
+ const decimal = (options || {}).decimal || '.';
588
+ const precision = clamp((_a = (options || {}).precision) !== null && _a !== void 0 ? _a : 2, 0, Infinity);
589
+ const round = (options || {}).round || 'round';
590
+ let [integer, fractional] = str.split('.');
591
+ let sign = '';
592
+ if (/^-/.test(integer)) {
593
+ integer = integer.substring(1);
594
+ sign = '-';
595
+ }
596
+ fractional = fractional !== null && fractional !== void 0 ? fractional : '';
597
+ if (fractional.length > precision) {
598
+ const roundMap = { round: roundBase, banker: roundBank, floor: roundFloor, ceil: roundCeil };
599
+ [integer, fractional] = (roundMap[round] || roundBase)(integer, fractional, precision, !!sign);
600
+ }
601
+ else if (fractional.length < precision) {
602
+ fractional += '0'.repeat(precision - fractional.length);
603
+ }
604
+ if (integer.length > separate) {
605
+ integer = chunk(Array.from(integer).reverse(), separate)
606
+ .map((part) => part.join(''))
607
+ .join(separator);
608
+ integer = Array.from(integer).reverse().join('');
609
+ }
610
+ if (precision > 0)
611
+ return sign + integer + decimal + fractional;
612
+ else
613
+ return sign + integer;
614
+ }
615
+
381
616
  function parallel(args, fn, options) {
382
617
  return __awaiter(this, void 0, void 0, function* () {
383
618
  if (!args.length)
@@ -2052,20 +2287,24 @@ See the Mulan PSL v2 for more details.
2052
2287
  exports.acceptableFileType = acceptableFileType;
2053
2288
  exports.camelCase = camelCase;
2054
2289
  exports.capitalize = capitalize;
2290
+ exports.cartesianProduct = cartesianProduct;
2055
2291
  exports.caseCamel = caseCamel;
2056
2292
  exports.caseConvert = caseConvert;
2057
2293
  exports.caseKebab = caseKebab;
2058
2294
  exports.casePascal = casePascal;
2059
2295
  exports.caseSnake = caseSnake;
2296
+ exports.chunk = chunk;
2060
2297
  exports.clamp = clamp;
2061
2298
  exports.compose = compose;
2062
2299
  exports.curry = _curryMore;
2063
2300
  exports.debounce = debounce;
2301
+ exports.decimalNotation = decimalNotation;
2064
2302
  exports.dedent = dedent;
2065
2303
  exports.deepClone = deepClone;
2066
2304
  exports.deepMerge = deepMerge;
2067
2305
  exports.defer = defer;
2068
2306
  exports.fastClone = fastClone;
2307
+ exports.format = format;
2069
2308
  exports.getAcceptableExtByMIME = getAcceptableExtByMIME;
2070
2309
  exports.getAcceptableMIMEByExt = getAcceptableMIMEByExt;
2071
2310
  exports.getGlobalThis = getGlobalThis;
@@ -2083,6 +2322,7 @@ See the Mulan PSL v2 for more details.
2083
2322
  exports.isDataView = isDataView;
2084
2323
  exports.isDate = isDate;
2085
2324
  exports.isEmpty = isEmpty;
2325
+ exports.isEven = isEven;
2086
2326
  exports.isFile = isFile;
2087
2327
  exports.isFloat32Array = isFloat32Array;
2088
2328
  exports.isFloat64Array = isFloat64Array;
@@ -2099,7 +2339,9 @@ See the Mulan PSL v2 for more details.
2099
2339
  exports.isNull = isNull;
2100
2340
  exports.isNumber = isNumber;
2101
2341
  exports.isObject = isObject;
2342
+ exports.isOdd = isOdd;
2102
2343
  exports.isPlaceholder = isPlaceholder;
2344
+ exports.isPlainObject = isPlainObject;
2103
2345
  exports.isPrimitive = isPrimitive;
2104
2346
  exports.isPromise = isPromise;
2105
2347
  exports.isPromiseLike = isPromiseLike;
@@ -2139,6 +2381,11 @@ See the Mulan PSL v2 for more details.
2139
2381
  exports.range = range;
2140
2382
  exports.remove = remove;
2141
2383
  exports.retry = retry;
2384
+ exports.round = round;
2385
+ exports.roundBank = roundBank;
2386
+ exports.roundBase = roundBase;
2387
+ exports.roundCeil = roundCeil;
2388
+ exports.roundFloor = roundFloor;
2142
2389
  exports.shuffle = shuffle;
2143
2390
  exports.sleep = sleep;
2144
2391
  exports.snakeCase = snakeCase;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foreslash",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Foreslash is a Javascript utilities lib which contains plenty of practical functions.",
5
5
  "author": "moushu",
6
6
  "license": "Mulan PSL v2",
@@ -35,11 +35,11 @@
35
35
  "scripts": {
36
36
  "dev": "rollup -c -w",
37
37
  "build": "rollup -c",
38
- "test": "jest --coverage",
39
- "prepublishOnly": "npm run build && npm run test",
40
- "docs:dev": "vitepress dev docs",
41
- "docs:build": "vitepress build docs",
42
- "docs:preview": "vitepress preview docs"
38
+ "test": "tsd --files /test/**/*.test-d.ts && jest --coverage",
39
+ "prepublishOnly": "jest --coverage && npm run build",
40
+ "docs:dev": "rollup -c && vitepress dev docs",
41
+ "docs:build": "rollup -c && vitepress build docs",
42
+ "docs:preview": "rollup -c && vitepress preview docs"
43
43
  },
44
44
  "keywords": [
45
45
  "foreslash",
@@ -57,6 +57,7 @@
57
57
  "rollup-plugin-dts": "^6.2.1",
58
58
  "sass-embedded": "^1.90.0",
59
59
  "ts-jest": "^29.2.5",
60
+ "tsd": "^0.33.0",
60
61
  "tslib": "^2.7.0",
61
62
  "typescript": "^5.5.4",
62
63
  "vitepress": "^1.6.3",