foreslash 0.2.3 → 0.3.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/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # Change Log
2
2
 
3
+ ## Version 0.3.0 - 2025-07-01
4
+
5
+ Unstable version
6
+
7
+ - Feat 🥥 Functions added: `capitalize` `deepMerge` `isBlob` and so forth
8
+ - Feat 🥥 Function change: `deepClone` now support `Blob` and `File`
9
+ - Other fixes and improvements
10
+
11
+ 不稳定版本
12
+
13
+ - 功能 🥥 添加函数: `capitalize` `deepMerge` `isBlob` 等
14
+ - 功能 🥥 变更函数: `deepClone` 现在支持 `Blob` 和 `File`
15
+ - 其他修复与优化
16
+
17
+ ## Version 0.2.4 - 2025-05-29
18
+
19
+ Unstable version
20
+
21
+ - Feat 🥥 Functions added: `retry` `parallel`
22
+ - Change 🥟 Dependencies change: upgrade devDependencies `rollup` `@rollup/plugin-typescript` `rollup-plugin-dts` `vitepress`
23
+ - Other fixes and improvements
24
+
25
+ 不稳定版本
26
+
27
+ - 功能 🥥 添加函数: `retry` `parallel`
28
+ - 变更 🥟 依赖变更: 升级开发依赖 `rollup` `@rollup/plugin-typescript` `rollup-plugin-dts` `vitepress`
29
+ - 其他修复与优化
30
+
3
31
  ## Version 0.2.3 - 2025-03-28
4
32
 
5
33
  Unstable version
package/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2024 moushu
1
+ Copyright (c) 2024-2025 moushu
2
2
  foreslash is licensed under Mulan PSL v2.
3
3
  You can use this software according to the terms and conditions of the Mulan PSL v2.
4
4
  You may obtain a copy of Mulan PSL v2 at:
package/lib/index.cmn.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- Copyright (c) 2024 moushu
2
+ Copyright (c) 2024-2025 moushu
3
3
  foreslash is licensed under Mulan PSL v2.
4
4
  You can use this software according to the terms and conditions of the Mulan PSL v2.
5
5
  You may obtain a copy of Mulan PSL v2 at:
@@ -116,8 +116,8 @@ function getGlobalThis() {
116
116
  return Function('return this')();
117
117
  }
118
118
 
119
- const global$7 = getGlobalThis();
120
- const ArrayBuffer$1 = global$7.ArrayBuffer;
119
+ const global$8 = getGlobalThis();
120
+ const ArrayBuffer$1 = global$8.ArrayBuffer;
121
121
  function isArrayBuffer(val) {
122
122
  return !!ArrayBuffer$1 && val instanceof ArrayBuffer$1;
123
123
  }
@@ -134,6 +134,16 @@ function isBigInt(value) {
134
134
  return typeof value === 'bigint';
135
135
  }
136
136
 
137
+ function isObject(value) {
138
+ return typeof value === 'object' && value !== null;
139
+ }
140
+
141
+ const global$7 = getGlobalThis();
142
+ const Blob = global$7.Blob;
143
+ function isBlob(value) {
144
+ return !!Blob && isObject(value) && getTag(value) === 'Blob';
145
+ }
146
+
137
147
  function isBoolean(value) {
138
148
  return typeof value === 'boolean';
139
149
  }
@@ -142,10 +152,6 @@ const global$6 = getGlobalThis();
142
152
  const Buffer = global$6.Buffer;
143
153
  const isBuffer = (Buffer && Buffer.isBuffer) || (() => false);
144
154
 
145
- function isObject(value) {
146
- return typeof value === 'object' && value !== null;
147
- }
148
-
149
155
  function isDataView(value) {
150
156
  return isObject(value) && getTag(value) === 'DataView';
151
157
  }
@@ -155,9 +161,9 @@ function isDate(value) {
155
161
  }
156
162
 
157
163
  const global$5 = getGlobalThis();
158
- const File = global$5.File;
164
+ const File$1 = global$5.File;
159
165
  function isFile(value) {
160
- return !!File && value instanceof File;
166
+ return !!File$1 && isObject(value) && getTag(value) === 'File';
161
167
  }
162
168
 
163
169
  const global$4 = getGlobalThis();
@@ -351,12 +357,100 @@ function defer(asyncFunction, options) {
351
357
  });
352
358
  }
353
359
 
360
+ function clamp(num, min, max, options) {
361
+ var _a, _b;
362
+ if (isNaN(min))
363
+ throw new Error('Invalid min parameter');
364
+ if (isNaN(max))
365
+ throw new Error('Invalid max parameter');
366
+ if (max < min) {
367
+ [min, max] = [max, min];
368
+ }
369
+ const { default: def, defaultMin: _dMin, defaultMax: _dMax } = options || {};
370
+ const defaultMin = (_a = _dMin !== null && _dMin !== void 0 ? _dMin : def) !== null && _a !== void 0 ? _a : min;
371
+ const defaultMax = (_b = _dMax !== null && _dMax !== void 0 ? _dMax : def) !== null && _b !== void 0 ? _b : max;
372
+ if (isNaN(num))
373
+ return defaultMin;
374
+ return num < min ? defaultMin : num > max ? defaultMax : num;
375
+ }
376
+
377
+ function parallel(args, fn, options) {
378
+ return __awaiter(this, void 0, void 0, function* () {
379
+ if (!args.length)
380
+ return [];
381
+ const { limit: _limit = 5 } = options || {};
382
+ const limit = clamp(Math.floor(_limit), 1, 100);
383
+ let current = 0;
384
+ const results = [];
385
+ const errors = [];
386
+ const asyncFn = tryit(fn);
387
+ const processor = () => __awaiter(this, void 0, void 0, function* () {
388
+ while (current < args.length) {
389
+ const index = current++;
390
+ const [err, result] = yield asyncFn(args[index]);
391
+ if (err)
392
+ errors.push({ index, error: err });
393
+ else
394
+ results[index] = result;
395
+ }
396
+ });
397
+ const tasks = [];
398
+ for (let i = 0; i < Math.min(args.length, limit); i++) {
399
+ tasks.push(processor());
400
+ }
401
+ yield Promise.all(tasks);
402
+ if (errors.length) {
403
+ throw new Error(`Parallel execution failed on index: ${errors.map((e) => e.index).join(', ')}`, { cause: errors });
404
+ }
405
+ return results;
406
+ });
407
+ }
408
+
354
409
  function sleep(time = 1000) {
355
410
  return new Promise((res) => {
356
411
  setTimeout(res, time);
357
412
  });
358
413
  }
359
414
 
415
+ function retry(asyncFunction, option) {
416
+ return __awaiter(this, void 0, void 0, function* () {
417
+ let retryCounts = 0;
418
+ const times = isNumber(option === null || option === void 0 ? void 0 : option.times) ? option.times : 3;
419
+ const delay = isFunction(option === null || option === void 0 ? void 0 : option.delay)
420
+ ? option.delay
421
+ : isNumber(option === null || option === void 0 ? void 0 : option.delay)
422
+ ? () => option.delay
423
+ : null;
424
+ const gap = isFunction(option === null || option === void 0 ? void 0 : option.gap) ? option.gap : isNumber(option === null || option === void 0 ? void 0 : option.gap) ? () => option.gap : null;
425
+ let lastRunTime = 0;
426
+ const getDelayTime = !option || (!delay && !gap)
427
+ ? () => 0
428
+ : gap
429
+ ? (retryCounts) => {
430
+ const time = gap(retryCounts);
431
+ return time - Date.now() + lastRunTime;
432
+ }
433
+ : delay;
434
+ while (1) {
435
+ lastRunTime = Date.now();
436
+ const [err, res] = yield tryit(asyncFunction)((err) => {
437
+ throw { $$exit_retry: err };
438
+ });
439
+ if (!err)
440
+ return res;
441
+ retryCounts++;
442
+ if (err && err.$$exit_retry)
443
+ throw err.$$exit_retry;
444
+ if (retryCounts >= times)
445
+ throw err;
446
+ const delayTime = getDelayTime(retryCounts);
447
+ if (delayTime > 0)
448
+ yield sleep(delayTime);
449
+ }
450
+ throw new Error('retry failed');
451
+ });
452
+ }
453
+
360
454
  const noop = function noop() { };
361
455
 
362
456
  function withResolvers(PromiseLike = Promise) {
@@ -370,23 +464,6 @@ function withResolvers(PromiseLike = Promise) {
370
464
  return { promise, resolve, reject };
371
465
  }
372
466
 
373
- function clamp(num, min, max, options) {
374
- var _a, _b;
375
- if (isNaN(min))
376
- throw new Error('Invalid min parameter');
377
- if (isNaN(max))
378
- throw new Error('Invalid max parameter');
379
- if (max < min) {
380
- [min, max] = [max, min];
381
- }
382
- const { default: def, defaultMin: _dMin, defaultMax: _dMax } = options || {};
383
- const defaultMin = (_a = _dMin !== null && _dMin !== void 0 ? _dMin : def) !== null && _a !== void 0 ? _a : min;
384
- const defaultMax = (_b = _dMax !== null && _dMax !== void 0 ? _dMax : def) !== null && _b !== void 0 ? _b : max;
385
- if (isNaN(num))
386
- return defaultMin;
387
- return num < min ? defaultMin : num > max ? defaultMax : num;
388
- }
389
-
390
467
  const mimeMap = {
391
468
  application: {
392
469
  acrobat: ['pdf'],
@@ -1180,6 +1257,12 @@ function titleCase(str, options) {
1180
1257
  : ({ code }) => code.slice(0, 1).toUpperCase() + code.slice(1).toLowerCase());
1181
1258
  }
1182
1259
 
1260
+ function capitalize(str) {
1261
+ if (!str)
1262
+ return str;
1263
+ return str.charAt(0).toUpperCase() + str.slice(1);
1264
+ }
1265
+
1183
1266
  function caseConvert(str, joiner = '', handler) {
1184
1267
  const hc = handler ? handler : (token) => token.code;
1185
1268
  return _caseConvert(_splitVar(str), joiner, hc);
@@ -1227,6 +1310,12 @@ function splitWords(str) {
1227
1310
  return _splitVar(str).map(({ code }) => code);
1228
1311
  }
1229
1312
 
1313
+ function uncapitalize(str) {
1314
+ if (!str)
1315
+ return str;
1316
+ return str.charAt(0).toLowerCase() + str.slice(1);
1317
+ }
1318
+
1230
1319
  function compose(...composeFunc) {
1231
1320
  if (composeFunc.length === 0) {
1232
1321
  throw new Error('Invalid composeFunc parameter: composeFunc is empty');
@@ -1468,6 +1557,16 @@ function _cloneArrayBuffer(obj, map) {
1468
1557
  new Uint8Array(res).set(new Uint8Array(obj));
1469
1558
  return res;
1470
1559
  }
1560
+ function _cloneBlob(obj, map) {
1561
+ const res = obj.slice(0, obj.size, obj.type);
1562
+ map.set(obj, res);
1563
+ return res;
1564
+ }
1565
+ function _cloneFile(obj, map) {
1566
+ const res = new File([obj], obj.name, { type: obj.type, lastModified: obj.lastModified });
1567
+ map.set(obj, res);
1568
+ return res;
1569
+ }
1471
1570
 
1472
1571
  function _deepClone(obj, map, options) {
1473
1572
  if (map.has(obj))
@@ -1512,6 +1611,12 @@ function _deepClone(obj, map, options) {
1512
1611
  res = new DataView(map.has(obj.buffer) ? map.get(obj.buffer) : _cloneArrayBuffer(obj.buffer, map), obj.byteOffset, obj.byteLength);
1513
1612
  map.set(obj, res);
1514
1613
  }
1614
+ else if (isFile(obj)) {
1615
+ res = _cloneFile(obj, map);
1616
+ }
1617
+ else if (isBlob(obj)) {
1618
+ res = _cloneBlob(obj, map);
1619
+ }
1515
1620
  else if (isWrapperObject(obj)) {
1516
1621
  res = Object(obj.valueOf());
1517
1622
  map.set(obj, res);
@@ -1546,6 +1651,201 @@ function deepClone(obj, options, map) {
1546
1651
  return res;
1547
1652
  }
1548
1653
 
1654
+ const $$Empty = Object.freeze({ '@@merge/placeholder': true });
1655
+ function getMergeStrategy(targetType, sourceType, strategy) {
1656
+ return (strategy[`${sourceType}2${targetType}`] ||
1657
+ strategy[`${sourceType}2Any`] ||
1658
+ strategy[`Any2${targetType}`] ||
1659
+ strategy[`Any2Any`] ||
1660
+ 'override');
1661
+ }
1662
+ function getBaseMargeType(obj) {
1663
+ if (isMergeEmptyPlaceholder(obj))
1664
+ return 'Empty';
1665
+ const _tag = getTag(obj);
1666
+ if (/Function/.test(_tag))
1667
+ return 'Function';
1668
+ if (/Iterator/.test(_tag))
1669
+ return 'Iterator';
1670
+ if (/(?:8|16|32|64)Array/.test(_tag))
1671
+ return 'TypedArray';
1672
+ if (/Error/.test(_tag))
1673
+ return 'Error';
1674
+ return _tag;
1675
+ }
1676
+ function isMergeEmptyPlaceholder(arg) {
1677
+ return typeof arg === 'object' && Boolean(arg) && arg['@@merge/placeholder'] === true;
1678
+ }
1679
+
1680
+ function _deepMergeBase(target, source, option, map, path, cloner) {
1681
+ const targetType = getBaseMargeType(target);
1682
+ const sourceType = getBaseMargeType(source);
1683
+ const strategy = getMergeStrategy(targetType, sourceType, option.typeStrategy);
1684
+ if (isFunction(strategy)) {
1685
+ const merger = _curryMore(_deepMergeBase)(_, _, option, map, _, cloner);
1686
+ const mergeRes = strategy({
1687
+ target,
1688
+ source,
1689
+ cloner,
1690
+ merger,
1691
+ path,
1692
+ typeStrategy: option.typeStrategy,
1693
+ unhandledValue: $$Empty,
1694
+ map,
1695
+ });
1696
+ if (!isMergeEmptyPlaceholder(mergeRes))
1697
+ return mergeRes;
1698
+ }
1699
+ if (strategy === 'keep') {
1700
+ if (isMergeEmptyPlaceholder(target))
1701
+ return $$Empty;
1702
+ return cloner(target);
1703
+ }
1704
+ else if (strategy === 'override') {
1705
+ return cloner(source);
1706
+ }
1707
+ else {
1708
+ return cloner(source);
1709
+ }
1710
+ }
1711
+ const defaultMergeStrategy = {
1712
+ Any2Any: 'override',
1713
+ Any2Empty: 'override',
1714
+ Any2Null: 'override',
1715
+ Any2Undefined: 'override',
1716
+ Null2Any: 'keep',
1717
+ Undefined2Any: 'keep',
1718
+ Null2Empty: 'override',
1719
+ Undefined2Empty: 'override',
1720
+ Number2Any: 'keep',
1721
+ Number2Number: 'override',
1722
+ String2Any: 'keep',
1723
+ String2String: 'override',
1724
+ Boolean2Any: 'keep',
1725
+ Boolean2Boolean: 'override',
1726
+ Symbol2Any: 'keep',
1727
+ Symbol2Symbol: 'override',
1728
+ BigInt2Any: 'keep',
1729
+ BigInt2BigInt: 'override',
1730
+ Number2Empty: 'override',
1731
+ String2Empty: 'override',
1732
+ Boolean2Empty: 'override',
1733
+ Symbol2Empty: 'override',
1734
+ BigInt2Empty: 'override',
1735
+ Number2Null: 'override',
1736
+ String2Null: 'override',
1737
+ Boolean2Null: 'override',
1738
+ Symbol2Null: 'override',
1739
+ BigInt2Null: 'override',
1740
+ Number2Undefined: 'override',
1741
+ String2Undefined: 'override',
1742
+ Boolean2Undefined: 'override',
1743
+ Symbol2Undefined: 'override',
1744
+ BigInt2Undefined: 'override',
1745
+ Object2Object: (({ target, source, cloner, path, merger }) => {
1746
+ const res = cloner(target);
1747
+ Reflect.ownKeys(source).forEach((key) => {
1748
+ const newPath = [...path, key];
1749
+ if (key in res) {
1750
+ res[key] = merger(res[key], source[key], newPath);
1751
+ }
1752
+ else {
1753
+ const mergeRes = merger($$Empty, source[key], newPath);
1754
+ if (!isMergeEmptyPlaceholder(mergeRes))
1755
+ res[key] = mergeRes;
1756
+ }
1757
+ });
1758
+ return res;
1759
+ }),
1760
+ Object2FormData: (({ target, source, cloner, path, merger }) => {
1761
+ const res = cloner(target);
1762
+ Reflect.ownKeys(source).forEach((key) => {
1763
+ if (isSymbol(key))
1764
+ return;
1765
+ const newPath = [...path, key];
1766
+ if (res.has(key)) {
1767
+ res.set(key, merger(res.get(key), source[key], newPath));
1768
+ }
1769
+ else {
1770
+ const mergeRes = merger($$Empty, source[key], newPath);
1771
+ if (!isMergeEmptyPlaceholder(mergeRes))
1772
+ res.set(key, mergeRes);
1773
+ }
1774
+ });
1775
+ return res;
1776
+ }),
1777
+ FormData2Object: (({ target, source, cloner, path, merger }) => {
1778
+ const res = cloner(target);
1779
+ source.forEach((val, key) => {
1780
+ const newPath = [...path, key];
1781
+ if (key in res) {
1782
+ res[key] = merger(res[key], val, newPath);
1783
+ }
1784
+ else {
1785
+ const mergeRes = merger($$Empty, val, newPath);
1786
+ if (!isMergeEmptyPlaceholder(mergeRes))
1787
+ res[key] = mergeRes;
1788
+ }
1789
+ });
1790
+ return res;
1791
+ }),
1792
+ FormData2FormData: (({ target, source, cloner, path, merger }) => {
1793
+ const res = cloner(target);
1794
+ source.forEach((val, key) => {
1795
+ const newPath = [...path, key];
1796
+ if (res.has(key)) {
1797
+ res.set(key, merger(res.get(key), val, newPath));
1798
+ }
1799
+ else {
1800
+ const mergeRes = merger($$Empty, val, newPath);
1801
+ if (!isMergeEmptyPlaceholder(mergeRes))
1802
+ res.set(key, mergeRes);
1803
+ }
1804
+ });
1805
+ return res;
1806
+ }),
1807
+ Set2Set: (({ target, source, cloner }) => {
1808
+ const res = cloner(target);
1809
+ for (const item of source)
1810
+ res.add(cloner(item));
1811
+ return res;
1812
+ }),
1813
+ Map2Map: (({ target, source, cloner }) => {
1814
+ const res = cloner(target);
1815
+ for (const [key, val] of source)
1816
+ res.set(cloner(key), cloner(val));
1817
+ return res;
1818
+ }),
1819
+ Array2Array: (({ target, source, cloner }) => {
1820
+ const res = cloner(target);
1821
+ for (const item of source)
1822
+ res.push(cloner(item));
1823
+ return res;
1824
+ }),
1825
+ Set2Array: (({ target, source, cloner }) => {
1826
+ const res = cloner(target);
1827
+ for (const item of source)
1828
+ res.push(cloner(item));
1829
+ return res;
1830
+ }),
1831
+ Array2Set: (({ target, source, cloner }) => {
1832
+ const res = cloner(target);
1833
+ for (const item of source)
1834
+ res.add(cloner(item));
1835
+ return res;
1836
+ }),
1837
+ };
1838
+
1839
+ function deepMerge(target, source, option) {
1840
+ const typeStrategy = Object.assign(Object.assign({}, defaultMergeStrategy), ((option === null || option === void 0 ? void 0 : option.typeStrategy) || {}));
1841
+ const cloneOptions = Object.assign({ cloneSymbol: true, clonePrototype: false, cloneDescriptor: false, customCloner: [] }, ((option === null || option === void 0 ? void 0 : option.cloneOptions) || {}));
1842
+ const map = new Map();
1843
+ const cloner = _curryMore(_deepClone)(_, map, cloneOptions);
1844
+ const res = _deepMergeBase(target, source, { typeStrategy, cloneOptions }, map, [], cloner);
1845
+ map.clear();
1846
+ return res;
1847
+ }
1848
+
1549
1849
  function _fastClone(obj, map) {
1550
1850
  if (map.has(obj))
1551
1851
  return map.get(obj);
@@ -1703,10 +2003,12 @@ function throttle(fn, delay, options) {
1703
2003
  return _throttle(fn, delay, Object.assign({ trailing: false, leading: true }, options));
1704
2004
  }
1705
2005
 
2006
+ exports.$$Empty = $$Empty;
1706
2007
  exports._ = _;
1707
2008
  exports.acceptableFileName = acceptableFileName;
1708
2009
  exports.acceptableFileType = acceptableFileType;
1709
2010
  exports.camelCase = camelCase;
2011
+ exports.capitalize = capitalize;
1710
2012
  exports.caseCamel = caseCamel;
1711
2013
  exports.caseConvert = caseConvert;
1712
2014
  exports.caseKebab = caseKebab;
@@ -1717,6 +2019,7 @@ exports.compose = compose;
1717
2019
  exports.curry = _curryMore;
1718
2020
  exports.debounce = debounce;
1719
2021
  exports.deepClone = deepClone;
2022
+ exports.deepMerge = deepMerge;
1720
2023
  exports.defer = defer;
1721
2024
  exports.fastClone = fastClone;
1722
2025
  exports.getAcceptableExtByMIME = getAcceptableExtByMIME;
@@ -1729,6 +2032,7 @@ exports.isArrayLike = isArrayLike;
1729
2032
  exports.isBigInt = isBigInt;
1730
2033
  exports.isBigInt64Array = isBigInt64Array;
1731
2034
  exports.isBigUint64Array = isBigUint64Array;
2035
+ exports.isBlob = isBlob;
1732
2036
  exports.isBoolean = isBoolean;
1733
2037
  exports.isBuffer = isBuffer;
1734
2038
  exports.isDataView = isDataView;
@@ -1745,6 +2049,7 @@ exports.isInt8Array = isInt8Array;
1745
2049
  exports.isInteger = isInteger;
1746
2050
  exports.isIterable = isIterable;
1747
2051
  exports.isMap = isMap;
2052
+ exports.isMergeEmptyPlaceholder = isMergeEmptyPlaceholder;
1748
2053
  exports.isNil = isNil;
1749
2054
  exports.isNull = isNull;
1750
2055
  exports.isNumber = isNumber;
@@ -1775,6 +2080,7 @@ exports.kebabCase = kebabCase;
1775
2080
  exports.memo = memo;
1776
2081
  exports.noop = noop;
1777
2082
  exports.not = not;
2083
+ exports.parallel = parallel;
1778
2084
  exports.pascalCase = pascalCase;
1779
2085
  exports.pass = pass;
1780
2086
  exports.passWith = passWith;
@@ -1787,6 +2093,7 @@ exports.randomIntFloor = randomIntFloor;
1787
2093
  exports.randomString = randomString;
1788
2094
  exports.range = range;
1789
2095
  exports.remove = remove;
2096
+ exports.retry = retry;
1790
2097
  exports.shuffle = shuffle;
1791
2098
  exports.sleep = sleep;
1792
2099
  exports.snakeCase = snakeCase;
@@ -1795,6 +2102,7 @@ exports.throttle = throttle;
1795
2102
  exports.titleCase = titleCase;
1796
2103
  exports.tryit = tryit;
1797
2104
  exports.ulid = ulid;
2105
+ exports.uncapitalize = uncapitalize;
1798
2106
  exports.uuidNil = uuidNil;
1799
2107
  exports.uuidV4 = uuidV4;
1800
2108
  exports.withResolvers = withResolvers;