@webqit/observer 2.0.7 → 2.1.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/src/main.js CHANGED
@@ -1,561 +1,585 @@
1
-
2
- /**
3
- * @imports
4
- */
5
- import { _isObject, _isTypeObject, _isFunction, _getType } from '@webqit/util/js/index.js';
6
- import { _from as _arrFrom } from '@webqit/util/arr/index.js';
7
- import ListenerRegistry from './core/ListenerRegistry.js';
8
- import TrapsRegistry from './core/TrapsRegistry.js';
9
- import Descriptor from './core/Descriptor.js';
10
- import { unproxy } from './actors.js';
11
- import { _ } from './util.js';
12
-
13
- /* ---------------SPECIAL APIs--------------- */
14
-
15
- /**
16
- * Reduces a path array against handler.
17
- *
18
- * @param Array|Object target
19
- * @param Array path
20
- * @param Function receiver
21
- * @param Function final
22
- * @param Object params
23
- *
24
- * @example deep( object, [ segement1, segement2 ], observe, ( value, flags ) => {}, params );
25
- *
26
- * @return Any
27
- */
28
- export function deep( target, path, receiver, final = x => x, params = {} ) {
29
- return ( function eat( target, path, _params ) {
30
- const segment = path[ _params.level ];
31
- // ---------------
32
- if ( _params.level < path.length - 1 ) { _params = { ..._params, preflight: true }; }
33
- else { _params = { ..._params, preflight: /*reset*/params.preflight }; }
34
- // ---------------
35
- return receiver( target, segment, ( result, ...args ) => {
36
- // -----------
37
- const paramsNext = ( flags = {} ) => ( { ..._params, ...flags, level: _params.level + 1, } );
38
- const addTrail = desc => {
39
- if ( !( desc instanceof Descriptor ) ) return;
40
- desc.path = [ desc.key ];
41
- if ( target instanceof Descriptor ) {
42
- desc.path = target.path.concat( desc.key );
43
- desc.context = target;
44
- }
45
- };
46
- // -----------
47
- if ( isPropsList( segment ) && Array.isArray( result ) ) {
48
- // -----------
49
- result.forEach( addTrail );
50
- if ( _params.level === path.length - 1 || ( !result.length && _params.midwayResults ) ) return final( result, ...args );
51
- return result.map( entry => eat( entry, path, paramsNext( ...args ) ) )
52
- // -----------
53
- }
54
- // -----------
55
- addTrail( result );
56
- const $isTypeObject = _isTypeObject( resolveObj( result, false ) );
57
- if ( _params.level === path.length - 1 || ( !$isTypeObject && _params.midwayResults ) ) return final( result, ...args );
58
- return $isTypeObject && eat( result, path, paramsNext( ...args ) );
59
- // -----------
60
- }, _params );
61
- } )( target, path.slice( 0 ), { ...params, level: 0 } );
62
- }
63
-
64
- /**
65
- * Adds an observer to a target's registry.
66
- *
67
- * @param Array|Object target
68
- * @param String|Object prop
69
- * @param Function receiver
70
- * @param Object params
71
- *
72
- * @return AbortController
73
- */
74
- export function observe( target, prop, receiver, params = {} ) {
75
- // ---------------
76
- target = resolveObj( target );
77
- if ( _isFunction( arguments[ 1 ] ) ) {
78
- [ , receiver, params = {} ] = arguments;
79
- prop = Infinity;
80
- }
81
- if ( !_isFunction( receiver ) ) throw new Error( `Handler must be a function; "${ _getType( receiver ) }" given!` );
82
- // ---------------
83
- const emit = bind( target, prop, receiver, params );
84
- if ( params.preflight ) {
85
- params = { ...params, descripted: true };
86
- delete params.live;
87
- return get( target, prop, emit, params );
88
- }
89
- return emit();
90
- }
91
-
92
- /**
93
- * Adds an interceptor object to a target's registry.
94
- *
95
- * @param Array|Object target
96
- * @param Object traps
97
- * @param Object params
98
- *
99
- * @return AbortRegistry
100
- */
101
- export function intercept( target, traps, params = {} ) {
102
- // ---------------
103
- target = resolveObj( target );
104
- if ( !_isObject( traps ) ) {
105
- [ /*target*/, /*type*/, /*handler*/, params = {} ] = arguments;
106
- traps = { [ arguments[ 1 ] ]: arguments[ 2 ] };
107
- }
108
- // ---------------
109
- return TrapsRegistry.getInstance( target, true, params.namespace ).addRegistration( { traps, params } );
110
- }
111
-
112
- /* ---------------QUERY APIs--------------- */
113
-
114
- /**
115
- * Performs a "getOwnPropertyDescriptor" operation.
116
- *
117
- * @param Array|Object target
118
- * @param String|Number prop
119
- * @param Function receiver
120
- * @param Object params
121
- *
122
- * @return Any
123
- */
124
- export function getOwnPropertyDescriptor( target, prop, receiver = x => x, params = {} ) {
125
- return exec( target, 'getOwnPropertyDescriptor', { key: prop }, receiver, params );
126
- }
127
-
128
- /**
129
- * Performs a "getOwnPropertyDescriptors" operation.
130
- * @note this isn't part of the standard Reflect API.
131
- *
132
- * @param Array|Object target
133
- * @param String|Number prop
134
- * @param Function receiver
135
- * @param Object params
136
- *
137
- * @return Any
138
- */
139
- export function getOwnPropertyDescriptors( target, prop, receiver = x => x, params = {} ) {
140
- return exec( target, 'getOwnPropertyDescriptors', { key: prop }, receiver, params );
141
- }
142
-
143
- /**
144
- * Performs a "getPrototypeOf" operation.
145
- *
146
- * @param Array|Object target
147
- * @param Function receiver
148
- * @param Object params
149
- *
150
- * @return Any
151
- */
152
- export function getPrototypeOf( target, receiver = x => x, params = {} ) {
153
- return exec( target, 'getPrototypeOf', {}, receiver, params );
154
- }
155
-
156
- /**
157
- * Performs a "isExtensible" operation.
158
- *
159
- * @param Array|Object target
160
- * @param Function receiver
161
- * @param Object params
162
- *
163
- * @return Any
164
- */
165
- export function isExtensible( target, receiver = x => x, params = {} ) {
166
- return exec( target, 'isExtensible', {}, receiver, params );
167
- }
168
-
169
- /**
170
- * Performs a "ownKeys" operation.
171
- *
172
- * @param Array|Object target
173
- * @param Function receiver
174
- * @param Object params
175
- *
176
- * @return Any
177
- */
178
- export function ownKeys( target, receiver = x => x, params = {} ) {
179
- return exec( target, 'ownKeys', {}, receiver, params );
180
- }
181
-
182
- /**
183
- * Performs an operation of the given "type".
184
- *
185
- * @param Array|Object target
186
- * @param String|Number prop
187
- * @param Function receiver
188
- * @param Object params
189
- *
190
- * @return Any
191
- */
192
- export function has( target, prop, receiver = x => x, params = {} ) {
193
- return exec( target, 'has', { key: prop }, receiver, params );
194
- }
195
-
196
- /**
197
- * Performs a get operation.
198
- *
199
- * @param Array|Object target
200
- * @param String|Number prop
201
- * @param Function receiver
202
- * @param Object params
203
- *
204
- * @return Any
205
- */
206
- export function get( target, prop, receiver = x => x, params = {} ) {
207
- // ---------------
208
- let isLive;
209
- target = resolveObj( target );
210
- if ( _isObject( receiver ) ) { [ params, receiver ] = [ receiver, x => x ]; }
211
- else if ( params.live ) { isLive = true; }
212
- // ---------------
213
- return resolveProps( target, prop, props => {
214
- const related = [ ...props ];
215
- return ( function next( results, _props, _done ) {
216
- if ( !_props.length ) return _done( results );
217
- const prop = _props.shift();
218
- // ---------
219
- function defaultGet( descriptor, value = undefined ) {
220
- const _next = value => ( descriptor.value = value, next( results.concat( params.live || params.descripted ? descriptor : value ), _props, _done ) );
221
- if ( arguments.length > 1 ) return _next( value );
222
- const accessorizedProps = _( target, 'accessorizedProps', false );
223
- const accessorization = accessorizedProps && accessorizedProps.get( descriptor.key );
224
- if ( accessorization && accessorization.intact() ) {
225
- return _next( accessorization.getValue() );
226
- }
227
- return _next( Reflect.get( target, descriptor.key, ...( params.receiver ? [ params.receiver ] : [] ) ) );
228
- }
229
- // ---------
230
- const descriptor = new Descriptor( target, {
231
- type: 'get',
232
- key: prop,
233
- value: undefined,
234
- related,
235
- } );
236
- const listenerRegistry = TrapsRegistry.getInstance( target, false, params.namespace );
237
- if ( listenerRegistry ) {
238
- return listenerRegistry.emit( descriptor, defaultGet );
239
- }
240
- return defaultGet( descriptor );
241
- } )( [], props.slice( 0 ), results => {
242
- const result_s = isPropsList( prop/*original*/ ) ? results : results[ 0 ];
243
- if ( isLive ) {
244
- const emit = bind( target, prop, receiver, params );
245
- return emit( result_s );
246
- }
247
- return receiver( result_s );
248
- } );
249
- } );
250
- }
251
-
252
- /* ---------------MUTATION APIs--------------- */
253
-
254
- /**
255
- * Performs a batch operation.
256
- *
257
- * @param Object target
258
- * @param Function callback
259
- * @param Object params
260
- *
261
- * @return Void
262
- */
263
- export function batch( target, callback, params = {} ) {
264
- return ListenerRegistry.getInstance( target, true, params.namespace ).batch( callback );
265
- }
266
-
267
- /**
268
- * Performs a set operation.
269
- *
270
- * @param Object target
271
- * @param String|Number prop
272
- * @param Any value
273
- * @param Function receiver
274
- * @param Object params
275
- * @param Bool def
276
- *
277
- * @return Any
278
- */
279
- export function set( target, prop, value, receiver = x => x, params = {}, def = false ) {
280
- // ---------------
281
- target = resolveObj( target );
282
- let entries = [ [ prop, value ] ];
283
- if ( _isObject( prop ) ) {
284
- [ /*target*/, /*hash*/, receiver = x => x, params = {}, def = false ] = arguments;
285
- entries = Object.entries( prop );
286
- }
287
- if ( _isObject( receiver ) ) { [ def, params, receiver ] = [ typeof params === 'boolean' ? params : false, receiver, x => x ]; }
288
- // ---------------
289
- const related = entries.map( ( [ prop ] ) => prop );
290
- return ( function next( descriptors, entries, _done ) {
291
- if ( !entries.length ) return _done( descriptors );
292
- const [ prop, value ] = entries.shift();
293
- // ---------
294
- function defaultSet( descriptor, status = undefined ) {
295
- const _next = status => ( descriptor.status = status, next( descriptors.concat( descriptor ), entries, _done ) );
296
- if ( arguments.length > 1 ) return _next( descriptor, status );
297
- const accessorizedProps = _( target, 'accessorizedProps', false );
298
- const accessorization = accessorizedProps && accessorizedProps.get( descriptor.key );
299
- if ( descriptor.type === 'defineProperty' ) {
300
- if ( accessorization && !accessorization.restore() ) _next( false );
301
- Object.defineProperty( target, descriptor.key, descriptor.value );
302
- return _next( true );
303
- }
304
- if ( accessorization && accessorization.intact() ) {
305
- return _next( accessorization.setValue( descriptor.value ) );
306
- }
307
- return _next( Reflect.set( target, descriptor.key, descriptor.value ) );
308
- }
309
- // ---------
310
- function exec( isUpdate, oldValue ) {
311
- if ( params.diff && value === oldValue ) return next( descriptors, entries, _done );
312
- const descriptor = new Descriptor( target, {
313
- type: def ? 'defineProperty' : 'set',
314
- key: prop,
315
- value,
316
- isUpdate,
317
- oldValue,
318
- related: [ ...related ],
319
- detail: params.detail,
320
- } );
321
- const listenerRegistry = TrapsRegistry.getInstance( target, false, params.namespace );
322
- return listenerRegistry
323
- ? listenerRegistry.emit( descriptor, defaultSet )
324
- : defaultSet( descriptor );
325
- }
326
- // ---------
327
- return has( target, prop, exists => {
328
- if ( !exists ) return exec( exists );
329
- return get( target, prop, oldValue => exec( exists, oldValue ), params );
330
- }, params );
331
- // ---------
332
- } )( [], entries.slice( 0 ), descriptors => {
333
- const listenerRegistry = ListenerRegistry.getInstance( target, false, params.namespace );
334
- if ( listenerRegistry ) listenerRegistry.emit( descriptors );
335
- return receiver(
336
- isPropsList( prop/*original*/ ) ? descriptors.map( opr => opr.status ) : descriptors[ 0 ]?.status
337
- );
338
- } );
339
- }
340
-
341
- /**
342
- * Performs a defineProperty operation.
343
- *
344
- * @param Object target
345
- * @param String|Number prop
346
- * @param Object descriptor
347
- * @param Function receiver
348
- * @param Object params
349
- *
350
- * @return Any
351
- */
352
- export function defineProperty( target, prop, descriptor, receiver = x => x, params = {} ) {
353
- return set( target, prop, descriptor, receiver, params, true/*def*/ );
354
- }
355
-
356
- /**
357
- * Performs a defineProperties operation.
358
- * @note this isn't part of the standard Reflect API.
359
- *
360
- * @param Object target
361
- * @param Object descriptors
362
- * @param Function receiver
363
- * @param Object params
364
- *
365
- * @return Any
366
- */
367
- export function defineProperties( target, descriptors, receiver = x => x, params = {} ) {
368
- return set( target, descriptors, receiver, params, true/*def*/ );
369
- }
370
-
371
- /**
372
- * Performs a delete operation.
373
- *
374
- * @param Object target
375
- * @param String|Number prop
376
- * @param Function receiver
377
- * @param Object params
378
- *
379
- * @return Any
380
- */
381
- export function deleteProperty( target, prop, receiver = x => x, params = {} ) {
382
- // ---------------
383
- target = resolveObj( target );
384
- if ( _isObject( receiver ) ) { [ params, receiver ] = [ receiver, x => x ]; }
385
- // ---------------
386
- const props = _arrFrom( prop ), related = [ ...props ];
387
- return ( function next( descriptors, props, _done ) {
388
- if ( !props.length ) return _done( descriptors );
389
- const prop = props.shift();
390
- // ---------
391
- function defaultDel( descriptor, status = undefined ) {
392
- const _next = status => ( descriptor.status = status, next( descriptors.concat( descriptor ), props, _done ) );
393
- if ( arguments.length > 1 ) return _next( descriptor, status );
394
- const accessorizedProps = _( target, 'accessorizedProps', false );
395
- const accessorization = accessorizedProps && accessorizedProps.get( descriptor.key );
396
- if ( accessorization && !accessorization.restore() ) _next( false );
397
- return _next( Reflect.deleteProperty( target, descriptor.key ) );
398
- }
399
- // ---------
400
- function exec( oldValue ) {
401
- const descriptor = new Descriptor( target, {
402
- type: 'deleteProperty',
403
- key: prop,
404
- oldValue,
405
- related: [ ...related ],
406
- detail: params.detail,
407
- } );
408
- const listenerRegistry = TrapsRegistry.getInstance( target, false, params.namespace );
409
- return listenerRegistry
410
- ? listenerRegistry.emit( descriptor, defaultDel )
411
- : defaultDel( descriptor );
412
- }
413
- // ---------
414
- return get( target, prop, exec, params );
415
- // ---------
416
- } )( [], props.slice( 0 ), descriptors => {
417
- const listenerRegistry = ListenerRegistry.getInstance( target, false, params.namespace );
418
- if ( listenerRegistry ) listenerRegistry.emit( descriptors );
419
- return receiver(
420
- isPropsList( prop/*original*/ ) ? descriptors.map( opr => opr.status ) : descriptors[ 0 ].status
421
- );
422
- } );
423
- }
424
-
425
- /* ---------------EFFECT APIs--------------- */
426
-
427
- /**
428
- * Performs a "construct" operation.
429
- *
430
- * @param Array|Object target
431
- * @param Array argumentsList
432
- * @param Object newTarget
433
- * @param Function receiver
434
- * @param Object params
435
- *
436
- * @return Any
437
- */
438
- export function construct( target, argumentsList, newTarget = null, receiver = x => x, params = {} ) {
439
- return exec( target, 'construct', arguments.length > 2 ? { argumentsList, newTarget } : { argumentsList }, receiver, params );
440
- }
441
-
442
- /**
443
- * Performs an "apply" operation.
444
- *
445
- * @param Array|Object target
446
- * @param Any thisArgument
447
- * @param Array argumentsList
448
- * @param Function receiver
449
- * @param Object params
450
- *
451
- * @return Any
452
- */
453
- export function apply( target, thisArgument, argumentsList, receiver = x => x, params = {} ) {
454
- return exec( target, 'apply', { thisArgument, argumentsList }, receiver, params );
455
- }
456
-
457
- /**
458
- * Performs a "setPrototypeOf" operation.
459
- *
460
- * @param Array|Object target
461
- * @param Anyr proto
462
- * @param Function receiver
463
- * @param Object params
464
- *
465
- * @return Any
466
- */
467
- export function setPrototypeOf( target, proto, receiver = x => x, params = {} ) {
468
- return exec( target, 'setPrototypeOf', { proto }, receiver, params );
469
- }
470
-
471
- /**
472
- * Performs a "preventExtension" operation.
473
- *
474
- * @param Array|Object target
475
- * @param Function receiver
476
- * @param Object params
477
- *
478
- * @return Any
479
- */
480
- export function preventExtensions( target, receiver = x => x, params = {} ) {
481
- return exec( target, 'preventExtensions', {}, receiver, params );
482
- }
483
-
484
- /* ---------------HELPER APIs--------------- */
485
-
486
- /**
487
- * Adds an observer to a target's registry.
488
- *
489
- * @param Array|Object target
490
- * @param String|Object prop
491
- * @param Function receiver
492
- * @param Object params
493
- *
494
- * @return Function: AbortController
495
- */
496
- function bind( target, prop, receiver, params = {} ) {
497
- let controller;
498
- if ( !params.signal ) {
499
- controller = new AbortController;
500
- params = { ...params, signal: controller.signal };
501
- }
502
- const listenerRegistry = ListenerRegistry.getInstance( target, true, params.namespace );
503
- return function emit( descriptor_s, prevRegistration = null ) {
504
- prevRegistration?.remove();
505
- const registrationNext = listenerRegistry.addRegistration( prop, emit, params );
506
- const flags = { signal: registrationNext.signal, };
507
- if ( arguments.length ) {
508
- receiver( descriptor_s, flags );
509
- }
510
- return controller;
511
- };
512
- }
513
-
514
- /**
515
- * Performs an operation of the given "type".
516
- *
517
- * @param Array|Object target
518
- * @param String type
519
- * @param Object payload
520
- * @param Function receiver
521
- * @param Object params
522
- *
523
- * @return Any
524
- */
525
- function exec( target, type, payload = {}, receiver = x => x, params = {} ) {
526
- // ---------
527
- target = resolveObj( target );
528
- if ( _isObject( receiver ) ) { [ params, receiver ] = [ receiver, x => x ]; }
529
- // ---------
530
- function defaultExec( descriptor, result ) {
531
- if ( arguments.length > 1 ) return receiver( result );
532
- return receiver( Reflect[ type ]( target, ...Object.values( payload ) ) );
533
- }
534
- // ---------
535
- const descriptor = new Descriptor( target, { type, ...payload } );
536
- const listenerRegistry = TrapsRegistry.getInstance( target, false, params.namespace );
537
- if ( listenerRegistry ) {
538
- return listenerRegistry.emit( descriptor, defaultExec );
539
- }
540
- return defaultExec( descriptor );
541
- }
542
-
543
- // Asks if prop is a multi-result field
544
- function isPropsList( prop ) {
545
- return prop === Infinity || Array.isArray( prop );
546
- }
547
-
548
- // Resolves obj down to it's self
549
- function resolveObj( obj, assert = true ) {
550
- if ( ( !obj || !_isTypeObject( obj ) ) && assert ) throw new Error( `Object must be of type object or array! "${ _getType( obj ) }" given.` );
551
- if ( obj instanceof Descriptor ) {
552
- obj = obj.value;
553
- }
554
- return obj && unproxy( obj );
555
- }
556
-
557
- // Resolves prop down to actual keys
558
- function resolveProps( obj, prop, receiver ) {
559
- if ( prop === Infinity ) return ownKeys( obj, receiver );
560
- return receiver( _arrFrom( prop ) );
561
- }
1
+
2
+ /**
3
+ * @imports
4
+ */
5
+ import { _isObject, _isTypeObject, _isFunction, _getType } from '@webqit/util/js/index.js';
6
+ import { _from as _arrFrom } from '@webqit/util/arr/index.js';
7
+ import ListenerRegistry from './core/ListenerRegistry.js';
8
+ import TrapsRegistry from './core/TrapsRegistry.js';
9
+ import Descriptor from './core/Descriptor.js';
10
+ import { unproxy } from './actors.js';
11
+ import { _, _await } from './util.js';
12
+
13
+ /* ---------------SPECIAL APIs--------------- */
14
+
15
+ /**
16
+ * Reduces a path array against handler.
17
+ *
18
+ * @param Array|Object target
19
+ * @param Array path
20
+ * @param Function receiver
21
+ * @param Function final
22
+ * @param Object params
23
+ *
24
+ * @example deep( object, [ segement1, segement2 ], observe, ( value, flags ) => {}, params );
25
+ *
26
+ * @return Any
27
+ */
28
+ export function deep( target, path, receiver, final = x => x, params = {} ) {
29
+ return ( function eat( target, path, $params ) {
30
+ const segment = path[ $params.level ];
31
+ const isLastSegment = $params.level === path.length - 1;
32
+ if ( target instanceof Descriptor && target.type !== 'get' ) {
33
+ // Always probe event-generated trees
34
+ $params = { ...$params, probe: 'always' };
35
+ } else if ( $params.probe !== 'always' ) {
36
+ // Probe until (before) last segment
37
+ $params = { ...$params, probe: !isLastSegment };
38
+ }
39
+ // ---------------
40
+ return receiver( target, segment, ( result, ...args ) => {
41
+ // -----------
42
+ const addTrail = desc => {
43
+ if ( !( desc instanceof Descriptor ) ) return;
44
+ desc.path = [ desc.key ];
45
+ if ( target instanceof Descriptor ) {
46
+ desc.path = target.path.concat( desc.key );
47
+ Object.defineProperty( desc, 'context', { get: () => target } );
48
+ }
49
+ };
50
+ const advance = result => {
51
+ const $value = resolveObj( result/* a Descriptor who's value could be proxied */, false );
52
+ return _await( $value/* could be a promise */, $value => {
53
+ if ( result instanceof Descriptor ) {
54
+ result.value = $value; // Update to (fulfilled), unproxied, value
55
+ } else {
56
+ result = $value;
57
+ }
58
+ const flags = args[ 0 ] || {};
59
+ return eat( result, path, { ...$params, ...flags, level: $params.level + 1, } );
60
+ } );
61
+ };
62
+ // -----------
63
+ if ( isPropsList( segment ) && Array.isArray( result ) ) {
64
+ result.forEach( addTrail );
65
+ if ( isLastSegment ) return final( result, ...args );
66
+ return result.map( advance );
67
+ }
68
+ // -----------
69
+ addTrail( result );
70
+ if ( isLastSegment ) return final( result, ...args );
71
+ return advance( result );
72
+ // -----------
73
+ }, $params );
74
+ } )( target, path.slice( 0 ), { ...params, level: 0 } );
75
+ }
76
+
77
+ /**
78
+ * Adds an observer to a target's registry.
79
+ *
80
+ * @param Array|Object target
81
+ * @param String|Object prop
82
+ * @param Function receiver
83
+ * @param Object params
84
+ *
85
+ * @return AbortController
86
+ */
87
+ export function observe( target, prop, receiver, params = {} ) {
88
+ // ---------------
89
+ target = resolveObj( target, !params.level );
90
+ if ( _isFunction( arguments[ 1 ] ) ) {
91
+ [ , receiver, params = {} ] = arguments;
92
+ prop = Infinity;
93
+ }
94
+ if ( !_isFunction( receiver ) ) throw new Error( `Handler must be a function; "${ _getType( receiver ) }" given!` );
95
+ // ---------------
96
+ params = { ...params, descripted: true };
97
+ delete params.live;
98
+ if ( !_isTypeObject( target ) ) return params.probe && get( target, prop, receiver, params );
99
+ // ---------------
100
+ const emit = bind( target, prop, receiver, params );
101
+ if ( params.probe ) {
102
+ return get( target, prop, emit, params );
103
+ }
104
+ return emit();
105
+ }
106
+
107
+ /**
108
+ * Adds an interceptor object to a target's registry.
109
+ *
110
+ * @param Array|Object target
111
+ * @param Object traps
112
+ * @param Object params
113
+ *
114
+ * @return AbortRegistry
115
+ */
116
+ export function intercept( target, traps, params = {} ) {
117
+ // ---------------
118
+ target = resolveObj( target );
119
+ if ( !_isObject( traps ) ) {
120
+ [ /*target*/, /*type*/, /*handler*/, params = {} ] = arguments;
121
+ traps = { [ arguments[ 1 ] ]: arguments[ 2 ] };
122
+ }
123
+ // ---------------
124
+ return TrapsRegistry.getInstance( target, true, params.namespace ).addRegistration( { traps, params } );
125
+ }
126
+
127
+ /* ---------------QUERY APIs--------------- */
128
+
129
+ /**
130
+ * Performs a "getOwnPropertyDescriptor" operation.
131
+ *
132
+ * @param Array|Object target
133
+ * @param String|Number prop
134
+ * @param Function receiver
135
+ * @param Object params
136
+ *
137
+ * @return Any
138
+ */
139
+ export function getOwnPropertyDescriptor( target, prop, receiver = x => x, params = {} ) {
140
+ return exec( target, 'getOwnPropertyDescriptor', { key: prop }, receiver, params );
141
+ }
142
+
143
+ /**
144
+ * Performs a "getOwnPropertyDescriptors" operation.
145
+ * @note this isn't part of the standard Reflect API.
146
+ *
147
+ * @param Array|Object target
148
+ * @param String|Number prop
149
+ * @param Function receiver
150
+ * @param Object params
151
+ *
152
+ * @return Any
153
+ */
154
+ export function getOwnPropertyDescriptors( target, prop, receiver = x => x, params = {} ) {
155
+ return exec( target, 'getOwnPropertyDescriptors', { key: prop }, receiver, params );
156
+ }
157
+
158
+ /**
159
+ * Performs a "getPrototypeOf" operation.
160
+ *
161
+ * @param Array|Object target
162
+ * @param Function receiver
163
+ * @param Object params
164
+ *
165
+ * @return Any
166
+ */
167
+ export function getPrototypeOf( target, receiver = x => x, params = {} ) {
168
+ return exec( target, 'getPrototypeOf', {}, receiver, params );
169
+ }
170
+
171
+ /**
172
+ * Performs a "isExtensible" operation.
173
+ *
174
+ * @param Array|Object target
175
+ * @param Function receiver
176
+ * @param Object params
177
+ *
178
+ * @return Any
179
+ */
180
+ export function isExtensible( target, receiver = x => x, params = {} ) {
181
+ return exec( target, 'isExtensible', {}, receiver, params );
182
+ }
183
+
184
+ /**
185
+ * Performs a "ownKeys" operation.
186
+ *
187
+ * @param Array|Object target
188
+ * @param Function receiver
189
+ * @param Object params
190
+ *
191
+ * @return Any
192
+ */
193
+ export function ownKeys( target, receiver = x => x, params = {} ) {
194
+ return exec( target, 'ownKeys', {}, receiver, params );
195
+ }
196
+
197
+ /**
198
+ * Performs an operation of the given "type".
199
+ *
200
+ * @param Array|Object target
201
+ * @param String|Number prop
202
+ * @param Function receiver
203
+ * @param Object params
204
+ *
205
+ * @return Any
206
+ */
207
+ export function has( target, prop, receiver = x => x, params = {} ) {
208
+ return exec( target, 'has', { key: prop }, receiver, params );
209
+ }
210
+
211
+ /**
212
+ * Performs a get operation.
213
+ *
214
+ * @param Array|Object target
215
+ * @param String|Number prop
216
+ * @param Function receiver
217
+ * @param Object params
218
+ *
219
+ * @return Any
220
+ */
221
+ export function get( target, prop, receiver = x => x, params = {} ) {
222
+ // ---------------
223
+ let isLive;
224
+ target = resolveObj( target, !params.level );
225
+ if ( _isObject( receiver ) ) { [ params, receiver ] = [ receiver, x => x ]; }
226
+ else if ( params.live ) { isLive = true; }
227
+ // ---------------
228
+ return resolveProps( target, prop, props => {
229
+ const related = [ ...props ];
230
+ return ( function next( results, _props, _done ) {
231
+ if ( !_props.length ) return _done( results );
232
+ const prop = _props.shift();
233
+ // ---------
234
+ function defaultGet( descriptor, value = undefined ) {
235
+ const _next = value => ( descriptor.value = value, next( results.concat( params.live || params.descripted ? descriptor : value ), _props, _done ) );
236
+ if ( arguments.length > 1 ) return _next( value );
237
+ const accessorizedProps = _( target, 'accessorizedProps', false );
238
+ const accessorization = accessorizedProps && accessorizedProps.get( descriptor.key + '' );
239
+ if ( accessorization && accessorization.intact() ) {
240
+ return _next( accessorization.getValue() );
241
+ }
242
+ return _next( Reflect.get( target, descriptor.key, ...( params.receiver ? [ params.receiver ] : [] ) ) );
243
+ }
244
+ // ---------
245
+ const descriptor = new Descriptor( target, {
246
+ type: 'get',
247
+ key: prop,
248
+ value: undefined,
249
+ related,
250
+ } );
251
+ if ( !_isTypeObject( target ) ) return next( results.concat( params.live || params.descripted ? descriptor : undefined ), _props, _done );
252
+ const listenerRegistry = TrapsRegistry.getInstance( target, false, params.namespace );
253
+ if ( listenerRegistry ) {
254
+ return listenerRegistry.emit( descriptor, defaultGet );
255
+ }
256
+ return defaultGet( descriptor );
257
+ } )( [], props.slice( 0 ), results => {
258
+ const result_s = isPropsList( prop/*original*/ ) ? results : results[ 0 ];
259
+ if ( isLive && _isTypeObject( target ) ) {
260
+ const emit = bind( target, prop, receiver, params );
261
+ return emit( result_s );
262
+ }
263
+ return receiver( result_s );
264
+ } );
265
+ } );
266
+ }
267
+
268
+ /* ---------------MUTATION APIs--------------- */
269
+
270
+ /**
271
+ * Performs a batch operation.
272
+ *
273
+ * @param Object target
274
+ * @param Function callback
275
+ * @param Object params
276
+ *
277
+ * @return Void
278
+ */
279
+ export function batch( target, callback, params = {} ) {
280
+ target = resolveObj( target );
281
+ return ListenerRegistry.getInstance( target, true, params.namespace ).batch( callback );
282
+ }
283
+
284
+ /**
285
+ * Performs a set operation.
286
+ *
287
+ * @param Object target
288
+ * @param String|Number prop
289
+ * @param Any value
290
+ * @param Function receiver
291
+ * @param Object params
292
+ * @param Bool def
293
+ *
294
+ * @return Any
295
+ */
296
+ export function set( target, prop, value, receiver = x => x, params = {}, def = false ) {
297
+ // ---------------
298
+ target = resolveObj( target );
299
+ let entries = [ [ prop, value ] ];
300
+ if ( _isObject( prop ) ) {
301
+ [ /*target*/, /*hash*/, receiver = x => x, params = {}, def = false ] = arguments;
302
+ entries = Object.entries( prop );
303
+ }
304
+ if ( _isObject( receiver ) ) { [ def, params, receiver ] = [ typeof params === 'boolean' ? params : false, receiver, x => x ]; }
305
+ // ---------------
306
+ const related = entries.map( ( [ prop ] ) => prop );
307
+ return ( function next( descriptors, entries, _done ) {
308
+ if ( !entries.length ) return _done( descriptors );
309
+ const [ prop, value ] = entries.shift();
310
+ // ---------
311
+ function defaultSet( descriptor, status = undefined ) {
312
+ const _next = status => ( descriptor.status = status, next( descriptors.concat( descriptor ), entries, _done ) );
313
+ if ( arguments.length > 1 ) return _next( descriptor, status );
314
+ const accessorizedProps = _( target, 'accessorizedProps', false );
315
+ const accessorization = accessorizedProps && accessorizedProps.get( descriptor.key + '' );
316
+ if ( descriptor.type === 'defineProperty' ) {
317
+ if ( accessorization && !accessorization.restore() ) _next( false );
318
+ Object.defineProperty( target, descriptor.key, descriptor.value );
319
+ return _next( true );
320
+ }
321
+ if ( accessorization && accessorization.intact() ) {
322
+ return _next( accessorization.setValue( descriptor.value ) );
323
+ }
324
+ return _next( Reflect.set( target, descriptor.key, descriptor.value ) );
325
+ }
326
+ // ---------
327
+ function exec( isUpdate, oldValue ) {
328
+ if ( params.diff && value === oldValue ) return next( descriptors, entries, _done );
329
+ const descriptor = new Descriptor( target, {
330
+ type: def ? 'defineProperty' : 'set',
331
+ key: prop,
332
+ value,
333
+ isUpdate,
334
+ oldValue,
335
+ related: [ ...related ],
336
+ detail: params.detail,
337
+ } );
338
+ const listenerRegistry = TrapsRegistry.getInstance( target, false, params.namespace );
339
+ return listenerRegistry
340
+ ? listenerRegistry.emit( descriptor, defaultSet )
341
+ : defaultSet( descriptor );
342
+ }
343
+ // ---------
344
+ return has( target, prop, exists => {
345
+ if ( !exists ) return exec( exists );
346
+ return get( target, prop, oldValue => exec( exists, oldValue ), params );
347
+ }, params );
348
+ // ---------
349
+ } )( [], entries.slice( 0 ), descriptors => {
350
+ const listenerRegistry = ListenerRegistry.getInstance( target, false, params.namespace );
351
+ if ( listenerRegistry ) listenerRegistry.emit( descriptors );
352
+ return receiver(
353
+ isPropsList( prop/*original*/ ) ? descriptors.map( opr => opr.status ) : descriptors[ 0 ]?.status
354
+ );
355
+ } );
356
+ }
357
+
358
+ /**
359
+ * Performs a defineProperty operation.
360
+ *
361
+ * @param Object target
362
+ * @param String|Number prop
363
+ * @param Object descriptor
364
+ * @param Function receiver
365
+ * @param Object params
366
+ *
367
+ * @return Any
368
+ */
369
+ export function defineProperty( target, prop, descriptor, receiver = x => x, params = {} ) {
370
+ return set( target, prop, descriptor, receiver, params, true/*def*/ );
371
+ }
372
+
373
+ /**
374
+ * Performs a defineProperties operation.
375
+ * @note this isn't part of the standard Reflect API.
376
+ *
377
+ * @param Object target
378
+ * @param Object descriptors
379
+ * @param Function receiver
380
+ * @param Object params
381
+ *
382
+ * @return Any
383
+ */
384
+ export function defineProperties( target, descriptors, receiver = x => x, params = {} ) {
385
+ return set( target, descriptors, receiver, params, true/*def*/ );
386
+ }
387
+
388
+ /**
389
+ * Performs a delete operation.
390
+ *
391
+ * @param Object target
392
+ * @param String|Number prop
393
+ * @param Function receiver
394
+ * @param Object params
395
+ *
396
+ * @return Any
397
+ */
398
+ export function deleteProperty( target, prop, receiver = x => x, params = {} ) {
399
+ // ---------------
400
+ target = resolveObj( target );
401
+ if ( _isObject( receiver ) ) { [ params, receiver ] = [ receiver, x => x ]; }
402
+ // ---------------
403
+ const props = _arrFrom( prop ), related = [ ...props ];
404
+ return ( function next( descriptors, props, _done ) {
405
+ if ( !props.length ) return _done( descriptors );
406
+ const prop = props.shift();
407
+ // ---------
408
+ function defaultDel( descriptor, status = undefined ) {
409
+ const _next = status => ( descriptor.status = status, next( descriptors.concat( descriptor ), props, _done ) );
410
+ if ( arguments.length > 1 ) return _next( descriptor, status );
411
+ const accessorizedProps = _( target, 'accessorizedProps', false );
412
+ const accessorization = accessorizedProps && accessorizedProps.get( descriptor.key + '' );
413
+ if ( accessorization && !accessorization.restore() ) _next( false );
414
+ return _next( Reflect.deleteProperty( target, descriptor.key ) );
415
+ }
416
+ // ---------
417
+ function exec( oldValue ) {
418
+ const descriptor = new Descriptor( target, {
419
+ type: 'deleteProperty',
420
+ key: prop,
421
+ oldValue,
422
+ related: [ ...related ],
423
+ detail: params.detail,
424
+ } );
425
+ const listenerRegistry = TrapsRegistry.getInstance( target, false, params.namespace );
426
+ return listenerRegistry
427
+ ? listenerRegistry.emit( descriptor, defaultDel )
428
+ : defaultDel( descriptor );
429
+ }
430
+ // ---------
431
+ return get( target, prop, exec, params );
432
+ // ---------
433
+ } )( [], props.slice( 0 ), descriptors => {
434
+ const listenerRegistry = ListenerRegistry.getInstance( target, false, params.namespace );
435
+ if ( listenerRegistry ) listenerRegistry.emit( descriptors );
436
+ return receiver(
437
+ isPropsList( prop/*original*/ ) ? descriptors.map( opr => opr.status ) : descriptors[ 0 ].status
438
+ );
439
+ } );
440
+ }
441
+
442
+ /**
443
+ * @alias deleteProperty()
444
+ */
445
+ export function deleteProperties( target, props, receiver = x => x, params = {} ) {
446
+ return deleteProperty( ...arguments );
447
+ }
448
+
449
+ /* ---------------EFFECT APIs--------------- */
450
+
451
+ /**
452
+ * Performs a "construct" operation.
453
+ *
454
+ * @param Array|Object target
455
+ * @param Array argumentsList
456
+ * @param Object newTarget
457
+ * @param Function receiver
458
+ * @param Object params
459
+ *
460
+ * @return Any
461
+ */
462
+ export function construct( target, argumentsList, newTarget = null, receiver = x => x, params = {} ) {
463
+ return exec( target, 'construct', arguments.length > 2 ? { argumentsList, newTarget } : { argumentsList }, receiver, params );
464
+ }
465
+
466
+ /**
467
+ * Performs an "apply" operation.
468
+ *
469
+ * @param Array|Object target
470
+ * @param Any thisArgument
471
+ * @param Array argumentsList
472
+ * @param Function receiver
473
+ * @param Object params
474
+ *
475
+ * @return Any
476
+ */
477
+ export function apply( target, thisArgument, argumentsList, receiver = x => x, params = {} ) {
478
+ return exec( target, 'apply', { thisArgument, argumentsList }, receiver, params );
479
+ }
480
+
481
+ /**
482
+ * Performs a "setPrototypeOf" operation.
483
+ *
484
+ * @param Array|Object target
485
+ * @param Anyr proto
486
+ * @param Function receiver
487
+ * @param Object params
488
+ *
489
+ * @return Any
490
+ */
491
+ export function setPrototypeOf( target, proto, receiver = x => x, params = {} ) {
492
+ return exec( target, 'setPrototypeOf', { proto }, receiver, params );
493
+ }
494
+
495
+ /**
496
+ * Performs a "preventExtension" operation.
497
+ *
498
+ * @param Array|Object target
499
+ * @param Function receiver
500
+ * @param Object params
501
+ *
502
+ * @return Any
503
+ */
504
+ export function preventExtensions( target, receiver = x => x, params = {} ) {
505
+ return exec( target, 'preventExtensions', {}, receiver, params );
506
+ }
507
+
508
+ /* ---------------HELPER APIs--------------- */
509
+
510
+ /**
511
+ * Adds an observer to a target's registry.
512
+ *
513
+ * @param Array|Object target
514
+ * @param String|Object prop
515
+ * @param Function receiver
516
+ * @param Object params
517
+ *
518
+ * @return Function: AbortController
519
+ */
520
+ function bind( target, prop, receiver, params = {} ) {
521
+ let controller;
522
+ if ( !params.signal ) {
523
+ controller = new AbortController;
524
+ params = { ...params, signal: controller.signal };
525
+ }
526
+ const listenerRegistry = ListenerRegistry.getInstance( target, true, params.namespace );
527
+ return function emit( descriptor_s, prevRegistration = null ) {
528
+ prevRegistration?.remove();
529
+ const registrationNext = listenerRegistry.addRegistration( prop, emit, params );
530
+ const flags = { signal: registrationNext.signal, };
531
+ if ( arguments.length ) {
532
+ receiver( descriptor_s, flags );
533
+ }
534
+ return controller;
535
+ };
536
+ }
537
+
538
+ /**
539
+ * Performs an operation of the given "type".
540
+ *
541
+ * @param Array|Object target
542
+ * @param String type
543
+ * @param Object payload
544
+ * @param Function receiver
545
+ * @param Object params
546
+ *
547
+ * @return Any
548
+ */
549
+ function exec( target, type, payload = {}, receiver = x => x, params = {} ) {
550
+ // ---------
551
+ target = resolveObj( target );
552
+ if ( _isObject( receiver ) ) { [ params, receiver ] = [ receiver, x => x ]; }
553
+ // ---------
554
+ function defaultExec( descriptor, result ) {
555
+ if ( arguments.length > 1 ) return receiver( result );
556
+ return receiver( Reflect[ type ]( target, ...Object.values( payload ) ) );
557
+ }
558
+ // ---------
559
+ const descriptor = new Descriptor( target, { type, ...payload } );
560
+ const listenerRegistry = TrapsRegistry.getInstance( target, false, params.namespace );
561
+ if ( listenerRegistry ) {
562
+ return listenerRegistry.emit( descriptor, defaultExec );
563
+ }
564
+ return defaultExec( descriptor );
565
+ }
566
+
567
+ // Asks if prop is a multi-result field
568
+ function isPropsList( prop ) {
569
+ return prop === Infinity || Array.isArray( prop );
570
+ }
571
+
572
+ // Resolves obj down to it's self
573
+ function resolveObj( obj, assert = true ) {
574
+ if ( ( !obj || !_isTypeObject( obj ) ) && assert ) throw new Error( `Object must be of type object or array! "${ _getType( obj ) }" given.` );
575
+ if ( obj instanceof Descriptor ) {
576
+ obj = obj.value;
577
+ }
578
+ return obj && unproxy( obj );
579
+ }
580
+
581
+ // Resolves prop down to actual keys
582
+ function resolveProps( obj, prop, receiver ) {
583
+ if ( prop === Infinity ) return ownKeys( obj, receiver );
584
+ return receiver( _arrFrom( prop ) );
585
+ }