@nymphjs/client 1.0.0-beta.11 → 1.0.0-beta.110
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/CHANGELOG.md +452 -0
- package/README.md +6 -6
- package/asyncitertest.js +53 -0
- package/dist/Entity.d.ts +156 -0
- package/{lib → dist}/Entity.js +202 -104
- package/dist/Entity.js.map +1 -0
- package/dist/Entity.types.d.ts +218 -0
- package/dist/Entity.types.js +2 -0
- package/{lib → dist}/EntityWeakCache.d.ts +1 -1
- package/{lib → dist}/EntityWeakCache.js +5 -9
- package/dist/EntityWeakCache.js.map +1 -0
- package/{lib → dist}/HttpRequester.d.ts +18 -4
- package/dist/HttpRequester.js +365 -0
- package/dist/HttpRequester.js.map +1 -0
- package/{lib → dist}/Nymph.d.ts +48 -11
- package/{lib → dist}/Nymph.js +167 -51
- package/dist/Nymph.js.map +1 -0
- package/{lib → dist}/Nymph.types.d.ts +82 -2
- package/dist/Nymph.types.js +2 -0
- package/{lib → dist}/PubSub.d.ts +16 -10
- package/{lib → dist}/PubSub.js +172 -108
- package/dist/PubSub.js.map +1 -0
- package/{lib → dist}/PubSub.types.d.ts +8 -3
- package/dist/PubSub.types.js +2 -0
- package/{lib → dist}/entityRefresh.d.ts +1 -1
- package/{lib → dist}/entityRefresh.js +21 -13
- package/dist/entityRefresh.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +13 -2
- package/dist/index.js.map +1 -1
- package/{lib → dist}/utils.d.ts +1 -1
- package/{lib → dist}/utils.js +28 -21
- package/dist/utils.js.map +1 -0
- package/jest.config.js +11 -2
- package/package.json +23 -27
- package/src/Entity.ts +173 -107
- package/src/Entity.types.ts +29 -47
- package/src/EntityWeakCache.ts +8 -6
- package/src/HttpRequester.ts +268 -31
- package/src/Nymph.ts +191 -88
- package/src/Nymph.types.ts +51 -2
- package/src/PubSub.ts +214 -141
- package/src/PubSub.types.ts +10 -5
- package/src/entityRefresh.ts +6 -6
- package/src/index.ts +10 -10
- package/src/utils.ts +12 -5
- package/tsconfig.json +6 -4
- package/typedoc.json +4 -0
- package/dist/index.js.LICENSE.txt +0 -8
- package/lib/Entity.d.ts +0 -51
- package/lib/Entity.js.map +0 -1
- package/lib/Entity.types.d.ts +0 -65
- package/lib/Entity.types.js +0 -3
- package/lib/EntityWeakCache.js.map +0 -1
- package/lib/HttpRequester.js +0 -190
- package/lib/HttpRequester.js.map +0 -1
- package/lib/Nymph.js.map +0 -1
- package/lib/Nymph.types.js +0 -3
- package/lib/PubSub.js.map +0 -1
- package/lib/PubSub.types.js +0 -3
- package/lib/entityRefresh.js.map +0 -1
- package/lib/index.d.ts +0 -13
- package/lib/index.js +0 -34
- package/lib/index.js.map +0 -1
- package/lib/utils.js.map +0 -1
- package/webpack.config.js +0 -28
- /package/{lib → dist}/Entity.types.js.map +0 -0
- /package/{lib → dist}/Nymph.types.js.map +0 -0
- /package/{lib → dist}/PubSub.types.js.map +0 -0
package/src/Entity.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { difference, isEqual } from 'lodash';
|
|
1
|
+
import { difference, isEqual } from 'lodash-es';
|
|
2
2
|
|
|
3
|
-
import type Nymph from './Nymph';
|
|
3
|
+
import type Nymph from './Nymph.js';
|
|
4
4
|
import {
|
|
5
5
|
EntityConstructor,
|
|
6
6
|
EntityData,
|
|
@@ -8,21 +8,23 @@ import {
|
|
|
8
8
|
EntityJson,
|
|
9
9
|
EntityPatch,
|
|
10
10
|
EntityReference,
|
|
11
|
-
} from './Entity.types';
|
|
11
|
+
} from './Entity.types.js';
|
|
12
12
|
import {
|
|
13
13
|
uniqueStrings,
|
|
14
14
|
entitiesToReferences,
|
|
15
15
|
referencesToEntities,
|
|
16
16
|
sortObj,
|
|
17
|
-
} from './utils';
|
|
17
|
+
} from './utils.js';
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
'You must use .$ready() to wake it.';
|
|
19
|
+
export type EntityDataType<T> =
|
|
20
|
+
T extends Entity<infer DataType> ? DataType : never;
|
|
22
21
|
|
|
23
|
-
export
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
export type EntityInstanceType<T extends EntityConstructor> =
|
|
23
|
+
T extends new () => infer E ? E & EntityDataType<E> : never;
|
|
24
|
+
|
|
25
|
+
export default class Entity<
|
|
26
|
+
T extends EntityData = EntityData,
|
|
27
|
+
> implements EntityInterface {
|
|
26
28
|
/**
|
|
27
29
|
* The instance of Nymph to use for queries.
|
|
28
30
|
*/
|
|
@@ -84,15 +86,14 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
84
86
|
*/
|
|
85
87
|
protected $sleepingReference: EntityReference | null = null;
|
|
86
88
|
/**
|
|
87
|
-
* A promise that resolved when the entity's data is
|
|
89
|
+
* A promise that resolved when the entity's data is wake.
|
|
88
90
|
*/
|
|
89
|
-
protected $
|
|
91
|
+
protected $wakePromise: Promise<Entity<T>> | null = null;
|
|
90
92
|
|
|
91
93
|
/**
|
|
92
|
-
*
|
|
93
|
-
* @param guid The ID of the entity to load, undefined for a new entity.
|
|
94
|
+
* Initialize an entity.
|
|
94
95
|
*/
|
|
95
|
-
public constructor(
|
|
96
|
+
public constructor(..._rest: any[]) {
|
|
96
97
|
this.$nymph = (this.constructor as EntityConstructor).nymph;
|
|
97
98
|
this.$dataHandler = {
|
|
98
99
|
has: (data: EntityData, name: string) => {
|
|
@@ -129,7 +130,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
129
130
|
deleteProperty: (data: EntityData, name: string) => {
|
|
130
131
|
if (typeof name !== 'symbol' && this.$isASleepingReference) {
|
|
131
132
|
console.error(
|
|
132
|
-
`Tried to delete data on a sleeping reference: ${name}
|
|
133
|
+
`Tried to delete data on a sleeping reference: ${name}`,
|
|
133
134
|
);
|
|
134
135
|
return false;
|
|
135
136
|
}
|
|
@@ -143,11 +144,11 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
143
144
|
defineProperty: (
|
|
144
145
|
data: EntityData,
|
|
145
146
|
name: string,
|
|
146
|
-
descriptor: PropertyDescriptor
|
|
147
|
+
descriptor: PropertyDescriptor,
|
|
147
148
|
) => {
|
|
148
149
|
if (typeof name !== 'symbol' && this.$isASleepingReference) {
|
|
149
150
|
console.error(
|
|
150
|
-
`Tried to define data on a sleeping reference: ${name}
|
|
151
|
+
`Tried to define data on a sleeping reference: ${name}`,
|
|
151
152
|
);
|
|
152
153
|
return false;
|
|
153
154
|
}
|
|
@@ -161,7 +162,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
161
162
|
getOwnPropertyDescriptor: (data: EntityData, name: string) => {
|
|
162
163
|
if (typeof name !== 'symbol' && this.$isASleepingReference) {
|
|
163
164
|
console.error(
|
|
164
|
-
`Tried to get property descriptor on a sleeping reference: ${name}
|
|
165
|
+
`Tried to get property descriptor on a sleeping reference: ${name}`,
|
|
165
166
|
);
|
|
166
167
|
return undefined;
|
|
167
168
|
}
|
|
@@ -179,17 +180,6 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
179
180
|
this.$dataStore = {} as T;
|
|
180
181
|
this.$data = new Proxy(this.$dataStore, this.$dataHandler);
|
|
181
182
|
|
|
182
|
-
if (guid != null) {
|
|
183
|
-
this.guid = guid;
|
|
184
|
-
this.$isASleepingReference = true;
|
|
185
|
-
this.$sleepingReference = [
|
|
186
|
-
'nymph_entity_reference',
|
|
187
|
-
this.guid,
|
|
188
|
-
(this.constructor as EntityConstructor).class,
|
|
189
|
-
];
|
|
190
|
-
this.$ready();
|
|
191
|
-
}
|
|
192
|
-
|
|
193
183
|
return new Proxy(this, {
|
|
194
184
|
has(entity: Entity, name: string) {
|
|
195
185
|
if (
|
|
@@ -245,7 +235,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
245
235
|
defineProperty(
|
|
246
236
|
entity: Entity,
|
|
247
237
|
name: string,
|
|
248
|
-
descriptor: PropertyDescriptor
|
|
238
|
+
descriptor: PropertyDescriptor,
|
|
249
239
|
) {
|
|
250
240
|
if (
|
|
251
241
|
typeof name !== 'string' ||
|
|
@@ -273,57 +263,130 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
273
263
|
|
|
274
264
|
ownKeys(entity: Entity) {
|
|
275
265
|
return Object.getOwnPropertyNames(entity).concat(
|
|
276
|
-
Object.getOwnPropertyNames(entity.$data)
|
|
266
|
+
Object.getOwnPropertyNames(entity.$data),
|
|
277
267
|
);
|
|
278
268
|
},
|
|
279
269
|
}) as Entity<T>;
|
|
280
270
|
}
|
|
281
271
|
|
|
282
|
-
|
|
272
|
+
/**
|
|
273
|
+
* Create or retrieve a new entity instance.
|
|
274
|
+
*
|
|
275
|
+
* Note that this will always return an entity, even if the GUID is not found.
|
|
276
|
+
*
|
|
277
|
+
* @param guid An optional GUID to retrieve.
|
|
278
|
+
*/
|
|
279
|
+
public static async factory<E extends Entity>(
|
|
280
|
+
this: {
|
|
281
|
+
new (): E;
|
|
282
|
+
},
|
|
283
|
+
guid?: string,
|
|
284
|
+
): Promise<E & EntityDataType<E>> {
|
|
283
285
|
const cacheEntity = (
|
|
284
|
-
guid
|
|
286
|
+
guid
|
|
287
|
+
? (this as unknown as EntityConstructor).nymph.getEntityFromCache(
|
|
288
|
+
this as unknown as EntityConstructor,
|
|
289
|
+
guid,
|
|
290
|
+
)
|
|
291
|
+
: null
|
|
285
292
|
) as Entity | null;
|
|
286
|
-
|
|
293
|
+
if (cacheEntity) {
|
|
294
|
+
return cacheEntity as E & EntityDataType<E>;
|
|
295
|
+
}
|
|
296
|
+
const entity = new this();
|
|
287
297
|
if (guid != null) {
|
|
288
|
-
|
|
298
|
+
entity.guid = guid;
|
|
299
|
+
entity.$isASleepingReference = true;
|
|
300
|
+
entity.$sleepingReference = [
|
|
301
|
+
'nymph_entity_reference',
|
|
302
|
+
guid,
|
|
303
|
+
(this as unknown as EntityConstructor).class,
|
|
304
|
+
];
|
|
305
|
+
await entity.$wake();
|
|
289
306
|
}
|
|
290
|
-
return entity
|
|
307
|
+
return entity as E & EntityDataType<E>;
|
|
291
308
|
}
|
|
292
309
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
310
|
+
/**
|
|
311
|
+
* Create a new entity instance.
|
|
312
|
+
*/
|
|
313
|
+
public static factorySync<E extends Entity>(this: {
|
|
314
|
+
new (): E;
|
|
315
|
+
}): E & EntityDataType<E> {
|
|
316
|
+
return new this() as E & EntityDataType<E>;
|
|
298
317
|
}
|
|
299
318
|
|
|
300
|
-
|
|
319
|
+
/**
|
|
320
|
+
* Create a new sleeping reference instance.
|
|
321
|
+
*
|
|
322
|
+
* Sleeping references won't retrieve their data from the server until they
|
|
323
|
+
* are readied with `$wake()` or a parent's `$wakeAll()`.
|
|
324
|
+
*
|
|
325
|
+
* @param reference The Nymph Entity Reference to use to wake.
|
|
326
|
+
* @returns The new instance.
|
|
327
|
+
*/
|
|
328
|
+
public static factoryReference<E extends Entity>(
|
|
329
|
+
this: {
|
|
330
|
+
new (): E;
|
|
331
|
+
},
|
|
332
|
+
reference: EntityReference,
|
|
333
|
+
): E & EntityDataType<E> {
|
|
301
334
|
const cacheEntity = (
|
|
302
|
-
reference[1]
|
|
335
|
+
reference[1]
|
|
336
|
+
? (this as unknown as EntityConstructor).nymph.getEntityFromCache(
|
|
337
|
+
this as unknown as EntityConstructor,
|
|
338
|
+
reference[1],
|
|
339
|
+
)
|
|
340
|
+
: null
|
|
303
341
|
) as Entity | null;
|
|
304
342
|
|
|
305
343
|
const entity = cacheEntity || new this();
|
|
306
344
|
if (!cacheEntity) {
|
|
307
345
|
entity.$referenceSleep(reference);
|
|
308
346
|
}
|
|
309
|
-
return entity
|
|
347
|
+
return entity as E & EntityDataType<E>;
|
|
310
348
|
}
|
|
311
349
|
|
|
350
|
+
/**
|
|
351
|
+
* Call a static method on the server version of this entity.
|
|
352
|
+
*
|
|
353
|
+
* @param method The name of the method.
|
|
354
|
+
* @param params The parameters to call the method with.
|
|
355
|
+
* @returns The value that the method on the server returned.
|
|
356
|
+
*/
|
|
312
357
|
public static async serverCallStatic(method: string, params: Iterable<any>) {
|
|
313
358
|
const data = await this.nymph.serverCallStatic(
|
|
314
359
|
this.class,
|
|
315
360
|
method,
|
|
316
361
|
// Turn the params into a real array, in case an arguments object was
|
|
317
362
|
// passed.
|
|
318
|
-
Array.prototype.slice.call(params)
|
|
363
|
+
Array.prototype.slice.call(params),
|
|
319
364
|
);
|
|
320
365
|
return data.return;
|
|
321
366
|
}
|
|
322
367
|
|
|
368
|
+
/**
|
|
369
|
+
* Call a static iterator method on the server version of this entity.
|
|
370
|
+
*
|
|
371
|
+
* @param method The name of the method.
|
|
372
|
+
* @param params The parameters to call the method with.
|
|
373
|
+
* @returns An iterator that iterates over values that the method on the server yields.
|
|
374
|
+
*/
|
|
375
|
+
public static async serverCallStaticIterator(
|
|
376
|
+
method: string,
|
|
377
|
+
params: Iterable<any>,
|
|
378
|
+
) {
|
|
379
|
+
return await this.nymph.serverCallStaticIterator(
|
|
380
|
+
this.class,
|
|
381
|
+
method,
|
|
382
|
+
// Turn the params into a real array, in case an arguments object was
|
|
383
|
+
// passed.
|
|
384
|
+
Array.prototype.slice.call(params),
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
|
|
323
388
|
public toJSON() {
|
|
324
|
-
|
|
325
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
326
|
-
}
|
|
389
|
+
this.$check();
|
|
327
390
|
const obj: EntityJson = {
|
|
328
391
|
class: (this.constructor as any).class as string,
|
|
329
392
|
guid: this.guid,
|
|
@@ -359,7 +422,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
359
422
|
})
|
|
360
423
|
.reduce(
|
|
361
424
|
(obj, { key, value }) => Object.assign(obj, { [key]: value }),
|
|
362
|
-
{}
|
|
425
|
+
{},
|
|
363
426
|
) as T;
|
|
364
427
|
this.$data = new Proxy(this.$dataStore, this.$dataHandler);
|
|
365
428
|
|
|
@@ -369,9 +432,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
369
432
|
}
|
|
370
433
|
|
|
371
434
|
public $addTag(...tags: string[]) {
|
|
372
|
-
|
|
373
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
374
|
-
}
|
|
435
|
+
this.$check();
|
|
375
436
|
|
|
376
437
|
if (tags.length < 1) {
|
|
377
438
|
return;
|
|
@@ -380,9 +441,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
380
441
|
}
|
|
381
442
|
|
|
382
443
|
public $arraySearch(array: any[], strict = false) {
|
|
383
|
-
|
|
384
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
385
|
-
}
|
|
444
|
+
this.$check();
|
|
386
445
|
|
|
387
446
|
if (!Array.isArray(array)) {
|
|
388
447
|
return -1;
|
|
@@ -397,9 +456,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
397
456
|
}
|
|
398
457
|
|
|
399
458
|
public async $delete(): Promise<boolean> {
|
|
400
|
-
|
|
401
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
402
|
-
}
|
|
459
|
+
this.$check();
|
|
403
460
|
|
|
404
461
|
const guid = this.guid;
|
|
405
462
|
|
|
@@ -407,9 +464,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
407
464
|
}
|
|
408
465
|
|
|
409
466
|
public $equals(object: any) {
|
|
410
|
-
|
|
411
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
412
|
-
}
|
|
467
|
+
this.$check();
|
|
413
468
|
|
|
414
469
|
if (!(object instanceof Entity)) {
|
|
415
470
|
return false;
|
|
@@ -435,12 +490,10 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
435
490
|
}
|
|
436
491
|
|
|
437
492
|
public $getPatch(): EntityPatch {
|
|
438
|
-
|
|
439
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
440
|
-
}
|
|
493
|
+
this.$check();
|
|
441
494
|
if (this.guid == null) {
|
|
442
495
|
throw new InvalidStateError(
|
|
443
|
-
"You can't make a patch from an unsaved entity."
|
|
496
|
+
"You can't make a patch from an unsaved entity.",
|
|
444
497
|
);
|
|
445
498
|
}
|
|
446
499
|
const patch: EntityPatch = {
|
|
@@ -448,10 +501,10 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
448
501
|
mdate: this.mdate,
|
|
449
502
|
class: (this.constructor as EntityConstructor).class,
|
|
450
503
|
addTags: this.tags.filter(
|
|
451
|
-
(tag) => this.$originalTags.indexOf(tag) === -1
|
|
504
|
+
(tag) => this.$originalTags.indexOf(tag) === -1,
|
|
452
505
|
),
|
|
453
506
|
removeTags: this.$originalTags.filter(
|
|
454
|
-
(tag) => this.tags.indexOf(tag) === -1
|
|
507
|
+
(tag) => this.tags.indexOf(tag) === -1,
|
|
455
508
|
),
|
|
456
509
|
unset: [],
|
|
457
510
|
set: {},
|
|
@@ -471,9 +524,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
471
524
|
}
|
|
472
525
|
|
|
473
526
|
public $hasTag(...tags: string[]) {
|
|
474
|
-
|
|
475
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
476
|
-
}
|
|
527
|
+
this.$check();
|
|
477
528
|
|
|
478
529
|
if (!tags.length) {
|
|
479
530
|
return false;
|
|
@@ -486,14 +537,16 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
486
537
|
return true;
|
|
487
538
|
}
|
|
488
539
|
|
|
540
|
+
public $isDirty(property: string) {
|
|
541
|
+
return property in this.$dirty ? this.$dirty[property] : null;
|
|
542
|
+
}
|
|
543
|
+
|
|
489
544
|
public $inArray(array: any[], strict = false) {
|
|
490
545
|
return this.$arraySearch(array, strict) !== -1;
|
|
491
546
|
}
|
|
492
547
|
|
|
493
548
|
public $is(object: any) {
|
|
494
|
-
|
|
495
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
496
|
-
}
|
|
549
|
+
this.$check();
|
|
497
550
|
|
|
498
551
|
if (!(object instanceof Entity)) {
|
|
499
552
|
return false;
|
|
@@ -514,9 +567,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
514
567
|
}
|
|
515
568
|
|
|
516
569
|
public async $patch() {
|
|
517
|
-
|
|
518
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
519
|
-
}
|
|
570
|
+
this.$check();
|
|
520
571
|
|
|
521
572
|
const mdate = this.mdate;
|
|
522
573
|
|
|
@@ -524,21 +575,42 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
524
575
|
return mdate !== this.mdate;
|
|
525
576
|
}
|
|
526
577
|
|
|
527
|
-
|
|
578
|
+
/**
|
|
579
|
+
* Check if this is a sleeping reference and throw an error if so.
|
|
580
|
+
*/
|
|
581
|
+
protected $check() {
|
|
582
|
+
if (this.$isASleepingReference || this.$sleepingReference != null) {
|
|
583
|
+
throw new EntityIsSleepingReferenceError(
|
|
584
|
+
'This entity is in a sleeping reference state. You must use .$wake() to wake it.',
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Check if this is a sleeping reference.
|
|
591
|
+
*/
|
|
592
|
+
public $asleep() {
|
|
593
|
+
return this.$isASleepingReference || this.$sleepingReference != null;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Wake from a sleeping reference.
|
|
598
|
+
*/
|
|
599
|
+
public $wake() {
|
|
528
600
|
if (!this.$isASleepingReference) {
|
|
529
|
-
this.$
|
|
601
|
+
this.$wakePromise = null;
|
|
530
602
|
return Promise.resolve(this);
|
|
531
603
|
}
|
|
532
604
|
if (this.$sleepingReference?.[1] == null) {
|
|
533
605
|
throw new InvalidStateError(
|
|
534
|
-
'Tried to
|
|
606
|
+
'Tried to wake a sleeping reference with no GUID.',
|
|
535
607
|
);
|
|
536
608
|
}
|
|
537
|
-
if (!this.$
|
|
538
|
-
this.$
|
|
609
|
+
if (!this.$wakePromise) {
|
|
610
|
+
this.$wakePromise = this.$nymph
|
|
539
611
|
.getEntityData(
|
|
540
612
|
{ class: this.constructor as EntityConstructor },
|
|
541
|
-
{ type: '&', guid: this.$sleepingReference[1] }
|
|
613
|
+
{ type: '&', guid: this.$sleepingReference[1] },
|
|
542
614
|
)
|
|
543
615
|
.then((data) => {
|
|
544
616
|
if (data == null) {
|
|
@@ -548,16 +620,16 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
548
620
|
return this.$init(data);
|
|
549
621
|
})
|
|
550
622
|
.finally(() => {
|
|
551
|
-
this.$
|
|
623
|
+
this.$wakePromise = null;
|
|
552
624
|
});
|
|
553
625
|
}
|
|
554
|
-
return this.$
|
|
626
|
+
return this.$wakePromise;
|
|
555
627
|
}
|
|
556
628
|
|
|
557
|
-
public $
|
|
629
|
+
public $wakeAll(level?: number) {
|
|
558
630
|
return new Promise((resolve, reject) => {
|
|
559
|
-
// Run this once this entity is
|
|
560
|
-
const
|
|
631
|
+
// Run this once this entity is awake.
|
|
632
|
+
const wakeProps = () => {
|
|
561
633
|
let newLevel;
|
|
562
634
|
// If level is undefined, keep going forever, otherwise, stop once we've
|
|
563
635
|
// gone deep enough.
|
|
@@ -569,17 +641,17 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
569
641
|
return;
|
|
570
642
|
}
|
|
571
643
|
const promises = [];
|
|
572
|
-
// Go through data looking for entities to
|
|
644
|
+
// Go through data looking for entities to wake.
|
|
573
645
|
for (let [key, value] of Object.entries(this.$data)) {
|
|
574
646
|
if (value instanceof Entity && value.$isASleepingReference) {
|
|
575
|
-
promises.push(value.$
|
|
647
|
+
promises.push(value.$wakeAll(newLevel));
|
|
576
648
|
} else if (Array.isArray(value)) {
|
|
577
649
|
for (let i = 0; i < value.length; i++) {
|
|
578
650
|
if (
|
|
579
651
|
value[i] instanceof Entity &&
|
|
580
652
|
value[i].$isASleepingReference
|
|
581
653
|
) {
|
|
582
|
-
promises.push(value[i].$
|
|
654
|
+
promises.push(value[i].$wakeAll(newLevel));
|
|
583
655
|
}
|
|
584
656
|
}
|
|
585
657
|
}
|
|
@@ -587,7 +659,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
587
659
|
if (promises.length) {
|
|
588
660
|
Promise.all(promises).then(
|
|
589
661
|
() => resolve(this),
|
|
590
|
-
(errObj) => reject(errObj)
|
|
662
|
+
(errObj) => reject(errObj),
|
|
591
663
|
);
|
|
592
664
|
} else {
|
|
593
665
|
resolve(this);
|
|
@@ -595,9 +667,9 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
595
667
|
};
|
|
596
668
|
|
|
597
669
|
if (this.$isASleepingReference) {
|
|
598
|
-
this.$
|
|
670
|
+
this.$wake().then(wakeProps, (errObj) => reject(errObj));
|
|
599
671
|
} else {
|
|
600
|
-
|
|
672
|
+
wakeProps();
|
|
601
673
|
}
|
|
602
674
|
}) as Promise<Entity<T>>;
|
|
603
675
|
}
|
|
@@ -610,7 +682,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
610
682
|
|
|
611
683
|
public async $refresh() {
|
|
612
684
|
if (this.$isASleepingReference) {
|
|
613
|
-
await this.$
|
|
685
|
+
await this.$wake();
|
|
614
686
|
return true;
|
|
615
687
|
}
|
|
616
688
|
|
|
@@ -624,24 +696,20 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
624
696
|
{
|
|
625
697
|
type: '&',
|
|
626
698
|
guid: this.guid,
|
|
627
|
-
}
|
|
699
|
+
},
|
|
628
700
|
);
|
|
629
701
|
this.$init(data);
|
|
630
702
|
return this.guid == null ? 0 : true;
|
|
631
703
|
}
|
|
632
704
|
|
|
633
705
|
public $removeTag(...tags: string[]) {
|
|
634
|
-
|
|
635
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
636
|
-
}
|
|
706
|
+
this.$check();
|
|
637
707
|
|
|
638
708
|
this.tags = difference(this.tags, tags);
|
|
639
709
|
}
|
|
640
710
|
|
|
641
711
|
public async $save() {
|
|
642
|
-
|
|
643
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
644
|
-
}
|
|
712
|
+
this.$check();
|
|
645
713
|
|
|
646
714
|
await this.$nymph.saveEntity(this);
|
|
647
715
|
return !!this.guid;
|
|
@@ -650,11 +718,9 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
650
718
|
public async $serverCall(
|
|
651
719
|
method: string,
|
|
652
720
|
params: Iterable<any>,
|
|
653
|
-
stateless = false
|
|
721
|
+
stateless = false,
|
|
654
722
|
) {
|
|
655
|
-
|
|
656
|
-
throw new EntityIsSleepingReferenceError(sleepErr);
|
|
657
|
-
}
|
|
723
|
+
this.$check();
|
|
658
724
|
// Turn the params into a real array, in case an arguments object was
|
|
659
725
|
// passed.
|
|
660
726
|
const paramArray = Array.prototype.slice.call(params);
|
|
@@ -662,7 +728,7 @@ export default class Entity<T extends EntityData = EntityData>
|
|
|
662
728
|
this,
|
|
663
729
|
method,
|
|
664
730
|
paramArray,
|
|
665
|
-
stateless
|
|
731
|
+
stateless,
|
|
666
732
|
);
|
|
667
733
|
if (!stateless && data.entity) {
|
|
668
734
|
this.$init(data.entity);
|
package/src/Entity.types.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type Nymph from './Nymph';
|
|
1
|
+
import type Nymph from './Nymph.js';
|
|
2
|
+
import type Entity from './Entity.js';
|
|
2
3
|
|
|
3
4
|
export type ServerCallResponse = {
|
|
4
5
|
return: any;
|
|
@@ -155,6 +156,24 @@ export interface EntityInterface extends DataObjectInterface {
|
|
|
155
156
|
* @returns True or false.
|
|
156
157
|
*/
|
|
157
158
|
$hasTag(...tags: string[]): boolean;
|
|
159
|
+
/**
|
|
160
|
+
* Check whether a property is dirty.
|
|
161
|
+
*
|
|
162
|
+
* To be a dirty property, it must have been set or deleted since the entity
|
|
163
|
+
* was initialized. A clean property existed on initialization and hasn't been
|
|
164
|
+
* set or deleted. An untracked property didn't exist on initialization and
|
|
165
|
+
* hasn't been set or deleted.
|
|
166
|
+
*
|
|
167
|
+
* Note that this doesn't necessarily mean the property has changed. It could
|
|
168
|
+
* have been set to the same value, or created and then deleted.
|
|
169
|
+
*
|
|
170
|
+
* Entities are initialized when they are pulled from the server or saved.
|
|
171
|
+
* This is done with the `$init` method.
|
|
172
|
+
*
|
|
173
|
+
* @param property The name of a property.
|
|
174
|
+
* @returns True if it's dirty, false if not, and null if it's not tracked.
|
|
175
|
+
*/
|
|
176
|
+
$isDirty(property: string): boolean | null;
|
|
158
177
|
/**
|
|
159
178
|
* Initialize this entity from a JSON representation.
|
|
160
179
|
*
|
|
@@ -166,14 +185,14 @@ export interface EntityInterface extends DataObjectInterface {
|
|
|
166
185
|
*
|
|
167
186
|
* @returns The entity.
|
|
168
187
|
*/
|
|
169
|
-
$
|
|
188
|
+
$wake(): Promise<EntityInterface>;
|
|
170
189
|
/**
|
|
171
190
|
* Ready this entity's data, and the data of entity's within this one's.
|
|
172
191
|
*
|
|
173
|
-
* @param level The number of levels deep to
|
|
192
|
+
* @param level The number of levels deep to wake. If undefined, it will keep going until there are no more entities. (Careful of infinite loops.)
|
|
174
193
|
* @returns The entity.
|
|
175
194
|
*/
|
|
176
|
-
$
|
|
195
|
+
$wakeAll(level?: number): Promise<EntityInterface>;
|
|
177
196
|
/**
|
|
178
197
|
* Remove one or more tags.
|
|
179
198
|
*
|
|
@@ -195,7 +214,7 @@ export interface EntityInterface extends DataObjectInterface {
|
|
|
195
214
|
$serverCall(
|
|
196
215
|
method: string,
|
|
197
216
|
params: Iterable<any>,
|
|
198
|
-
stateless: boolean
|
|
217
|
+
stateless: boolean,
|
|
199
218
|
): Promise<any>;
|
|
200
219
|
/**
|
|
201
220
|
* Return a Nymph Entity Reference for this entity.
|
|
@@ -208,46 +227,9 @@ export interface EntityInterface extends DataObjectInterface {
|
|
|
208
227
|
$toReference(): EntityReference | EntityInterface;
|
|
209
228
|
}
|
|
210
229
|
|
|
211
|
-
export type EntityConstructor
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* The lookup name for this entity.
|
|
218
|
-
*
|
|
219
|
-
* This is used for reference arrays (and sleeping references) and client
|
|
220
|
-
* requests.
|
|
221
|
-
*/
|
|
222
|
-
class: string;
|
|
223
|
-
/**
|
|
224
|
-
* Create a new entity instance.
|
|
225
|
-
*
|
|
226
|
-
* @param guid An optional GUID to retrieve.
|
|
227
|
-
*/
|
|
228
|
-
factory(guid?: string): Promise<EntityInterface>;
|
|
229
|
-
/**
|
|
230
|
-
* Create a new entity instance.
|
|
231
|
-
*
|
|
232
|
-
* @param guid An optional GUID to retrieve.
|
|
233
|
-
*/
|
|
234
|
-
factorySync(guid?: string): EntityInterface;
|
|
235
|
-
/**
|
|
236
|
-
* Create a new sleeping reference instance.
|
|
237
|
-
*
|
|
238
|
-
* Sleeping references won't retrieve their data from the server until they
|
|
239
|
-
* are readied with `ready()` or a parent's `readyAll()`.
|
|
240
|
-
*
|
|
241
|
-
* @param reference The Nymph Entity Reference to use to wake.
|
|
242
|
-
* @returns The new instance.
|
|
243
|
-
*/
|
|
244
|
-
factoryReference(reference: EntityReference): EntityInterface;
|
|
245
|
-
/**
|
|
246
|
-
* Call a static method on the server version of this entity.
|
|
247
|
-
*
|
|
248
|
-
* @param method The name of the method.
|
|
249
|
-
* @param params The parameters to call the method with.
|
|
250
|
-
* @returns The value that the method on the server returned.
|
|
251
|
-
*/
|
|
252
|
-
serverCallStatic(method: string, params: Iterable<any>): Promise<any>;
|
|
230
|
+
export type EntityConstructor<
|
|
231
|
+
D extends EntityData = EntityData,
|
|
232
|
+
E extends Entity<D> = Entity<D>,
|
|
233
|
+
> = (new (...args: any[]) => E) & {
|
|
234
|
+
[k in keyof typeof Entity]: (typeof Entity)[k];
|
|
253
235
|
};
|
package/src/EntityWeakCache.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
import { EntityConstructor, EntityInterface } from './Entity.types';
|
|
1
|
+
import { EntityConstructor, EntityInterface } from './Entity.types.js';
|
|
2
2
|
|
|
3
3
|
export default class EntityWeakCache {
|
|
4
|
-
private references: WeakMap<
|
|
5
|
-
|
|
4
|
+
private references: WeakMap<
|
|
5
|
+
EntityConstructor,
|
|
6
|
+
{ [k: string]: WeakRef<EntityInterface> }
|
|
7
|
+
> = new WeakMap();
|
|
6
8
|
|
|
7
9
|
get(EntityClass: EntityConstructor, guid: string): EntityInterface | null {
|
|
8
10
|
const classMap = this.references.get(EntityClass);
|
|
9
11
|
if (classMap && guid in classMap) {
|
|
10
12
|
const weakRef = classMap[guid];
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
const deref = weakRef && weakRef.deref();
|
|
14
|
+
if (deref != null) {
|
|
15
|
+
return deref;
|
|
13
16
|
} else {
|
|
14
17
|
delete classMap[guid];
|
|
15
18
|
}
|
|
@@ -22,7 +25,6 @@ export default class EntityWeakCache {
|
|
|
22
25
|
return;
|
|
23
26
|
}
|
|
24
27
|
|
|
25
|
-
// @ts-ignore TS doesn't know about WeakRef.
|
|
26
28
|
const weakRef = new WeakRef(entity);
|
|
27
29
|
|
|
28
30
|
const classMap = this.references.get(EntityClass) || {};
|