@naturalcycles/js-lib 15.42.1 → 15.44.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/dist/array/array.util.d.ts +1 -21
- package/dist/array/array.util.js +0 -23
- package/dist/array/array2.d.ts +17 -0
- package/dist/array/array2.js +44 -0
- package/dist/array/index.d.ts +4 -0
- package/dist/array/index.js +4 -0
- package/dist/array/sort.d.ts +51 -0
- package/dist/array/sort.js +61 -0
- package/dist/array/sortedArray.d.ts +32 -0
- package/dist/array/sortedArray.js +55 -0
- package/dist/array/sortedSet.d.ts +22 -0
- package/dist/array/sortedSet.js +37 -0
- package/dist/datetime/localDate.d.ts +1 -2
- package/dist/datetime/localTime.d.ts +1 -2
- package/dist/log/commonLogger.d.ts +1 -1
- package/dist/math/math.util.js +3 -3
- package/dist/number/number.util.d.ts +0 -11
- package/dist/number/number.util.js +0 -13
- package/dist/object/keySortedMap.d.ts +9 -7
- package/dist/object/keySortedMap.js +1 -11
- package/dist/object/object.util.d.ts +1 -2
- package/dist/object/set2.d.ts +4 -0
- package/dist/object/set2.js +16 -0
- package/dist/semver.d.ts +1 -1
- package/dist/types.d.ts +23 -10
- package/dist/types.js +0 -7
- package/package.json +2 -2
- package/src/array/array.util.ts +1 -42
- package/src/array/array2.ts +52 -0
- package/src/array/index.ts +4 -0
- package/src/array/sort.ts +96 -0
- package/src/array/sortedArray.ts +78 -0
- package/src/array/sortedSet.ts +54 -0
- package/src/datetime/localDate.ts +2 -1
- package/src/datetime/localTime.ts +1 -1
- package/src/log/commonLogger.ts +1 -1
- package/src/math/math.util.ts +3 -3
- package/src/number/number.util.ts +0 -15
- package/src/object/keySortedMap.ts +10 -16
- package/src/object/object.util.ts +1 -1
- package/src/object/set2.ts +21 -1
- package/src/semver.ts +1 -1
- package/src/types.ts +25 -18
package/dist/types.d.ts
CHANGED
|
@@ -273,9 +273,10 @@ export type SemVerString = string;
|
|
|
273
273
|
*/
|
|
274
274
|
export type Reviver = (this: any, key: string, value: any) => any;
|
|
275
275
|
/**
|
|
276
|
-
*
|
|
276
|
+
* Function to be passed to the `sort` method.
|
|
277
|
+
* Returns -1 | 0 | 1 canonically, but any positive/negative number is supported.
|
|
277
278
|
*/
|
|
278
|
-
export
|
|
279
|
+
export type Comparator<T> = (a: T, b: T) => number;
|
|
279
280
|
/**
|
|
280
281
|
* Needed due to https://github.com/microsoft/TypeScript/issues/13778
|
|
281
282
|
* Only affects typings, no runtime effect.
|
|
@@ -328,6 +329,18 @@ export declare const _objectAssign: <T extends AnyObject>(target: T, part: Parti
|
|
|
328
329
|
*/
|
|
329
330
|
export type ErrorDataTuple<T = unknown, ERR = Error> = [err: null, data: T] | [err: ERR, data: null];
|
|
330
331
|
export type SortDirection = 'asc' | 'desc';
|
|
332
|
+
export interface MutateOptions {
|
|
333
|
+
/**
|
|
334
|
+
* Defaults to false.
|
|
335
|
+
*/
|
|
336
|
+
mutate?: boolean;
|
|
337
|
+
}
|
|
338
|
+
export interface SortOptions extends MutateOptions {
|
|
339
|
+
/**
|
|
340
|
+
* Defaults to 'asc'.
|
|
341
|
+
*/
|
|
342
|
+
dir?: SortDirection;
|
|
343
|
+
}
|
|
331
344
|
export type Inclusiveness = '[]' | '[)';
|
|
332
345
|
/**
|
|
333
346
|
* @experimental
|
|
@@ -346,29 +359,29 @@ export type Promisable<T> = T | PromiseLike<T>;
|
|
|
346
359
|
export type Class<T = any> = new (...args: any[]) => T;
|
|
347
360
|
/**
|
|
348
361
|
Convert `object`s, `Map`s, `Set`s, and `Array`s and all of their keys/elements into immutable structures recursively.
|
|
349
|
-
|
|
362
|
+
|
|
350
363
|
This is useful when a deeply nested structure needs to be exposed as completely immutable, for example, an imported JSON module or when receiving an API response that is passed around.
|
|
351
|
-
|
|
364
|
+
|
|
352
365
|
Please upvote [this issue](https://github.com/microsoft/TypeScript/issues/13923) if you want to have this type as a built-in in TypeScript.
|
|
353
|
-
|
|
366
|
+
|
|
354
367
|
@example
|
|
355
368
|
```
|
|
356
369
|
// data.json
|
|
357
370
|
{
|
|
358
371
|
"foo": ["bar"]
|
|
359
372
|
}
|
|
360
|
-
|
|
373
|
+
|
|
361
374
|
// main.ts
|
|
362
375
|
import {ReadonlyDeep} from 'type-fest';
|
|
363
376
|
import dataJson = require('./data.json');
|
|
364
|
-
|
|
377
|
+
|
|
365
378
|
const data: ReadonlyDeep<typeof dataJson> = dataJson;
|
|
366
|
-
|
|
379
|
+
|
|
367
380
|
export default data;
|
|
368
|
-
|
|
381
|
+
|
|
369
382
|
// test.ts
|
|
370
383
|
import data from './main';
|
|
371
|
-
|
|
384
|
+
|
|
372
385
|
data.foo.push('bar');
|
|
373
386
|
//=> error TS2339: Property 'push' does not exist on type 'readonly string[]'
|
|
374
387
|
```
|
package/dist/types.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { _sortBy } from './array/array.util.js';
|
|
2
1
|
/**
|
|
3
2
|
* Symbol to indicate END of Sequence.
|
|
4
3
|
*/
|
|
@@ -21,12 +20,6 @@ export const _noop = (..._args) => undefined;
|
|
|
21
20
|
export const _passthroughPredicate = () => true;
|
|
22
21
|
export const _passNothingPredicate = () => false;
|
|
23
22
|
export const JWT_REGEX = /^[\w-]+\.[\w-]+\.[\w-]+$/;
|
|
24
|
-
/**
|
|
25
|
-
* Like _stringMapValues, but values are sorted.
|
|
26
|
-
*/
|
|
27
|
-
export function _stringMapValuesSorted(map, mapper, dir = 'asc') {
|
|
28
|
-
return _sortBy(_stringMapValues(map), mapper, { dir });
|
|
29
|
-
}
|
|
30
23
|
/**
|
|
31
24
|
* Needed due to https://github.com/microsoft/TypeScript/issues/13778
|
|
32
25
|
* Only affects typings, no runtime effect.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naturalcycles/js-lib",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "15.
|
|
4
|
+
"version": "15.44.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"tslib": "^2",
|
|
7
7
|
"undici": "^7",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"@types/semver": "^7",
|
|
14
14
|
"crypto-js": "^4",
|
|
15
15
|
"dayjs": "^1",
|
|
16
|
-
"@naturalcycles/dev-lib": "
|
|
16
|
+
"@naturalcycles/dev-lib": "20.7.0"
|
|
17
17
|
},
|
|
18
18
|
"exports": {
|
|
19
19
|
".": "./dist/index.js",
|
package/src/array/array.util.ts
CHANGED
|
@@ -3,8 +3,8 @@ import type {
|
|
|
3
3
|
AbortablePredicate,
|
|
4
4
|
FalsyValue,
|
|
5
5
|
Mapper,
|
|
6
|
+
MutateOptions,
|
|
6
7
|
Predicate,
|
|
7
|
-
SortDirection,
|
|
8
8
|
StringMap,
|
|
9
9
|
} from '../types.js'
|
|
10
10
|
import { END } from '../types.js'
|
|
@@ -170,47 +170,6 @@ export function _groupBy<T>(items: readonly T[], mapper: Mapper<T, any>): String
|
|
|
170
170
|
return map
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
-
export interface MutateOptions {
|
|
174
|
-
/**
|
|
175
|
-
* Defaults to false.
|
|
176
|
-
*/
|
|
177
|
-
mutate?: boolean
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
export interface SortOptions extends MutateOptions {
|
|
181
|
-
/**
|
|
182
|
-
* Defaults to 'asc'.
|
|
183
|
-
*/
|
|
184
|
-
dir?: SortDirection
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* _sortBy([{age: 20}, {age: 10}], 'age')
|
|
189
|
-
* // => [{age: 10}, {age: 20}]
|
|
190
|
-
*
|
|
191
|
-
* Same:
|
|
192
|
-
* _sortBy([{age: 20}, {age: 10}], o => o.age)
|
|
193
|
-
*/
|
|
194
|
-
export function _sortBy<T, COMPARE_TYPE extends string | number>(
|
|
195
|
-
items: T[],
|
|
196
|
-
mapper: Mapper<T, COMPARE_TYPE>,
|
|
197
|
-
opt: SortOptions = {},
|
|
198
|
-
): T[] {
|
|
199
|
-
const mod = opt.dir === 'desc' ? -1 : 1
|
|
200
|
-
|
|
201
|
-
return (opt.mutate ? items : [...items]).sort((_a, _b) => {
|
|
202
|
-
// This implementation may call mapper more than once per item,
|
|
203
|
-
// but the benchmarks show no significant difference in performance.
|
|
204
|
-
const a = mapper(_a)
|
|
205
|
-
const b = mapper(_b)
|
|
206
|
-
// if (typeof a === 'number' && typeof b === 'number') return (a - b) * mod
|
|
207
|
-
// return String(a).localeCompare(String(b)) * mod
|
|
208
|
-
if (a > b) return mod
|
|
209
|
-
if (a < b) return -mod
|
|
210
|
-
return 0
|
|
211
|
-
})
|
|
212
|
-
}
|
|
213
|
-
|
|
214
173
|
/**
|
|
215
174
|
* Similar to `Array.find`, but the `predicate` may return `END` to stop the iteration early.
|
|
216
175
|
*
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { _shuffle } from './array.util.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Better Array.
|
|
5
|
+
*
|
|
6
|
+
* @experimental
|
|
7
|
+
*/
|
|
8
|
+
export class Array2<T> extends Array<T> {
|
|
9
|
+
static override of<T>(...items: T[]): Array2<T> {
|
|
10
|
+
return new Array2(...items)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/class-literal-property-style
|
|
14
|
+
get [Symbol.toStringTag](): string {
|
|
15
|
+
return 'Array2'
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
firstOrUndefined(): T | undefined {
|
|
19
|
+
return this[0]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
first(): T {
|
|
23
|
+
if (!this.length) throw new Error('Array.first called on empty array')
|
|
24
|
+
return this[0]!
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
lastOrUndefined(): T | undefined {
|
|
28
|
+
return this[this.length - 1]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
last(): T {
|
|
32
|
+
const { length } = this
|
|
33
|
+
if (!length) throw new Error('Array.last called on empty array')
|
|
34
|
+
return this[length - 1]!
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
uniq(): Array2<T> {
|
|
38
|
+
return new Array2<T>(...new Set(this))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
shuffle(): Array2<T> {
|
|
42
|
+
return new Array2(..._shuffle(this))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
isEmpty(): boolean {
|
|
46
|
+
return this.length === 0
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
isNotEmpty(): boolean {
|
|
50
|
+
return this.length !== 0
|
|
51
|
+
}
|
|
52
|
+
}
|
package/src/array/index.ts
CHANGED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import {
|
|
2
|
+
_stringMapValues,
|
|
3
|
+
type Comparator,
|
|
4
|
+
type Mapper,
|
|
5
|
+
type SortDirection,
|
|
6
|
+
type SortOptions,
|
|
7
|
+
type StringMap,
|
|
8
|
+
} from '../types.js'
|
|
9
|
+
|
|
10
|
+
class Comparators {
|
|
11
|
+
/**
|
|
12
|
+
* Good for numbers.
|
|
13
|
+
*/
|
|
14
|
+
numericAsc(a: number, b: number): number {
|
|
15
|
+
return a - b
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
numericDesc(a: number, b: number): number {
|
|
19
|
+
return b - a
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
localeAsc(a: string, b: string): number {
|
|
23
|
+
return a.localeCompare(b)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
localeDesc(a: string, b: string): number {
|
|
27
|
+
return -a.localeCompare(b)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
by<T, COMPARE_TYPE extends string | number>(
|
|
31
|
+
mapper: Mapper<T, COMPARE_TYPE>,
|
|
32
|
+
opt: ComparatorByOptions = {},
|
|
33
|
+
): Comparator<T> {
|
|
34
|
+
const mod = opt.dir === 'desc' ? -1 : 1
|
|
35
|
+
return (objA: T, objB: T): number => {
|
|
36
|
+
// This implementation may call mapper more than once per item,
|
|
37
|
+
// but the benchmarks show no significant difference in performance.
|
|
38
|
+
const a = mapper(objA)
|
|
39
|
+
const b = mapper(objB)
|
|
40
|
+
if (a > b) return mod
|
|
41
|
+
if (a < b) return -mod
|
|
42
|
+
return 0
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
updatedAsc(a: { updated: number }, b: { updated: number }): number {
|
|
47
|
+
return a.updated - b.updated
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
updatedDesc(a: { updated: number }, b: { updated: number }): number {
|
|
51
|
+
return b.updated - a.updated
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
createdAsc(a: { created: number }, b: { created: number }): number {
|
|
55
|
+
return a.created - b.created
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
createdDesc(a: { created: number }, b: { created: number }): number {
|
|
59
|
+
return b.created - a.created
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const comparators = new Comparators()
|
|
64
|
+
|
|
65
|
+
interface ComparatorByOptions {
|
|
66
|
+
/**
|
|
67
|
+
* Defaults to 'asc'.
|
|
68
|
+
*/
|
|
69
|
+
dir?: SortDirection
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* _sortBy([{age: 20}, {age: 10}], 'age')
|
|
74
|
+
* // => [{age: 10}, {age: 20}]
|
|
75
|
+
*
|
|
76
|
+
* Same:
|
|
77
|
+
* _sortBy([{age: 20}, {age: 10}], o => o.age)
|
|
78
|
+
*/
|
|
79
|
+
export function _sortBy<T, COMPARE_TYPE extends string | number>(
|
|
80
|
+
items: T[],
|
|
81
|
+
mapper: Mapper<T, COMPARE_TYPE>,
|
|
82
|
+
opt: SortOptions = {},
|
|
83
|
+
): T[] {
|
|
84
|
+
return (opt.mutate ? items : [...items]).sort(comparators.by(mapper, opt))
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Like _stringMapValues, but values are sorted.
|
|
89
|
+
*/
|
|
90
|
+
export function _stringMapValuesSorted<T>(
|
|
91
|
+
map: StringMap<T>,
|
|
92
|
+
mapper: Mapper<T, any>,
|
|
93
|
+
dir: SortDirection = 'asc',
|
|
94
|
+
): T[] {
|
|
95
|
+
return _sortBy(_stringMapValues(map), mapper, { dir })
|
|
96
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { Comparator } from '../types.js'
|
|
2
|
+
import { Array2 } from './array2.js'
|
|
3
|
+
import { comparators } from './sort.js'
|
|
4
|
+
|
|
5
|
+
export interface SortedArrayOptions<T> {
|
|
6
|
+
/**
|
|
7
|
+
* Defaults to undefined.
|
|
8
|
+
* Undefined (default comparator) works well for String keys.
|
|
9
|
+
* For Number keys - use comparators.numericAsc (or desc),
|
|
10
|
+
* otherwise sorting will be wrong (lexicographic).
|
|
11
|
+
*/
|
|
12
|
+
comparator?: Comparator<T>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Like Array, but keeps values sorted after every insertion.
|
|
17
|
+
*/
|
|
18
|
+
export class SortedArray<T> extends Array2<T> {
|
|
19
|
+
constructor(values: Iterable<T> = [], opt: SortedArrayOptions<T> = {}) {
|
|
20
|
+
super(...values)
|
|
21
|
+
this.#comparator = opt.comparator
|
|
22
|
+
this.resort()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
readonly #comparator: Comparator<T> | undefined
|
|
26
|
+
|
|
27
|
+
override push(...values: T[]): number {
|
|
28
|
+
const length = super.push(...values)
|
|
29
|
+
this.resort()
|
|
30
|
+
return length
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
override unshift(...values: T[]): number {
|
|
34
|
+
const length = super.unshift(...values)
|
|
35
|
+
this.resort()
|
|
36
|
+
return length
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override splice(start: number, deleteCount?: number, ...items: T[]): T[] {
|
|
40
|
+
const removed = super.splice(start, deleteCount ?? this.length - start, ...items)
|
|
41
|
+
if (items.length) {
|
|
42
|
+
this.resort()
|
|
43
|
+
}
|
|
44
|
+
return removed
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static override get [Symbol.species](): ArrayConstructor {
|
|
48
|
+
return Array
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
override get [Symbol.toStringTag](): string {
|
|
52
|
+
return 'Array'
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private resort(): void {
|
|
56
|
+
super.sort(this.#comparator)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export class SortedStringArray extends SortedArray<string> {
|
|
61
|
+
constructor(values: Iterable<string> = []) {
|
|
62
|
+
super(values)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
override get [Symbol.toStringTag](): string {
|
|
66
|
+
return 'Array'
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export class SortedNumberArray extends SortedArray<number> {
|
|
71
|
+
constructor(values: Iterable<number> = []) {
|
|
72
|
+
super(values, { comparator: comparators.numericAsc })
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
override get [Symbol.toStringTag](): string {
|
|
76
|
+
return 'Array'
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Set2 } from '../object/index.js'
|
|
2
|
+
import type { Comparator } from '../types.js'
|
|
3
|
+
|
|
4
|
+
export interface SortedSetOptions<T> {
|
|
5
|
+
/**
|
|
6
|
+
* Defaults to undefined.
|
|
7
|
+
* Undefined (default comparator) works well for String keys.
|
|
8
|
+
* For Number keys - use comparators.numericAsc (or desc),
|
|
9
|
+
* otherwise sorting will be wrong (lexicographic).
|
|
10
|
+
*/
|
|
11
|
+
comparator?: Comparator<T>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Like Set, but keeps members sorted after every insertion.
|
|
16
|
+
*/
|
|
17
|
+
export class SortedSet<T> extends Set2<T> {
|
|
18
|
+
constructor(values: Iterable<T> = [], opt: SortedSetOptions<T> = {}) {
|
|
19
|
+
super()
|
|
20
|
+
this.#comparator = opt.comparator
|
|
21
|
+
this.addMany(values)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
readonly #comparator: Comparator<T> | undefined
|
|
25
|
+
|
|
26
|
+
override add(value: T): this {
|
|
27
|
+
if (super.has(value)) {
|
|
28
|
+
return this
|
|
29
|
+
}
|
|
30
|
+
super.add(value)
|
|
31
|
+
return this.recreate()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
override addMany(items: Iterable<T>): this {
|
|
35
|
+
for (const item of items) {
|
|
36
|
+
super.add(item)
|
|
37
|
+
}
|
|
38
|
+
return this.recreate()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private recreate(): this {
|
|
42
|
+
const items = Array.from(super.values())
|
|
43
|
+
items.sort(this.#comparator)
|
|
44
|
+
super.clear()
|
|
45
|
+
for (const item of items) {
|
|
46
|
+
super.add(item)
|
|
47
|
+
}
|
|
48
|
+
return this
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
override get [Symbol.toStringTag](): string {
|
|
52
|
+
return 'Set'
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { MutateOptions, SortOptions } from '../array/array.util.js'
|
|
2
1
|
import { _assert } from '../error/assert.js'
|
|
3
2
|
import { Iterable2 } from '../iter/iterable2.js'
|
|
4
3
|
import type {
|
|
@@ -6,6 +5,8 @@ import type {
|
|
|
6
5
|
IsoDate,
|
|
7
6
|
IsoDateTime,
|
|
8
7
|
MonthId,
|
|
8
|
+
MutateOptions,
|
|
9
|
+
SortOptions,
|
|
9
10
|
UnixTimestamp,
|
|
10
11
|
UnixTimestampMillis,
|
|
11
12
|
} from '../types.js'
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { MutateOptions } from '../array/array.util.js'
|
|
2
1
|
import { _assert } from '../error/assert.js'
|
|
3
2
|
import type {
|
|
4
3
|
IANATimezone,
|
|
@@ -6,6 +5,7 @@ import type {
|
|
|
6
5
|
IsoDate,
|
|
7
6
|
IsoDateTime,
|
|
8
7
|
MonthId,
|
|
8
|
+
MutateOptions,
|
|
9
9
|
NumberOfHours,
|
|
10
10
|
NumberOfMinutes,
|
|
11
11
|
SortDirection,
|
package/src/log/commonLogger.ts
CHANGED
package/src/math/math.util.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { comparators } from '../array/sort.js'
|
|
1
2
|
import { _assert } from '../error/assert.js'
|
|
2
|
-
import { _sortNumbers } from '../number/number.util.js'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @returns Average of the array of numbers
|
|
@@ -49,7 +49,7 @@ export function _averageWeighted(values: number[], weights: number[]): number {
|
|
|
49
49
|
* // 3
|
|
50
50
|
*/
|
|
51
51
|
export function _percentile(values: number[], pc: number): number {
|
|
52
|
-
const sorted =
|
|
52
|
+
const sorted = values.sort(comparators.numericAsc)
|
|
53
53
|
|
|
54
54
|
// Floating pos in the range of [0; length - 1]
|
|
55
55
|
const pos = ((values.length - 1) * pc) / 100
|
|
@@ -66,7 +66,7 @@ export function _percentile(values: number[], pc: number): number {
|
|
|
66
66
|
export function _percentiles(values: number[], pcs: number[]): Record<number, number> {
|
|
67
67
|
const r = {} as Record<number, number>
|
|
68
68
|
|
|
69
|
-
const sorted =
|
|
69
|
+
const sorted = values.sort(comparators.numericAsc)
|
|
70
70
|
|
|
71
71
|
for (const pc of pcs) {
|
|
72
72
|
// Floating pos in the range of [0; length - 1]
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { SortOptions } from '../array/array.util.js'
|
|
2
1
|
import type { Inclusiveness } from '../types.js'
|
|
3
2
|
|
|
4
3
|
export function _randomInt(minIncl: number, maxIncl: number): number {
|
|
@@ -55,20 +54,6 @@ export function _clamp(x: number, minIncl: number, maxIncl: number): number {
|
|
|
55
54
|
return x <= minIncl ? minIncl : x >= maxIncl ? maxIncl : x
|
|
56
55
|
}
|
|
57
56
|
|
|
58
|
-
/**
|
|
59
|
-
* This function exists, because in JS you cannot just .sort() numbers,
|
|
60
|
-
* as .sort() function first maps everything to String.
|
|
61
|
-
*
|
|
62
|
-
* @example
|
|
63
|
-
*
|
|
64
|
-
* _sortNumbers([1, 3, 2])
|
|
65
|
-
* // [1, 2, 3]
|
|
66
|
-
*/
|
|
67
|
-
export function _sortNumbers(numbers: number[], opt: SortOptions = {}): number[] {
|
|
68
|
-
const mod = opt.dir === 'desc' ? -1 : 1
|
|
69
|
-
return (opt.mutate ? numbers : [...numbers]).sort((a, b) => (a - b) * mod)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
57
|
/**
|
|
73
58
|
* Same as .toFixed(), but conveniently casts the output to Number.
|
|
74
59
|
*
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Comparator } from '../types.js'
|
|
2
|
+
|
|
3
|
+
export interface KeySortedMapOptions<K> {
|
|
2
4
|
/**
|
|
3
|
-
* Defaults to
|
|
4
|
-
*
|
|
5
|
-
*
|
|
5
|
+
* Defaults to undefined.
|
|
6
|
+
* Undefined (default comparator) works well for String keys.
|
|
7
|
+
* For Number keys - use comparators.numericAsc (or desc),
|
|
8
|
+
* otherwise sorting will be wrong (lexicographic).
|
|
6
9
|
*/
|
|
7
|
-
|
|
10
|
+
comparator?: Comparator<K>
|
|
8
11
|
}
|
|
9
12
|
|
|
10
13
|
/**
|
|
@@ -24,7 +27,7 @@ export class KeySortedMap<K, V> implements Map<K, V> {
|
|
|
24
27
|
|
|
25
28
|
constructor(
|
|
26
29
|
entries: [K, V][] = [],
|
|
27
|
-
public opt: KeySortedMapOptions = {},
|
|
30
|
+
public opt: KeySortedMapOptions<K> = {},
|
|
28
31
|
) {
|
|
29
32
|
this.map = new Map(entries)
|
|
30
33
|
this.sortedKeys = [...this.map.keys()]
|
|
@@ -220,15 +223,6 @@ export class KeySortedMap<K, V> implements Map<K, V> {
|
|
|
220
223
|
}
|
|
221
224
|
|
|
222
225
|
private sortKeys(): void {
|
|
223
|
-
|
|
224
|
-
;(this.sortedKeys as number[]).sort(numericAscCompare)
|
|
225
|
-
} else {
|
|
226
|
-
// Default sort - fastest for Strings
|
|
227
|
-
this.sortedKeys.sort()
|
|
228
|
-
}
|
|
226
|
+
this.sortedKeys.sort(this.opt.comparator)
|
|
229
227
|
}
|
|
230
228
|
}
|
|
231
|
-
|
|
232
|
-
function numericAscCompare(a: number, b: number): number {
|
|
233
|
-
return a - b
|
|
234
|
-
}
|
package/src/object/set2.ts
CHANGED
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
* @experimental
|
|
7
7
|
*/
|
|
8
8
|
export class Set2<T = any> extends Set<T> {
|
|
9
|
+
static of<T>(items?: Iterable<T> | null): Set2<T> {
|
|
10
|
+
return new Set2(items)
|
|
11
|
+
}
|
|
12
|
+
|
|
9
13
|
/**
|
|
10
14
|
* Like .add(), but allows to add multiple items at once.
|
|
11
15
|
* Mutates the Set, but also returns it conveniently.
|
|
@@ -17,6 +21,18 @@ export class Set2<T = any> extends Set<T> {
|
|
|
17
21
|
return this
|
|
18
22
|
}
|
|
19
23
|
|
|
24
|
+
first(): T {
|
|
25
|
+
if (!this.size) throw new Error('Set.first called on empty set')
|
|
26
|
+
return this.firstOrUndefined()!
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
firstOrUndefined(): T | undefined {
|
|
30
|
+
return this.values().next().value
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Last is not implemented, because it requires to traverse the whole Set - not optimal
|
|
34
|
+
// last(): T {
|
|
35
|
+
|
|
20
36
|
toArray(): T[] {
|
|
21
37
|
return [...this]
|
|
22
38
|
}
|
|
@@ -25,5 +41,9 @@ export class Set2<T = any> extends Set<T> {
|
|
|
25
41
|
return [...this]
|
|
26
42
|
}
|
|
27
43
|
|
|
28
|
-
|
|
44
|
+
override get [Symbol.toStringTag](): string {
|
|
45
|
+
return 'Set'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// todo: consider more helpful .toString() ?
|
|
29
49
|
}
|
package/src/semver.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { SortOptions } from './array/array.util.js'
|
|
2
1
|
import { _range } from './array/range.js'
|
|
3
2
|
import { _assert } from './error/assert.js'
|
|
3
|
+
import type { SortOptions } from './types.js'
|
|
4
4
|
|
|
5
5
|
export type SemverInput = string | Semver
|
|
6
6
|
export type SemverInputNullable = SemverInput | null | undefined
|