@schukai/monster 3.2.0 → 3.4.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/README.md +1 -1
- package/package.json +1 -1
- package/source/data/datasource/{restapi.mjs → server/restapi.mjs} +63 -88
- package/source/data/datasource/server/webconnect.mjs +201 -0
- package/source/data/datasource/server.mjs +108 -0
- package/source/i18n/locale.mjs +1 -1
- package/source/monster.mjs +11 -3
- package/source/net/webconnect/message.mjs +55 -0
- package/source/{data/datasource/websocket.mjs → net/webconnect.mjs} +109 -148
- package/source/types/global.mjs +2 -2
- package/source/types/mediatype.mjs +1 -1
- package/source/types/observablequeue.mjs +110 -0
- package/source/types/proxyobserver.mjs +2 -2
- package/source/types/uniquequeue.mjs +9 -6
- package/source/types/version.mjs +1 -1
- package/test/cases/data/datasource/{restapi.mjs → server/restapi.mjs} +19 -13
- package/test/cases/data/datasource/server/websocket.mjs +194 -0
- package/test/cases/data/datasource/server.mjs +53 -0
- package/test/cases/monster.mjs +1 -1
- package/test/cases/net/webconnect/message.mjs +50 -0
- package/test/cases/net/webconnect.mjs +116 -0
- package/test/cases/types/observablequeue.mjs +17 -0
- package/test/cases/types/queue.mjs +4 -1
- package/test/web/import.js +6 -2
- package/test/web/test.html +3 -3
- package/test/web/tests.js +891 -393
- package/test/cases/data/datasource/websocket.mjs +0 -107
@@ -0,0 +1,55 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright schukai GmbH and contributors 2022. All Rights Reserved.
|
3
|
+
* Node module: @schukai/monster
|
4
|
+
* This file is licensed under the AGPLv3 License.
|
5
|
+
* License text available at https://www.gnu.org/licenses/agpl-3.0.en.html
|
6
|
+
*/
|
7
|
+
|
8
|
+
import {Base} from "../../types/base.mjs";
|
9
|
+
import {validateObject, validateString} from "../../types/validate.mjs";
|
10
|
+
|
11
|
+
export {Message}
|
12
|
+
|
13
|
+
const dataSymbol = Symbol("@@data");
|
14
|
+
|
15
|
+
/**
|
16
|
+
* This class represents a WebSocket message.
|
17
|
+
*/
|
18
|
+
class Message extends Base {
|
19
|
+
|
20
|
+
/**
|
21
|
+
* @param {Object} data
|
22
|
+
* @throws {TypeError} value is not a object
|
23
|
+
*/
|
24
|
+
constructor(data) {
|
25
|
+
super();
|
26
|
+
this[dataSymbol] = validateObject(data);
|
27
|
+
}
|
28
|
+
|
29
|
+
/**
|
30
|
+
* Returns the raw message.
|
31
|
+
*
|
32
|
+
* @returns {object}
|
33
|
+
*/
|
34
|
+
getData() {
|
35
|
+
return this[dataSymbol];
|
36
|
+
}
|
37
|
+
|
38
|
+
/**
|
39
|
+
* @returns {*}
|
40
|
+
*/
|
41
|
+
toJSON() {
|
42
|
+
return this[dataSymbol];
|
43
|
+
}
|
44
|
+
|
45
|
+
/**
|
46
|
+
* @param {string} json
|
47
|
+
* @returns {Message}
|
48
|
+
* @throws {TypeError} value is not a string
|
49
|
+
*/
|
50
|
+
static fromJSON(json) {
|
51
|
+
validateString(json);
|
52
|
+
return new Message(JSON.parse(json));
|
53
|
+
}
|
54
|
+
|
55
|
+
}
|
@@ -5,21 +5,25 @@
|
|
5
5
|
* License text available at https://www.gnu.org/licenses/agpl-3.0.en.html
|
6
6
|
*/
|
7
7
|
|
8
|
-
import {
|
9
|
-
import {isInteger, isString, isObject} from "
|
10
|
-
import {
|
11
|
-
import {
|
12
|
-
import {
|
13
|
-
import {Pipe} from "../pipe.mjs";
|
8
|
+
import {instanceSymbol} from "../constants.mjs";
|
9
|
+
import {isInteger, isString, isObject} from "../types/is.mjs";
|
10
|
+
import {BaseWithOptions} from "../types/basewithoptions.mjs";
|
11
|
+
import {ObservableQueue} from "../types/observablequeue.mjs";
|
12
|
+
import {Message} from "./webconnect/message.mjs";
|
14
13
|
|
15
|
-
|
14
|
+
|
15
|
+
export {WebConnect}
|
16
16
|
|
17
17
|
/**
|
18
18
|
* @private
|
19
19
|
* @type {Symbol}
|
20
20
|
*/
|
21
|
-
const receiveQueueSymbol = Symbol("
|
22
|
-
|
21
|
+
const receiveQueueSymbol = Symbol("receiveQueue");
|
22
|
+
/**
|
23
|
+
* @private
|
24
|
+
* @type {Symbol}
|
25
|
+
*/
|
26
|
+
const sendQueueSymbol = Symbol("sendQueue");
|
23
27
|
|
24
28
|
/**
|
25
29
|
* @private
|
@@ -36,6 +40,7 @@ const connectionSymbol = Symbol("connection");
|
|
36
40
|
const manualCloseSymbol = Symbol("manualClose");
|
37
41
|
|
38
42
|
/**
|
43
|
+
* @private
|
39
44
|
* @see https://www.rfc-editor.org/rfc/rfc6455.html#section-7.4.1
|
40
45
|
* @type {{"1000": string, "1011": string, "1010": string, "1008": string, "1007": string, "1006": string, "1005": string, "1004": string, "1015": string, "1003": string, "1002": string, "1001": string, "1009": string}}
|
41
46
|
*/
|
@@ -57,13 +62,20 @@ const connectionStatusCode = {
|
|
57
62
|
|
58
63
|
/**
|
59
64
|
* @private
|
60
|
-
* @this {
|
65
|
+
* @this {WebConnect}
|
61
66
|
* @throws {Error} No url defined for websocket datasource.
|
62
67
|
*/
|
63
68
|
function connectServer(resolve, reject) {
|
64
69
|
const self = this;
|
65
70
|
|
71
|
+
const url = self.getOption('url');
|
72
|
+
if (!url) {
|
73
|
+
reject('No url defined for webconnect.');
|
74
|
+
return;
|
75
|
+
}
|
76
|
+
|
66
77
|
let promiseAllredyResolved = false;
|
78
|
+
|
67
79
|
let connectionTimeout = self.getOption('connection.timeout');
|
68
80
|
if (!isInteger(connectionTimeout) || connectionTimeout < 100) {
|
69
81
|
connectionTimeout = 5000;
|
@@ -90,20 +102,18 @@ function connectServer(resolve, reject) {
|
|
90
102
|
self[connectionSymbol].socket.close();
|
91
103
|
}
|
92
104
|
self[connectionSymbol].socket = null;
|
93
|
-
|
94
|
-
const url = self.getOption('url');
|
95
|
-
if (!url) {
|
96
|
-
reject('No url defined for websocket datasource.');
|
97
|
-
return;
|
98
|
-
}
|
99
|
-
|
100
105
|
self[connectionSymbol].socket = new WebSocket(url);
|
101
106
|
|
102
107
|
self[connectionSymbol].socket.onmessage = function (event) {
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
108
|
+
if (event.data instanceof Blob) {
|
109
|
+
const reader = new FileReader();
|
110
|
+
reader.addEventListener("loadend", function () {
|
111
|
+
self[receiveQueueSymbol].add(new Message(reader.result))
|
112
|
+
});
|
113
|
+
reader.readAsText(new Message(event.data));
|
114
|
+
} else {
|
115
|
+
self[receiveQueueSymbol].add(Message.fromJSON(event.data));
|
116
|
+
}
|
107
117
|
};
|
108
118
|
|
109
119
|
self[connectionSymbol].socket.onopen = function () {
|
@@ -155,22 +165,22 @@ function connectServer(resolve, reject) {
|
|
155
165
|
* @memberOf Monster.Data.Datasource
|
156
166
|
* @summary The LocalStorage class encapsulates the access to data objects.
|
157
167
|
*/
|
158
|
-
class
|
168
|
+
class WebConnect extends BaseWithOptions {
|
159
169
|
|
160
170
|
/**
|
161
171
|
*
|
162
172
|
* @param {Object} [options] options contains definitions for the datasource.
|
163
173
|
*/
|
164
174
|
constructor(options) {
|
165
|
-
super();
|
166
175
|
|
167
176
|
if (isString(options)) {
|
168
177
|
options = {url: options};
|
169
178
|
}
|
179
|
+
|
180
|
+
super(options);
|
170
181
|
|
171
|
-
|
172
|
-
this
|
173
|
-
this[receiveQueueSymbol] = new Queue();
|
182
|
+
this[receiveQueueSymbol] = new ObservableQueue();
|
183
|
+
this[sendQueueSymbol] = new ObservableQueue();
|
174
184
|
|
175
185
|
this[connectionSymbol] = {};
|
176
186
|
this[connectionSymbol].socket = null;
|
@@ -194,7 +204,7 @@ class WebSocketDatasource extends Datasource {
|
|
194
204
|
* @returns {boolean}
|
195
205
|
*/
|
196
206
|
isConnected() {
|
197
|
-
|
207
|
+
return this[connectionSymbol]?.socket?.readyState === 1;
|
198
208
|
}
|
199
209
|
|
200
210
|
/**
|
@@ -202,7 +212,7 @@ class WebSocketDatasource extends Datasource {
|
|
202
212
|
* @returns {symbol}
|
203
213
|
*/
|
204
214
|
static get [instanceSymbol]() {
|
205
|
-
return Symbol.for("@schukai/monster/
|
215
|
+
return Symbol.for("@schukai/monster/net/webconnect");
|
206
216
|
}
|
207
217
|
|
208
218
|
/**
|
@@ -212,42 +222,10 @@ class WebSocketDatasource extends Datasource {
|
|
212
222
|
* @property {Number} connection.reconnect.timeout The timeout in milliseconds for the reconnect.
|
213
223
|
* @property {Number} connection.reconnect.attempts The maximum number of reconnects.
|
214
224
|
* @property {Bool} connection.reconnect.enabled If the reconnect is enabled.
|
215
|
-
* @property {Object} write={} Options
|
216
|
-
* @property {Object} write.mapping the mapping is applied before writing.
|
217
|
-
* @property {String} write.mapping.transformer Transformer to select the appropriate entries
|
218
|
-
* @property {Monster.Data.Datasource~exampleCallback[]} write.mapping.callback with the help of the callback, the structures can be adjusted before writing.
|
219
|
-
* @property {Object} write.report
|
220
|
-
* @property {String} write.report.path Path to validations
|
221
|
-
* @property {Object} write.sheathing
|
222
|
-
* @property {Object} write.sheathing.object Object to be wrapped
|
223
|
-
* @property {string} write.sheathing.path Path to the data
|
224
|
-
* @property {Object} read={} Options
|
225
|
-
* @property {Object} read.mapping the mapping is applied after reading.
|
226
|
-
* @property {String} read.mapping.transformer Transformer to select the appropriate entries
|
227
|
-
* @property {Monster.Data.Datasource~exampleCallback[]} read.mapping.callback with the help of the callback, the structures can be adjusted after reading.
|
228
225
|
*/
|
229
226
|
get defaults() {
|
230
227
|
return Object.assign({}, super.defaults, {
|
231
228
|
url: undefined,
|
232
|
-
write: {
|
233
|
-
mapping: {
|
234
|
-
transformer: undefined,
|
235
|
-
callbacks: []
|
236
|
-
},
|
237
|
-
report: {
|
238
|
-
path: undefined
|
239
|
-
},
|
240
|
-
sheathing: {
|
241
|
-
object: undefined,
|
242
|
-
path: undefined,
|
243
|
-
},
|
244
|
-
},
|
245
|
-
read: {
|
246
|
-
mapping: {
|
247
|
-
transformer: undefined,
|
248
|
-
callbacks: []
|
249
|
-
},
|
250
|
-
},
|
251
229
|
connection: {
|
252
230
|
timeout: 5000,
|
253
231
|
reconnect: {
|
@@ -262,124 +240,107 @@ class WebSocketDatasource extends Datasource {
|
|
262
240
|
/**
|
263
241
|
* This method closes the connection.
|
264
242
|
*
|
243
|
+
* @param {Number} [code=1000] The close code.
|
244
|
+
* @param {String} [reason=""] The close reason.
|
265
245
|
* @returns {Promise}
|
246
|
+
* @see https://www.rfc-editor.org/rfc/rfc6455.html#section-7.4.1
|
266
247
|
*/
|
267
|
-
close() {
|
268
|
-
|
269
|
-
|
270
|
-
this[connectionSymbol].socket.close();
|
248
|
+
close(statusCode, reason ) {
|
249
|
+
if (!isInteger(statusCode) || statusCode < 1000 || statusCode > 4999) {
|
250
|
+
statusCode = 1000;
|
271
251
|
}
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
/**
|
276
|
-
* @return {Promise}
|
277
|
-
*/
|
278
|
-
read() {
|
279
|
-
const self = this;
|
280
|
-
let response;
|
281
|
-
|
282
|
-
if (self[connectionSymbol]?.socket?.readyState !== 1) {
|
283
|
-
return Promise.reject('The connection is not established.');
|
252
|
+
if (!isString(reason)) {
|
253
|
+
reason = '';
|
284
254
|
}
|
285
255
|
|
286
256
|
return new Promise((resolve, reject) => {
|
287
|
-
|
288
|
-
|
257
|
+
try {
|
258
|
+
this[manualCloseSymbol] = true;
|
259
|
+
if (this[connectionSymbol].socket) {
|
260
|
+
this[connectionSymbol].socket.close(statusCode, reason);
|
261
|
+
}
|
262
|
+
} catch (error) {
|
263
|
+
reject(error);
|
289
264
|
}
|
265
|
+
resolve();
|
266
|
+
});
|
290
267
|
|
291
|
-
|
292
|
-
|
293
|
-
const event = self[receiveQueueSymbol].poll();
|
294
|
-
const body = event?.data;
|
295
|
-
if (!body) continue;
|
296
|
-
|
297
|
-
let obj;
|
298
|
-
try {
|
299
|
-
obj = JSON.parse(body);
|
300
|
-
} catch (e) {
|
301
|
-
|
302
|
-
let msg = 'the response does not contain a valid json (actual: ';
|
303
|
-
|
304
|
-
if (body.length > 100) {
|
305
|
-
msg += body.substring(0, 97) + '...';
|
306
|
-
} else {
|
307
|
-
msg += body;
|
308
|
-
}
|
268
|
+
}
|
309
269
|
|
310
|
-
|
270
|
+
/**
|
271
|
+
* Polls the receive queue for new messages.
|
272
|
+
*
|
273
|
+
* @returns {Message}
|
274
|
+
*/
|
275
|
+
poll() {
|
276
|
+
return this[receiveQueueSymbol].poll();
|
277
|
+
}
|
311
278
|
|
312
|
-
|
313
|
-
|
279
|
+
/**
|
280
|
+
* Are there any messages in the receive queue?
|
281
|
+
*
|
282
|
+
* @returns {boolean}
|
283
|
+
*/
|
284
|
+
dataReceived() {
|
285
|
+
return !this[receiveQueueSymbol].isEmpty();
|
286
|
+
}
|
314
287
|
|
315
|
-
|
316
|
-
|
317
|
-
|
288
|
+
/**
|
289
|
+
* Get Message from the receive queue, but do not remove it.
|
290
|
+
*
|
291
|
+
* @returns {Object}
|
292
|
+
*/
|
293
|
+
peek() {
|
294
|
+
return this[receiveQueueSymbol].peek();
|
295
|
+
}
|
318
296
|
|
319
|
-
|
320
|
-
|
321
|
-
|
297
|
+
/**
|
298
|
+
* Attach a new observer
|
299
|
+
*
|
300
|
+
* @param {Observer} observer
|
301
|
+
* @returns {ProxyObserver}
|
302
|
+
*/
|
303
|
+
attachObserver(observer) {
|
304
|
+
this[receiveQueueSymbol].attachObserver(observer);
|
305
|
+
return this;
|
306
|
+
}
|
322
307
|
|
323
|
-
|
324
|
-
|
308
|
+
/**
|
309
|
+
* Detach a observer
|
310
|
+
*
|
311
|
+
* @param {Observer} observer
|
312
|
+
* @returns {ProxyObserver}
|
313
|
+
*/
|
314
|
+
detachObserver(observer) {
|
315
|
+
this[receiveQueueSymbol].detachObserver(observer);
|
316
|
+
return this;
|
317
|
+
}
|
325
318
|
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
319
|
+
/**
|
320
|
+
* @param {Observer} observer
|
321
|
+
* @returns {boolean}
|
322
|
+
*/
|
323
|
+
containsObserver(observer) {
|
324
|
+
return this[receiveQueueSymbol].containsObserver(observer);
|
330
325
|
}
|
331
326
|
|
332
327
|
/**
|
328
|
+
* @param {Message|Object} message
|
333
329
|
* @return {Promise}
|
334
330
|
*/
|
335
|
-
|
331
|
+
send(message) {
|
336
332
|
const self = this;
|
337
333
|
|
338
|
-
if (self[connectionSymbol]?.socket?.readyState !== 1) {
|
339
|
-
return Promise.reject('The connection is not established.');
|
340
|
-
}
|
341
|
-
|
342
|
-
let obj = self.get();
|
343
|
-
let transformation = self.getOption('write.mapping.transformer');
|
344
|
-
if (transformation !== undefined) {
|
345
|
-
const pipe = new Pipe(transformation);
|
346
|
-
|
347
|
-
for (const callback of self.getOption('write.mapping.callbacks')) {
|
348
|
-
pipe.setCallback(callback.constructor.name, callback);
|
349
|
-
}
|
350
|
-
|
351
|
-
obj = pipe.run(obj);
|
352
|
-
}
|
353
|
-
|
354
|
-
let sheathingObject = self.getOption('write.sheathing.object');
|
355
|
-
let sheathingPath = self.getOption('write.sheathing.path');
|
356
|
-
let reportPath = self.getOption('write.report.path');
|
357
|
-
|
358
|
-
if (sheathingObject && sheathingPath) {
|
359
|
-
const sub = obj;
|
360
|
-
obj = sheathingObject;
|
361
|
-
(new Pathfinder(obj)).setVia(sheathingPath, sub);
|
362
|
-
}
|
363
|
-
|
364
334
|
return new Promise((resolve, reject) => {
|
365
335
|
|
366
336
|
if (self[connectionSymbol].socket.readyState !== 1) {
|
367
337
|
reject('the socket is not ready');
|
368
338
|
}
|
369
339
|
|
370
|
-
self[connectionSymbol].socket.send(JSON.stringify(
|
340
|
+
self[connectionSymbol].socket.send(JSON.stringify(message))
|
371
341
|
resolve();
|
372
342
|
});
|
373
343
|
}
|
374
344
|
|
375
|
-
|
376
|
-
/**
|
377
|
-
* @return {RestAPI}
|
378
|
-
*/
|
379
|
-
getClone() {
|
380
|
-
const self = this;
|
381
|
-
return new WebSocketDatasource(self[internalSymbol].getRealSubject()['options']);
|
382
|
-
}
|
383
|
-
|
384
345
|
}
|
385
346
|
|
package/source/types/global.mjs
CHANGED
@@ -84,7 +84,7 @@ function getGlobal() {
|
|
84
84
|
*
|
85
85
|
* ```
|
86
86
|
* <script type="module">
|
87
|
-
* import {Monster} from '
|
87
|
+
* import {Monster} from '@schukai/monster/source/monster.mjs';
|
88
88
|
* Monster.Types.getGlobalObject('document')
|
89
89
|
* // ↦ { }
|
90
90
|
* </script>
|
@@ -124,7 +124,7 @@ function getGlobalObject(name) {
|
|
124
124
|
*
|
125
125
|
* ```
|
126
126
|
* <script type="module">
|
127
|
-
* import {Monster} from '
|
127
|
+
* import {Monster} from '@schukai/monster/source/monster.mjs';
|
128
128
|
* console.log(Monster.Types.getGlobalFunction('parseInt')) // ↦ f parseInt() { }
|
129
129
|
* </script>
|
130
130
|
* ```
|
@@ -134,7 +134,7 @@ class MediaType extends Base {
|
|
134
134
|
*
|
135
135
|
* ```
|
136
136
|
* <script type="module">
|
137
|
-
* import {Monster} from '@schukai/monster/source
|
137
|
+
* import {Monster} from '@schukai/monster/source/monster.mjs';
|
138
138
|
* console.log(Monster.Types.parseMediaType())
|
139
139
|
* </script>
|
140
140
|
* ```
|
@@ -0,0 +1,110 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright schukai GmbH and contributors 2022. All Rights Reserved.
|
3
|
+
* Node module: @schukai/monster
|
4
|
+
* This file is licensed under the AGPLv3 License.
|
5
|
+
* License text available at https://www.gnu.org/licenses/agpl-3.0.en.html
|
6
|
+
*/
|
7
|
+
|
8
|
+
import {Queue} from './queue.mjs';
|
9
|
+
import {instanceSymbol, internalSymbol} from '../constants.mjs';
|
10
|
+
import {ObserverList} from "./observerlist.mjs";
|
11
|
+
|
12
|
+
export {ObservableQueue};
|
13
|
+
|
14
|
+
/**
|
15
|
+
* An observable queue is a list of items that are processed one after another (first in, first out).
|
16
|
+
*
|
17
|
+
* `Queue.add()` and `Queue.clear()` notify all observers.
|
18
|
+
*
|
19
|
+
* @externalExample ../../example/types/queue.mjs
|
20
|
+
* @license AGPLv3
|
21
|
+
* @since 3.3.0
|
22
|
+
* @copyright schukai GmbH
|
23
|
+
* @memberOf Monster.Types
|
24
|
+
* @summary An observable Queue (Fifo)
|
25
|
+
*/
|
26
|
+
class ObservableQueue extends Queue {
|
27
|
+
|
28
|
+
/**
|
29
|
+
*
|
30
|
+
*/
|
31
|
+
constructor() {
|
32
|
+
super();
|
33
|
+
this[internalSymbol]= {
|
34
|
+
observers: new ObserverList()
|
35
|
+
};
|
36
|
+
}
|
37
|
+
|
38
|
+
/**
|
39
|
+
* This method is called by the `instanceof` operator.
|
40
|
+
* @returns {symbol}
|
41
|
+
* @since 2.1.0
|
42
|
+
*/
|
43
|
+
static get [instanceSymbol]() {
|
44
|
+
return Symbol.for("@schukai/monster/types/observablequeue");
|
45
|
+
}
|
46
|
+
|
47
|
+
/**
|
48
|
+
* Add a new element to the end of the queue.
|
49
|
+
*
|
50
|
+
* @param {*} value
|
51
|
+
* @returns {Queue}
|
52
|
+
*/
|
53
|
+
add(value) {
|
54
|
+
super.add(value);
|
55
|
+
this.notifyObservers();
|
56
|
+
return this;
|
57
|
+
}
|
58
|
+
|
59
|
+
/**
|
60
|
+
* remove all entries
|
61
|
+
*
|
62
|
+
* @returns {Queue}
|
63
|
+
*/
|
64
|
+
clear() {
|
65
|
+
super.clear();
|
66
|
+
this.notifyObservers();
|
67
|
+
return this;
|
68
|
+
}
|
69
|
+
|
70
|
+
/**
|
71
|
+
* Attach a new observer
|
72
|
+
*
|
73
|
+
* @param {Observer} observer
|
74
|
+
* @returns {ProxyObserver}
|
75
|
+
*/
|
76
|
+
attachObserver(observer) {
|
77
|
+
this[internalSymbol].observers.attach(observer)
|
78
|
+
return this;
|
79
|
+
}
|
80
|
+
|
81
|
+
/**
|
82
|
+
* Detach a observer
|
83
|
+
*
|
84
|
+
* @param {Observer} observer
|
85
|
+
* @returns {ProxyObserver}
|
86
|
+
*/
|
87
|
+
detachObserver(observer) {
|
88
|
+
this[internalSymbol].observers.detach(observer)
|
89
|
+
return this;
|
90
|
+
}
|
91
|
+
|
92
|
+
/**
|
93
|
+
* Notify all observer
|
94
|
+
*
|
95
|
+
* @returns {Promise}
|
96
|
+
*/
|
97
|
+
notifyObservers() {
|
98
|
+
return this[internalSymbol].observers.notify(this);
|
99
|
+
}
|
100
|
+
|
101
|
+
/**
|
102
|
+
* @param {Observer} observer
|
103
|
+
* @returns {boolean}
|
104
|
+
*/
|
105
|
+
containsObserver(observer) {
|
106
|
+
return this[internalSymbol].observers.contains(observer)
|
107
|
+
}
|
108
|
+
|
109
|
+
|
110
|
+
}
|
@@ -61,9 +61,9 @@ export {ProxyObserver}
|
|
61
61
|
|
62
62
|
|
63
63
|
/**
|
64
|
-
*
|
64
|
+
* Get the real object
|
65
65
|
*
|
66
|
-
*
|
66
|
+
* Changes to this object are not noticed by the observers, so you can make a large number of changes and inform the observers later.
|
67
67
|
*
|
68
68
|
* @returns {object}
|
69
69
|
*/
|
@@ -6,12 +6,13 @@
|
|
6
6
|
*/
|
7
7
|
|
8
8
|
import {Queue} from "./queue.mjs";
|
9
|
+
import {internalSymbol} from "../constants.mjs";
|
9
10
|
import {validateObject} from "./validate.mjs";
|
10
11
|
|
11
12
|
export {UniqueQueue}
|
12
13
|
|
13
14
|
/**
|
14
|
-
*
|
15
|
+
* An UniqueQueue is a queue that contains items only once.
|
15
16
|
*
|
16
17
|
* @license AGPLv3
|
17
18
|
* @since 1.4.0
|
@@ -26,7 +27,9 @@ export {UniqueQueue}
|
|
26
27
|
*/
|
27
28
|
constructor() {
|
28
29
|
super();
|
29
|
-
this
|
30
|
+
this[internalSymbol]={
|
31
|
+
unique : new WeakSet()
|
32
|
+
};
|
30
33
|
}
|
31
34
|
|
32
35
|
/**
|
@@ -40,8 +43,8 @@ export {UniqueQueue}
|
|
40
43
|
|
41
44
|
validateObject(value);
|
42
45
|
|
43
|
-
if (!this.unique.has(value)) {
|
44
|
-
this.unique.add(value);
|
46
|
+
if (!this[internalSymbol].unique.has(value)) {
|
47
|
+
this[internalSymbol].unique.add(value);
|
45
48
|
super.add(value);
|
46
49
|
}
|
47
50
|
|
@@ -55,7 +58,7 @@ export {UniqueQueue}
|
|
55
58
|
*/
|
56
59
|
clear() {
|
57
60
|
super.clear();
|
58
|
-
this.unique = new WeakSet;
|
61
|
+
this[internalSymbol].unique = new WeakSet;
|
59
62
|
return this;
|
60
63
|
}
|
61
64
|
|
@@ -71,7 +74,7 @@ export {UniqueQueue}
|
|
71
74
|
return undefined;
|
72
75
|
}
|
73
76
|
let value = this.data.shift();
|
74
|
-
this.unique.delete(value);
|
77
|
+
this[internalSymbol].unique.delete(value);
|
75
78
|
return value;
|
76
79
|
}
|
77
80
|
|
package/source/types/version.mjs
CHANGED