@mocanvas/store 4.0.1 → 4.1.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/ARCHITECTURE.md +8 -2
- package/BENCHMARK.md +244 -84
- package/MIGRATION.md +46 -22
- package/UI.md +24 -2
- package/dist/index.d.ts +13 -3
- package/dist/index.js +48 -13
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -816,11 +816,21 @@ declare class StoreSchema<R extends UnknownRecord, Props = unknown> {
|
|
|
816
816
|
/** Scope of a record type; unknown types are treated as `document`. */
|
|
817
817
|
getScope(typeName: string): RecordScope;
|
|
818
818
|
/**
|
|
819
|
-
* Validate a record, delegating to its record type's validator.
|
|
820
|
-
*
|
|
821
|
-
*
|
|
819
|
+
* Validate a record, delegating to its record type's validator.
|
|
820
|
+
*
|
|
821
|
+
* Two things are checked before the delegation. First, the value has to be a
|
|
822
|
+
* record at all: an object with a string `id` and a string `typeName`.
|
|
823
|
+
* Without that check a value carrying no `typeName` looks up `undefined` in
|
|
824
|
+
* the type map, misses, and takes the unknown-type path below — which is how
|
|
825
|
+
* `store.put([{ id: "shape:bogus", x: 0, y: 0 }])` used to be accepted.
|
|
826
|
+
*
|
|
827
|
+
* Second, a record whose `typeName` this schema does not know is passed
|
|
828
|
+
* through untouched, so foreign data survives a load/save round-trip. That
|
|
829
|
+
* is the escape hatch; it is not meant to cover malformed input, hence the
|
|
830
|
+
* first check.
|
|
822
831
|
*/
|
|
823
832
|
validateRecord(store: Store<R, any>, record: R, phase: StoreValidationPhase, recordBefore: R | undefined): R;
|
|
833
|
+
private onFailure;
|
|
824
834
|
/** The current version of every sequence. Always the v2 shape — mocanvas never writes v1. */
|
|
825
835
|
serialize(): SerializedSchemaV2;
|
|
826
836
|
/** A schema at version 0 of every sequence (all migrations still pending). */
|
package/dist/index.js
CHANGED
|
@@ -435,28 +435,51 @@ var StoreSchema = class _StoreSchema {
|
|
|
435
435
|
return this.typeByName.get(typeName)?.scope ?? "document";
|
|
436
436
|
}
|
|
437
437
|
/**
|
|
438
|
-
* Validate a record, delegating to its record type's validator.
|
|
439
|
-
*
|
|
440
|
-
*
|
|
438
|
+
* Validate a record, delegating to its record type's validator.
|
|
439
|
+
*
|
|
440
|
+
* Two things are checked before the delegation. First, the value has to be a
|
|
441
|
+
* record at all: an object with a string `id` and a string `typeName`.
|
|
442
|
+
* Without that check a value carrying no `typeName` looks up `undefined` in
|
|
443
|
+
* the type map, misses, and takes the unknown-type path below — which is how
|
|
444
|
+
* `store.put([{ id: "shape:bogus", x: 0, y: 0 }])` used to be accepted.
|
|
445
|
+
*
|
|
446
|
+
* Second, a record whose `typeName` this schema does not know is passed
|
|
447
|
+
* through untouched, so foreign data survives a load/save round-trip. That
|
|
448
|
+
* is the escape hatch; it is not meant to cover malformed input, hence the
|
|
449
|
+
* first check.
|
|
441
450
|
*/
|
|
442
451
|
validateRecord(store, record, phase, recordBefore) {
|
|
452
|
+
if (!isRecordLike(record)) {
|
|
453
|
+
return this.onFailure(
|
|
454
|
+
new Error(
|
|
455
|
+
`Expected a record with a string \`id\` and \`typeName\`, got ${describeRecord(record)}`
|
|
456
|
+
),
|
|
457
|
+
store,
|
|
458
|
+
record,
|
|
459
|
+
phase,
|
|
460
|
+
recordBefore
|
|
461
|
+
);
|
|
462
|
+
}
|
|
443
463
|
const type = this.typeByName.get(record.typeName);
|
|
444
464
|
if (!type) return record;
|
|
445
465
|
try {
|
|
446
466
|
return type.validate(record, recordBefore);
|
|
447
467
|
} catch (error) {
|
|
448
|
-
|
|
449
|
-
return this.options.onValidationFailure({
|
|
450
|
-
error,
|
|
451
|
-
store,
|
|
452
|
-
record,
|
|
453
|
-
phase,
|
|
454
|
-
recordBefore: recordBefore ?? null
|
|
455
|
-
});
|
|
456
|
-
}
|
|
457
|
-
throw error;
|
|
468
|
+
return this.onFailure(error, store, record, phase, recordBefore);
|
|
458
469
|
}
|
|
459
470
|
}
|
|
471
|
+
onFailure(error, store, record, phase, recordBefore) {
|
|
472
|
+
if (this.options.onValidationFailure) {
|
|
473
|
+
return this.options.onValidationFailure({
|
|
474
|
+
error,
|
|
475
|
+
store,
|
|
476
|
+
record,
|
|
477
|
+
phase,
|
|
478
|
+
recordBefore: recordBefore ?? null
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
throw error;
|
|
482
|
+
}
|
|
460
483
|
/** The current version of every sequence. Always the v2 shape — mocanvas never writes v1. */
|
|
461
484
|
serialize() {
|
|
462
485
|
const sequences = {};
|
|
@@ -570,6 +593,18 @@ var StoreSchema = class _StoreSchema {
|
|
|
570
593
|
return { type: "success", value: store };
|
|
571
594
|
}
|
|
572
595
|
};
|
|
596
|
+
function describeRecord(value) {
|
|
597
|
+
if (value === null) return "null";
|
|
598
|
+
if (typeof value !== "object") return typeof value;
|
|
599
|
+
if (Array.isArray(value)) return "an array";
|
|
600
|
+
const { id, typeName } = value;
|
|
601
|
+
const parts = [];
|
|
602
|
+
parts.push(typeof id === "string" ? `id ${JSON.stringify(id)}` : `id ${id === void 0 ? "missing" : typeof id}`);
|
|
603
|
+
parts.push(
|
|
604
|
+
typeof typeName === "string" ? `typeName ${JSON.stringify(typeName)}` : `typeName ${typeName === void 0 ? "missing" : typeof typeName}`
|
|
605
|
+
);
|
|
606
|
+
return `an object with ${parts.join(" and ")}`;
|
|
607
|
+
}
|
|
573
608
|
|
|
574
609
|
// src/query.ts
|
|
575
610
|
function matchesQueryValue(matcher, value) {
|