foreslash 0.0.1 → 0.1.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/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ Copyright (c) 2024 moushu
2
+ foreslash is licensed under Mulan PSL v2.
3
+ You can use this software according to the terms and conditions of the Mulan PSL v2.
4
+ You may obtain a copy of Mulan PSL v2 at:
5
+ http://license.coscl.org.cn/MulanPSL2
6
+ THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
7
+ EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
8
+ MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
9
+ See the Mulan PSL v2 for more details.
package/README.md CHANGED
@@ -1,13 +1,93 @@
1
- # Foreslash
2
-
3
- Foreslash 是一个 javascript 工具库,包含大量函数。
4
-
5
- Foreslash is a javascript utilities lib which contains plenty of functions.
6
-
7
- ## 安装
8
-
9
- ```bash
10
- npm install foreslash # 使用 npm 安装
11
- yarn add foreslash # 使用 yarn 安装
12
- pnpm install foreslash # 使用 pnpm 安装
13
- ```
1
+ # Foreslash
2
+
3
+ ![GitHub top lang](https://img.shields.io/github/languages/top/Moushudyx/foreslash)
4
+ ![GitHub license](https://img.shields.io/badge/license-Mulan_PSL_v2-blue)
5
+ ![NPM Version](https://img.shields.io/npm/v/foreslash)
6
+ ![NPM Downloads](https://img.shields.io/npm/dm/foreslash)
7
+ ![npm package minimized gzipped size](https://img.shields.io/bundlejs/size/foreslash?label=gzipped)
8
+
9
+ Foreslash 是一个 Javascript 工具库,包含大量实用函数。
10
+
11
+ Foreslash is a Javascript utilities lib which contains plenty of practical functions.
12
+
13
+ [文档](https://moushudyx.github.io/foreslash) | [Documentation](https://moushudyx.github.io/foreslash/en)
14
+
15
+ ## 设计理念 Design Concept
16
+
17
+ ### 函数式 Functional
18
+
19
+ 此库提供了诸如`curry`、`pipe`等函数式编程的方法,但若无特殊说明,此库的任何方法都**不是柯里化**的。
20
+
21
+ - 这是出于性能优化和调试方便的考量。
22
+
23
+ 此库的柯里化方法`curry`和柯里化占位符`_`与 [ramda](https://github.com/ramda/ramda) 兼容。
24
+
25
+ ### 不变性 Immutability
26
+
27
+ 若无特殊说明,此库的任何方法都是**不可变**的,即不会修改传入的原数据,返回值将是一个新的数据。
28
+
29
+ ### 类型 Type
30
+
31
+ 此库使用 [typescript](https://github.com/microsoft/TypeScript) 编写,并使用 [jest](https://github.com/facebook/jest) 和 [ts-jest](https://github.com/kulshekhar/ts-jest) 来单元测试。
32
+
33
+ ## 安装与使用 Install & Usage
34
+
35
+ ```bash
36
+ npm install foreslash # 使用 npm 安装
37
+ yarn add foreslash # 使用 yarn 安装
38
+ pnpm install foreslash # 使用 pnpm 安装
39
+ ```
40
+
41
+ ```js
42
+ // curry & randomString
43
+ import { _, curry, randomString } from 'foreslash'
44
+
45
+ randomString(3) // 'bcD' or 'T30' or '7c5' or ...
46
+
47
+ const curriedRanStr = curry(randomString)
48
+
49
+ const randomABCD = curriedRanStr(_, 'ABCD')
50
+ randomABCD(3) // 'BDC' or 'ACD' or 'DBB' or ...
51
+
52
+ const random1234 = curriedRanStr(_, '1234')
53
+ random1234(3) // '431' or '213' or '241' or ...
54
+
55
+ // fastClone
56
+ import { fastClone } from 'foreslash'
57
+
58
+ const obj = { a: { b: { c: {} } }, map: new Map() }
59
+ obj.a.b.c.d = obj
60
+ obj.map.set(obj, 'val')
61
+
62
+ const clone = fastClone(obj)
63
+ clone === obj // false
64
+ // clone Deep
65
+ clone.a.b.c === obj.a.b.c // false
66
+ clone.a.b.c.d === clone // true
67
+ // clone Map
68
+ clone.map === obj.map // false
69
+ clone.map.get(clone) === 'val' // true
70
+ ```
71
+
72
+ ## 兼容性 Compatibility
73
+
74
+ 此库兼容任何能正确运行 ES6 代码的 Javascript 环境,包括 node.js 和浏览器
75
+
76
+ - 不支持 Internet Explorer,但是使用 [core-js](https://github.com/zloirock/core-js) 处理并由 [babel](https://babeljs.io/) 转译为 ES5(ES2009) 后可以使用
77
+
78
+ ### polyfill
79
+
80
+ 此库没有 polyfill,如果要在旧版浏览器中使用,请使用 [core-js](https://github.com/zloirock/core-js) 或其他 polyfill 工具
81
+
82
+ ### ES2015
83
+
84
+ 此库使用 ES6(ES2015) 语法,如果要在旧版浏览器中使用,请使用 [babel](https://babeljs.io/) 或其他打包/转译工具
85
+
86
+ ## 开源软件 Credits
87
+
88
+ - [jest](https://github.com/facebook/jest)
89
+ - [rollup](https://github.com/rollup/rollup)
90
+ - [ts-jest](https://github.com/kulshekhar/ts-jest)
91
+ - [ts-toolbelt](https://github.com/millsp/ts-toolbelt)
92
+ - [typescript](https://github.com/microsoft/TypeScript)
93
+ - [yarn](https://github.com/yarnpkg/yarn)
@@ -0,0 +1,478 @@
1
+ /*!
2
+ Copyright (c) 2024 moushu
3
+ foreslash is licensed under Mulan PSL v2.
4
+ You can use this software according to the terms and conditions of the Mulan PSL v2.
5
+ You may obtain a copy of Mulan PSL v2 at:
6
+ http://license.coscl.org.cn/MulanPSL2
7
+ THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
8
+ EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
9
+ MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
10
+ See the Mulan PSL v2 for more details.
11
+ */
12
+ 'use strict';
13
+
14
+ const isArray = Array.isArray;
15
+
16
+ function _cloneArray(obj, map, cloner, ...args) {
17
+ const res = obj.slice();
18
+ map.set(obj, res);
19
+ for (let index = 0; index < obj.length; index++) {
20
+ res[index] = cloner(obj[index], map, ...args);
21
+ }
22
+ return res;
23
+ }
24
+ function _cloneMap(obj, map, cloner, ...args) {
25
+ const res = new Map();
26
+ map.set(obj, res);
27
+ obj.forEach((value, key) => {
28
+ res.set(cloner(key, map, ...args), cloner(value, map, ...args));
29
+ });
30
+ return res;
31
+ }
32
+ function _cloneSet(obj, map, cloner, ...args) {
33
+ const res = new Set();
34
+ map.set(obj, res);
35
+ obj.forEach((item) => res.add(cloner(item, map, ...args)));
36
+ return res;
37
+ }
38
+
39
+ function _fastClone(obj, map) {
40
+ if (map.has(obj))
41
+ return map.get(obj);
42
+ if (!isObject(obj) || isFunction(obj) || isWeakMap(obj) || isWeakSet(obj) || isPromise(obj))
43
+ return obj;
44
+ if (isArray(obj))
45
+ return _cloneArray(obj, map, _fastClone);
46
+ if (isMap(obj))
47
+ return _cloneMap(obj, map, _fastClone);
48
+ if (isSet(obj))
49
+ return _cloneSet(obj, map, _fastClone);
50
+ let res;
51
+ if (obj instanceof Date) {
52
+ res = new Date(obj.valueOf());
53
+ map.set(obj, res);
54
+ }
55
+ else if (obj instanceof RegExp) {
56
+ res = new RegExp(obj.source, obj.flags);
57
+ map.set(obj, res);
58
+ }
59
+ else {
60
+ res = {};
61
+ map.set(obj, res);
62
+ Object.keys(obj).forEach((key) => {
63
+ res[key] = _fastClone(obj[key], map);
64
+ });
65
+ }
66
+ return res;
67
+ }
68
+
69
+ const object2String = Object.prototype.toString;
70
+ function getTag(value) {
71
+ return object2String.call(value).slice(8, -1);
72
+ }
73
+
74
+ function getGlobalThis() {
75
+ if (typeof self !== 'undefined') {
76
+ return self;
77
+ }
78
+ if (typeof window !== 'undefined') {
79
+ return window;
80
+ }
81
+ if (typeof global !== 'undefined') {
82
+ return global;
83
+ }
84
+ return Function('return this')();
85
+ }
86
+
87
+ const global$5 = getGlobalThis();
88
+ const ArrayBuffer = global$5.ArrayBuffer;
89
+ function isArrayBuffer(val) {
90
+ return !!ArrayBuffer && val instanceof ArrayBuffer;
91
+ }
92
+
93
+ function isInteger(value) {
94
+ return typeof value === 'number' && isFinite(value) && value % 1 === 0;
95
+ }
96
+
97
+ function isArrayLike(value) {
98
+ return value != null && typeof value !== 'function' && isInteger(value.length) && value.length >= 0;
99
+ }
100
+
101
+ function isBigInt(value) {
102
+ return typeof value === 'bigint';
103
+ }
104
+
105
+ function isBoolean(value) {
106
+ return typeof value === 'boolean';
107
+ }
108
+
109
+ const global$4 = getGlobalThis();
110
+ const Buffer = global$4.Buffer;
111
+ const isBuffer = (Buffer && Buffer.isBuffer) || (() => false);
112
+
113
+ function isFunction(value) {
114
+ return typeof value === 'function';
115
+ }
116
+
117
+ const global$3 = getGlobalThis();
118
+ function isMap(value) {
119
+ return !!global$3.Map && value instanceof Map;
120
+ }
121
+ function isWeakMap(value) {
122
+ return !!global$3.WeakMap && value instanceof WeakMap;
123
+ }
124
+
125
+ function isNil(value) {
126
+ return value == null;
127
+ }
128
+ function isNull(value) {
129
+ return value === null;
130
+ }
131
+ function isUndefined(value) {
132
+ return value === void 0;
133
+ }
134
+
135
+ function isNumber(value) {
136
+ return typeof value === 'number';
137
+ }
138
+
139
+ function isObject(value) {
140
+ return typeof value === 'object' && value !== null;
141
+ }
142
+
143
+ function isPromise(value) {
144
+ return isObject(value) && isFunction(value.then) && getTag(value) === 'Promise';
145
+ }
146
+
147
+ function isPromiseLike(value) {
148
+ return isObject(value) && isFunction(value.then);
149
+ }
150
+
151
+ const global$2 = getGlobalThis();
152
+ function isSet(value) {
153
+ return !!global$2.Set && value instanceof Set;
154
+ }
155
+ function isWeakSet(value) {
156
+ return !!global$2.WeakSet && value instanceof WeakSet;
157
+ }
158
+
159
+ function isString(value) {
160
+ return typeof value === 'string';
161
+ }
162
+
163
+ function isSymbol(value) {
164
+ return typeof value === 'symbol';
165
+ }
166
+
167
+ const global$1 = getGlobalThis();
168
+ function isWrapperObject(value) {
169
+ return (!!value &&
170
+ typeof value === 'object' &&
171
+ (isWrapperNumber(value) ||
172
+ isWrapperBoolean(value) ||
173
+ isWrapperString(value) ||
174
+ isWrapperSymbol(value) ||
175
+ isWrapperBigInt(value)));
176
+ }
177
+ function isWrapperNumber(value) {
178
+ return value instanceof Number;
179
+ }
180
+ function isWrapperBoolean(value) {
181
+ return value instanceof Boolean;
182
+ }
183
+ function isWrapperString(value) {
184
+ return value instanceof String;
185
+ }
186
+ function isWrapperSymbol(value) {
187
+ return !!global$1.Symbol && value instanceof Symbol;
188
+ }
189
+ function isWrapperBigInt(value) {
190
+ return !!global$1.BigInt && value instanceof BigInt;
191
+ }
192
+
193
+ function randomInt(min, max) {
194
+ return Math.floor(Math.random() * (max - min + 1)) + min;
195
+ }
196
+ function randomIntFloor(min, max) {
197
+ return Math.floor(Math.random() * (max - min)) + min;
198
+ }
199
+
200
+ function randomChoice(arr) {
201
+ return arr[randomIntFloor(0, arr.length)];
202
+ }
203
+
204
+ function randomString(length, chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') {
205
+ if (!Number.isInteger(length) || length <= 0) {
206
+ throw new Error('Invalid length parameter');
207
+ }
208
+ let res = '';
209
+ for (let i = 0; i < length; i++)
210
+ res += randomChoice(chars);
211
+ return res;
212
+ }
213
+ function randomHexString(length) {
214
+ if (!Number.isInteger(length) || length <= 0) {
215
+ throw new Error('Invalid length parameter');
216
+ }
217
+ if (length > 13) {
218
+ const count = Math.floor(length / 13);
219
+ let res = _randomHexString(length % 13);
220
+ for (let i = 0; i < count; i++)
221
+ res += _randomHexString(13);
222
+ return res;
223
+ }
224
+ else {
225
+ return _randomHexString(length);
226
+ }
227
+ }
228
+ function _randomHexString(length) {
229
+ let res = Math.floor(Math.random() * 16 ** length).toString(16);
230
+ while (res.length < length)
231
+ res = '0' + res;
232
+ return res;
233
+ }
234
+
235
+ function compose(...composeFunc) {
236
+ if (composeFunc.length === 0) {
237
+ throw new Error('Invalid composeFunc parameter: composeFunc is empty');
238
+ }
239
+ for (let i = 0; i < composeFunc.length; i++) {
240
+ if (typeof composeFunc[i] !== 'function') {
241
+ throw new Error(`Invalid composeFunc parameter: composeFunc[${i}] is not a function`);
242
+ }
243
+ }
244
+ const _fnList = composeFunc.slice().reverse();
245
+ return (...args) => {
246
+ let result = _fnList[0](...args);
247
+ for (let i = 1; i < _fnList.length; i++) {
248
+ result = _fnList[i](result);
249
+ }
250
+ return result;
251
+ };
252
+ }
253
+
254
+ const _ = Object.freeze({ '@@functional/placeholder': true });
255
+ function isPlaceholder(arg) {
256
+ return typeof arg === 'object' && Boolean(arg) && arg['@@functional/placeholder'] === true;
257
+ }
258
+
259
+ const _curry1 = function _curry1(fn) {
260
+ return function curried1(arg1) {
261
+ if (arguments.length < 1 || isPlaceholder(arg1)) {
262
+ return curried1;
263
+ }
264
+ else {
265
+ return fn.apply(this, arguments);
266
+ }
267
+ };
268
+ };
269
+
270
+ const _curry2 = function _curry2(fn) {
271
+ return function curried2(arg1, arg2) {
272
+ const p1 = arguments.length < 1 || isPlaceholder(arg1);
273
+ const p2 = arguments.length < 2 || isPlaceholder(arg2);
274
+ if (p1 && p2) {
275
+ return curried2;
276
+ }
277
+ else if (!p1 && p2) {
278
+ return _curry1(function (_arg2) {
279
+ return fn.apply(this, [arg1, _arg2]);
280
+ });
281
+ }
282
+ else if (p1 && !p2) {
283
+ return _curry1(function (_arg1) {
284
+ return fn.apply(this, [_arg1, arg2]);
285
+ });
286
+ }
287
+ else {
288
+ return fn.apply(this, arguments);
289
+ }
290
+ };
291
+ };
292
+
293
+ const _curry3 = function _curry3(fn) {
294
+ return function curried3(arg1, arg2, arg3) {
295
+ const p1 = arguments.length < 1 || isPlaceholder(arg1);
296
+ const p2 = arguments.length < 2 || isPlaceholder(arg2);
297
+ const p3 = arguments.length < 3 || isPlaceholder(arg3);
298
+ if (p1) {
299
+ if (p2 && p3) {
300
+ return curried3;
301
+ }
302
+ else if (p2 && !p3) {
303
+ return _curry2(function (_arg1, _arg2) {
304
+ return fn.apply(this, [_arg1, _arg2, arg3]);
305
+ });
306
+ }
307
+ else if (!p2 && p3) {
308
+ return _curry2(function (_arg1, _arg3) {
309
+ return fn.apply(this, [_arg1, arg2, _arg3]);
310
+ });
311
+ }
312
+ else {
313
+ return _curry1(function (_arg1) {
314
+ return fn.apply(this, [_arg1, arg2, arg3]);
315
+ });
316
+ }
317
+ }
318
+ else {
319
+ if (p2 && p3) {
320
+ return _curry2(function (_arg2, _arg3) {
321
+ return fn.apply(this, [arg1, _arg2, _arg3]);
322
+ });
323
+ }
324
+ else if (p2 && !p3) {
325
+ return _curry1(function (_arg2) {
326
+ return fn.apply(this, [arg1, _arg2, arg3]);
327
+ });
328
+ }
329
+ else if (!p2 && p3) {
330
+ return _curry1(function (_arg3) {
331
+ return fn.apply(this, [arg1, arg2, _arg3]);
332
+ });
333
+ }
334
+ else {
335
+ return fn.apply(this, arguments);
336
+ }
337
+ }
338
+ };
339
+ };
340
+
341
+ const _curryAny = function _curryAny(fn, args) {
342
+ return function curriedAny(...currentArguments) {
343
+ const currArgs = _mergeArguments(args, currentArguments);
344
+ if (_countArguments(currArgs) >= fn.length) {
345
+ return fn.apply(this, currArgs);
346
+ }
347
+ else
348
+ return _curryAny.apply(this, [fn, currArgs]);
349
+ };
350
+ };
351
+ function _mergeArguments(args, currentArguments) {
352
+ let p1 = 0;
353
+ const res = args.concat([]);
354
+ for (let i = 0; i < currentArguments.length; i++) {
355
+ while (!isPlaceholder(res[p1]) && p1 < res.length)
356
+ p1++;
357
+ res[p1] = currentArguments[i];
358
+ p1++;
359
+ }
360
+ return res;
361
+ }
362
+ function _countArguments(args) {
363
+ for (let i = 0; i < args.length; i++) {
364
+ if (isPlaceholder(args[i]))
365
+ return i;
366
+ }
367
+ return args.length;
368
+ }
369
+
370
+ function _curryMore(fn) {
371
+ if (typeof fn !== 'function') {
372
+ throw new Error('Invalid fn parameter: fn is not a function.');
373
+ }
374
+ const fnStr = fn.toString();
375
+ const rightBracket = fnStr.indexOf(')');
376
+ if (rightBracket < 3 || /=|\.{3}/.test(fnStr.substring(0, rightBracket))) {
377
+ return _curryAny(fn, []);
378
+ }
379
+ switch (fn.length) {
380
+ case 0:
381
+ return fn;
382
+ case 1:
383
+ return _curry1(fn);
384
+ case 2:
385
+ return _curry2(fn);
386
+ case 3:
387
+ return _curry3(fn);
388
+ default:
389
+ return _curryAny(fn, []);
390
+ }
391
+ }
392
+
393
+ function fastClone(obj, map) {
394
+ if (!isMap(map))
395
+ map = new Map();
396
+ const res = _fastClone(obj, map);
397
+ map.clear();
398
+ return res;
399
+ }
400
+
401
+ const noop = function noop() { };
402
+ function pass(value) {
403
+ return value;
404
+ }
405
+ function passWith(fn) {
406
+ return ((arg) => {
407
+ fn(arg);
408
+ return arg;
409
+ });
410
+ }
411
+
412
+ function not(value) {
413
+ return !Boolean(value);
414
+ }
415
+
416
+ function pipe(...pipeFunc) {
417
+ if (pipeFunc.length === 0) {
418
+ throw new Error('Invalid pipeFunc parameter: pipeFunc is empty');
419
+ }
420
+ for (let i = 0; i < pipeFunc.length; i++) {
421
+ if (typeof pipeFunc[i] !== 'function') {
422
+ throw new Error(`Invalid pipeFunc parameter: pipeFunc[${i}] is not a function`);
423
+ }
424
+ }
425
+ return (...args) => {
426
+ let result = pipeFunc[0](...args);
427
+ for (let i = 1; i < pipeFunc.length; i++) {
428
+ result = pipeFunc[i](result);
429
+ }
430
+ return result;
431
+ };
432
+ }
433
+
434
+ exports._ = _;
435
+ exports._fastClone = _fastClone;
436
+ exports.compose = compose;
437
+ exports.curry = _curryMore;
438
+ exports.fastClone = fastClone;
439
+ exports.getGlobalThis = getGlobalThis;
440
+ exports.getTag = getTag;
441
+ exports.isArray = isArray;
442
+ exports.isArrayBuffer = isArrayBuffer;
443
+ exports.isArrayLike = isArrayLike;
444
+ exports.isBigInt = isBigInt;
445
+ exports.isBoolean = isBoolean;
446
+ exports.isBuffer = isBuffer;
447
+ exports.isFunction = isFunction;
448
+ exports.isInteger = isInteger;
449
+ exports.isMap = isMap;
450
+ exports.isNil = isNil;
451
+ exports.isNull = isNull;
452
+ exports.isNumber = isNumber;
453
+ exports.isObject = isObject;
454
+ exports.isPlaceholder = isPlaceholder;
455
+ exports.isPromise = isPromise;
456
+ exports.isPromiseLike = isPromiseLike;
457
+ exports.isSet = isSet;
458
+ exports.isString = isString;
459
+ exports.isSymbol = isSymbol;
460
+ exports.isUndefined = isUndefined;
461
+ exports.isWeakMap = isWeakMap;
462
+ exports.isWeakSet = isWeakSet;
463
+ exports.isWrapperBigInt = isWrapperBigInt;
464
+ exports.isWrapperBoolean = isWrapperBoolean;
465
+ exports.isWrapperNumber = isWrapperNumber;
466
+ exports.isWrapperObject = isWrapperObject;
467
+ exports.isWrapperString = isWrapperString;
468
+ exports.isWrapperSymbol = isWrapperSymbol;
469
+ exports.noop = noop;
470
+ exports.not = not;
471
+ exports.pass = pass;
472
+ exports.passWith = passWith;
473
+ exports.pipe = pipe;
474
+ exports.randomChoice = randomChoice;
475
+ exports.randomHexString = randomHexString;
476
+ exports.randomInt = randomInt;
477
+ exports.randomIntFloor = randomIntFloor;
478
+ exports.randomString = randomString;