atomic-fns 0.1.1 → 0.2.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/.esdoc.json +27 -0
- package/.eslintrc.json +1 -0
- package/README.md +16 -17
- package/package.json +24 -13
- package/{build → src}/collections.d.ts +34 -10
- package/src/collections.js +553 -0
- package/src/collections.ts +48 -21
- package/{build → src}/datetime.d.ts +4 -0
- package/src/datetime.js +5 -0
- package/src/datetime.ts +5 -0
- package/{build → src}/functools.d.ts +7 -3
- package/{build → src}/functools.js +48 -49
- package/src/functools.ts +7 -3
- package/src/globals.d.ts +178 -4
- package/src/globals.js +309 -0
- package/src/globals.ts +24 -24
- package/{build → src}/index.d.ts +0 -0
- package/src/index.js +7 -0
- package/{build → src}/itertools.d.ts +4 -0
- package/src/itertools.js +98 -0
- package/src/itertools.ts +8 -5
- package/{build → src}/math.d.ts +1 -1
- package/src/math.js +70 -0
- package/src/math.ts +5 -1
- package/{build → src}/objects.d.ts +0 -0
- package/src/objects.js +1 -0
- package/{build → src}/operators.d.ts +1 -1
- package/src/operators.js +109 -0
- package/src/operators.ts +5 -1
- package/src/random.d.ts +22 -0
- package/src/random.js +48 -0
- package/src/random.ts +32 -8
- package/{build → src}/strings.d.ts +0 -0
- package/src/strings.js +1 -0
- package/{build → src}/util.d.ts +0 -0
- package/src/util.js +1 -0
- package/tests/collections.spec.ts +81 -9
- package/tests/globals.spec.ts +44 -4
- package/tests/itertools.spec.ts +17 -10
- package/tests/operators.spec.ts +8 -5
- package/tsconfig.json +17 -3
- package/build/collections.js +0 -545
- package/build/datetime.js +0 -1
- package/build/globals.d.ts +0 -175
- package/build/globals.js +0 -332
- package/build/index.js +0 -7
- package/build/itertools.js +0 -102
- package/build/math.js +0 -67
- package/build/objects.js +0 -1
- package/build/operators.js +0 -128
- package/build/random.d.ts +0 -5
- package/build/random.js +0 -28
- package/build/strings.js +0 -1
- package/build/util.js +0 -1
package/src/globals.js
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
export const True = () => true
|
|
2
|
+
export const False = () => false
|
|
3
|
+
/**
|
|
4
|
+
* A custom error class that inherits from the Error object.
|
|
5
|
+
*
|
|
6
|
+
*
|
|
7
|
+
* @class CustomError
|
|
8
|
+
* @extends {Error}
|
|
9
|
+
*/
|
|
10
|
+
export class CustomError extends Error {
|
|
11
|
+
/**
|
|
12
|
+
* Returns a new CustomError with the specified message.
|
|
13
|
+
* @param {string} message
|
|
14
|
+
* @constructor
|
|
15
|
+
*/
|
|
16
|
+
constructor(message) {
|
|
17
|
+
super(message)
|
|
18
|
+
this.name = this.constructor.name
|
|
19
|
+
if (typeof Error.captureStackTrace === 'function') {
|
|
20
|
+
Error.captureStackTrace(this, this.constructor)
|
|
21
|
+
} else {
|
|
22
|
+
this.stack = new Error(message).stack
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Custom error to signal an invalid index access.
|
|
28
|
+
* @extends {CustomError}
|
|
29
|
+
*/
|
|
30
|
+
export class IndexError extends CustomError {}
|
|
31
|
+
/**
|
|
32
|
+
* Raised when a system function returns an I/O failure such as "file not found"
|
|
33
|
+
* or "disk full".
|
|
34
|
+
* @extends {CustomError}
|
|
35
|
+
*/
|
|
36
|
+
export class IOError extends CustomError {}
|
|
37
|
+
/**
|
|
38
|
+
* Custom error to signal an invalid key access.
|
|
39
|
+
* @extends {CustomError}
|
|
40
|
+
*/
|
|
41
|
+
export class KeyError extends CustomError {}
|
|
42
|
+
/**
|
|
43
|
+
* Custom error to signal an invalid operation.
|
|
44
|
+
* @extends {CustomError}
|
|
45
|
+
*/
|
|
46
|
+
export class NotImplementedError extends CustomError {}
|
|
47
|
+
/**
|
|
48
|
+
* Custom error to signal an invalid value.
|
|
49
|
+
* @extends {CustomError}
|
|
50
|
+
*/
|
|
51
|
+
export class ValueError extends CustomError {}
|
|
52
|
+
/**
|
|
53
|
+
* Raised when the second argument of a division or modulo operation is zero.
|
|
54
|
+
* @extends {CustomError}
|
|
55
|
+
*/
|
|
56
|
+
export class ZeroDivisionError extends CustomError {}
|
|
57
|
+
/**
|
|
58
|
+
* Returns the true type of any value with correct detection for null, Array,
|
|
59
|
+
* Object, Promise, Symbol, and NaN.
|
|
60
|
+
*
|
|
61
|
+
*
|
|
62
|
+
* @param {*} value
|
|
63
|
+
* @return
|
|
64
|
+
*/
|
|
65
|
+
export function type(value) {
|
|
66
|
+
const result = typeof value
|
|
67
|
+
if (result === 'object') {
|
|
68
|
+
if (value) {
|
|
69
|
+
if (value instanceof String) return 'string'
|
|
70
|
+
if (value instanceof Boolean) return 'boolean'
|
|
71
|
+
if (value instanceof Function) return 'function'
|
|
72
|
+
// IE improperly marshals typeof across execution contexts, but a
|
|
73
|
+
// cross-context object will still return false for "instanceof Object".
|
|
74
|
+
if (value instanceof Array) return 'array'
|
|
75
|
+
const className = str(value)
|
|
76
|
+
// In Firefox 3.6, attempting to access iframe window objects' length
|
|
77
|
+
// property throws an NS_ERROR_FAILURE, so we need to special-case it
|
|
78
|
+
// here.
|
|
79
|
+
if (className === '[object Window]') return 'object'
|
|
80
|
+
// We cannot always use constructor === Array or instanceof Array because
|
|
81
|
+
// different frames have different Array objects.
|
|
82
|
+
// Mark Miller noticed that Object.prototype.toString
|
|
83
|
+
// allows access to the unforgeable [[Class]] property.
|
|
84
|
+
// 15.2.4.2 Object.prototype.toString ( )
|
|
85
|
+
// When the toString method is called, the following steps are taken:
|
|
86
|
+
// 1. Get the [[Class]] property of this object.
|
|
87
|
+
// 2. Compute a string value by concatenating the three strings
|
|
88
|
+
// "[object ", Result(1), and "]".
|
|
89
|
+
// 3. Return Result(2).
|
|
90
|
+
// and this behavior survives the destruction of the execution context.
|
|
91
|
+
if (className.endsWith('Array]') || Array.isArray(value)) {
|
|
92
|
+
return 'array'
|
|
93
|
+
}
|
|
94
|
+
// HACK: There is still an array case that fails.
|
|
95
|
+
// function ArrayImpostor() {}
|
|
96
|
+
// ArrayImpostor.prototype = [];
|
|
97
|
+
// var impostor = new ArrayImpostor;
|
|
98
|
+
// this can be fixed by getting rid of the fast path
|
|
99
|
+
// (value instanceof Array) and solely relying on
|
|
100
|
+
// (value && Object.prototype.toString.vall(value) === '[object Array]')
|
|
101
|
+
// but that would require many more function calls and is not warranted
|
|
102
|
+
// unless closure code is receiving objects from untrusted sources.
|
|
103
|
+
// IE in cross-window calls does not correctly marshal the function type
|
|
104
|
+
// (it appears just as an object) so we cannot use just typeof val ==
|
|
105
|
+
// 'function'. However, if the object has a call property, it is a
|
|
106
|
+
// function.
|
|
107
|
+
if (className.endsWith('Function]') || typeof value.call === 'function') {
|
|
108
|
+
return 'function'
|
|
109
|
+
}
|
|
110
|
+
if (className === '[object Promise]' || value instanceof Promise) {
|
|
111
|
+
return 'promise'
|
|
112
|
+
}
|
|
113
|
+
if (className === '[object Symbol]') {
|
|
114
|
+
return 'symbol'
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
return 'null'
|
|
118
|
+
}
|
|
119
|
+
} else if (result === 'function' && typeof value.call === 'undefined') {
|
|
120
|
+
// In Safari typeof nodeList returns 'function', and on Firefox typeof
|
|
121
|
+
// behaves similarly for HTML{Applet,Embed,Object}, Elements and RegExps. We
|
|
122
|
+
// would like to return object for those and we can detect an invalid
|
|
123
|
+
// function by making sure that the function object has a call method.
|
|
124
|
+
return 'object'
|
|
125
|
+
} else if (Number.isNaN(value)) return 'NaN'
|
|
126
|
+
return result
|
|
127
|
+
}
|
|
128
|
+
/** Same as `x.toString()`. Returns `''` when x is null or undefined */
|
|
129
|
+
export const str = (x) => (x != null ? x.toString() : '')
|
|
130
|
+
/** Check if value is a boolean type */
|
|
131
|
+
export const isBool = (x) => type(x) === 'boolean'
|
|
132
|
+
/** Check if value is an object type */
|
|
133
|
+
export const isObject = (x) => typeof x === 'object' && type(x) === 'object'
|
|
134
|
+
/** Check if value is a string type */
|
|
135
|
+
export const isString = (x) => type(x) === 'string'
|
|
136
|
+
/** Check if value is an Array type */
|
|
137
|
+
export const isArray = (x) => type(x) === 'array'
|
|
138
|
+
/** Check if value is Array-like type.
|
|
139
|
+
* A value is considered array-like if it's not a function and has a
|
|
140
|
+
* `.length` number property.
|
|
141
|
+
*/
|
|
142
|
+
export const isArrayLike = (x) => {
|
|
143
|
+
const T = type(x)
|
|
144
|
+
return T === 'array' || (T === 'object' && isNumber(x.length))
|
|
145
|
+
}
|
|
146
|
+
/** Check if value is a function type */
|
|
147
|
+
export const isFunc = (x) => x?.constructor === Function
|
|
148
|
+
/** Check if value is a number type */
|
|
149
|
+
export const isNumber = (x) => type(x) === 'number'
|
|
150
|
+
/** Check if value is a Bigint type */
|
|
151
|
+
export const isBigint = (x) => type(x) === 'bigint'
|
|
152
|
+
/** Check if value is NaN based on `Number.isNaN` */
|
|
153
|
+
export const isNaN = (x) => Number.isNaN(x)
|
|
154
|
+
/** Check if value is a Promise type */
|
|
155
|
+
export const isPromise = (x) => type(x) === 'promise'
|
|
156
|
+
/** Check if value is an async function type */
|
|
157
|
+
export const isAsync = (x) => get(x, 'constructor.name') === 'AsyncFunction'
|
|
158
|
+
/** Check if value is a generator function type */
|
|
159
|
+
export const isGenerator = (x) => {
|
|
160
|
+
return get(x, 'constructor.constructor.name') === 'GeneratorFunction'
|
|
161
|
+
}
|
|
162
|
+
/** Check if value is null or undefined */
|
|
163
|
+
export const isNull = (x) => x == null
|
|
164
|
+
/** Check if value is not null or undefined */
|
|
165
|
+
export const notNull = (x) => x != null
|
|
166
|
+
export function len(x) {
|
|
167
|
+
if (x == null) return
|
|
168
|
+
if (x.length !== undefined) {
|
|
169
|
+
return x.length
|
|
170
|
+
}
|
|
171
|
+
if (isFunc(x.size)) {
|
|
172
|
+
return x.size()
|
|
173
|
+
}
|
|
174
|
+
if (isObject(x)) {
|
|
175
|
+
return Object.keys(x).length
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/** Returns true for objects without length or falsey values. */
|
|
179
|
+
export const isEmpty = (x) => (len(x) === 0 ? true : !x)
|
|
180
|
+
/** Check if value is a Symbol type */
|
|
181
|
+
export const isSymbol = (x) => type(x) === 'symbol'
|
|
182
|
+
/**
|
|
183
|
+
* Generates a unique ID using random numbers.
|
|
184
|
+
* If prefix is given, the ID is appended to it
|
|
185
|
+
*/
|
|
186
|
+
export const uniqueId = (pre = '') =>
|
|
187
|
+
// @ts-expect-error
|
|
188
|
+
(pre || 0) + ((Math.random() * 1e10) >>> 0)
|
|
189
|
+
/**
|
|
190
|
+
* Checks if `obj.key` is a function, and calls it with any `args`.
|
|
191
|
+
*
|
|
192
|
+
*
|
|
193
|
+
* @param {*} obj
|
|
194
|
+
* @param {PropertyKey} key
|
|
195
|
+
* @param {...any[]} args
|
|
196
|
+
* @return `obj.key(...args)`
|
|
197
|
+
*/
|
|
198
|
+
export function call(obj, key, ...args) {
|
|
199
|
+
if (isFunc(get(obj, key))) {
|
|
200
|
+
return obj[key](...args)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/** Convert number to unicode character */
|
|
204
|
+
export const chr = (x) => String.fromCodePoint(x)
|
|
205
|
+
/** Convert character to Unicode code point */
|
|
206
|
+
export const ord = (x) => x.charCodeAt(0)
|
|
207
|
+
/** `Object.keys(x)` */
|
|
208
|
+
export const keys = (x) => Object.keys(x)
|
|
209
|
+
/** `Object.values(x)` */
|
|
210
|
+
export const values = (x) => Object.values(x)
|
|
211
|
+
/**
|
|
212
|
+
* Round `x` to the number of digits after the decimal point. If `digits` is
|
|
213
|
+
* omitted, it returns the nearest integer to x.
|
|
214
|
+
*
|
|
215
|
+
* @param {number} x
|
|
216
|
+
* @param {number} [digits=0]
|
|
217
|
+
*/
|
|
218
|
+
export function round(x, digits = 0) {
|
|
219
|
+
const base = 10 ** digits
|
|
220
|
+
return Math.round(x * base) / base
|
|
221
|
+
}
|
|
222
|
+
export const floor = (x) => Math.floor(x)
|
|
223
|
+
export const ceil = (x) => Math.ceil(x)
|
|
224
|
+
/**
|
|
225
|
+
* Yields elements like `[index, item]` from an iterable.
|
|
226
|
+
*
|
|
227
|
+
*
|
|
228
|
+
* @template T
|
|
229
|
+
* @param {Iterable<T>} iterable
|
|
230
|
+
*/
|
|
231
|
+
export function* enumerate(iterable) {
|
|
232
|
+
let i = 0
|
|
233
|
+
for (const item of iterable) {
|
|
234
|
+
yield [i++, item]
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
export const has = (obj, attr) => obj && attr in obj
|
|
238
|
+
/**
|
|
239
|
+
* Check if the attribute is present in the object, or return optional default.
|
|
240
|
+
*
|
|
241
|
+
*
|
|
242
|
+
* @param {*} obj
|
|
243
|
+
* @param {PropertyKey} key
|
|
244
|
+
* @param {*} [value=undefined]
|
|
245
|
+
* @return The property value or default value
|
|
246
|
+
*/
|
|
247
|
+
export function get(obj, key, value = undefined) {
|
|
248
|
+
if (obj == null) return value
|
|
249
|
+
let paths = Array.isArray(key) ? key : [key]
|
|
250
|
+
if (typeof key === 'string') {
|
|
251
|
+
paths = key.split('.')
|
|
252
|
+
}
|
|
253
|
+
try {
|
|
254
|
+
let result = obj
|
|
255
|
+
for (const k of paths) {
|
|
256
|
+
result = result[k]
|
|
257
|
+
}
|
|
258
|
+
return result === undefined ? value : result
|
|
259
|
+
} catch (error) {
|
|
260
|
+
return value
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
export function del(x, attr) {
|
|
264
|
+
if (x != null) delete x[attr]
|
|
265
|
+
return x
|
|
266
|
+
}
|
|
267
|
+
export function set(self, attr, value, writable = false, enumerable = false) {
|
|
268
|
+
return Object.defineProperty(self, attr, {
|
|
269
|
+
value,
|
|
270
|
+
enumerable,
|
|
271
|
+
writable
|
|
272
|
+
})
|
|
273
|
+
}
|
|
274
|
+
export const HASH_KEY = Symbol.for('HASH_KEY')
|
|
275
|
+
export function hash(obj) {
|
|
276
|
+
if (typeof obj === 'string') {
|
|
277
|
+
return hashCode(obj)
|
|
278
|
+
}
|
|
279
|
+
if (typeof obj === 'object') {
|
|
280
|
+
if (obj[HASH_KEY] == null) {
|
|
281
|
+
set(obj, HASH_KEY, uniqueId())
|
|
282
|
+
}
|
|
283
|
+
return obj[HASH_KEY]
|
|
284
|
+
}
|
|
285
|
+
return obj
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* A hash value generator for strings
|
|
289
|
+
*
|
|
290
|
+
* @param {string} str
|
|
291
|
+
* @return {number}
|
|
292
|
+
* @see http://isthe.com/chongo/tech/comp/fnv/
|
|
293
|
+
*/
|
|
294
|
+
export function hashCode(str) {
|
|
295
|
+
const FNV1_32A_INIT = 0x811c9dc5
|
|
296
|
+
let hval = FNV1_32A_INIT
|
|
297
|
+
for (let i = 0; i < str.length; ++i) {
|
|
298
|
+
hval ^= str.charCodeAt(i)
|
|
299
|
+
hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24)
|
|
300
|
+
}
|
|
301
|
+
return hval >>> 0
|
|
302
|
+
}
|
|
303
|
+
export const bin = (n) => n.toString(2)
|
|
304
|
+
export const hex = (n) => n.toString(16)
|
|
305
|
+
export const oct = (n) => n.toString(8)
|
|
306
|
+
export const float = (x) => parseFloat(x)
|
|
307
|
+
export const int = (x, base = 10) => parseInt(x, base)
|
|
308
|
+
export const list = (arr) => (arr ? Array.from(arr) : [])
|
|
309
|
+
export const next = (iter) => iter.next().value
|
package/src/globals.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Globals
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
1
5
|
export type Comp = (x, y) => number
|
|
2
6
|
|
|
3
7
|
export type Function = (...args) => any
|
|
@@ -11,17 +15,17 @@ export const False = () => false
|
|
|
11
15
|
/**
|
|
12
16
|
* A custom error class that inherits from the Error object.
|
|
13
17
|
*
|
|
14
|
-
*
|
|
18
|
+
*
|
|
15
19
|
* @class CustomError
|
|
16
20
|
* @extends {Error}
|
|
17
21
|
*/
|
|
18
22
|
export class CustomError extends Error {
|
|
19
23
|
/**
|
|
20
24
|
* Returns a new CustomError with the specified message.
|
|
21
|
-
* @param message
|
|
25
|
+
* @param {string} message
|
|
22
26
|
* @constructor
|
|
23
27
|
*/
|
|
24
|
-
constructor(message
|
|
28
|
+
constructor(message?: string) {
|
|
25
29
|
super(message)
|
|
26
30
|
this.name = this.constructor.name
|
|
27
31
|
if (typeof Error.captureStackTrace === 'function') {
|
|
@@ -73,7 +77,7 @@ export class ZeroDivisionError extends CustomError {}
|
|
|
73
77
|
* Returns the true type of any value with correct detection for null, Array,
|
|
74
78
|
* Object, Promise, Symbol, and NaN.
|
|
75
79
|
*
|
|
76
|
-
*
|
|
80
|
+
*
|
|
77
81
|
* @param {*} value
|
|
78
82
|
* @return
|
|
79
83
|
*/
|
|
@@ -144,11 +148,8 @@ export function type(value) {
|
|
|
144
148
|
return result
|
|
145
149
|
}
|
|
146
150
|
|
|
147
|
-
/** Same as
|
|
148
|
-
export const str = (x)
|
|
149
|
-
if (isNull(x)) return ''
|
|
150
|
-
return x.toString?.() ?? String(x)
|
|
151
|
-
}
|
|
151
|
+
/** Same as `x.toString()`. Returns `''` when x is null or undefined */
|
|
152
|
+
export const str = (x) => (x != null ? x.toString() : '')
|
|
152
153
|
|
|
153
154
|
/** Check if value is a boolean type */
|
|
154
155
|
export const isBool = (x) => type(x) === 'boolean'
|
|
@@ -172,7 +173,7 @@ export const isArrayLike = (x) => {
|
|
|
172
173
|
}
|
|
173
174
|
|
|
174
175
|
/** Check if value is a function type */
|
|
175
|
-
export const isFunc = (x) =>
|
|
176
|
+
export const isFunc = (x) => x?.constructor === Function
|
|
176
177
|
|
|
177
178
|
/** Check if value is a number type */
|
|
178
179
|
export const isNumber = (x) => type(x) === 'number'
|
|
@@ -187,11 +188,11 @@ export const isNaN = (x) => Number.isNaN(x)
|
|
|
187
188
|
export const isPromise = (x) => type(x) === 'promise'
|
|
188
189
|
|
|
189
190
|
/** Check if value is an async function type */
|
|
190
|
-
export const isAsync = (x) => x
|
|
191
|
+
export const isAsync = (x) => get(x, 'constructor.name') === 'AsyncFunction'
|
|
191
192
|
|
|
192
193
|
/** Check if value is a generator function type */
|
|
193
194
|
export const isGenerator = (x) => {
|
|
194
|
-
return x
|
|
195
|
+
return get(x, 'constructor.constructor.name') === 'GeneratorFunction'
|
|
195
196
|
}
|
|
196
197
|
|
|
197
198
|
/** Check if value is null or undefined */
|
|
@@ -201,10 +202,11 @@ export const isNull = (x) => x == null
|
|
|
201
202
|
export const notNull = (x) => x != null
|
|
202
203
|
|
|
203
204
|
export function len(x) {
|
|
204
|
-
if (
|
|
205
|
+
if (x == null) return
|
|
206
|
+
if (x.length !== undefined) {
|
|
205
207
|
return x.length
|
|
206
208
|
}
|
|
207
|
-
if (isFunc(x
|
|
209
|
+
if (isFunc(x.size)) {
|
|
208
210
|
return x.size()
|
|
209
211
|
}
|
|
210
212
|
if (isObject(x)) {
|
|
@@ -229,7 +231,7 @@ export const uniqueId = (pre: string = '') =>
|
|
|
229
231
|
/**
|
|
230
232
|
* Checks if `obj.key` is a function, and calls it with any `args`.
|
|
231
233
|
*
|
|
232
|
-
*
|
|
234
|
+
*
|
|
233
235
|
* @param {*} obj
|
|
234
236
|
* @param {PropertyKey} key
|
|
235
237
|
* @param {...any[]} args
|
|
@@ -256,7 +258,7 @@ export const values = (x) => Object.values(x)
|
|
|
256
258
|
/**
|
|
257
259
|
* Round `x` to the number of digits after the decimal point. If `digits` is
|
|
258
260
|
* omitted, it returns the nearest integer to x.
|
|
259
|
-
*
|
|
261
|
+
*
|
|
260
262
|
* @param {number} x
|
|
261
263
|
* @param {number} [digits=0]
|
|
262
264
|
*/
|
|
@@ -270,9 +272,9 @@ export const floor = (x: number) => Math.floor(x)
|
|
|
270
272
|
export const ceil = (x: number) => Math.ceil(x)
|
|
271
273
|
|
|
272
274
|
/**
|
|
273
|
-
* Yields elements like [index, item] from an iterable.
|
|
275
|
+
* Yields elements like `[index, item]` from an iterable.
|
|
276
|
+
*
|
|
274
277
|
*
|
|
275
|
-
* @export
|
|
276
278
|
* @template T
|
|
277
279
|
* @param {Iterable<T>} iterable
|
|
278
280
|
*/
|
|
@@ -288,16 +290,14 @@ export const has = (obj, attr: PropertyKey) => obj && attr in obj
|
|
|
288
290
|
/**
|
|
289
291
|
* Check if the attribute is present in the object, or return optional default.
|
|
290
292
|
*
|
|
291
|
-
*
|
|
293
|
+
*
|
|
292
294
|
* @param {*} obj
|
|
293
295
|
* @param {PropertyKey} key
|
|
294
296
|
* @param {*} [value=undefined]
|
|
295
297
|
* @return The property value or default value
|
|
296
298
|
*/
|
|
297
299
|
export function get(obj: any, key: PropertyKey | PropertyKey[], value: any = undefined) {
|
|
298
|
-
if (obj == null)
|
|
299
|
-
return value ?? obj
|
|
300
|
-
}
|
|
300
|
+
if (obj == null) return value
|
|
301
301
|
|
|
302
302
|
let paths = Array.isArray(key) ? key : [key]
|
|
303
303
|
if (typeof key === 'string') {
|
|
@@ -309,7 +309,7 @@ export function get(obj: any, key: PropertyKey | PropertyKey[], value: any = und
|
|
|
309
309
|
for (const k of paths) {
|
|
310
310
|
result = result[k]
|
|
311
311
|
}
|
|
312
|
-
return result
|
|
312
|
+
return result === undefined ? value : result
|
|
313
313
|
} catch (error) {
|
|
314
314
|
return value
|
|
315
315
|
}
|
|
@@ -347,7 +347,7 @@ export function hash(obj) {
|
|
|
347
347
|
|
|
348
348
|
/**
|
|
349
349
|
* A hash value generator for strings
|
|
350
|
-
*
|
|
350
|
+
*
|
|
351
351
|
* @param {string} str
|
|
352
352
|
* @return {number}
|
|
353
353
|
* @see http://isthe.com/chongo/tech/comp/fnv/
|
package/{build → src}/index.d.ts
RENAMED
|
File without changes
|
package/src/index.js
ADDED
package/src/itertools.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Iterators
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
import { isObject, len } from './globals.js'
|
|
6
|
+
import { comp, id } from './operators.js'
|
|
7
|
+
const compKey = (cmp, key) => (x, y) => cmp(key(x), key(y))
|
|
8
|
+
export function* range(...args) {
|
|
9
|
+
if (args.length === 1) {
|
|
10
|
+
const stop = args[0]
|
|
11
|
+
for (let i = 0; i < stop; i++) {
|
|
12
|
+
yield i
|
|
13
|
+
}
|
|
14
|
+
} else if (args.length === 2) {
|
|
15
|
+
let [start, stop] = args
|
|
16
|
+
for (; start < stop; start++) {
|
|
17
|
+
yield start
|
|
18
|
+
}
|
|
19
|
+
} else {
|
|
20
|
+
let [start, stop, step] = args
|
|
21
|
+
for (; start < stop; start += step) {
|
|
22
|
+
yield start
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** Creates a new list with the elements from the iterable in reverse order. */
|
|
27
|
+
export function reversed(iterable) {
|
|
28
|
+
return Array.from(iterable).reverse()
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Creates a new list from `args` and sorts it. This can be called many ways:
|
|
32
|
+
* - sorted([...], true) => reverse order
|
|
33
|
+
* - sorted([...], fn = (x) => any) => using a key fn
|
|
34
|
+
* - sorted([...], fn = (x) => any, true) => reverse order using key
|
|
35
|
+
* - sorted([...], false, (x, y) => number) => using custom compare
|
|
36
|
+
* - sorted([...], fn = (x) => any, true, (x, y) => number) => custom key, reverse and compare
|
|
37
|
+
*
|
|
38
|
+
* If `args` is an Object, returns the sorted keys.
|
|
39
|
+
*
|
|
40
|
+
*
|
|
41
|
+
* @param {(Array | Object)} args
|
|
42
|
+
* @param {(boolean | Function)} [key]
|
|
43
|
+
* @param {(boolean | Comp)} [reverse]
|
|
44
|
+
* @param {Comp} [compareFn]
|
|
45
|
+
* @return
|
|
46
|
+
*/
|
|
47
|
+
export function sorted(args, key, reverse, compareFn) {
|
|
48
|
+
if (isObject(args)) args = Object.keys(args)
|
|
49
|
+
if (typeof key === 'boolean') {
|
|
50
|
+
if (typeof reverse === 'function') {
|
|
51
|
+
compareFn = reverse
|
|
52
|
+
reverse = false
|
|
53
|
+
} else {
|
|
54
|
+
reverse = true
|
|
55
|
+
}
|
|
56
|
+
key = id
|
|
57
|
+
}
|
|
58
|
+
const copy = Array.from(args)
|
|
59
|
+
const _compare = compKey(compareFn || comp, key || id)
|
|
60
|
+
copy.sort(_compare)
|
|
61
|
+
if (reverse) copy.reverse()
|
|
62
|
+
return copy
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Sort `args` in place. Can be called like this:
|
|
66
|
+
* - sort([...], true) => reverse order
|
|
67
|
+
* - sort([...], (x, y) => number) => using custom compare
|
|
68
|
+
* - sort([...], true, (x, y) => number) => reverse and using custom compare
|
|
69
|
+
*
|
|
70
|
+
* @param {any[]} args
|
|
71
|
+
* @param {(boolean | Comp)} [reverse]
|
|
72
|
+
* @param {Comp} [compareFn]
|
|
73
|
+
* @return
|
|
74
|
+
*/
|
|
75
|
+
export function sort(args, reverse, compareFn) {
|
|
76
|
+
if (typeof reverse === 'function') {
|
|
77
|
+
compareFn = reverse
|
|
78
|
+
reverse = false
|
|
79
|
+
}
|
|
80
|
+
args.sort(compareFn || comp)
|
|
81
|
+
if (reverse === true) args.reverse()
|
|
82
|
+
return args
|
|
83
|
+
}
|
|
84
|
+
/** Returns a generator that calls `fn(index)` for each index < n */
|
|
85
|
+
export function* times(n, fn) {
|
|
86
|
+
for (let i = 0; i < n; i++) yield fn(i)
|
|
87
|
+
}
|
|
88
|
+
export function* zip(...args) {
|
|
89
|
+
const size = len(args[0])
|
|
90
|
+
for (let i = 0; i < size; i++) {
|
|
91
|
+
const tuple = []
|
|
92
|
+
for (let k = 0; k < args.length; k++) {
|
|
93
|
+
const item = args[k][i]
|
|
94
|
+
tuple.push(item)
|
|
95
|
+
}
|
|
96
|
+
yield tuple
|
|
97
|
+
}
|
|
98
|
+
}
|
package/src/itertools.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Iterators
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
1
5
|
import { Comp, Function, isObject, len } from './globals.js'
|
|
2
6
|
import { comp, id } from './operators.js'
|
|
3
7
|
|
|
@@ -43,7 +47,7 @@ export function sorted(args: any[], key: Function, reverse: boolean): any[]
|
|
|
43
47
|
*
|
|
44
48
|
* If `args` is an Object, returns the sorted keys.
|
|
45
49
|
*
|
|
46
|
-
*
|
|
50
|
+
*
|
|
47
51
|
* @param {(Array | Object)} args
|
|
48
52
|
* @param {(boolean | Function)} [key]
|
|
49
53
|
* @param {(boolean | Comp)} [reverse]
|
|
@@ -62,7 +66,7 @@ export function sorted(args, key?: boolean | Function, reverse?: boolean | Comp,
|
|
|
62
66
|
key = id
|
|
63
67
|
}
|
|
64
68
|
const copy = Array.from(args)
|
|
65
|
-
const _compare = compKey(compareFn
|
|
69
|
+
const _compare = compKey(compareFn || comp, key || id)
|
|
66
70
|
copy.sort(_compare)
|
|
67
71
|
if (reverse) copy.reverse()
|
|
68
72
|
return copy
|
|
@@ -78,19 +82,18 @@ export function sort(args: any[], reverse: boolean, compareFn: Comp): any[]
|
|
|
78
82
|
* - sort([...], true) => reverse order
|
|
79
83
|
* - sort([...], (x, y) => number) => using custom compare
|
|
80
84
|
* - sort([...], true, (x, y) => number) => reverse and using custom compare
|
|
81
|
-
*
|
|
85
|
+
*
|
|
82
86
|
* @param {any[]} args
|
|
83
87
|
* @param {(boolean | Comp)} [reverse]
|
|
84
88
|
* @param {Comp} [compareFn]
|
|
85
89
|
* @return
|
|
86
90
|
*/
|
|
87
91
|
export function sort(args: any[], reverse?: boolean | Comp, compareFn?: Comp) {
|
|
88
|
-
compareFn ??= comp
|
|
89
92
|
if (typeof reverse === 'function') {
|
|
90
93
|
compareFn = reverse
|
|
91
94
|
reverse = false
|
|
92
95
|
}
|
|
93
|
-
args.sort(compareFn)
|
|
96
|
+
args.sort(compareFn || comp)
|
|
94
97
|
if (reverse === true) args.reverse()
|
|
95
98
|
return args
|
|
96
99
|
}
|