@converse/skeletor 4.0.0 → 4.0.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/CHANGES.md +5 -0
- package/dist/skeletor.d.ts +922 -953
- package/dist/skeletor.esm.js +75 -72
- package/dist/skeletor.esm.js.map +1 -1
- package/dist/skeletor.js +75 -72
- package/dist/skeletor.js.map +1 -1
- package/dist/skeletor.min.js +5 -5
- package/dist/skeletor.node.d.ts +947 -978
- package/dist/skeletor.node.js +75 -72
- package/dist/skeletor.node.mjs +75 -72
- package/package.json +7 -10
- package/src/collection.ts +14 -9
- package/src/model.ts +85 -52
package/dist/skeletor.node.js
CHANGED
|
@@ -35,19 +35,6 @@ function __values(o) {
|
|
|
35
35
|
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
function __classPrivateFieldGet(receiver, state, kind, f) {
|
|
39
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
40
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
41
|
-
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function __classPrivateFieldSet(receiver, state, value, kind, f) {
|
|
45
|
-
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
46
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
47
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
48
|
-
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
38
|
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
52
39
|
var e = new Error(message);
|
|
53
40
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
@@ -11161,7 +11148,47 @@ var pick = flatRest(function(object, paths) {
|
|
|
11161
11148
|
return object == null ? {} : basePick(object, paths);
|
|
11162
11149
|
});
|
|
11163
11150
|
|
|
11164
|
-
|
|
11151
|
+
const INTERNALS = new WeakMap();
|
|
11152
|
+
function internals(model) {
|
|
11153
|
+
let priv = INTERNALS.get(model);
|
|
11154
|
+
if (!priv) {
|
|
11155
|
+
priv = { state: 'constructing' };
|
|
11156
|
+
INTERNALS.set(model, priv);
|
|
11157
|
+
}
|
|
11158
|
+
return priv;
|
|
11159
|
+
}
|
|
11160
|
+
/** Load the model from storage, marking it ready whether or not the read succeeds. */
|
|
11161
|
+
async function hydrate$1(model, priv) {
|
|
11162
|
+
ensureUnloadListener(PersistentStorage);
|
|
11163
|
+
try {
|
|
11164
|
+
await model.fetch({ fromStorage: true, promise: true });
|
|
11165
|
+
}
|
|
11166
|
+
finally {
|
|
11167
|
+
priv.state = 'ready';
|
|
11168
|
+
}
|
|
11169
|
+
}
|
|
11170
|
+
/** Evaluate the model's declared computed properties once, seeding the cache. */
|
|
11171
|
+
function initComputed(model, priv) {
|
|
11172
|
+
const defs = result(model, 'computed');
|
|
11173
|
+
if (!defs || isEmpty(defs))
|
|
11174
|
+
return;
|
|
11175
|
+
priv.computedDefs = defs;
|
|
11176
|
+
priv.computedCache = {};
|
|
11177
|
+
for (const [key, def] of Object.entries(defs)) {
|
|
11178
|
+
priv.computedCache[key] = def.fn(model);
|
|
11179
|
+
}
|
|
11180
|
+
}
|
|
11181
|
+
/** Recompute one computed property, firing `change:key` when its value changed. */
|
|
11182
|
+
function updateComputed(model, priv, key, def, silent, options) {
|
|
11183
|
+
const newVal = def.fn(model);
|
|
11184
|
+
if (!isEqual(priv.computedCache[key], newVal)) {
|
|
11185
|
+
priv.computedCache[key] = newVal;
|
|
11186
|
+
if (!silent) {
|
|
11187
|
+
model.changed[key] = newVal;
|
|
11188
|
+
model.trigger('change:' + key, model, newVal, options);
|
|
11189
|
+
}
|
|
11190
|
+
}
|
|
11191
|
+
}
|
|
11165
11192
|
/**
|
|
11166
11193
|
* @public
|
|
11167
11194
|
* **Models** are the basic data object in the framework --
|
|
@@ -11176,15 +11203,12 @@ class Model extends EventEmitterObject {
|
|
|
11176
11203
|
*/
|
|
11177
11204
|
constructor(attributes, options) {
|
|
11178
11205
|
super();
|
|
11179
|
-
_Model_instances.add(this);
|
|
11180
|
-
_Model_computedCache.set(this, void 0);
|
|
11181
|
-
_Model_computedDefs.set(this, void 0);
|
|
11182
|
-
_Model_state.set(this, 'constructing');
|
|
11183
11206
|
this._changing = false;
|
|
11184
11207
|
this._pending = false;
|
|
11185
11208
|
this._url = '';
|
|
11186
11209
|
this.changed = {};
|
|
11187
11210
|
this.validationError = null;
|
|
11211
|
+
const priv = internals(this);
|
|
11188
11212
|
let attrs = attributes || {};
|
|
11189
11213
|
options = options || {};
|
|
11190
11214
|
this.preinitialize.apply(this, arguments);
|
|
@@ -11197,11 +11221,12 @@ class Model extends EventEmitterObject {
|
|
|
11197
11221
|
const default_attrs = result(this, 'defaults');
|
|
11198
11222
|
attrs = defaults(Object.assign({}, default_attrs, attrs), default_attrs);
|
|
11199
11223
|
this.set(attrs, options);
|
|
11200
|
-
|
|
11224
|
+
initComputed(this, priv);
|
|
11201
11225
|
this.attrs = new Proxy(this.attributes, {
|
|
11202
11226
|
get: (_target, key) => {
|
|
11203
|
-
|
|
11204
|
-
|
|
11227
|
+
const cache = priv.computedCache;
|
|
11228
|
+
if (typeof key !== 'symbol' && cache && key in cache) {
|
|
11229
|
+
return cache[key];
|
|
11205
11230
|
}
|
|
11206
11231
|
return this.attributes[key];
|
|
11207
11232
|
},
|
|
@@ -11219,16 +11244,16 @@ class Model extends EventEmitterObject {
|
|
|
11219
11244
|
// otherwise it's already ready and resolves immediately.
|
|
11220
11245
|
if (this.autoSync) {
|
|
11221
11246
|
if (getStorage(this) && !this.isNew()) {
|
|
11222
|
-
|
|
11223
|
-
this.hydrated =
|
|
11247
|
+
priv.state = 'hydrating';
|
|
11248
|
+
this.hydrated = hydrate$1(this, priv);
|
|
11224
11249
|
}
|
|
11225
11250
|
else {
|
|
11226
|
-
|
|
11251
|
+
priv.state = 'ready';
|
|
11227
11252
|
this.hydrated = Promise.resolve();
|
|
11228
11253
|
}
|
|
11229
11254
|
}
|
|
11230
11255
|
else {
|
|
11231
|
-
|
|
11256
|
+
priv.state = 'ready';
|
|
11232
11257
|
}
|
|
11233
11258
|
}
|
|
11234
11259
|
/**
|
|
@@ -11327,8 +11352,9 @@ class Model extends EventEmitterObject {
|
|
|
11327
11352
|
* Get the value of an attribute, or a computed property.
|
|
11328
11353
|
*/
|
|
11329
11354
|
get(attr) {
|
|
11330
|
-
|
|
11331
|
-
|
|
11355
|
+
const cache = internals(this).computedCache;
|
|
11356
|
+
if (cache && attr in cache) {
|
|
11357
|
+
return cache[attr];
|
|
11332
11358
|
}
|
|
11333
11359
|
return this.attributes[attr];
|
|
11334
11360
|
}
|
|
@@ -11404,9 +11430,10 @@ class Model extends EventEmitterObject {
|
|
|
11404
11430
|
attrs[key] = val;
|
|
11405
11431
|
}
|
|
11406
11432
|
options = options || {};
|
|
11433
|
+
const priv = internals(this);
|
|
11407
11434
|
// Guard must come after arg normalization: when called as set(obj, opts),
|
|
11408
11435
|
// fromStorage lives in `val` (second arg), not `options` (third arg).
|
|
11409
|
-
if (this.autoSync &&
|
|
11436
|
+
if (this.autoSync && priv.state === 'hydrating' && !options.fromStorage) {
|
|
11410
11437
|
throw new Error(`Skeletor: set() called on an autoSync model before hydration resolved. Await model.hydrated first.`);
|
|
11411
11438
|
}
|
|
11412
11439
|
// Run validation.
|
|
@@ -11450,10 +11477,10 @@ class Model extends EventEmitterObject {
|
|
|
11450
11477
|
}
|
|
11451
11478
|
}
|
|
11452
11479
|
// Recalculate computed properties whose deps changed.
|
|
11453
|
-
if (changes.length &&
|
|
11454
|
-
for (const [key, def] of Object.entries(
|
|
11480
|
+
if (changes.length && priv.computedDefs) {
|
|
11481
|
+
for (const [key, def] of Object.entries(priv.computedDefs)) {
|
|
11455
11482
|
if (def.deps.some((dep) => changes.includes(dep))) {
|
|
11456
|
-
|
|
11483
|
+
updateComputed(this, priv, key, def, silent, options);
|
|
11457
11484
|
}
|
|
11458
11485
|
}
|
|
11459
11486
|
}
|
|
@@ -11473,13 +11500,13 @@ class Model extends EventEmitterObject {
|
|
|
11473
11500
|
// Auto-save: schedule a debounced write when autoSync is on and there
|
|
11474
11501
|
// were actual changes that originated from application code (not a
|
|
11475
11502
|
// storage read or an explicit noAutoSave call).
|
|
11476
|
-
if (
|
|
11503
|
+
if (priv.state === 'ready' &&
|
|
11477
11504
|
this.autoSync &&
|
|
11478
11505
|
getStorage(this) &&
|
|
11479
11506
|
changes.length &&
|
|
11480
11507
|
!options.fromStorage &&
|
|
11481
11508
|
!options.noAutoSave) {
|
|
11482
|
-
scheduleAutoSave(this, () =>
|
|
11509
|
+
scheduleAutoSave(this, () => this.save(null, { noAutoSave: true }), this.autoSyncDelay);
|
|
11483
11510
|
}
|
|
11484
11511
|
return this;
|
|
11485
11512
|
}
|
|
@@ -11760,37 +11787,8 @@ class Model extends EventEmitterObject {
|
|
|
11760
11787
|
return false;
|
|
11761
11788
|
}
|
|
11762
11789
|
}
|
|
11763
|
-
_Model_computedCache = new WeakMap(), _Model_computedDefs = new WeakMap(), _Model_state = new WeakMap(), _Model_instances = new WeakSet(), _Model_hydrate = async function _Model_hydrate() {
|
|
11764
|
-
ensureUnloadListener(PersistentStorage);
|
|
11765
|
-
try {
|
|
11766
|
-
await this.fetch({ fromStorage: true, promise: true });
|
|
11767
|
-
}
|
|
11768
|
-
finally {
|
|
11769
|
-
__classPrivateFieldSet(this, _Model_state, 'ready', "f");
|
|
11770
|
-
}
|
|
11771
|
-
}, _Model_doAutoSave = function _Model_doAutoSave() {
|
|
11772
|
-
return this.save(null, { noAutoSave: true });
|
|
11773
|
-
}, _Model_updateComputed = function _Model_updateComputed(key, def, silent, options) {
|
|
11774
|
-
const newVal = def.fn(this);
|
|
11775
|
-
if (!isEqual(__classPrivateFieldGet(this, _Model_computedCache, "f")[key], newVal)) {
|
|
11776
|
-
__classPrivateFieldGet(this, _Model_computedCache, "f")[key] = newVal;
|
|
11777
|
-
if (!silent) {
|
|
11778
|
-
this.changed[key] = newVal;
|
|
11779
|
-
this.trigger('change:' + key, this, newVal, options);
|
|
11780
|
-
}
|
|
11781
|
-
}
|
|
11782
|
-
}, _Model_initComputed = function _Model_initComputed() {
|
|
11783
|
-
const defs = result(this, 'computed');
|
|
11784
|
-
if (!defs || isEmpty(defs))
|
|
11785
|
-
return;
|
|
11786
|
-
__classPrivateFieldSet(this, _Model_computedDefs, defs, "f");
|
|
11787
|
-
__classPrivateFieldSet(this, _Model_computedCache, {}, "f");
|
|
11788
|
-
for (const [key, def] of Object.entries(defs)) {
|
|
11789
|
-
__classPrivateFieldGet(this, _Model_computedCache, "f")[key] = def.fn(this);
|
|
11790
|
-
}
|
|
11791
|
-
};
|
|
11792
11790
|
|
|
11793
|
-
var
|
|
11791
|
+
var _a;
|
|
11794
11792
|
// Default options for `Collection#set`.
|
|
11795
11793
|
const setOptions = { add: true, remove: true, merge: true };
|
|
11796
11794
|
const addOptions = { add: true, remove: false };
|
|
@@ -11811,6 +11809,18 @@ function toModelPredicate(pred) {
|
|
|
11811
11809
|
const matcher = matches(pred);
|
|
11812
11810
|
return (m) => matcher(m.attributes);
|
|
11813
11811
|
}
|
|
11812
|
+
/**
|
|
11813
|
+
* Load the collection's members from storage. A module-level function rather
|
|
11814
|
+
* than a `#private` method so the published declarations carry no private
|
|
11815
|
+
* members, which TypeScript 6 rejects in anonymously extended classes (TS4094).
|
|
11816
|
+
*/
|
|
11817
|
+
async function hydrate(collection) {
|
|
11818
|
+
ensureUnloadListener(PersistentStorage);
|
|
11819
|
+
// An empty store is a normal first-run state: findAll() returns [] and a
|
|
11820
|
+
// missing model record resolves to null, so hydration resolves rather
|
|
11821
|
+
// than rejecting.
|
|
11822
|
+
await collection.fetch({ fromStorage: true, promise: true });
|
|
11823
|
+
}
|
|
11814
11824
|
/**
|
|
11815
11825
|
* @public
|
|
11816
11826
|
* If models tend to represent a single row of data, a Collection is
|
|
@@ -11828,7 +11838,6 @@ class Collection extends EventEmitterObject {
|
|
|
11828
11838
|
*/
|
|
11829
11839
|
constructor(models, options) {
|
|
11830
11840
|
super();
|
|
11831
|
-
_Collection_instances.add(this);
|
|
11832
11841
|
this._url = '';
|
|
11833
11842
|
/**
|
|
11834
11843
|
* @public
|
|
@@ -11850,7 +11859,7 @@ class Collection extends EventEmitterObject {
|
|
|
11850
11859
|
// uniformly `await collection.hydrated`; it resolves immediately when
|
|
11851
11860
|
// there's no storage to hydrate from.
|
|
11852
11861
|
if (this.autoSync) {
|
|
11853
|
-
this.hydrated = getStorage(this) ?
|
|
11862
|
+
this.hydrated = getStorage(this) ? hydrate(this) : Promise.resolve();
|
|
11854
11863
|
}
|
|
11855
11864
|
}
|
|
11856
11865
|
get comparator() {
|
|
@@ -12533,13 +12542,7 @@ class Collection extends EventEmitterObject {
|
|
|
12533
12542
|
this.trigger.apply(this, arguments);
|
|
12534
12543
|
}
|
|
12535
12544
|
}
|
|
12536
|
-
|
|
12537
|
-
ensureUnloadListener(PersistentStorage);
|
|
12538
|
-
// An empty store is a normal first-run state: findAll() returns [] and a
|
|
12539
|
-
// missing model record resolves to null, so hydration resolves rather
|
|
12540
|
-
// than rejecting.
|
|
12541
|
-
await this.fetch({ fromStorage: true, promise: true });
|
|
12542
|
-
}, _a = Symbol.iterator;
|
|
12545
|
+
_a = Symbol.iterator;
|
|
12543
12546
|
// This "enum" defines the three possible kinds of values which can be emitted
|
|
12544
12547
|
// by a CollectionIterator that correspond to the values(), keys() and entries()
|
|
12545
12548
|
// methods on Collection, respectively.
|
package/dist/skeletor.node.mjs
CHANGED
|
@@ -31,19 +31,6 @@ function __values(o) {
|
|
|
31
31
|
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
function __classPrivateFieldGet(receiver, state, kind, f) {
|
|
35
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
36
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
37
|
-
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function __classPrivateFieldSet(receiver, state, value, kind, f) {
|
|
41
|
-
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
42
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
43
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
44
|
-
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
34
|
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
48
35
|
var e = new Error(message);
|
|
49
36
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
@@ -11157,7 +11144,47 @@ var pick = flatRest(function(object, paths) {
|
|
|
11157
11144
|
return object == null ? {} : basePick(object, paths);
|
|
11158
11145
|
});
|
|
11159
11146
|
|
|
11160
|
-
|
|
11147
|
+
const INTERNALS = new WeakMap();
|
|
11148
|
+
function internals(model) {
|
|
11149
|
+
let priv = INTERNALS.get(model);
|
|
11150
|
+
if (!priv) {
|
|
11151
|
+
priv = { state: 'constructing' };
|
|
11152
|
+
INTERNALS.set(model, priv);
|
|
11153
|
+
}
|
|
11154
|
+
return priv;
|
|
11155
|
+
}
|
|
11156
|
+
/** Load the model from storage, marking it ready whether or not the read succeeds. */
|
|
11157
|
+
async function hydrate$1(model, priv) {
|
|
11158
|
+
ensureUnloadListener(PersistentStorage);
|
|
11159
|
+
try {
|
|
11160
|
+
await model.fetch({ fromStorage: true, promise: true });
|
|
11161
|
+
}
|
|
11162
|
+
finally {
|
|
11163
|
+
priv.state = 'ready';
|
|
11164
|
+
}
|
|
11165
|
+
}
|
|
11166
|
+
/** Evaluate the model's declared computed properties once, seeding the cache. */
|
|
11167
|
+
function initComputed(model, priv) {
|
|
11168
|
+
const defs = result(model, 'computed');
|
|
11169
|
+
if (!defs || isEmpty(defs))
|
|
11170
|
+
return;
|
|
11171
|
+
priv.computedDefs = defs;
|
|
11172
|
+
priv.computedCache = {};
|
|
11173
|
+
for (const [key, def] of Object.entries(defs)) {
|
|
11174
|
+
priv.computedCache[key] = def.fn(model);
|
|
11175
|
+
}
|
|
11176
|
+
}
|
|
11177
|
+
/** Recompute one computed property, firing `change:key` when its value changed. */
|
|
11178
|
+
function updateComputed(model, priv, key, def, silent, options) {
|
|
11179
|
+
const newVal = def.fn(model);
|
|
11180
|
+
if (!isEqual(priv.computedCache[key], newVal)) {
|
|
11181
|
+
priv.computedCache[key] = newVal;
|
|
11182
|
+
if (!silent) {
|
|
11183
|
+
model.changed[key] = newVal;
|
|
11184
|
+
model.trigger('change:' + key, model, newVal, options);
|
|
11185
|
+
}
|
|
11186
|
+
}
|
|
11187
|
+
}
|
|
11161
11188
|
/**
|
|
11162
11189
|
* @public
|
|
11163
11190
|
* **Models** are the basic data object in the framework --
|
|
@@ -11172,15 +11199,12 @@ class Model extends EventEmitterObject {
|
|
|
11172
11199
|
*/
|
|
11173
11200
|
constructor(attributes, options) {
|
|
11174
11201
|
super();
|
|
11175
|
-
_Model_instances.add(this);
|
|
11176
|
-
_Model_computedCache.set(this, void 0);
|
|
11177
|
-
_Model_computedDefs.set(this, void 0);
|
|
11178
|
-
_Model_state.set(this, 'constructing');
|
|
11179
11202
|
this._changing = false;
|
|
11180
11203
|
this._pending = false;
|
|
11181
11204
|
this._url = '';
|
|
11182
11205
|
this.changed = {};
|
|
11183
11206
|
this.validationError = null;
|
|
11207
|
+
const priv = internals(this);
|
|
11184
11208
|
let attrs = attributes || {};
|
|
11185
11209
|
options = options || {};
|
|
11186
11210
|
this.preinitialize.apply(this, arguments);
|
|
@@ -11193,11 +11217,12 @@ class Model extends EventEmitterObject {
|
|
|
11193
11217
|
const default_attrs = result(this, 'defaults');
|
|
11194
11218
|
attrs = defaults(Object.assign({}, default_attrs, attrs), default_attrs);
|
|
11195
11219
|
this.set(attrs, options);
|
|
11196
|
-
|
|
11220
|
+
initComputed(this, priv);
|
|
11197
11221
|
this.attrs = new Proxy(this.attributes, {
|
|
11198
11222
|
get: (_target, key) => {
|
|
11199
|
-
|
|
11200
|
-
|
|
11223
|
+
const cache = priv.computedCache;
|
|
11224
|
+
if (typeof key !== 'symbol' && cache && key in cache) {
|
|
11225
|
+
return cache[key];
|
|
11201
11226
|
}
|
|
11202
11227
|
return this.attributes[key];
|
|
11203
11228
|
},
|
|
@@ -11215,16 +11240,16 @@ class Model extends EventEmitterObject {
|
|
|
11215
11240
|
// otherwise it's already ready and resolves immediately.
|
|
11216
11241
|
if (this.autoSync) {
|
|
11217
11242
|
if (getStorage(this) && !this.isNew()) {
|
|
11218
|
-
|
|
11219
|
-
this.hydrated =
|
|
11243
|
+
priv.state = 'hydrating';
|
|
11244
|
+
this.hydrated = hydrate$1(this, priv);
|
|
11220
11245
|
}
|
|
11221
11246
|
else {
|
|
11222
|
-
|
|
11247
|
+
priv.state = 'ready';
|
|
11223
11248
|
this.hydrated = Promise.resolve();
|
|
11224
11249
|
}
|
|
11225
11250
|
}
|
|
11226
11251
|
else {
|
|
11227
|
-
|
|
11252
|
+
priv.state = 'ready';
|
|
11228
11253
|
}
|
|
11229
11254
|
}
|
|
11230
11255
|
/**
|
|
@@ -11323,8 +11348,9 @@ class Model extends EventEmitterObject {
|
|
|
11323
11348
|
* Get the value of an attribute, or a computed property.
|
|
11324
11349
|
*/
|
|
11325
11350
|
get(attr) {
|
|
11326
|
-
|
|
11327
|
-
|
|
11351
|
+
const cache = internals(this).computedCache;
|
|
11352
|
+
if (cache && attr in cache) {
|
|
11353
|
+
return cache[attr];
|
|
11328
11354
|
}
|
|
11329
11355
|
return this.attributes[attr];
|
|
11330
11356
|
}
|
|
@@ -11400,9 +11426,10 @@ class Model extends EventEmitterObject {
|
|
|
11400
11426
|
attrs[key] = val;
|
|
11401
11427
|
}
|
|
11402
11428
|
options = options || {};
|
|
11429
|
+
const priv = internals(this);
|
|
11403
11430
|
// Guard must come after arg normalization: when called as set(obj, opts),
|
|
11404
11431
|
// fromStorage lives in `val` (second arg), not `options` (third arg).
|
|
11405
|
-
if (this.autoSync &&
|
|
11432
|
+
if (this.autoSync && priv.state === 'hydrating' && !options.fromStorage) {
|
|
11406
11433
|
throw new Error(`Skeletor: set() called on an autoSync model before hydration resolved. Await model.hydrated first.`);
|
|
11407
11434
|
}
|
|
11408
11435
|
// Run validation.
|
|
@@ -11446,10 +11473,10 @@ class Model extends EventEmitterObject {
|
|
|
11446
11473
|
}
|
|
11447
11474
|
}
|
|
11448
11475
|
// Recalculate computed properties whose deps changed.
|
|
11449
|
-
if (changes.length &&
|
|
11450
|
-
for (const [key, def] of Object.entries(
|
|
11476
|
+
if (changes.length && priv.computedDefs) {
|
|
11477
|
+
for (const [key, def] of Object.entries(priv.computedDefs)) {
|
|
11451
11478
|
if (def.deps.some((dep) => changes.includes(dep))) {
|
|
11452
|
-
|
|
11479
|
+
updateComputed(this, priv, key, def, silent, options);
|
|
11453
11480
|
}
|
|
11454
11481
|
}
|
|
11455
11482
|
}
|
|
@@ -11469,13 +11496,13 @@ class Model extends EventEmitterObject {
|
|
|
11469
11496
|
// Auto-save: schedule a debounced write when autoSync is on and there
|
|
11470
11497
|
// were actual changes that originated from application code (not a
|
|
11471
11498
|
// storage read or an explicit noAutoSave call).
|
|
11472
|
-
if (
|
|
11499
|
+
if (priv.state === 'ready' &&
|
|
11473
11500
|
this.autoSync &&
|
|
11474
11501
|
getStorage(this) &&
|
|
11475
11502
|
changes.length &&
|
|
11476
11503
|
!options.fromStorage &&
|
|
11477
11504
|
!options.noAutoSave) {
|
|
11478
|
-
scheduleAutoSave(this, () =>
|
|
11505
|
+
scheduleAutoSave(this, () => this.save(null, { noAutoSave: true }), this.autoSyncDelay);
|
|
11479
11506
|
}
|
|
11480
11507
|
return this;
|
|
11481
11508
|
}
|
|
@@ -11756,37 +11783,8 @@ class Model extends EventEmitterObject {
|
|
|
11756
11783
|
return false;
|
|
11757
11784
|
}
|
|
11758
11785
|
}
|
|
11759
|
-
_Model_computedCache = new WeakMap(), _Model_computedDefs = new WeakMap(), _Model_state = new WeakMap(), _Model_instances = new WeakSet(), _Model_hydrate = async function _Model_hydrate() {
|
|
11760
|
-
ensureUnloadListener(PersistentStorage);
|
|
11761
|
-
try {
|
|
11762
|
-
await this.fetch({ fromStorage: true, promise: true });
|
|
11763
|
-
}
|
|
11764
|
-
finally {
|
|
11765
|
-
__classPrivateFieldSet(this, _Model_state, 'ready', "f");
|
|
11766
|
-
}
|
|
11767
|
-
}, _Model_doAutoSave = function _Model_doAutoSave() {
|
|
11768
|
-
return this.save(null, { noAutoSave: true });
|
|
11769
|
-
}, _Model_updateComputed = function _Model_updateComputed(key, def, silent, options) {
|
|
11770
|
-
const newVal = def.fn(this);
|
|
11771
|
-
if (!isEqual(__classPrivateFieldGet(this, _Model_computedCache, "f")[key], newVal)) {
|
|
11772
|
-
__classPrivateFieldGet(this, _Model_computedCache, "f")[key] = newVal;
|
|
11773
|
-
if (!silent) {
|
|
11774
|
-
this.changed[key] = newVal;
|
|
11775
|
-
this.trigger('change:' + key, this, newVal, options);
|
|
11776
|
-
}
|
|
11777
|
-
}
|
|
11778
|
-
}, _Model_initComputed = function _Model_initComputed() {
|
|
11779
|
-
const defs = result(this, 'computed');
|
|
11780
|
-
if (!defs || isEmpty(defs))
|
|
11781
|
-
return;
|
|
11782
|
-
__classPrivateFieldSet(this, _Model_computedDefs, defs, "f");
|
|
11783
|
-
__classPrivateFieldSet(this, _Model_computedCache, {}, "f");
|
|
11784
|
-
for (const [key, def] of Object.entries(defs)) {
|
|
11785
|
-
__classPrivateFieldGet(this, _Model_computedCache, "f")[key] = def.fn(this);
|
|
11786
|
-
}
|
|
11787
|
-
};
|
|
11788
11786
|
|
|
11789
|
-
var
|
|
11787
|
+
var _a;
|
|
11790
11788
|
// Default options for `Collection#set`.
|
|
11791
11789
|
const setOptions = { add: true, remove: true, merge: true };
|
|
11792
11790
|
const addOptions = { add: true, remove: false };
|
|
@@ -11807,6 +11805,18 @@ function toModelPredicate(pred) {
|
|
|
11807
11805
|
const matcher = matches(pred);
|
|
11808
11806
|
return (m) => matcher(m.attributes);
|
|
11809
11807
|
}
|
|
11808
|
+
/**
|
|
11809
|
+
* Load the collection's members from storage. A module-level function rather
|
|
11810
|
+
* than a `#private` method so the published declarations carry no private
|
|
11811
|
+
* members, which TypeScript 6 rejects in anonymously extended classes (TS4094).
|
|
11812
|
+
*/
|
|
11813
|
+
async function hydrate(collection) {
|
|
11814
|
+
ensureUnloadListener(PersistentStorage);
|
|
11815
|
+
// An empty store is a normal first-run state: findAll() returns [] and a
|
|
11816
|
+
// missing model record resolves to null, so hydration resolves rather
|
|
11817
|
+
// than rejecting.
|
|
11818
|
+
await collection.fetch({ fromStorage: true, promise: true });
|
|
11819
|
+
}
|
|
11810
11820
|
/**
|
|
11811
11821
|
* @public
|
|
11812
11822
|
* If models tend to represent a single row of data, a Collection is
|
|
@@ -11824,7 +11834,6 @@ class Collection extends EventEmitterObject {
|
|
|
11824
11834
|
*/
|
|
11825
11835
|
constructor(models, options) {
|
|
11826
11836
|
super();
|
|
11827
|
-
_Collection_instances.add(this);
|
|
11828
11837
|
this._url = '';
|
|
11829
11838
|
/**
|
|
11830
11839
|
* @public
|
|
@@ -11846,7 +11855,7 @@ class Collection extends EventEmitterObject {
|
|
|
11846
11855
|
// uniformly `await collection.hydrated`; it resolves immediately when
|
|
11847
11856
|
// there's no storage to hydrate from.
|
|
11848
11857
|
if (this.autoSync) {
|
|
11849
|
-
this.hydrated = getStorage(this) ?
|
|
11858
|
+
this.hydrated = getStorage(this) ? hydrate(this) : Promise.resolve();
|
|
11850
11859
|
}
|
|
11851
11860
|
}
|
|
11852
11861
|
get comparator() {
|
|
@@ -12529,13 +12538,7 @@ class Collection extends EventEmitterObject {
|
|
|
12529
12538
|
this.trigger.apply(this, arguments);
|
|
12530
12539
|
}
|
|
12531
12540
|
}
|
|
12532
|
-
|
|
12533
|
-
ensureUnloadListener(PersistentStorage);
|
|
12534
|
-
// An empty store is a normal first-run state: findAll() returns [] and a
|
|
12535
|
-
// missing model record resolves to null, so hydration resolves rather
|
|
12536
|
-
// than rejecting.
|
|
12537
|
-
await this.fetch({ fromStorage: true, promise: true });
|
|
12538
|
-
}, _a = Symbol.iterator;
|
|
12541
|
+
_a = Symbol.iterator;
|
|
12539
12542
|
// This "enum" defines the three possible kinds of values which can be emitted
|
|
12540
12543
|
// by a CollectionIterator that correspond to the values(), keys() and entries()
|
|
12541
12544
|
// methods on Collection, respectively.
|
package/package.json
CHANGED
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"contributors": [
|
|
40
40
|
"JC Brand"
|
|
41
41
|
],
|
|
42
|
-
"version": "4.0.
|
|
42
|
+
"version": "4.0.1",
|
|
43
43
|
"engines": {
|
|
44
44
|
"node": ">=22.0.0"
|
|
45
45
|
},
|
|
@@ -49,15 +49,12 @@
|
|
|
49
49
|
"url": "https://github.com/conversejs/skeletor.git"
|
|
50
50
|
},
|
|
51
51
|
"scripts": {
|
|
52
|
-
"build": "npm run
|
|
53
|
-
"build:declarations": "npm run build:types && api-extractor run --local && api-extractor run --local -c api-extractor.node.json && rm -rf dist/defs",
|
|
54
|
-
"build:types": "tsc -p tsconfig.declarations.json",
|
|
52
|
+
"build": "npm run clean && rollup -c",
|
|
55
53
|
"check": "npm run check:types && npm run test && npm run test:node && npm run lint",
|
|
56
54
|
"check:types": "tsc --noEmit",
|
|
57
55
|
"clean": "rm -rf dist",
|
|
58
56
|
"dev": "karma start --single-run=false",
|
|
59
57
|
"lint": "eslint src/*.ts test/*.ts",
|
|
60
|
-
"prebuild": "npm run clean && mkdir -p dist/defs",
|
|
61
58
|
"prepack": "npm run build",
|
|
62
59
|
"prettier": "prettier --write src/**/*.js test/**/*.js src/**/*.ts test/**/*.ts",
|
|
63
60
|
"test": "karma start && karma start --mocha-only",
|
|
@@ -74,7 +71,6 @@
|
|
|
74
71
|
"dist/skeletor.node.js",
|
|
75
72
|
"dist/skeletor.node.mjs",
|
|
76
73
|
"dist/skeletor.d.ts",
|
|
77
|
-
"dist/skeletor.d.ts.map",
|
|
78
74
|
"dist/skeletor.node.d.ts",
|
|
79
75
|
"src/**/*.ts"
|
|
80
76
|
],
|
|
@@ -95,14 +91,14 @@
|
|
|
95
91
|
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
|
|
96
92
|
"@babel/plugin-proposal-optional-chaining": "^7.13.12",
|
|
97
93
|
"@babel/preset-env": "^7.9.5",
|
|
98
|
-
"@microsoft/api-extractor": "^7.53.2",
|
|
99
94
|
"@rollup/plugin-babel": "^6.0.4",
|
|
100
95
|
"@rollup/plugin-commonjs": "^28.0.3",
|
|
101
96
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
102
|
-
"@rollup/plugin-terser": "^0.
|
|
97
|
+
"@rollup/plugin-terser": "^1.0.0",
|
|
103
98
|
"@rollup/plugin-typescript": "^12.1.4",
|
|
104
99
|
"@types/chai": "^5.2.3",
|
|
105
100
|
"@types/mocha": "^10.0.10",
|
|
101
|
+
"@types/node": "^26.6.5",
|
|
106
102
|
"@types/qunit": "^2.19.13",
|
|
107
103
|
"@types/sinon": "^17.0.4",
|
|
108
104
|
"@typescript-eslint/eslint-plugin": "^8.29.0",
|
|
@@ -117,15 +113,16 @@
|
|
|
117
113
|
"karma-mocha": "^2.0.1",
|
|
118
114
|
"karma-qunit": "^4.1.1",
|
|
119
115
|
"karma-webpack": "^5.0.1",
|
|
120
|
-
"mocha": "^
|
|
116
|
+
"mocha": "^12.0.0",
|
|
121
117
|
"prettier": "^3.0.0",
|
|
122
118
|
"qunit": "^2.10.0",
|
|
123
119
|
"rollup": "^4.39.0",
|
|
120
|
+
"rollup-plugin-dts": "^6.5.1",
|
|
124
121
|
"rollup-plugin-summary": "^3.0.0",
|
|
125
122
|
"sinon": "^9.0.2",
|
|
126
123
|
"ts-loader": "^9.5.4",
|
|
127
124
|
"tsx": "^4.21.0",
|
|
128
|
-
"typescript": "^
|
|
125
|
+
"typescript": "^6.0.3",
|
|
129
126
|
"webpack": "^5.98.0",
|
|
130
127
|
"webpack-cli": "^6.0.1",
|
|
131
128
|
"window-or-global": "^1.0.1"
|
package/src/collection.ts
CHANGED
|
@@ -52,6 +52,19 @@ function toModelPredicate<T extends Model>(
|
|
|
52
52
|
return (m: T) => matcher(m.attributes);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Load the collection's members from storage. A module-level function rather
|
|
57
|
+
* than a `#private` method so the published declarations carry no private
|
|
58
|
+
* members, which TypeScript 6 rejects in anonymously extended classes (TS4094).
|
|
59
|
+
*/
|
|
60
|
+
async function hydrate(collection: Collection<any>): Promise<void> {
|
|
61
|
+
ensureUnloadListener(PersistentStorage);
|
|
62
|
+
// An empty store is a normal first-run state: findAll() returns [] and a
|
|
63
|
+
// missing model record resolves to null, so hydration resolves rather
|
|
64
|
+
// than rejecting.
|
|
65
|
+
await collection.fetch({ fromStorage: true, promise: true });
|
|
66
|
+
}
|
|
67
|
+
|
|
55
68
|
/**
|
|
56
69
|
* @public
|
|
57
70
|
* If models tend to represent a single row of data, a Collection is
|
|
@@ -91,7 +104,7 @@ export class Collection<T extends Model = Model> extends EventEmitterObject {
|
|
|
91
104
|
// uniformly `await collection.hydrated`; it resolves immediately when
|
|
92
105
|
// there's no storage to hydrate from.
|
|
93
106
|
if (this.autoSync) {
|
|
94
|
-
this.hydrated = getStorage(this) ?
|
|
107
|
+
this.hydrated = getStorage(this) ? hydrate(this) : Promise.resolve();
|
|
95
108
|
}
|
|
96
109
|
}
|
|
97
110
|
|
|
@@ -143,14 +156,6 @@ export class Collection<T extends Model = Model> extends EventEmitterObject {
|
|
|
143
156
|
return false;
|
|
144
157
|
}
|
|
145
158
|
|
|
146
|
-
async #hydrate(): Promise<void> {
|
|
147
|
-
ensureUnloadListener(PersistentStorage);
|
|
148
|
-
// An empty store is a normal first-run state: findAll() returns [] and a
|
|
149
|
-
// missing model record resolves to null, so hydration resolves rather
|
|
150
|
-
// than rejecting.
|
|
151
|
-
await this.fetch({ fromStorage: true, promise: true });
|
|
152
|
-
}
|
|
153
|
-
|
|
154
159
|
/**
|
|
155
160
|
* The default model for a collection is just a **Model**.
|
|
156
161
|
* This should be overridden in most cases.
|