@oscarpalmer/atoms 0.192.0 → 0.193.1
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/index.d.mts +25 -23
- package/dist/index.mjs +30 -31
- package/dist/queue.d.mts +25 -23
- package/dist/queue.mjs +27 -28
- package/package.json +3 -4
- package/src/array/difference.ts +0 -73
- package/src/array/exists.ts +0 -93
- package/src/array/filter.ts +0 -182
- package/src/array/find.ts +0 -183
- package/src/array/first.ts +0 -196
- package/src/array/flatten.ts +0 -20
- package/src/array/from.ts +0 -129
- package/src/array/get.ts +0 -131
- package/src/array/group-by.ts +0 -369
- package/src/array/index.ts +0 -26
- package/src/array/insert.ts +0 -52
- package/src/array/intersection.ts +0 -72
- package/src/array/last.ts +0 -194
- package/src/array/match.ts +0 -436
- package/src/array/move.ts +0 -315
- package/src/array/partition.ts +0 -91
- package/src/array/push.ts +0 -23
- package/src/array/reverse.ts +0 -33
- package/src/array/select.ts +0 -260
- package/src/array/single.ts +0 -93
- package/src/array/slice.ts +0 -335
- package/src/array/sort.ts +0 -607
- package/src/array/splice.ts +0 -106
- package/src/array/swap.ts +0 -322
- package/src/array/to-map.ts +0 -371
- package/src/array/to-record.ts +0 -351
- package/src/array/to-set.ts +0 -80
- package/src/array/toggle.ts +0 -79
- package/src/array/union.ts +0 -72
- package/src/array/unique.ts +0 -67
- package/src/array/update.ts +0 -75
- package/src/beacon.ts +0 -378
- package/src/color/constants.ts +0 -137
- package/src/color/index.ts +0 -83
- package/src/color/instance.ts +0 -162
- package/src/color/misc/alpha.ts +0 -56
- package/src/color/misc/format.ts +0 -29
- package/src/color/misc/get.ts +0 -210
- package/src/color/misc/is.ts +0 -221
- package/src/color/misc/state.ts +0 -243
- package/src/color/models.ts +0 -389
- package/src/color/space/hex.ts +0 -184
- package/src/color/space/hsl.ts +0 -174
- package/src/color/space/hwb.ts +0 -153
- package/src/color/space/rgb.ts +0 -240
- package/src/function/assert.ts +0 -174
- package/src/function/index.ts +0 -2
- package/src/function/limit.ts +0 -83
- package/src/function/memoize.ts +0 -202
- package/src/function/once.ts +0 -200
- package/src/function/retry.ts +0 -175
- package/src/function/work.ts +0 -1007
- package/src/herald.ts +0 -216
- package/src/index.ts +0 -68
- package/src/internal/array/callbacks.ts +0 -46
- package/src/internal/array/chunk.ts +0 -51
- package/src/internal/array/compact.ts +0 -56
- package/src/internal/array/find.ts +0 -200
- package/src/internal/array/group.ts +0 -42
- package/src/internal/array/index-of.ts +0 -182
- package/src/internal/array/insert.ts +0 -80
- package/src/internal/array/overlap.ts +0 -35
- package/src/internal/array/sets.ts +0 -74
- package/src/internal/array/shuffle.ts +0 -33
- package/src/internal/array/update.ts +0 -52
- package/src/internal/function/misc.ts +0 -8
- package/src/internal/function/timer.ts +0 -168
- package/src/internal/is.ts +0 -244
- package/src/internal/math/aggregate.ts +0 -164
- package/src/internal/math/misc.ts +0 -28
- package/src/internal/number.ts +0 -129
- package/src/internal/random.ts +0 -49
- package/src/internal/result.ts +0 -92
- package/src/internal/sized.ts +0 -25
- package/src/internal/string.ts +0 -128
- package/src/internal/subscription.ts +0 -264
- package/src/internal/value/compare.ts +0 -170
- package/src/internal/value/equal.ts +0 -465
- package/src/internal/value/get.ts +0 -57
- package/src/internal/value/handlers.ts +0 -95
- package/src/internal/value/has.ts +0 -118
- package/src/internal/value/misc.ts +0 -125
- package/src/internal/value/partial.ts +0 -46
- package/src/internal/value/set.ts +0 -132
- package/src/is.ts +0 -182
- package/src/logger.ts +0 -230
- package/src/math.ts +0 -281
- package/src/models.ts +0 -286
- package/src/number.ts +0 -1
- package/src/promise/delay.ts +0 -62
- package/src/promise/helpers.ts +0 -96
- package/src/promise/index.ts +0 -300
- package/src/promise/misc.ts +0 -96
- package/src/promise/models.ts +0 -195
- package/src/promise/timed.ts +0 -91
- package/src/query.ts +0 -147
- package/src/queue.ts +0 -814
- package/src/random.ts +0 -125
- package/src/result/index.ts +0 -105
- package/src/result/match.ts +0 -124
- package/src/result/misc.ts +0 -129
- package/src/result/models.ts +0 -83
- package/src/result/work/flow.ts +0 -488
- package/src/result/work/pipe.ts +0 -496
- package/src/sized/map.ts +0 -110
- package/src/sized/set.ts +0 -107
- package/src/string/case.ts +0 -236
- package/src/string/fuzzy.ts +0 -444
- package/src/string/index.ts +0 -199
- package/src/string/match.ts +0 -80
- package/src/string/normalize.ts +0 -205
- package/src/string/template.ts +0 -161
- package/src/value/clone.ts +0 -319
- package/src/value/collection.ts +0 -63
- package/src/value/diff.ts +0 -232
- package/src/value/freeze.ts +0 -322
- package/src/value/handle.ts +0 -3
- package/src/value/index.ts +0 -5
- package/src/value/merge.ts +0 -278
- package/src/value/omit.ts +0 -20
- package/src/value/pick.ts +0 -20
- package/src/value/shake.ts +0 -45
- package/src/value/smush.ts +0 -89
- package/src/value/transform.ts +0 -153
- package/src/value/unsmush.ts +0 -84
package/src/value/clone.ts
DELETED
|
@@ -1,319 +0,0 @@
|
|
|
1
|
-
import {isArrayOrPlainObject, isTypedArray} from '../internal/is';
|
|
2
|
-
import {getSelfHandlers} from '../internal/value/handlers';
|
|
3
|
-
import type {ArrayOrPlainObject, Constructor, PlainObject, TypedArray} from '../models';
|
|
4
|
-
|
|
5
|
-
// #region Special variables
|
|
6
|
-
|
|
7
|
-
const CLONE_NAME = 'clone';
|
|
8
|
-
|
|
9
|
-
// #endregion
|
|
10
|
-
|
|
11
|
-
// #region Functions
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Clone any kind of value _(shallowly)_
|
|
15
|
-
*
|
|
16
|
-
* @param value Value to clone
|
|
17
|
-
* @param flat Clone only the value itself, without cloning nested values
|
|
18
|
-
* @returns Cloned value
|
|
19
|
-
*/
|
|
20
|
-
export function clone<Value>(value: Value, flat: true): Value;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Clone any kind of value _(deeply, if needed)_
|
|
24
|
-
*
|
|
25
|
-
* @param value Value to clone
|
|
26
|
-
* @returns Cloned value
|
|
27
|
-
*/
|
|
28
|
-
export function clone<Value>(value: Value): Value;
|
|
29
|
-
|
|
30
|
-
export function clone(value: unknown, flat?: boolean): unknown {
|
|
31
|
-
return flat === true ? copy(value) : cloneValue(value, 0, new WeakMap(), false);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
clone.handlers = getSelfHandlers(clone, {
|
|
35
|
-
callback: tryStructuredClone,
|
|
36
|
-
method: CLONE_NAME,
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
clone.deregister = deregisterCloner;
|
|
40
|
-
clone.register = registerCloner;
|
|
41
|
-
|
|
42
|
-
function cloneArrayBuffer(
|
|
43
|
-
value: ArrayBuffer,
|
|
44
|
-
depth?: number,
|
|
45
|
-
references?: WeakMap<WeakKey, unknown>,
|
|
46
|
-
): ArrayBuffer {
|
|
47
|
-
if (typeof depth === 'number' && depth >= MAX_CLONE_DEPTH) {
|
|
48
|
-
return value;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const cloned = new ArrayBuffer(value.byteLength);
|
|
52
|
-
|
|
53
|
-
new Uint8Array(cloned).set(new Uint8Array(value));
|
|
54
|
-
|
|
55
|
-
references?.set(value, cloned);
|
|
56
|
-
|
|
57
|
-
return cloned;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function cloneDataView(
|
|
61
|
-
value: DataView,
|
|
62
|
-
depth: number,
|
|
63
|
-
references: WeakMap<WeakKey, unknown>,
|
|
64
|
-
): DataView {
|
|
65
|
-
if (depth >= MAX_CLONE_DEPTH) {
|
|
66
|
-
return value;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const buffer = cloneArrayBuffer(value.buffer as ArrayBuffer);
|
|
70
|
-
|
|
71
|
-
const cloned = new DataView(buffer, value.byteOffset, value.byteLength);
|
|
72
|
-
|
|
73
|
-
references.set(value, cloned);
|
|
74
|
-
|
|
75
|
-
return cloned;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function cloneMap(
|
|
79
|
-
map: Map<unknown, unknown>,
|
|
80
|
-
depth: number,
|
|
81
|
-
references: WeakMap<WeakKey, unknown>,
|
|
82
|
-
flat: boolean,
|
|
83
|
-
): Map<unknown, unknown> {
|
|
84
|
-
if (depth >= MAX_CLONE_DEPTH) {
|
|
85
|
-
return map;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const cloned = new Map<unknown, unknown>();
|
|
89
|
-
const entries = map.entries();
|
|
90
|
-
|
|
91
|
-
for (const entry of entries) {
|
|
92
|
-
cloned.set(
|
|
93
|
-
flat ? entry[0] : cloneValue(entry[0], depth + 1, references, false),
|
|
94
|
-
flat ? entry[1] : cloneValue(entry[1], depth + 1, references, false),
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
references.set(map, cloned);
|
|
99
|
-
|
|
100
|
-
return cloned;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function cloneNode(node: Node, depth: number, references: WeakMap<WeakKey, unknown>): Node {
|
|
104
|
-
if (depth >= MAX_CLONE_DEPTH) {
|
|
105
|
-
return node;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const cloned = node.cloneNode(true);
|
|
109
|
-
|
|
110
|
-
references.set(node, cloned);
|
|
111
|
-
|
|
112
|
-
return cloned;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function cloneObject(
|
|
116
|
-
value: ArrayOrPlainObject,
|
|
117
|
-
depth: number,
|
|
118
|
-
references: WeakMap<WeakKey, unknown>,
|
|
119
|
-
flat: boolean,
|
|
120
|
-
): ArrayOrPlainObject {
|
|
121
|
-
if (flat || depth >= MAX_CLONE_DEPTH) {
|
|
122
|
-
return Array.isArray(value) ? value.slice() : {...value};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const cloned = (Array.isArray(value) ? [] : {}) as PlainObject;
|
|
126
|
-
const keys = [...Object.keys(value), ...Object.getOwnPropertySymbols(value)];
|
|
127
|
-
const {length} = keys;
|
|
128
|
-
|
|
129
|
-
for (let index = 0; index < length; index += 1) {
|
|
130
|
-
const key = keys[index];
|
|
131
|
-
|
|
132
|
-
cloned[key] = cloneValue((value as PlainObject)[key], depth + 1, references, false);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
references.set(value, cloned);
|
|
136
|
-
|
|
137
|
-
return cloned;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
function cloneRegularExpression(
|
|
141
|
-
value: RegExp,
|
|
142
|
-
depth: number,
|
|
143
|
-
references: WeakMap<WeakKey, unknown>,
|
|
144
|
-
): RegExp {
|
|
145
|
-
if (depth >= MAX_CLONE_DEPTH) {
|
|
146
|
-
return value;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const cloned = new RegExp(value.source, value.flags);
|
|
150
|
-
|
|
151
|
-
cloned.lastIndex = value.lastIndex;
|
|
152
|
-
|
|
153
|
-
references.set(value, cloned);
|
|
154
|
-
|
|
155
|
-
return cloned;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function cloneSet(
|
|
159
|
-
set: Set<unknown>,
|
|
160
|
-
depth: number,
|
|
161
|
-
references: WeakMap<WeakKey, unknown>,
|
|
162
|
-
flat: boolean,
|
|
163
|
-
): Set<unknown> {
|
|
164
|
-
if (depth >= MAX_CLONE_DEPTH) {
|
|
165
|
-
return set;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const cloned = new Set<unknown>();
|
|
169
|
-
const values = [...set.values()];
|
|
170
|
-
const {length} = values;
|
|
171
|
-
|
|
172
|
-
for (let index = 0; index < length; index += 1) {
|
|
173
|
-
cloned.add(flat ? values[index] : cloneValue(values[index], depth + 1, references, false));
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
references.set(set, cloned);
|
|
177
|
-
|
|
178
|
-
return cloned;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function cloneTypedArray(
|
|
182
|
-
value: TypedArray,
|
|
183
|
-
depth: number,
|
|
184
|
-
references: WeakMap<WeakKey, unknown>,
|
|
185
|
-
): TypedArray {
|
|
186
|
-
if (depth >= MAX_CLONE_DEPTH) {
|
|
187
|
-
return value;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const cloned = new (value.constructor as new (...args: unknown[]) => TypedArray)(value);
|
|
191
|
-
|
|
192
|
-
references.set(value, cloned);
|
|
193
|
-
|
|
194
|
-
return cloned as TypedArray;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
function cloneValue(
|
|
198
|
-
value: unknown,
|
|
199
|
-
depth: number,
|
|
200
|
-
references: WeakMap<WeakKey, unknown>,
|
|
201
|
-
flat: boolean,
|
|
202
|
-
): unknown {
|
|
203
|
-
switch (true) {
|
|
204
|
-
case value == null:
|
|
205
|
-
case typeof value === 'bigint':
|
|
206
|
-
case typeof value === 'boolean':
|
|
207
|
-
case typeof value === 'number':
|
|
208
|
-
case typeof value === 'string':
|
|
209
|
-
return value;
|
|
210
|
-
|
|
211
|
-
case typeof value === 'function':
|
|
212
|
-
return;
|
|
213
|
-
|
|
214
|
-
case typeof value === 'symbol':
|
|
215
|
-
return Symbol(value.description);
|
|
216
|
-
|
|
217
|
-
case references.has(value as object):
|
|
218
|
-
return references.get(value);
|
|
219
|
-
|
|
220
|
-
case value instanceof ArrayBuffer:
|
|
221
|
-
return cloneArrayBuffer(value, depth, references);
|
|
222
|
-
|
|
223
|
-
case value instanceof DataView:
|
|
224
|
-
return cloneDataView(value, depth, references);
|
|
225
|
-
|
|
226
|
-
case value instanceof Date:
|
|
227
|
-
return new Date(value.getTime());
|
|
228
|
-
|
|
229
|
-
case value instanceof RegExp:
|
|
230
|
-
return cloneRegularExpression(value, depth, references);
|
|
231
|
-
|
|
232
|
-
case value instanceof Map:
|
|
233
|
-
return cloneMap(value, depth, references, flat);
|
|
234
|
-
|
|
235
|
-
case typeof Node !== 'undefined' && value instanceof Node:
|
|
236
|
-
return cloneNode(value, depth, references);
|
|
237
|
-
|
|
238
|
-
case value instanceof Set:
|
|
239
|
-
return cloneSet(value, depth, references, flat);
|
|
240
|
-
|
|
241
|
-
case isArrayOrPlainObject(value):
|
|
242
|
-
return cloneObject(value, depth, references, flat);
|
|
243
|
-
|
|
244
|
-
case isTypedArray(value):
|
|
245
|
-
return cloneTypedArray(value, depth, references);
|
|
246
|
-
|
|
247
|
-
default:
|
|
248
|
-
return clone.handlers.handle(value, depth, references);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Copy any kind of value
|
|
254
|
-
*
|
|
255
|
-
* - Clones the value shallowly, without cloning nested values
|
|
256
|
-
* - To copy a value deeply, use `clone` instead
|
|
257
|
-
*
|
|
258
|
-
* @param value Value to copy
|
|
259
|
-
* @returns Copied value
|
|
260
|
-
*/
|
|
261
|
-
export function copy<Value>(value: Value): Value {
|
|
262
|
-
return cloneValue(value, 0, new WeakMap(), true) as Value;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Deregister a clone handler for a specific class
|
|
267
|
-
*
|
|
268
|
-
* _Available as `deregisterCloner` and `template.deregister`_
|
|
269
|
-
*
|
|
270
|
-
* @param constructor Class constructor
|
|
271
|
-
*/
|
|
272
|
-
export function deregisterCloner<Instance>(constructor: Constructor<Instance>): void {
|
|
273
|
-
clone.handlers.deregister(constructor);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Register a clone handler for a specific class
|
|
278
|
-
*
|
|
279
|
-
* _Available as `registerCloner` and `template.register`_
|
|
280
|
-
*
|
|
281
|
-
* @param constructor Class constructor
|
|
282
|
-
* @param handler Method name or clone function _(defaults to method name `clone`)_
|
|
283
|
-
*/
|
|
284
|
-
export function registerCloner<Instance>(
|
|
285
|
-
constructor: Constructor<Instance>,
|
|
286
|
-
handler?: string | ((value: Instance) => Instance),
|
|
287
|
-
): void {
|
|
288
|
-
clone.handlers.register(constructor, handler);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
function tryStructuredClone(
|
|
292
|
-
value: object,
|
|
293
|
-
depth: number,
|
|
294
|
-
references: WeakMap<WeakKey, unknown>,
|
|
295
|
-
): unknown {
|
|
296
|
-
if (depth >= MAX_CLONE_DEPTH) {
|
|
297
|
-
return value;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
try {
|
|
301
|
-
const cloned = structuredClone(value);
|
|
302
|
-
|
|
303
|
-
references.set(value, cloned);
|
|
304
|
-
|
|
305
|
-
return cloned;
|
|
306
|
-
} catch {
|
|
307
|
-
references.set(value, value);
|
|
308
|
-
|
|
309
|
-
return value;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// #endregion
|
|
314
|
-
|
|
315
|
-
// #region Variables
|
|
316
|
-
|
|
317
|
-
const MAX_CLONE_DEPTH = 100;
|
|
318
|
-
|
|
319
|
-
// #endregion
|
package/src/value/collection.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import {equal} from '../internal/value/equal';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Does the value exist for a key in a _Map_?
|
|
5
|
-
*
|
|
6
|
-
* @param map _Map_ to check in
|
|
7
|
-
* @param value Value to check for
|
|
8
|
-
* @returns `true` if the value exists, otherwise `false`
|
|
9
|
-
*/
|
|
10
|
-
export function inMap<Value>(map: Map<unknown, Value>, value: Value): boolean;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Does the value exist for a key in a _Map_?
|
|
14
|
-
*
|
|
15
|
-
* @param map _Map_ to check in
|
|
16
|
-
* @param value Value to check for
|
|
17
|
-
* @param key To return the key for the value
|
|
18
|
-
* @returns The key for the value if it exists, otherwise `undefined`
|
|
19
|
-
*/
|
|
20
|
-
export function inMap<Key, Value>(map: Map<Key, Value>, value: Value, key: true): Key;
|
|
21
|
-
|
|
22
|
-
export function inMap<Key, Value>(map: Map<Key, Value>, value: Value, key?: unknown): unknown {
|
|
23
|
-
const getKey = key === true;
|
|
24
|
-
|
|
25
|
-
if (!(map instanceof Map)) {
|
|
26
|
-
return getKey ? undefined : false;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (!getKey) {
|
|
30
|
-
return inSet(new Set(map.values()), value);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
for (const [key, item] of map) {
|
|
34
|
-
if (equal(item, value)) {
|
|
35
|
-
return key;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Does the value exist in a _Set_?
|
|
42
|
-
*
|
|
43
|
-
* @param set _Set_ to check in
|
|
44
|
-
* @param value Value to check for
|
|
45
|
-
* @returns `true` if the value exists, otherwise `false`
|
|
46
|
-
*/
|
|
47
|
-
export function inSet<Value>(set: Set<Value>, value: Value): boolean {
|
|
48
|
-
if (!(set instanceof Set)) {
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (set.has(value)) {
|
|
53
|
-
return true;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
for (const item of set) {
|
|
57
|
-
if (equal(item, value)) {
|
|
58
|
-
return true;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return false;
|
|
63
|
-
}
|
package/src/value/diff.ts
DELETED
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
import {isArrayOrPlainObject} from '../internal/is';
|
|
2
|
-
import {join} from '../internal/string';
|
|
3
|
-
import {equal} from '../internal/value/equal';
|
|
4
|
-
|
|
5
|
-
// #region Types
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Options for value comparison
|
|
9
|
-
*/
|
|
10
|
-
export type DiffOptions = {
|
|
11
|
-
/**
|
|
12
|
-
* Should `null` and `undefined` be considered equal and ignored in results?
|
|
13
|
-
*/
|
|
14
|
-
relaxedNullish?: boolean;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* The result of a comparison beteen two values
|
|
19
|
-
*/
|
|
20
|
-
export type DiffResult<First, Second = First> = {
|
|
21
|
-
/**
|
|
22
|
-
* The original values that were compared
|
|
23
|
-
*/
|
|
24
|
-
original: DiffValue<First, Second>;
|
|
25
|
-
/**
|
|
26
|
-
* The type of difference between the two values
|
|
27
|
-
*/
|
|
28
|
-
type: DiffType;
|
|
29
|
-
/**
|
|
30
|
-
* The differences between the two values
|
|
31
|
-
*
|
|
32
|
-
* - Keys are in dot notation
|
|
33
|
-
* - Values are objects with `from` and `to` properties
|
|
34
|
-
*/
|
|
35
|
-
values: Record<string, DiffValue>;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
type DiffType = 'full' | 'none' | 'partial';
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* The difference between two values
|
|
42
|
-
*/
|
|
43
|
-
export type DiffValue<First = unknown, Second = First> = {
|
|
44
|
-
/**
|
|
45
|
-
* The value from the first value
|
|
46
|
-
*/
|
|
47
|
-
from: First;
|
|
48
|
-
/**
|
|
49
|
-
* The value from the second value
|
|
50
|
-
*/
|
|
51
|
-
to: Second;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
type KeyedDiffValue = {
|
|
55
|
-
key: string;
|
|
56
|
-
} & DiffValue;
|
|
57
|
-
|
|
58
|
-
type Parameters = {
|
|
59
|
-
changes: KeyedDiffValue[];
|
|
60
|
-
key: PropertyKey;
|
|
61
|
-
options: Required<DiffOptions>;
|
|
62
|
-
values: {first: unknown; second: unknown};
|
|
63
|
-
prefix?: string;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
// #endregion
|
|
67
|
-
|
|
68
|
-
// #region Functions
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Find the differences between two values
|
|
72
|
-
*
|
|
73
|
-
* @param first First value
|
|
74
|
-
* @param second Second value
|
|
75
|
-
* @param options Comparison options
|
|
76
|
-
* @returns Difference result
|
|
77
|
-
*/
|
|
78
|
-
export function diff<First, Second = First>(
|
|
79
|
-
first: First,
|
|
80
|
-
second: Second,
|
|
81
|
-
options?: DiffOptions,
|
|
82
|
-
): DiffResult<First, Second> {
|
|
83
|
-
const relaxedNullish = typeof options === 'object' && options?.relaxedNullish === true;
|
|
84
|
-
|
|
85
|
-
const diffResult: DiffResult<First, Second> = {
|
|
86
|
-
original: {
|
|
87
|
-
from: first,
|
|
88
|
-
to: second,
|
|
89
|
-
},
|
|
90
|
-
type: DIFF_PARTIAL,
|
|
91
|
-
values: {},
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const same = (relaxedNullish && first == null && second == null) || Object.is(first, second);
|
|
95
|
-
|
|
96
|
-
const firstIsArrayOrObject = isArrayOrPlainObject(first);
|
|
97
|
-
const secondIsArrayOrObject = isArrayOrPlainObject(second);
|
|
98
|
-
|
|
99
|
-
if (same || !(firstIsArrayOrObject || secondIsArrayOrObject)) {
|
|
100
|
-
diffResult.type = same ? DIFF_NONE : DIFF_FULL;
|
|
101
|
-
|
|
102
|
-
return diffResult;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (firstIsArrayOrObject !== secondIsArrayOrObject) {
|
|
106
|
-
diffResult.type = DIFF_FULL;
|
|
107
|
-
|
|
108
|
-
return diffResult;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const diffs = getDiffs(first, second, {relaxedNullish});
|
|
112
|
-
|
|
113
|
-
const {length} = diffs;
|
|
114
|
-
|
|
115
|
-
if (length === 0) {
|
|
116
|
-
diffResult.type = DIFF_NONE;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
for (let index = 0; index < length; index += 1) {
|
|
120
|
-
const differences = diffs[index];
|
|
121
|
-
|
|
122
|
-
diffResult.values[differences.key] = {from: differences.from, to: differences.to};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return diffResult;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function getChanges(
|
|
129
|
-
changes: KeyedDiffValue[],
|
|
130
|
-
first: unknown,
|
|
131
|
-
second: unknown,
|
|
132
|
-
options: Required<DiffOptions>,
|
|
133
|
-
prefix?: string,
|
|
134
|
-
): KeyedDiffValue[] {
|
|
135
|
-
const checked = new Set<PropertyKey>();
|
|
136
|
-
|
|
137
|
-
for (let outerIndex = 0; outerIndex < 2; outerIndex += 1) {
|
|
138
|
-
const value = (outerIndex === 0 ? first : second) ?? {};
|
|
139
|
-
|
|
140
|
-
const keys = [...Object.keys(value), ...Object.getOwnPropertySymbols(value)];
|
|
141
|
-
|
|
142
|
-
const {length} = keys;
|
|
143
|
-
|
|
144
|
-
for (let innerIndex = 0; innerIndex < length; innerIndex += 1) {
|
|
145
|
-
const key = keys[innerIndex];
|
|
146
|
-
|
|
147
|
-
if (checked.has(key)) {
|
|
148
|
-
continue;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
checked.add(key);
|
|
152
|
-
|
|
153
|
-
setChanges({
|
|
154
|
-
changes,
|
|
155
|
-
key,
|
|
156
|
-
options,
|
|
157
|
-
prefix,
|
|
158
|
-
values: {first, second},
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return changes;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function getDiffs(
|
|
167
|
-
first: unknown,
|
|
168
|
-
second: unknown,
|
|
169
|
-
options: Required<DiffOptions>,
|
|
170
|
-
prefix?: string,
|
|
171
|
-
): KeyedDiffValue[] {
|
|
172
|
-
const changes: KeyedDiffValue[] = [];
|
|
173
|
-
|
|
174
|
-
if (Array.isArray(first) && Array.isArray(second)) {
|
|
175
|
-
const maximumLength = Math.max(first.length, second.length);
|
|
176
|
-
const minimumLength = Math.min(first.length, second.length);
|
|
177
|
-
|
|
178
|
-
for (let index = minimumLength; index < maximumLength; index += 1) {
|
|
179
|
-
const key = join([prefix, index], '.');
|
|
180
|
-
|
|
181
|
-
changes.push({
|
|
182
|
-
key,
|
|
183
|
-
from: index >= first.length ? undefined : first[index],
|
|
184
|
-
to: index >= first.length ? second[index] : undefined,
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return getChanges(changes, first, second, options, prefix);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function setChanges(parameters: Parameters): void {
|
|
193
|
-
const {changes, key, prefix, options, values} = parameters;
|
|
194
|
-
|
|
195
|
-
const prefixed = join([prefix, key], '.');
|
|
196
|
-
|
|
197
|
-
const from: unknown = values.first?.[key as never];
|
|
198
|
-
const to: unknown = values.second?.[key as never];
|
|
199
|
-
|
|
200
|
-
const nested = isArrayOrPlainObject(from) || isArrayOrPlainObject(to);
|
|
201
|
-
const diffs = nested ? getDiffs(from, to, options, prefixed) : [];
|
|
202
|
-
|
|
203
|
-
if (nested ? diffs.length === 0 : equal(from, to, options)) {
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
const change = {
|
|
208
|
-
from,
|
|
209
|
-
to,
|
|
210
|
-
key: prefixed,
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
changes.push(change);
|
|
214
|
-
|
|
215
|
-
const diffsLength = diffs.length;
|
|
216
|
-
|
|
217
|
-
for (let diffIndex = 0; diffIndex < diffsLength; diffIndex += 1) {
|
|
218
|
-
changes.push(diffs[diffIndex]);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// #endregion
|
|
223
|
-
|
|
224
|
-
// #region Variables
|
|
225
|
-
|
|
226
|
-
const DIFF_FULL: DiffType = 'full';
|
|
227
|
-
|
|
228
|
-
const DIFF_NONE: DiffType = 'none';
|
|
229
|
-
|
|
230
|
-
const DIFF_PARTIAL: DiffType = 'partial';
|
|
231
|
-
|
|
232
|
-
// #endregion
|