@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/.gitignore +3 -3
- package/LICENSE +20 -20
- package/README.md +425 -202
- package/dist/main.js +1 -1
- package/dist/main.js.map +3 -3
- package/package.json +68 -68
- package/src/actors.js +180 -176
- package/src/core/Descriptor.js +22 -22
- package/src/core/ListenerRegistration.js +61 -57
- package/src/core/ListenerRegistry.js +73 -70
- package/src/core/Registration.js +34 -34
- package/src/core/Registry.js +92 -92
- package/src/core/TrapsRegistration.js +34 -34
- package/src/core/TrapsRegistry.js +50 -50
- package/src/index.js +9 -9
- package/src/main.js +585 -561
- package/src/targets.browser.js +8 -8
- package/src/util.js +9 -7
- package/test/reactions.test.js +351 -352
- package/webpack.config.cjs +5 -5
package/src/actors.js
CHANGED
|
@@ -1,176 +1,180 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* @imports
|
|
4
|
-
*/
|
|
5
|
-
import { _from as _arrFrom } from '@webqit/util/arr/index.js';
|
|
6
|
-
import { _isClass, _isFunction, _isTypeObject, _getType } from '@webqit/util/js/index.js';
|
|
7
|
-
import { set, deleteProperty, has, get, ownKeys, defineProperty, getOwnPropertyDescriptor } from "./main.js";
|
|
8
|
-
import { apply, construct, getPrototypeOf, setPrototypeOf, isExtensible, preventExtensions } from "./main.js";
|
|
9
|
-
import { _ } from './util.js';
|
|
10
|
-
|
|
11
|
-
/* ---------------ACCESSORIZE METHODS--------------- */
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Accessorizes props.
|
|
15
|
-
*
|
|
16
|
-
* @param Array|Object target
|
|
17
|
-
* @param String|Array props
|
|
18
|
-
* @param Object params
|
|
19
|
-
*
|
|
20
|
-
* @return Array
|
|
21
|
-
*/
|
|
22
|
-
export function accessorize( target, props, params = {} ) {
|
|
23
|
-
target = resolveTarget( target );
|
|
24
|
-
const accessorizedProps = _( target, 'accessorizedProps' );
|
|
25
|
-
// ---------
|
|
26
|
-
function getDescriptorDeep( prop ) {
|
|
27
|
-
let descriptor, proto = target;
|
|
28
|
-
|
|
29
|
-
descriptor = Object.getOwnPropertyDescriptor( proto, prop );
|
|
30
|
-
}
|
|
31
|
-
return descriptor
|
|
32
|
-
? { proto, descriptor }
|
|
33
|
-
: { descriptor: { value: undefined } };
|
|
34
|
-
}
|
|
35
|
-
// ---------
|
|
36
|
-
function accessorizeProp( prop ) {
|
|
37
|
-
if ( accessorizedProps.has( prop ) ) return true;
|
|
38
|
-
// ------------------
|
|
39
|
-
// Current Descriptor Record
|
|
40
|
-
const currentDescriptorRecord = getDescriptorDeep( prop );
|
|
41
|
-
currentDescriptorRecord.getValue = function() {
|
|
42
|
-
return
|
|
43
|
-
};
|
|
44
|
-
currentDescriptorRecord.setValue = function( value ) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
&&
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if ( this.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* @param
|
|
94
|
-
* @param
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
* @param Object
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
*
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
*
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* @imports
|
|
4
|
+
*/
|
|
5
|
+
import { _from as _arrFrom } from '@webqit/util/arr/index.js';
|
|
6
|
+
import { _isClass, _isFunction, _isTypeObject, _getType } from '@webqit/util/js/index.js';
|
|
7
|
+
import { set, deleteProperty, has, get, ownKeys, defineProperty, getOwnPropertyDescriptor } from "./main.js";
|
|
8
|
+
import { batch, apply, construct, getPrototypeOf, setPrototypeOf, isExtensible, preventExtensions } from "./main.js";
|
|
9
|
+
import { _ } from './util.js';
|
|
10
|
+
|
|
11
|
+
/* ---------------ACCESSORIZE METHODS--------------- */
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Accessorizes props.
|
|
15
|
+
*
|
|
16
|
+
* @param Array|Object target
|
|
17
|
+
* @param String|Array props
|
|
18
|
+
* @param Object params
|
|
19
|
+
*
|
|
20
|
+
* @return Array
|
|
21
|
+
*/
|
|
22
|
+
export function accessorize( target, props, params = {} ) {
|
|
23
|
+
target = resolveTarget( target );
|
|
24
|
+
const accessorizedProps = _( target, 'accessorizedProps' );
|
|
25
|
+
// ---------
|
|
26
|
+
function getDescriptorDeep( prop ) {
|
|
27
|
+
let descriptor, proto = target;
|
|
28
|
+
do {
|
|
29
|
+
descriptor = Object.getOwnPropertyDescriptor( proto, prop );
|
|
30
|
+
} while ( !descriptor && ( proto = Object.getPrototypeOf( proto ) ) );
|
|
31
|
+
return descriptor
|
|
32
|
+
? { proto, descriptor }
|
|
33
|
+
: { descriptor: { value: undefined, configurable: true, enumerable: true, writable: true } };
|
|
34
|
+
}
|
|
35
|
+
// ---------
|
|
36
|
+
function accessorizeProp( prop ) {
|
|
37
|
+
if ( accessorizedProps.has( prop + '' ) ) return true;
|
|
38
|
+
// ------------------
|
|
39
|
+
// Current Descriptor Record
|
|
40
|
+
const currentDescriptorRecord = getDescriptorDeep( prop );
|
|
41
|
+
currentDescriptorRecord.getValue = function() {
|
|
42
|
+
return this.descriptor.get ? this.descriptor.get() : this.descriptor.value;
|
|
43
|
+
};
|
|
44
|
+
currentDescriptorRecord.setValue = function( value ) {
|
|
45
|
+
this.dirty = true;
|
|
46
|
+
return this.descriptor.set ? this.descriptor.set( value ) !== false : ( this.descriptor.value = value, true );
|
|
47
|
+
};
|
|
48
|
+
currentDescriptorRecord.intact = function() {
|
|
49
|
+
const currentDescriptor = Object.getOwnPropertyDescriptor( target, prop );
|
|
50
|
+
return currentDescriptor?.get === accessorization.get
|
|
51
|
+
&& currentDescriptor?.set === accessorization.set
|
|
52
|
+
&& accessorizedProps.get( prop + '' ) === this;
|
|
53
|
+
};
|
|
54
|
+
currentDescriptorRecord.restore = function() {
|
|
55
|
+
if ( !this.intact() ) return false;
|
|
56
|
+
if ( ( this.proto && this.proto !== target ) || ( !this.proto && !this.dirty ) ) { delete target[ prop ]; }
|
|
57
|
+
else { Object.defineProperty( target, prop, this.descriptor ); }
|
|
58
|
+
accessorizedProps.delete( prop + '' );
|
|
59
|
+
return true;
|
|
60
|
+
};
|
|
61
|
+
accessorizedProps.set( prop + '', currentDescriptorRecord );
|
|
62
|
+
// ------------------
|
|
63
|
+
// enumerable, configurable
|
|
64
|
+
const { enumerable = true } = currentDescriptorRecord.descriptor;
|
|
65
|
+
const accessorization = { enumerable, configurable: true };
|
|
66
|
+
// set, get
|
|
67
|
+
if ( ( 'value' in currentDescriptorRecord.descriptor ) || currentDescriptorRecord.descriptor.set ) {
|
|
68
|
+
accessorization.set = function ( value ) { return set( this, prop, value, params ); };
|
|
69
|
+
}
|
|
70
|
+
if ( ( 'value' in currentDescriptorRecord.descriptor ) || currentDescriptorRecord.descriptor.get ) {
|
|
71
|
+
accessorization.get = function () { return get( this, prop, params ); };
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
Object.defineProperty( target, prop, accessorization );
|
|
75
|
+
return true;
|
|
76
|
+
} catch( e ) {
|
|
77
|
+
accessorizedProps.delete( prop + '' );
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const _props = Array.isArray( props ) ? props : (
|
|
82
|
+
props === undefined ? Object.keys( target ) : [ props ]
|
|
83
|
+
);
|
|
84
|
+
const statuses = _props.map( accessorizeProp );
|
|
85
|
+
return props === undefined || Array.isArray( props )
|
|
86
|
+
? statuses
|
|
87
|
+
: statuses[ 0 ];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Unaccessorizes previously accessorized props.
|
|
92
|
+
*
|
|
93
|
+
* @param Array|Object target
|
|
94
|
+
* @param String|Array props
|
|
95
|
+
* @param Object params
|
|
96
|
+
*
|
|
97
|
+
* @return Array
|
|
98
|
+
*/
|
|
99
|
+
export function unaccessorize( target, props, params = {} ) {
|
|
100
|
+
target = resolveTarget( target );
|
|
101
|
+
const accessorizedProps = _( target, 'accessorizedProps' );
|
|
102
|
+
function unaccessorizeProp( prop ) {
|
|
103
|
+
if ( !accessorizedProps.has( prop + '' ) ) return true;
|
|
104
|
+
return accessorizedProps.get( prop + '' ).restore();
|
|
105
|
+
}
|
|
106
|
+
const _props = Array.isArray( props ) ? props : (
|
|
107
|
+
props === undefined ? Object.keys( target ) : [ props ]
|
|
108
|
+
);
|
|
109
|
+
const statuses = _props.map( unaccessorizeProp );
|
|
110
|
+
return props === undefined || Array.isArray( props )
|
|
111
|
+
? statuses
|
|
112
|
+
: statuses[ 0 ];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* ---------------PROXY METHODS--------------- */
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Returns an object as a proxy and binds all instance methods
|
|
119
|
+
* to the proxy instead of the object itself.
|
|
120
|
+
*
|
|
121
|
+
* @param Array|Object target
|
|
122
|
+
* @param Object params
|
|
123
|
+
*
|
|
124
|
+
* @return Proxy
|
|
125
|
+
*/
|
|
126
|
+
export function proxy( target, params = {} ) {
|
|
127
|
+
target = resolveTarget( target );
|
|
128
|
+
const proxy = new Proxy( target, {
|
|
129
|
+
apply: ( target, thisArgument, argumentsList ) => apply( target, thisArgument, argumentsList, params ),
|
|
130
|
+
construct: ( target, argumentsList, newTarget = null ) => construct( target, argumentsList, newTarget, params ),
|
|
131
|
+
defineProperty: ( target, propertyKey, attributes ) => defineProperty( target, propertyKey, attributes, params ),
|
|
132
|
+
deleteProperty: ( target, propertyKey ) => deleteProperty( target, propertyKey, params ),
|
|
133
|
+
get: ( target, propertyKey, receiver = null ) => {
|
|
134
|
+
const val = get( target, propertyKey, { ...params, receiver } );
|
|
135
|
+
if ( params.proxyAutoBinding !== false && _isFunction( val ) && !_isClass( val )) {
|
|
136
|
+
return function( ...args ) {
|
|
137
|
+
const _this = this || proxy;
|
|
138
|
+
return batch( _this, () => val.call( _this, ...args ) );
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return val;
|
|
142
|
+
},
|
|
143
|
+
getOwnPropertyDescriptor: ( target, propertyKey ) => getOwnPropertyDescriptor( target, propertyKey, params ),
|
|
144
|
+
getPrototypeOf: target => getPrototypeOf( target, params ),
|
|
145
|
+
has: ( target, propertyKey ) => has( target, propertyKey, params ),
|
|
146
|
+
isExtensible: target => isExtensible( target, params ),
|
|
147
|
+
ownKeys: target => ownKeys( target, params ),
|
|
148
|
+
preventExtensions: target => preventExtensions( target, params ),
|
|
149
|
+
set: ( target, propertyKey, value, receiver = null ) => set( target, propertyKey, value, { ...params, receiver } ),
|
|
150
|
+
setPrototypeOf: ( target, prototype ) => setPrototypeOf( target, prototype, params ),
|
|
151
|
+
});
|
|
152
|
+
_( proxy ).set( proxy, target );
|
|
153
|
+
return proxy;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Returns the original object earlier proxied by proxy().
|
|
158
|
+
*
|
|
159
|
+
* @param Proxy|Any target
|
|
160
|
+
*
|
|
161
|
+
* @return Any
|
|
162
|
+
*/
|
|
163
|
+
export function unproxy( target ) {
|
|
164
|
+
// Proxy targets are mapped to their own instances internally
|
|
165
|
+
return _( target ).get( target ) || target;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* ---------------HELPERS--------------- */
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Ensures target object is an object or array.
|
|
172
|
+
*
|
|
173
|
+
* @param Array|Object target
|
|
174
|
+
*
|
|
175
|
+
* @return Array|Object
|
|
176
|
+
*/
|
|
177
|
+
function resolveTarget( target ) {
|
|
178
|
+
if ( !target || !_isTypeObject( target ) ) throw new Error('Target must be of type object!');
|
|
179
|
+
return unproxy( target );
|
|
180
|
+
}
|
package/src/core/Descriptor.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* ---------------------------
|
|
4
|
-
* The Descriptor class
|
|
5
|
-
* ---------------------------
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export default class Descriptor {
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Initializes the instance.
|
|
12
|
-
*
|
|
13
|
-
* @param array|object target
|
|
14
|
-
* @param object dfn
|
|
15
|
-
*
|
|
16
|
-
* @return void
|
|
17
|
-
*/
|
|
18
|
-
constructor( target, dfn ) {
|
|
19
|
-
this.target = target;
|
|
20
|
-
if ( !( dfn.type ) ) throw new Error( 'Descriptor type must be given in definition!' );
|
|
21
|
-
Object.assign( this, dfn );
|
|
22
|
-
}
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* ---------------------------
|
|
4
|
+
* The Descriptor class
|
|
5
|
+
* ---------------------------
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export default class Descriptor {
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Initializes the instance.
|
|
12
|
+
*
|
|
13
|
+
* @param array|object target
|
|
14
|
+
* @param object dfn
|
|
15
|
+
*
|
|
16
|
+
* @return void
|
|
17
|
+
*/
|
|
18
|
+
constructor( target, dfn ) {
|
|
19
|
+
this.target = target;
|
|
20
|
+
if ( !( dfn.type ) ) throw new Error( 'Descriptor type must be given in definition!' );
|
|
21
|
+
Object.assign( this, dfn );
|
|
22
|
+
}
|
|
23
23
|
}
|
|
@@ -1,57 +1,61 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* @imports
|
|
4
|
-
*/
|
|
5
|
-
import { _from as _arrFrom } from '@webqit/util/arr/index.js';
|
|
6
|
-
import Registration from './Registration.js';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* ---------------------------
|
|
10
|
-
* The ListenerRegistration class
|
|
11
|
-
* ---------------------------
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
export default class ListenerRegistration extends Registration {
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* @constructor
|
|
18
|
-
*/
|
|
19
|
-
constructor() {
|
|
20
|
-
super( ...arguments );
|
|
21
|
-
Object.defineProperty( this, 'abortController', { value: new AbortController } );
|
|
22
|
-
Object.defineProperty( this, 'signal', { value: this.abortController.signal } );
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* De-registers the instance.
|
|
27
|
-
*
|
|
28
|
-
* @return Void
|
|
29
|
-
*/
|
|
30
|
-
remove() {
|
|
31
|
-
this.abortController.abort();
|
|
32
|
-
super.remove();
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Calls the observer's handler function
|
|
37
|
-
* on matching with the event's fields.
|
|
38
|
-
*
|
|
39
|
-
* @param Array events
|
|
40
|
-
*
|
|
41
|
-
* @return Any
|
|
42
|
-
*/
|
|
43
|
-
fire( events ) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* @imports
|
|
4
|
+
*/
|
|
5
|
+
import { _from as _arrFrom } from '@webqit/util/arr/index.js';
|
|
6
|
+
import Registration from './Registration.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* ---------------------------
|
|
10
|
+
* The ListenerRegistration class
|
|
11
|
+
* ---------------------------
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
export default class ListenerRegistration extends Registration {
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @constructor
|
|
18
|
+
*/
|
|
19
|
+
constructor() {
|
|
20
|
+
super( ...arguments );
|
|
21
|
+
Object.defineProperty( this, 'abortController', { value: new AbortController } );
|
|
22
|
+
Object.defineProperty( this, 'signal', { value: this.abortController.signal } );
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* De-registers the instance.
|
|
27
|
+
*
|
|
28
|
+
* @return Void
|
|
29
|
+
*/
|
|
30
|
+
remove() {
|
|
31
|
+
this.abortController.abort();
|
|
32
|
+
super.remove();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Calls the observer's handler function
|
|
37
|
+
* on matching with the event's fields.
|
|
38
|
+
*
|
|
39
|
+
* @param Array events
|
|
40
|
+
*
|
|
41
|
+
* @return Any
|
|
42
|
+
*/
|
|
43
|
+
fire( events ) {
|
|
44
|
+
if ( this.handler.firing ) return;
|
|
45
|
+
let matches = events, filter = this.filter;
|
|
46
|
+
if ( filter !== Infinity && ( filter = _arrFrom( filter ) ) ) {
|
|
47
|
+
matches = events.filter( event => filter.includes( event.key ) );
|
|
48
|
+
}
|
|
49
|
+
if ( this.params.diff ) {
|
|
50
|
+
matches = matches.filter( event => event.type !== 'set' || event.value !== event.oldValue );
|
|
51
|
+
}
|
|
52
|
+
if ( matches.length ) {
|
|
53
|
+
this.handler.firing = true;
|
|
54
|
+
const ret = this.filter === Infinity || Array.isArray( this.filter )
|
|
55
|
+
? this.handler( matches, this )
|
|
56
|
+
: this.handler( matches[ 0 ], this );
|
|
57
|
+
this.handler.firing = false;
|
|
58
|
+
return ret;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|