teamplay 0.5.0-alpha.36 → 0.5.0-alpha.38
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 +3 -3
- package/dist/orm/Query.js +0 -51
- package/dist/orm/Signal.d.ts +0 -2
- package/dist/orm/Signal.js +1 -4
- package/dist/orm/dataTree.js +13 -19
- package/dist/orm/initModels.js +1 -1
- package/dist/orm/queryReadiness.js +1 -1
- package/package.json +10 -13
- package/dist/orm/Compat/SignalCompat.d.ts +0 -3
- package/dist/orm/Compat/SignalCompat.js +0 -640
- package/dist/orm/compatEnv.d.ts +0 -1
- package/dist/orm/compatEnv.js +0 -4
package/README.md
CHANGED
|
@@ -13,16 +13,16 @@ Features:
|
|
|
13
13
|
|
|
14
14
|
> __*__ deep signals -- with support for objects and arrays\
|
|
15
15
|
> __**__ concurrent changes to the same data are auto-merged using [OT](https://en.wikipedia.org/wiki/Operational_transformation)\
|
|
16
|
-
> __***__ similar to Firebase but with your own MongoDB
|
|
16
|
+
> __***__ similar to Firebase but with your own MongoDB database
|
|
17
17
|
|
|
18
18
|
## Installation
|
|
19
19
|
|
|
20
20
|
For installation and documentation see [teamplay.dev](https://teamplay.dev)
|
|
21
21
|
|
|
22
|
-
## ORM
|
|
22
|
+
## ORM Helpers
|
|
23
23
|
|
|
24
24
|
For legacy Racer-style model mixins (for example versioning libraries which call
|
|
25
|
-
`getAssociations()`), use ORM
|
|
25
|
+
`getAssociations()`), use ORM helpers from the `teamplay/orm` subpath:
|
|
26
26
|
|
|
27
27
|
```js
|
|
28
28
|
import BaseModel, { hasMany, hasOne, belongsTo } from 'teamplay/orm'
|
package/dist/orm/Query.js
CHANGED
|
@@ -2,7 +2,6 @@ import { raw } from '@nx-js/observer-util';
|
|
|
2
2
|
import { set as _set, getRaw } from './dataTree.js';
|
|
3
3
|
import getSignal from "./getSignal.js";
|
|
4
4
|
import { getConnection } from "./connection.js";
|
|
5
|
-
import { isCompatEnv } from './compatEnv.js';
|
|
6
5
|
import { docSubscriptions } from './Doc.js';
|
|
7
6
|
import FinalizationRegistry from "../utils/MockFinalizationRegistry.js";
|
|
8
7
|
import SubscriptionState from './SubscriptionState.js';
|
|
@@ -836,8 +835,6 @@ export class QuerySubscriptions {
|
|
|
836
835
|
}
|
|
837
836
|
export const querySubscriptions = new QuerySubscriptions();
|
|
838
837
|
function maybeMaterializeQueryDocsToCollection(collectionName, shareDocs) {
|
|
839
|
-
if (!isCompatEnv())
|
|
840
|
-
return;
|
|
841
838
|
for (const doc of shareDocs) {
|
|
842
839
|
if (!doc?.id || doc.data == null)
|
|
843
840
|
continue;
|
|
@@ -937,7 +934,6 @@ function getQueryOwnerKey(rootId, transportHash) {
|
|
|
937
934
|
return getScopedSignalHash(rootId, transportHash, 'queryOwner');
|
|
938
935
|
}
|
|
939
936
|
export function cloneQueryParams(collectionName, params) {
|
|
940
|
-
warnIfCompatQueryParamsHaveUndefinedFields(collectionName, params);
|
|
941
937
|
return JSON.parse(JSON.stringify(params));
|
|
942
938
|
}
|
|
943
939
|
function parseQuerySignalOptions(options) {
|
|
@@ -951,55 +947,8 @@ function parseQuerySignalOptions(options) {
|
|
|
951
947
|
return { root, signalOptions };
|
|
952
948
|
}
|
|
953
949
|
function normalizeQueryParamsForHash(collectionName, params) {
|
|
954
|
-
warnIfCompatQueryParamsHaveUndefinedFields(collectionName, params);
|
|
955
950
|
return params;
|
|
956
951
|
}
|
|
957
|
-
const warnedUndefinedQueryParamKeys = new Set();
|
|
958
|
-
function warnIfCompatQueryParamsHaveUndefinedFields(collectionName, params) {
|
|
959
|
-
if (!isCompatEnv())
|
|
960
|
-
return;
|
|
961
|
-
const paths = getUndefinedQueryParamFieldPaths(params);
|
|
962
|
-
if (paths.length === 0)
|
|
963
|
-
return;
|
|
964
|
-
const key = `${collectionName || '<unknown>'}:${paths.join(',')}`;
|
|
965
|
-
if (warnedUndefinedQueryParamKeys.has(key))
|
|
966
|
-
return;
|
|
967
|
-
warnedUndefinedQueryParamKeys.add(key);
|
|
968
|
-
console.warn('[teamplay] Compat query params contain object fields with undefined values. ' +
|
|
969
|
-
'TeamPlay now clones query params like non-compat mode, so these fields are dropped ' +
|
|
970
|
-
'instead of being converted to null. Normalize query params explicitly.', {
|
|
971
|
-
collectionName,
|
|
972
|
-
paths
|
|
973
|
-
}, new Error().stack);
|
|
974
|
-
}
|
|
975
|
-
function getUndefinedQueryParamFieldPaths(value) {
|
|
976
|
-
const paths = [];
|
|
977
|
-
collectUndefinedQueryParamFieldPaths(value, '', paths, new WeakSet());
|
|
978
|
-
return paths;
|
|
979
|
-
}
|
|
980
|
-
function collectUndefinedQueryParamFieldPaths(value, path, paths, seen) {
|
|
981
|
-
if (value == null || typeof value !== 'object')
|
|
982
|
-
return;
|
|
983
|
-
if (seen.has(value))
|
|
984
|
-
return;
|
|
985
|
-
seen.add(value);
|
|
986
|
-
if (Array.isArray(value)) {
|
|
987
|
-
for (let i = 0; i < value.length; i++) {
|
|
988
|
-
collectUndefinedQueryParamFieldPaths(value[i], `${path}[${i}]`, paths, seen);
|
|
989
|
-
}
|
|
990
|
-
return;
|
|
991
|
-
}
|
|
992
|
-
for (const key in value) {
|
|
993
|
-
if (!Object.prototype.hasOwnProperty.call(value, key))
|
|
994
|
-
continue;
|
|
995
|
-
const childPath = path ? `${path}.${key}` : key;
|
|
996
|
-
if (value[key] === undefined) {
|
|
997
|
-
paths.push(childPath);
|
|
998
|
-
continue;
|
|
999
|
-
}
|
|
1000
|
-
collectUndefinedQueryParamFieldPaths(value[key], childPath, paths, seen);
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
952
|
function createPendingDestroyEntry() {
|
|
1004
953
|
let resolvePending;
|
|
1005
954
|
let rejectPending;
|
package/dist/orm/Signal.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import SignalCompat from './Compat/SignalCompat.js';
|
|
2
1
|
import type { SignalConstructor } from './types/signal.js';
|
|
3
2
|
export type { FromJsonSchema, InferZodSchema, JsonSchema, JsonSchemaObject, ZodLikeSchema } from './types/jsonSchema.js';
|
|
4
3
|
export type { ComputedQueryParamsInput, QueryParams, QueryParamsInput } from './types/query.js';
|
|
@@ -7,6 +6,5 @@ export type { AppendPath, JoinPath, PathSegment, SignalPath, WildcardPathSegment
|
|
|
7
6
|
export type { AggregationSignal, AnySignal, ArraySignal, CollectionAggregationSignal, CollectionDocument, CollectionDocumentModel, CollectionQuerySignal, CollectionSignal, CollectionSignalFromSpec, CollectionSpec, DocumentSignal, JsonSchemaSpec, MaybePromise, MaybePromiseSubResult, PublicSignal, LocalSignalFactory, RegisteredAggregationInput, RuntimeSignalConstructor, RuntimeSignalInstance, QuerySignal, RootCollections, RootSignal, SignalBaseInstance, SignalChild, SignalChildren, SignalClass, SignalConstructor, SignalForKind, SignalKind, SignalInstance, SignalModelConstructor, PrivateSignalFromSpec, RootPrivateCollections, SubResult, TypedAggregationInput, TypedAggregationSignal, TypedSignal, ZodSchemaSpec } from './types/signal.js';
|
|
8
7
|
export type { CollectionsFromManifest, ModelEntry, ModelManifest, PathModelsFromManifest, PrivateCollectionsFromManifest } from './types/modelManifest.js';
|
|
9
8
|
export { Signal, SEGMENTS, ARRAY_METHOD, GET, GETTERS, DEFAULT_GETTERS, regularBindings, extremelyLateBindings, isPublicCollectionSignal, isPublicDocumentSignal, isPublicCollection, isPrivateCollection } from './SignalBase.js';
|
|
10
|
-
export { SignalCompat };
|
|
11
9
|
declare const DefaultSignal: SignalConstructor;
|
|
12
10
|
export default DefaultSignal;
|
package/dist/orm/Signal.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import { Signal } from "./SignalBase.js";
|
|
2
|
-
import SignalCompat from './Compat/SignalCompat.js';
|
|
3
|
-
import { isCompatEnv } from './compatEnv.js';
|
|
4
2
|
export { Signal, SEGMENTS, ARRAY_METHOD, GET, GETTERS, DEFAULT_GETTERS, regularBindings, extremelyLateBindings, isPublicCollectionSignal, isPublicDocumentSignal, isPublicCollection, isPrivateCollection } from "./SignalBase.js";
|
|
5
|
-
|
|
6
|
-
const DefaultSignal = (isCompatEnv() ? SignalCompat : Signal);
|
|
3
|
+
const DefaultSignal = Signal;
|
|
7
4
|
export default DefaultSignal;
|
package/dist/orm/dataTree.js
CHANGED
|
@@ -4,7 +4,6 @@ import diffMatchPatch from 'diff-match-patch';
|
|
|
4
4
|
import { getConnection } from "./connection.js";
|
|
5
5
|
import setDiffDeep from '../utils/setDiffDeep.js';
|
|
6
6
|
import { getIdFieldsForSegments, injectIdFields, stripIdFields, isPlainObject, isIdFieldPath } from "./idFields.js";
|
|
7
|
-
import { isCompatEnv } from './compatEnv.js';
|
|
8
7
|
import { isMissingShareDoc } from './missingDoc.js';
|
|
9
8
|
import { getLogicalRootSnapshot as getLogicalRootSnapshotFromTree } from "./rootScope.js";
|
|
10
9
|
import { getRootContext } from "./rootContext.js";
|
|
@@ -150,7 +149,7 @@ export async function setPublicDoc(segments, value, deleteValue = false) {
|
|
|
150
149
|
const doc = getConnection().get(collection, docId);
|
|
151
150
|
let docState = resolvePublicDocState({ collection, docId, doc, idFields, hydrateDocDataFromLocal: true });
|
|
152
151
|
if (!docState.exists && segments.length > 2) {
|
|
153
|
-
docState = await
|
|
152
|
+
docState = await resolvePublicDocStateWithLocalRecovery({
|
|
154
153
|
collection,
|
|
155
154
|
docId,
|
|
156
155
|
doc,
|
|
@@ -159,7 +158,7 @@ export async function setPublicDoc(segments, value, deleteValue = false) {
|
|
|
159
158
|
});
|
|
160
159
|
}
|
|
161
160
|
if (!docState.exists && deleteValue)
|
|
162
|
-
|
|
161
|
+
return;
|
|
163
162
|
// make sure that the value is not observable to not trigger extra reads. And clone it
|
|
164
163
|
value = raw(value);
|
|
165
164
|
if (value == null) {
|
|
@@ -258,7 +257,7 @@ export async function setPublicDocReplace(segments, value) {
|
|
|
258
257
|
const doc = getConnection().get(collection, docId);
|
|
259
258
|
let docState = resolvePublicDocState({ collection, docId, doc, idFields, hydrateDocDataFromLocal: true });
|
|
260
259
|
if (!docState.exists && segments.length > 2) {
|
|
261
|
-
docState = await
|
|
260
|
+
docState = await resolvePublicDocStateWithLocalRecovery({
|
|
262
261
|
collection,
|
|
263
262
|
docId,
|
|
264
263
|
doc,
|
|
@@ -306,7 +305,7 @@ export async function setPublicDocReplace(segments, value) {
|
|
|
306
305
|
}
|
|
307
306
|
const relativePath = segments.slice(2);
|
|
308
307
|
// json0 direct replace ops require every ancestor container to already exist.
|
|
309
|
-
//
|
|
308
|
+
// setPublicDoc() materializes missing/primitive parents while
|
|
310
309
|
// descending into the path. Fall back to the older diff-based path when the
|
|
311
310
|
// direct op would target a non-existent/non-object ancestor.
|
|
312
311
|
if (!canApplyDirectReplaceOp(docState.snapshot || {}, relativePath)) {
|
|
@@ -381,13 +380,13 @@ function resolvePublicDocState({ collection, docId, doc, idFields, hydrateDocDat
|
|
|
381
380
|
}
|
|
382
381
|
return { exists: true, snapshot: localSnapshot, source: 'local' };
|
|
383
382
|
}
|
|
384
|
-
async function
|
|
383
|
+
async function resolvePublicDocStateWithLocalRecovery({ collection, docId, doc, idFields, hydrateDocDataFromLocal = false }) {
|
|
385
384
|
let docState = resolvePublicDocState({ collection, docId, doc, idFields, hydrateDocDataFromLocal });
|
|
386
385
|
if (docState.exists)
|
|
387
386
|
return docState;
|
|
388
|
-
const shouldFetch =
|
|
387
|
+
const shouldFetch = getRaw([collection, docId]) != null &&
|
|
389
388
|
isMissingShareDoc(doc) &&
|
|
390
|
-
doc.version == null
|
|
389
|
+
doc.version == null;
|
|
391
390
|
if (!shouldFetch)
|
|
392
391
|
return docState;
|
|
393
392
|
await new Promise((resolve, reject) => {
|
|
@@ -529,7 +528,7 @@ export async function incrementPublic(segments, byNumber) {
|
|
|
529
528
|
throw Error(ERRORS.publicDoc(segments));
|
|
530
529
|
const doc = getConnection().get(collection, docId);
|
|
531
530
|
const idFields = getIdFieldsForSegments([collection, docId]);
|
|
532
|
-
const docState = await
|
|
531
|
+
const docState = await resolvePublicDocStateWithLocalRecovery({
|
|
533
532
|
collection,
|
|
534
533
|
docId,
|
|
535
534
|
doc,
|
|
@@ -572,7 +571,7 @@ export async function arrayInsertPublic(segments, index, values) {
|
|
|
572
571
|
throw Error(ERRORS.publicDoc(segments));
|
|
573
572
|
const doc = getConnection().get(collection, docId);
|
|
574
573
|
const idFields = getIdFieldsForSegments([collection, docId]);
|
|
575
|
-
const docState = await
|
|
574
|
+
const docState = await resolvePublicDocStateWithLocalRecovery({
|
|
576
575
|
collection,
|
|
577
576
|
docId,
|
|
578
577
|
doc,
|
|
@@ -631,7 +630,7 @@ export async function arrayRemovePublic(segments, index, howMany = 1) {
|
|
|
631
630
|
throw Error(ERRORS.publicDoc(segments));
|
|
632
631
|
const doc = getConnection().get(collection, docId);
|
|
633
632
|
const idFields = getIdFieldsForSegments([collection, docId]);
|
|
634
|
-
const docState = await
|
|
633
|
+
const docState = await resolvePublicDocStateWithLocalRecovery({
|
|
635
634
|
collection,
|
|
636
635
|
docId,
|
|
637
636
|
doc,
|
|
@@ -659,7 +658,7 @@ export async function arrayMovePublic(segments, from, to, howMany = 1) {
|
|
|
659
658
|
throw Error(ERRORS.publicDoc(segments));
|
|
660
659
|
const doc = getConnection().get(collection, docId);
|
|
661
660
|
const idFields = getIdFieldsForSegments([collection, docId]);
|
|
662
|
-
const docState = await
|
|
661
|
+
const docState = await resolvePublicDocStateWithLocalRecovery({
|
|
663
662
|
collection,
|
|
664
663
|
docId,
|
|
665
664
|
doc,
|
|
@@ -734,7 +733,7 @@ export async function stringInsertPublic(segments, index, text) {
|
|
|
734
733
|
throw Error(ERRORS.publicDoc(segments));
|
|
735
734
|
const doc = getConnection().get(collection, docId);
|
|
736
735
|
const idFields = getIdFieldsForSegments([collection, docId]);
|
|
737
|
-
const docState = await
|
|
736
|
+
const docState = await resolvePublicDocStateWithLocalRecovery({
|
|
738
737
|
collection,
|
|
739
738
|
docId,
|
|
740
739
|
doc,
|
|
@@ -768,7 +767,7 @@ export async function stringRemovePublic(segments, index, howMany) {
|
|
|
768
767
|
throw Error(ERRORS.publicDoc(segments));
|
|
769
768
|
const doc = getConnection().get(collection, docId);
|
|
770
769
|
const idFields = getIdFieldsForSegments([collection, docId]);
|
|
771
|
-
const docState = await
|
|
770
|
+
const docState = await resolvePublicDocStateWithLocalRecovery({
|
|
772
771
|
collection,
|
|
773
772
|
docId,
|
|
774
773
|
doc,
|
|
@@ -807,11 +806,6 @@ const ERRORS = {
|
|
|
807
806
|
`,
|
|
808
807
|
publicDocIdNumber: segments => `
|
|
809
808
|
Public doc id must be a string. Got a number: ${segments}
|
|
810
|
-
`,
|
|
811
|
-
deleteNonExistentDoc: segments => `
|
|
812
|
-
Trying to delete data from a non-existing doc ${segments}.
|
|
813
|
-
Make sure that the document exists and you are subscribed to it
|
|
814
|
-
before trying to delete anything from it or the doc itself.
|
|
815
809
|
`,
|
|
816
810
|
publicDocIdUndefined: segments => `
|
|
817
811
|
Trying to modify a public document with the id 'undefined'.
|
package/dist/orm/initModels.js
CHANGED
|
@@ -36,7 +36,7 @@ function warnIfSchemaWasNotDefined(pattern, schema) {
|
|
|
36
36
|
warnedUnwrappedSchemaPatterns.add(pattern);
|
|
37
37
|
console.warn(`[teamplay] Schema for model "${pattern}" was loaded as a plain object. ` +
|
|
38
38
|
'Wrap it with defineSchema(schema) to enable the conventional schema setup. ' +
|
|
39
|
-
'Plain schemas still work
|
|
39
|
+
'Plain schemas still work.');
|
|
40
40
|
}
|
|
41
41
|
function shouldWarnAboutUnwrappedSchemas() {
|
|
42
42
|
const env = getProcessEnv();
|
|
@@ -157,7 +157,7 @@ function createImperativeQueryReadinessError($query, timeoutMs) {
|
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
return Error(`
|
|
160
|
-
|
|
160
|
+
Query did not fully materialize within ${timeoutMs}ms.
|
|
161
161
|
Collection: ${collection}
|
|
162
162
|
Params: ${JSON.stringify(params)}
|
|
163
163
|
Hash: ${hash}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "teamplay",
|
|
3
|
-
"version": "0.5.0-alpha.
|
|
3
|
+
"version": "0.5.0-alpha.38",
|
|
4
4
|
"description": "Full-stack signals ORM with multiplayer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -57,16 +57,13 @@
|
|
|
57
57
|
"scripts": {
|
|
58
58
|
"build": "rm -rf dist && tsc -p tsconfig.build.json && rsync -a --include='*/' --include='*.d.ts' --include='*.cjs' --exclude='*' src/ dist/ && node ../../scripts/rewrite-dts-extensions.cjs dist",
|
|
59
59
|
"prepublishOnly": "npm run build",
|
|
60
|
-
"test": "npm run test-types && npm run test-types:external && npm run test-server && npm run test-client
|
|
60
|
+
"test": "npm run test-types && npm run test-types:external && npm run test-server && npm run test-client",
|
|
61
61
|
"test-types": "tsc -p tsconfig.type-tests.json",
|
|
62
62
|
"test-types:external": "tsc -p tsconfig.external-consumer.json",
|
|
63
63
|
"test-types:dist": "tsc -p tsconfig.external-consumer.dist.json",
|
|
64
64
|
"test-server": "NODE_OPTIONS=\"${NODE_OPTIONS:-} --expose-gc -C teamplay-ts\" mocha 'test/[!_]*.js'",
|
|
65
65
|
"test-server-only": "NODE_OPTIONS=\"${NODE_OPTIONS:-} --expose-gc -C teamplay-ts\" mocha --grep '@only' 'test/[!_]*.js'",
|
|
66
66
|
"test-client": "NODE_OPTIONS=\"${NODE_OPTIONS:-} --expose-gc --experimental-vm-modules -C teamplay-ts\" jest --runInBand",
|
|
67
|
-
"test-compat": "npm run test-server-compat && npm run test-client-compat",
|
|
68
|
-
"test-server-compat": "TEAMPLAY_COMPAT=1 NODE_OPTIONS=\"${NODE_OPTIONS:-} --expose-gc -C teamplay-ts\" mocha 'test/[!_]*.js'",
|
|
69
|
-
"test-client-compat": "TEAMPLAY_COMPAT=1 NODE_OPTIONS=\"${NODE_OPTIONS:-} --expose-gc --experimental-vm-modules -C teamplay-ts\" jest --runInBand",
|
|
70
67
|
"coverage-server": "NODE_OPTIONS=\"${NODE_OPTIONS:-} --expose-gc -C teamplay-ts\" c8 --include 'src/orm/**' --include 'src/react/**' --include 'src/utils/**' mocha 'test/[!_]*.js'",
|
|
71
68
|
"coverage-client": "NODE_OPTIONS=\"${NODE_OPTIONS:-} --expose-gc --experimental-vm-modules -C teamplay-ts\" jest --coverage --coverageDirectory=coverage-client",
|
|
72
69
|
"coverage": "npm run coverage-server && npm run coverage-client"
|
|
@@ -74,13 +71,13 @@
|
|
|
74
71
|
"dependencies": {
|
|
75
72
|
"@nx-js/observer-util": "^4.1.3",
|
|
76
73
|
"@startupjs/sharedb-mingo-memory": "^4.0.0-2",
|
|
77
|
-
"@teamplay/backend": "^0.5.0-alpha.
|
|
78
|
-
"@teamplay/cache": "^0.5.0-alpha.
|
|
79
|
-
"@teamplay/channel": "^0.5.0-alpha.
|
|
80
|
-
"@teamplay/debug": "^0.5.0-alpha.
|
|
81
|
-
"@teamplay/schema": "^0.5.0-alpha.
|
|
82
|
-
"@teamplay/utils": "^0.5.0-alpha.
|
|
83
|
-
"babel-plugin-teamplay": "^0.5.0-alpha.
|
|
74
|
+
"@teamplay/backend": "^0.5.0-alpha.38",
|
|
75
|
+
"@teamplay/cache": "^0.5.0-alpha.38",
|
|
76
|
+
"@teamplay/channel": "^0.5.0-alpha.38",
|
|
77
|
+
"@teamplay/debug": "^0.5.0-alpha.38",
|
|
78
|
+
"@teamplay/schema": "^0.5.0-alpha.38",
|
|
79
|
+
"@teamplay/utils": "^0.5.0-alpha.38",
|
|
80
|
+
"babel-plugin-teamplay": "^0.5.0-alpha.38",
|
|
84
81
|
"diff-match-patch": "^1.0.5",
|
|
85
82
|
"events": "^3.3.0",
|
|
86
83
|
"json0-ot-diff": "^1.1.2",
|
|
@@ -139,5 +136,5 @@
|
|
|
139
136
|
]
|
|
140
137
|
},
|
|
141
138
|
"license": "MIT",
|
|
142
|
-
"gitHead": "
|
|
139
|
+
"gitHead": "bda8f3ddc879c9b9ac491b946e24b7a3e04adb65"
|
|
143
140
|
}
|
|
@@ -1,640 +0,0 @@
|
|
|
1
|
-
import { raw } from '@nx-js/observer-util';
|
|
2
|
-
import arrayDiff from 'arraydiff';
|
|
3
|
-
import { Signal, GETTERS, DEFAULT_GETTERS, SEGMENTS, isPublicCollection } from "../SignalBase.js";
|
|
4
|
-
import { getRoot, ROOT, ROOT_ID } from "../Root.js";
|
|
5
|
-
import { IS_QUERY } from '../Query.js';
|
|
6
|
-
import { AGGREGATIONS, IS_AGGREGATION } from '../Aggregation.js';
|
|
7
|
-
import { getIdFieldsForSegments, isIdFieldPath, isPublicDocPath, normalizeIdFields, isPlainObject } from "../idFields.js";
|
|
8
|
-
import { incrementPublic as _incrementPublic, arrayPushPublic as _arrayPushPublic, arrayUnshiftPublic as _arrayUnshiftPublic, arrayInsertPublic as _arrayInsertPublic, arrayPopPublic as _arrayPopPublic, arrayShiftPublic as _arrayShiftPublic, arrayRemovePublic as _arrayRemovePublic, arrayMovePublic as _arrayMovePublic, setPublicDocReplace as _setPublicDocReplace, stringInsertPublic as _stringInsertPublic, stringRemovePublic as _stringRemovePublic } from '../dataTree.js';
|
|
9
|
-
import { on as onCustomEvent, removeListener as removeCustomEventListener } from '../events.js';
|
|
10
|
-
import { runInBatch } from '../batchScheduler.js';
|
|
11
|
-
import { arrayInsertPrivateData, arrayMovePrivateData, arrayPopPrivateData, arrayPushPrivateData, arrayRemovePrivateData, arrayShiftPrivateData, arrayUnshiftPrivateData, delPrivateData, setReplacePrivateData, stringInsertPrivateData, stringRemovePrivateData } from '../privateData.js';
|
|
12
|
-
class SignalCompat extends Signal {
|
|
13
|
-
static [GETTERS] = DEFAULT_GETTERS;
|
|
14
|
-
path() {
|
|
15
|
-
if (arguments.length > 0)
|
|
16
|
-
throw Error('Signal.path() does not accept any arguments');
|
|
17
|
-
return super.path();
|
|
18
|
-
}
|
|
19
|
-
getId() {
|
|
20
|
-
if (isAggregationValuePath(this[SEGMENTS]))
|
|
21
|
-
return super.getId();
|
|
22
|
-
return super.getId();
|
|
23
|
-
}
|
|
24
|
-
getCollection() {
|
|
25
|
-
return super.getCollection();
|
|
26
|
-
}
|
|
27
|
-
getCopy() {
|
|
28
|
-
if (arguments.length > 0)
|
|
29
|
-
throw Error('Signal.getCopy() does not accept any arguments');
|
|
30
|
-
return shallowCopy(this.get());
|
|
31
|
-
}
|
|
32
|
-
getDeepCopy() {
|
|
33
|
-
if (arguments.length > 0)
|
|
34
|
-
throw Error('Signal.getDeepCopy() does not accept any arguments');
|
|
35
|
-
return deepCopy(this.get());
|
|
36
|
-
}
|
|
37
|
-
getExtra() {
|
|
38
|
-
if (arguments.length > 0)
|
|
39
|
-
throw Error('Signal.getExtra() does not accept any arguments');
|
|
40
|
-
if (this[IS_AGGREGATION])
|
|
41
|
-
return this.get();
|
|
42
|
-
if (this[IS_QUERY])
|
|
43
|
-
return this.extra.get();
|
|
44
|
-
return undefined;
|
|
45
|
-
}
|
|
46
|
-
get() {
|
|
47
|
-
if (arguments.length > 0)
|
|
48
|
-
throw Error('Signal.get() does not accept any arguments');
|
|
49
|
-
return Signal.prototype.get.apply(this, arguments);
|
|
50
|
-
}
|
|
51
|
-
peek() {
|
|
52
|
-
if (arguments.length > 0)
|
|
53
|
-
throw Error('Signal.peek() does not accept any arguments');
|
|
54
|
-
return Signal.prototype.peek.apply(this, arguments);
|
|
55
|
-
}
|
|
56
|
-
async set(value) {
|
|
57
|
-
if (arguments.length > 1)
|
|
58
|
-
throw Error('Signal.set() expects a single argument');
|
|
59
|
-
return Signal.prototype.set.call(this, value);
|
|
60
|
-
}
|
|
61
|
-
async setReplace(value) {
|
|
62
|
-
if (arguments.length > 1)
|
|
63
|
-
throw Error('Signal.setReplace() expects a single argument');
|
|
64
|
-
if (value === undefined)
|
|
65
|
-
return Signal.prototype.set.call(this, value);
|
|
66
|
-
return setReplaceOnSignal(this, value);
|
|
67
|
-
}
|
|
68
|
-
async setNull(value) {
|
|
69
|
-
if (arguments.length > 1)
|
|
70
|
-
throw Error('Signal.setNull() expects a single argument');
|
|
71
|
-
if (this.get() != null)
|
|
72
|
-
return;
|
|
73
|
-
return setReplaceOnSignal(this, value);
|
|
74
|
-
}
|
|
75
|
-
async setDiffDeep(value) {
|
|
76
|
-
if (arguments.length > 1)
|
|
77
|
-
throw Error('Signal.setDiffDeep() expects a single argument');
|
|
78
|
-
return runInBatch(() => setDiffDeepOnSignal(this, value));
|
|
79
|
-
}
|
|
80
|
-
async setDiff(value) {
|
|
81
|
-
if (arguments.length > 1)
|
|
82
|
-
throw Error('Signal.setDiff() expects a single argument');
|
|
83
|
-
const before = this.peek();
|
|
84
|
-
if (racerEqualCompat(before, value))
|
|
85
|
-
return;
|
|
86
|
-
return setReplaceOnSignal(this, value);
|
|
87
|
-
}
|
|
88
|
-
async setEach(object) {
|
|
89
|
-
if (arguments.length > 1)
|
|
90
|
-
throw Error('Signal.setEach() expects a single argument');
|
|
91
|
-
if (!object)
|
|
92
|
-
return;
|
|
93
|
-
if (typeof object !== 'object') {
|
|
94
|
-
throw Error('Signal.setEach() expects an object argument, got: ' + typeof object);
|
|
95
|
-
}
|
|
96
|
-
return runInBatch(async () => {
|
|
97
|
-
const promises = [];
|
|
98
|
-
for (const key of Object.keys(object)) {
|
|
99
|
-
promises.push(SignalCompat.prototype.set.call(this[key], object[key]));
|
|
100
|
-
}
|
|
101
|
-
await Promise.all(promises);
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
async del() {
|
|
105
|
-
if (arguments.length > 0)
|
|
106
|
-
throw Error('Signal.del() does not accept any arguments');
|
|
107
|
-
try {
|
|
108
|
-
return await Signal.prototype.del.call(this);
|
|
109
|
-
}
|
|
110
|
-
catch (error) {
|
|
111
|
-
if (isMissingPublicDocDeleteError(this, error))
|
|
112
|
-
return;
|
|
113
|
-
throw error;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
async increment(byNumber) {
|
|
117
|
-
if (arguments.length > 1)
|
|
118
|
-
throw Error('Signal.increment() expects zero or one argument');
|
|
119
|
-
if (byNumber != null && (typeof byNumber !== 'number' || !Number.isFinite(byNumber))) {
|
|
120
|
-
throw Error('Signal.increment() expects a numeric argument');
|
|
121
|
-
}
|
|
122
|
-
return incrementOnSignal(this, byNumber);
|
|
123
|
-
}
|
|
124
|
-
async push(value) {
|
|
125
|
-
if (arguments.length > 1)
|
|
126
|
-
throw Error('Signal.push() expects a single argument');
|
|
127
|
-
return arrayPushOnSignal(this, value);
|
|
128
|
-
}
|
|
129
|
-
async unshift(value) {
|
|
130
|
-
if (arguments.length > 1)
|
|
131
|
-
throw Error('Signal.unshift() expects a single argument');
|
|
132
|
-
return arrayUnshiftOnSignal(this, value);
|
|
133
|
-
}
|
|
134
|
-
async insert(index, values) {
|
|
135
|
-
if (arguments.length < 2)
|
|
136
|
-
throw Error('Not enough arguments for insert');
|
|
137
|
-
if (arguments.length > 2)
|
|
138
|
-
throw Error('Signal.insert() expects two arguments');
|
|
139
|
-
if (typeof index !== 'number' || !Number.isFinite(index)) {
|
|
140
|
-
throw Error('Signal.insert() expects a numeric index');
|
|
141
|
-
}
|
|
142
|
-
return arrayInsertOnSignal(this, index, values);
|
|
143
|
-
}
|
|
144
|
-
async pop() {
|
|
145
|
-
if (arguments.length > 0)
|
|
146
|
-
throw Error('Signal.pop() does not accept any arguments');
|
|
147
|
-
return arrayPopOnSignal(this);
|
|
148
|
-
}
|
|
149
|
-
async shift() {
|
|
150
|
-
if (arguments.length > 0)
|
|
151
|
-
throw Error('Signal.shift() does not accept any arguments');
|
|
152
|
-
return arrayShiftOnSignal(this);
|
|
153
|
-
}
|
|
154
|
-
async remove(index, howMany) {
|
|
155
|
-
if (arguments.length === 0) {
|
|
156
|
-
const segments = this[SEGMENTS].slice();
|
|
157
|
-
if (!segments.length || typeof segments[segments.length - 1] !== 'number') {
|
|
158
|
-
throw Error('Signal.remove() expects an index');
|
|
159
|
-
}
|
|
160
|
-
index = segments.pop();
|
|
161
|
-
const $root = getRoot(this) || this;
|
|
162
|
-
const $target = resolveSignal($root, segments);
|
|
163
|
-
return arrayRemoveOnSignal($target, +index, howMany);
|
|
164
|
-
}
|
|
165
|
-
if (arguments.length > 2)
|
|
166
|
-
throw Error('Signal.remove() expects zero to two arguments');
|
|
167
|
-
if (typeof index !== 'number' || !Number.isFinite(index)) {
|
|
168
|
-
throw Error('Signal.remove() expects a numeric index');
|
|
169
|
-
}
|
|
170
|
-
return arrayRemoveOnSignal(this, index, howMany);
|
|
171
|
-
}
|
|
172
|
-
async move(from, to, howMany) {
|
|
173
|
-
if (arguments.length < 2)
|
|
174
|
-
throw Error('Not enough arguments for move');
|
|
175
|
-
if (arguments.length > 3)
|
|
176
|
-
throw Error('Signal.move() expects two or three arguments');
|
|
177
|
-
if (typeof from !== 'number' || !Number.isFinite(from) || typeof to !== 'number' || !Number.isFinite(to)) {
|
|
178
|
-
throw Error('Signal.move() expects numeric from/to');
|
|
179
|
-
}
|
|
180
|
-
return arrayMoveOnSignal(this, from, to, howMany);
|
|
181
|
-
}
|
|
182
|
-
async stringInsert(index, text) {
|
|
183
|
-
if (arguments.length < 2)
|
|
184
|
-
throw Error('Not enough arguments for stringInsert');
|
|
185
|
-
if (arguments.length > 2)
|
|
186
|
-
throw Error('Signal.stringInsert() expects two arguments');
|
|
187
|
-
if (typeof index !== 'number' || !Number.isFinite(index)) {
|
|
188
|
-
throw Error('Signal.stringInsert() expects a numeric index');
|
|
189
|
-
}
|
|
190
|
-
return stringInsertOnSignal(this, index, text);
|
|
191
|
-
}
|
|
192
|
-
async stringRemove(index, howMany) {
|
|
193
|
-
if (arguments.length < 2)
|
|
194
|
-
throw Error('Not enough arguments for stringRemove');
|
|
195
|
-
if (arguments.length > 2)
|
|
196
|
-
throw Error('Signal.stringRemove() expects two arguments');
|
|
197
|
-
if (typeof index !== 'number' || !Number.isFinite(index)) {
|
|
198
|
-
throw Error('Signal.stringRemove() expects a numeric index');
|
|
199
|
-
}
|
|
200
|
-
if (howMany == null)
|
|
201
|
-
howMany = 1;
|
|
202
|
-
return stringRemoveOnSignal(this, index, howMany);
|
|
203
|
-
}
|
|
204
|
-
async assign(value) {
|
|
205
|
-
if (arguments.length > 1)
|
|
206
|
-
throw Error('Signal.assign() expects a single argument');
|
|
207
|
-
return Signal.prototype.assign.call(this, value);
|
|
208
|
-
}
|
|
209
|
-
on(eventName, pattern, handler) {
|
|
210
|
-
if (arguments.length < 2)
|
|
211
|
-
throw Error('Signal.on() expects at least two arguments');
|
|
212
|
-
if ((eventName === 'change' || eventName === 'all') && typeof pattern !== 'function') {
|
|
213
|
-
throw Error('Signal model events are not supported. Use reaction() for signal changes.');
|
|
214
|
-
}
|
|
215
|
-
if (typeof pattern !== 'function')
|
|
216
|
-
throw Error('Signal.on() expects a handler function');
|
|
217
|
-
return onCustomEvent(eventName, pattern);
|
|
218
|
-
}
|
|
219
|
-
once(eventName, pattern, handler) {
|
|
220
|
-
if (arguments.length < 2)
|
|
221
|
-
throw Error('Signal.once() expects at least two arguments');
|
|
222
|
-
if ((eventName === 'change' || eventName === 'all') && typeof pattern !== 'function') {
|
|
223
|
-
throw Error('Signal model events are not supported. Use reaction() for signal changes.');
|
|
224
|
-
}
|
|
225
|
-
if (typeof pattern !== 'function')
|
|
226
|
-
throw Error('Signal.once() expects a handler function');
|
|
227
|
-
const onceHandler = (...args) => {
|
|
228
|
-
this.removeListener(eventName, onceHandler);
|
|
229
|
-
pattern(...args);
|
|
230
|
-
};
|
|
231
|
-
this.on(eventName, onceHandler);
|
|
232
|
-
return onceHandler;
|
|
233
|
-
}
|
|
234
|
-
removeListener(eventName, handler) {
|
|
235
|
-
if (arguments.length !== 2)
|
|
236
|
-
throw Error('Signal.removeListener() expects two arguments');
|
|
237
|
-
return removeCustomEventListener(eventName, handler);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
function isAggregationValuePath(segments) {
|
|
241
|
-
return Array.isArray(segments) &&
|
|
242
|
-
segments.length >= 3 &&
|
|
243
|
-
segments[0] === AGGREGATIONS;
|
|
244
|
-
}
|
|
245
|
-
function isReactLike(value) {
|
|
246
|
-
return !!(value && typeof value === 'object' && typeof value.$$typeof === 'symbol');
|
|
247
|
-
}
|
|
248
|
-
function resolveSignal($signal, segments) {
|
|
249
|
-
let $cursor = $signal;
|
|
250
|
-
for (const segment of segments) {
|
|
251
|
-
$cursor = $cursor[segment];
|
|
252
|
-
}
|
|
253
|
-
return $cursor;
|
|
254
|
-
}
|
|
255
|
-
function isMissingPublicDocDeleteError($signal, error) {
|
|
256
|
-
const segments = $signal?.[SEGMENTS];
|
|
257
|
-
if (!Array.isArray(segments) || segments.length < 2)
|
|
258
|
-
return false;
|
|
259
|
-
if (!isPublicCollection(segments[0]))
|
|
260
|
-
return false;
|
|
261
|
-
if (!(error instanceof Error))
|
|
262
|
-
return false;
|
|
263
|
-
return error.message.includes('Trying to delete data from a non-existing doc');
|
|
264
|
-
}
|
|
265
|
-
async function setDiffDeepOnSignal($target, value) {
|
|
266
|
-
if ($target[SEGMENTS].length === 0)
|
|
267
|
-
throw Error('Can\'t set the root signal data');
|
|
268
|
-
// Use peek() here. compat start() writes via setDiffDeep inside an observer and must not
|
|
269
|
-
// subscribe to its own target, otherwise later local edits on child signals cause start()
|
|
270
|
-
// to rerun and overwrite them from source.
|
|
271
|
-
const before = $target.peek();
|
|
272
|
-
if (isPublicCollection($target[SEGMENTS][0])) {
|
|
273
|
-
await diffDeepCompat($target, before, value);
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
diffDeepCompatSync($target, before, value);
|
|
277
|
-
}
|
|
278
|
-
async function diffDeepCompat($signal, before, after) {
|
|
279
|
-
if (before === after)
|
|
280
|
-
return;
|
|
281
|
-
if (Array.isArray(before) && Array.isArray(after)) {
|
|
282
|
-
const diff = arrayDiff(before, after, deepEqualCompat);
|
|
283
|
-
if (!diff.length)
|
|
284
|
-
return;
|
|
285
|
-
const index = getSingleArrayReplacementIndex(diff);
|
|
286
|
-
if (index != null) {
|
|
287
|
-
await diffDeepCompat(getChildSignal($signal, index), before[index], after[index]);
|
|
288
|
-
return;
|
|
289
|
-
}
|
|
290
|
-
await applyArrayDiffCompat($signal, diff);
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
if (isDiffableObject(before, after)) {
|
|
294
|
-
for (const key of Object.keys(before)) {
|
|
295
|
-
if (Object.prototype.hasOwnProperty.call(after, key))
|
|
296
|
-
continue;
|
|
297
|
-
await SignalCompat.prototype.del.call(getChildSignal($signal, key));
|
|
298
|
-
}
|
|
299
|
-
for (const key of Object.keys(after)) {
|
|
300
|
-
await diffDeepCompat(getChildSignal($signal, key), before[key], after[key]);
|
|
301
|
-
}
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
304
|
-
await SignalCompat.prototype.set.call($signal, after);
|
|
305
|
-
}
|
|
306
|
-
function diffDeepCompatSync($signal, before, after) {
|
|
307
|
-
if (before === after)
|
|
308
|
-
return;
|
|
309
|
-
if (Array.isArray(before) && Array.isArray(after)) {
|
|
310
|
-
const diff = arrayDiff(before, after, deepEqualCompat);
|
|
311
|
-
if (!diff.length)
|
|
312
|
-
return;
|
|
313
|
-
const index = getSingleArrayReplacementIndex(diff);
|
|
314
|
-
if (index != null) {
|
|
315
|
-
diffDeepCompatSync(getChildSignal($signal, index), before[index], after[index]);
|
|
316
|
-
return;
|
|
317
|
-
}
|
|
318
|
-
applyArrayDiffCompatSync($signal, diff);
|
|
319
|
-
return;
|
|
320
|
-
}
|
|
321
|
-
if (isDiffableObject(before, after)) {
|
|
322
|
-
const preservePath = $signal[SEGMENTS];
|
|
323
|
-
for (const key of Object.keys(before)) {
|
|
324
|
-
if (Object.prototype.hasOwnProperty.call(after, key))
|
|
325
|
-
continue;
|
|
326
|
-
delPrivateCompatSync(getChildSignal($signal, key), { preservePath });
|
|
327
|
-
}
|
|
328
|
-
for (const key of Object.keys(after)) {
|
|
329
|
-
diffDeepCompatSync(getChildSignal($signal, key), before[key], after[key]);
|
|
330
|
-
}
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
333
|
-
setReplacePrivateCompatSync($signal, after);
|
|
334
|
-
}
|
|
335
|
-
function isDiffableObject(before, after) {
|
|
336
|
-
if (!isPlainObject(before) || !isPlainObject(after))
|
|
337
|
-
return false;
|
|
338
|
-
if (isReactLike(before) || isReactLike(after))
|
|
339
|
-
return false;
|
|
340
|
-
return true;
|
|
341
|
-
}
|
|
342
|
-
function getSingleArrayReplacementIndex(diff) {
|
|
343
|
-
if (!Array.isArray(diff) || diff.length !== 2)
|
|
344
|
-
return null;
|
|
345
|
-
const first = diff[0];
|
|
346
|
-
const second = diff[1];
|
|
347
|
-
if (first instanceof arrayDiff.RemoveDiff &&
|
|
348
|
-
second instanceof arrayDiff.InsertDiff &&
|
|
349
|
-
first.index === second.index &&
|
|
350
|
-
first.howMany === 1 &&
|
|
351
|
-
second.values.length === 1) {
|
|
352
|
-
return first.index;
|
|
353
|
-
}
|
|
354
|
-
return null;
|
|
355
|
-
}
|
|
356
|
-
async function applyArrayDiffCompat($signal, diff) {
|
|
357
|
-
for (const item of diff) {
|
|
358
|
-
if (item instanceof arrayDiff.InsertDiff) {
|
|
359
|
-
await arrayInsertOnSignal($signal, item.index, item.values);
|
|
360
|
-
continue;
|
|
361
|
-
}
|
|
362
|
-
if (item instanceof arrayDiff.RemoveDiff) {
|
|
363
|
-
await arrayRemoveOnSignal($signal, item.index, item.howMany);
|
|
364
|
-
continue;
|
|
365
|
-
}
|
|
366
|
-
if (item instanceof arrayDiff.MoveDiff) {
|
|
367
|
-
await arrayMoveOnSignal($signal, item.from, item.to, item.howMany);
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
function applyArrayDiffCompatSync($signal, diff) {
|
|
372
|
-
const segments = ensureArrayTarget($signal);
|
|
373
|
-
const rootId = getOwningRootId($signal);
|
|
374
|
-
for (const item of diff) {
|
|
375
|
-
if (item instanceof arrayDiff.InsertDiff) {
|
|
376
|
-
arrayInsertPrivateData(rootId, segments, item.index, item.values);
|
|
377
|
-
continue;
|
|
378
|
-
}
|
|
379
|
-
if (item instanceof arrayDiff.RemoveDiff) {
|
|
380
|
-
arrayRemovePrivateData(rootId, segments, item.index, item.howMany);
|
|
381
|
-
continue;
|
|
382
|
-
}
|
|
383
|
-
if (item instanceof arrayDiff.MoveDiff) {
|
|
384
|
-
arrayMovePrivateData(rootId, segments, item.from, item.to, item.howMany);
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
function getChildSignal($parent, key) {
|
|
389
|
-
const $child = new SignalCompat([...$parent[SEGMENTS], key]);
|
|
390
|
-
const $root = getRoot($parent);
|
|
391
|
-
if ($root)
|
|
392
|
-
$child[ROOT] = $root;
|
|
393
|
-
return $child;
|
|
394
|
-
}
|
|
395
|
-
function setReplacePrivateCompatSync($signal, value) {
|
|
396
|
-
const segments = $signal[SEGMENTS];
|
|
397
|
-
if (segments.length === 0)
|
|
398
|
-
throw Error('Can\'t set the root signal data');
|
|
399
|
-
const idFields = getIdFieldsForSegments(segments);
|
|
400
|
-
if (isIdFieldPath(segments, idFields))
|
|
401
|
-
return;
|
|
402
|
-
if (isPublicDocPath(segments)) {
|
|
403
|
-
value = normalizeIdFields(value, idFields, segments[1]);
|
|
404
|
-
}
|
|
405
|
-
setReplacePrivateData(getOwningRootId($signal), segments, value);
|
|
406
|
-
}
|
|
407
|
-
function delPrivateCompatSync($signal, options) {
|
|
408
|
-
const segments = $signal[SEGMENTS];
|
|
409
|
-
if (segments.length === 0)
|
|
410
|
-
throw Error('Can\'t delete the root signal data');
|
|
411
|
-
const idFields = getIdFieldsForSegments(segments);
|
|
412
|
-
if (isIdFieldPath(segments, idFields))
|
|
413
|
-
return;
|
|
414
|
-
delPrivateData(getOwningRootId($signal), segments, options);
|
|
415
|
-
}
|
|
416
|
-
function deepEqualCompat(left, right) {
|
|
417
|
-
if (left === right)
|
|
418
|
-
return true;
|
|
419
|
-
if (left == null || right == null)
|
|
420
|
-
return false;
|
|
421
|
-
if (typeof left !== 'object' || typeof right !== 'object')
|
|
422
|
-
return false;
|
|
423
|
-
if (Array.isArray(left) !== Array.isArray(right))
|
|
424
|
-
return false;
|
|
425
|
-
if (Array.isArray(left)) {
|
|
426
|
-
if (left.length !== right.length)
|
|
427
|
-
return false;
|
|
428
|
-
for (let i = 0; i < left.length; i++) {
|
|
429
|
-
if (!deepEqualCompat(left[i], right[i]))
|
|
430
|
-
return false;
|
|
431
|
-
}
|
|
432
|
-
return true;
|
|
433
|
-
}
|
|
434
|
-
if (!isPlainObject(left) || !isPlainObject(right))
|
|
435
|
-
return false;
|
|
436
|
-
const leftKeys = Object.keys(left);
|
|
437
|
-
const rightKeys = Object.keys(right);
|
|
438
|
-
if (leftKeys.length !== rightKeys.length)
|
|
439
|
-
return false;
|
|
440
|
-
for (const key of leftKeys) {
|
|
441
|
-
if (!Object.prototype.hasOwnProperty.call(right, key))
|
|
442
|
-
return false;
|
|
443
|
-
if (!deepEqualCompat(left[key], right[key]))
|
|
444
|
-
return false;
|
|
445
|
-
}
|
|
446
|
-
return true;
|
|
447
|
-
}
|
|
448
|
-
function racerEqualCompat(left, right) {
|
|
449
|
-
return left === right || (Number.isNaN(left) && Number.isNaN(right));
|
|
450
|
-
}
|
|
451
|
-
async function setReplaceOnSignal($signal, value) {
|
|
452
|
-
const segments = $signal[SEGMENTS];
|
|
453
|
-
if (segments.length === 0)
|
|
454
|
-
throw Error('Can\'t set the root signal data');
|
|
455
|
-
const idFields = getIdFieldsForSegments(segments);
|
|
456
|
-
if (isIdFieldPath(segments, idFields))
|
|
457
|
-
return;
|
|
458
|
-
if (isPublicDocPath(segments)) {
|
|
459
|
-
value = normalizeIdFields(value, idFields, segments[1]);
|
|
460
|
-
}
|
|
461
|
-
if (isPublicCollection(segments[0])) {
|
|
462
|
-
return _setPublicDocReplace(segments, value);
|
|
463
|
-
}
|
|
464
|
-
return setReplacePrivateData(getOwningRootId($signal), segments, value);
|
|
465
|
-
}
|
|
466
|
-
async function incrementOnSignal($signal, byNumber) {
|
|
467
|
-
const segments = $signal[SEGMENTS];
|
|
468
|
-
if (segments.length === 0)
|
|
469
|
-
throw Error('Can\'t increment the root signal data');
|
|
470
|
-
const idFields = getIdFieldsForSegments(segments);
|
|
471
|
-
if (isIdFieldPath(segments, idFields))
|
|
472
|
-
return $signal.get();
|
|
473
|
-
if (byNumber == null)
|
|
474
|
-
byNumber = 1;
|
|
475
|
-
if (typeof byNumber !== 'number')
|
|
476
|
-
throw Error('Signal.increment() expects a number argument');
|
|
477
|
-
let currentValue = $signal.get();
|
|
478
|
-
if (currentValue == null)
|
|
479
|
-
currentValue = 0;
|
|
480
|
-
if (typeof currentValue !== 'number')
|
|
481
|
-
throw Error('Signal.increment() tried to increment a non-number value');
|
|
482
|
-
if (isPublicCollection(segments[0])) {
|
|
483
|
-
await _incrementPublic(segments, byNumber);
|
|
484
|
-
return currentValue + byNumber;
|
|
485
|
-
}
|
|
486
|
-
setReplacePrivateData(getOwningRootId($signal), segments, currentValue + byNumber);
|
|
487
|
-
return currentValue + byNumber;
|
|
488
|
-
}
|
|
489
|
-
function ensureArrayTarget($signal) {
|
|
490
|
-
const segments = $signal[SEGMENTS];
|
|
491
|
-
if (segments.length < 2)
|
|
492
|
-
throw Error('Can\'t mutate array on a collection or root signal');
|
|
493
|
-
if ($signal[IS_QUERY])
|
|
494
|
-
throw Error('Array mutators can\'t be used on a query signal');
|
|
495
|
-
return segments;
|
|
496
|
-
}
|
|
497
|
-
function ensureValueTarget($signal) {
|
|
498
|
-
const segments = $signal[SEGMENTS];
|
|
499
|
-
if (segments.length < 2)
|
|
500
|
-
throw Error('Can\'t mutate on a collection or root signal');
|
|
501
|
-
if ($signal[IS_QUERY])
|
|
502
|
-
throw Error('Mutators can\'t be used on a query signal');
|
|
503
|
-
return segments;
|
|
504
|
-
}
|
|
505
|
-
async function arrayPushOnSignal($signal, value) {
|
|
506
|
-
const segments = ensureArrayTarget($signal);
|
|
507
|
-
const idFields = getIdFieldsForSegments(segments);
|
|
508
|
-
if (isIdFieldPath(segments, idFields))
|
|
509
|
-
return;
|
|
510
|
-
if (isPublicCollection(segments[0]))
|
|
511
|
-
return _arrayPushPublic(segments, value);
|
|
512
|
-
return arrayPushPrivateData(getOwningRootId($signal), segments, value);
|
|
513
|
-
}
|
|
514
|
-
async function arrayUnshiftOnSignal($signal, value) {
|
|
515
|
-
const segments = ensureArrayTarget($signal);
|
|
516
|
-
const idFields = getIdFieldsForSegments(segments);
|
|
517
|
-
if (isIdFieldPath(segments, idFields))
|
|
518
|
-
return;
|
|
519
|
-
if (isPublicCollection(segments[0]))
|
|
520
|
-
return _arrayUnshiftPublic(segments, value);
|
|
521
|
-
return arrayUnshiftPrivateData(getOwningRootId($signal), segments, value);
|
|
522
|
-
}
|
|
523
|
-
async function arrayInsertOnSignal($signal, index, values) {
|
|
524
|
-
const segments = ensureArrayTarget($signal);
|
|
525
|
-
const idFields = getIdFieldsForSegments(segments);
|
|
526
|
-
if (isIdFieldPath(segments, idFields))
|
|
527
|
-
return;
|
|
528
|
-
if (isPublicCollection(segments[0]))
|
|
529
|
-
return _arrayInsertPublic(segments, index, values);
|
|
530
|
-
return arrayInsertPrivateData(getOwningRootId($signal), segments, index, values);
|
|
531
|
-
}
|
|
532
|
-
async function arrayPopOnSignal($signal) {
|
|
533
|
-
const segments = ensureArrayTarget($signal);
|
|
534
|
-
const idFields = getIdFieldsForSegments(segments);
|
|
535
|
-
if (isIdFieldPath(segments, idFields))
|
|
536
|
-
return;
|
|
537
|
-
if (isPublicCollection(segments[0]))
|
|
538
|
-
return _arrayPopPublic(segments);
|
|
539
|
-
return arrayPopPrivateData(getOwningRootId($signal), segments);
|
|
540
|
-
}
|
|
541
|
-
async function arrayShiftOnSignal($signal) {
|
|
542
|
-
const segments = ensureArrayTarget($signal);
|
|
543
|
-
const idFields = getIdFieldsForSegments(segments);
|
|
544
|
-
if (isIdFieldPath(segments, idFields))
|
|
545
|
-
return;
|
|
546
|
-
if (isPublicCollection(segments[0]))
|
|
547
|
-
return _arrayShiftPublic(segments);
|
|
548
|
-
return arrayShiftPrivateData(getOwningRootId($signal), segments);
|
|
549
|
-
}
|
|
550
|
-
async function arrayRemoveOnSignal($signal, index, howMany) {
|
|
551
|
-
const segments = ensureArrayTarget($signal);
|
|
552
|
-
const idFields = getIdFieldsForSegments(segments);
|
|
553
|
-
if (isIdFieldPath(segments, idFields))
|
|
554
|
-
return;
|
|
555
|
-
if (isPublicCollection(segments[0]))
|
|
556
|
-
return _arrayRemovePublic(segments, index, howMany);
|
|
557
|
-
return arrayRemovePrivateData(getOwningRootId($signal), segments, index, howMany);
|
|
558
|
-
}
|
|
559
|
-
async function arrayMoveOnSignal($signal, from, to, howMany) {
|
|
560
|
-
const segments = ensureArrayTarget($signal);
|
|
561
|
-
const idFields = getIdFieldsForSegments(segments);
|
|
562
|
-
if (isIdFieldPath(segments, idFields))
|
|
563
|
-
return;
|
|
564
|
-
if (isPublicCollection(segments[0]))
|
|
565
|
-
return _arrayMovePublic(segments, from, to, howMany);
|
|
566
|
-
return arrayMovePrivateData(getOwningRootId($signal), segments, from, to, howMany);
|
|
567
|
-
}
|
|
568
|
-
async function stringInsertOnSignal($signal, index, text) {
|
|
569
|
-
const segments = ensureValueTarget($signal);
|
|
570
|
-
const idFields = getIdFieldsForSegments(segments);
|
|
571
|
-
if (isIdFieldPath(segments, idFields))
|
|
572
|
-
return;
|
|
573
|
-
if (isPublicCollection(segments[0]))
|
|
574
|
-
return _stringInsertPublic(segments, index, text);
|
|
575
|
-
return stringInsertPrivateData(getOwningRootId($signal), segments, index, text);
|
|
576
|
-
}
|
|
577
|
-
async function stringRemoveOnSignal($signal, index, howMany) {
|
|
578
|
-
const segments = ensureValueTarget($signal);
|
|
579
|
-
const idFields = getIdFieldsForSegments(segments);
|
|
580
|
-
if (isIdFieldPath(segments, idFields))
|
|
581
|
-
return;
|
|
582
|
-
if (isPublicCollection(segments[0]))
|
|
583
|
-
return _stringRemovePublic(segments, index, howMany);
|
|
584
|
-
return stringRemovePrivateData(getOwningRootId($signal), segments, index, howMany);
|
|
585
|
-
}
|
|
586
|
-
function getOwningRootId($signal) {
|
|
587
|
-
const $root = getRoot($signal) || $signal;
|
|
588
|
-
return $root?.[ROOT_ID];
|
|
589
|
-
}
|
|
590
|
-
function shallowCopy(value) {
|
|
591
|
-
const rawValue = raw(value);
|
|
592
|
-
if (Array.isArray(rawValue))
|
|
593
|
-
return rawValue.slice();
|
|
594
|
-
if (rawValue && typeof rawValue === 'object')
|
|
595
|
-
return { ...rawValue };
|
|
596
|
-
return rawValue;
|
|
597
|
-
}
|
|
598
|
-
function deepCopy(value) {
|
|
599
|
-
const rawValue = raw(value);
|
|
600
|
-
if (!rawValue || typeof rawValue !== 'object')
|
|
601
|
-
return rawValue;
|
|
602
|
-
if (typeof globalThis.structuredClone === 'function') {
|
|
603
|
-
try {
|
|
604
|
-
return globalThis.structuredClone(rawValue);
|
|
605
|
-
}
|
|
606
|
-
catch { }
|
|
607
|
-
}
|
|
608
|
-
return racerDeepCopy(rawValue);
|
|
609
|
-
}
|
|
610
|
-
// Racer-style deep copy:
|
|
611
|
-
// - Preserves prototypes by instantiating via `new value.constructor()`
|
|
612
|
-
// - Copies own enumerable props recursively
|
|
613
|
-
// - Keeps functions as-is (no cloning)
|
|
614
|
-
// - Handles Date by creating a new Date
|
|
615
|
-
// Limitations: does not handle cyclic refs, Map/Set/RegExp/TypedArray, non-enumerables.
|
|
616
|
-
function racerDeepCopy(value) {
|
|
617
|
-
if (value instanceof Date)
|
|
618
|
-
return new Date(value);
|
|
619
|
-
if (typeof value === 'object') {
|
|
620
|
-
if (value === null)
|
|
621
|
-
return null;
|
|
622
|
-
if (Array.isArray(value)) {
|
|
623
|
-
const array = [];
|
|
624
|
-
for (let i = value.length; i--;) {
|
|
625
|
-
array[i] = racerDeepCopy(value[i]);
|
|
626
|
-
}
|
|
627
|
-
return array;
|
|
628
|
-
}
|
|
629
|
-
const object = new value.constructor();
|
|
630
|
-
for (const key in value) {
|
|
631
|
-
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
|
632
|
-
object[key] = racerDeepCopy(value[key]);
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
return object;
|
|
636
|
-
}
|
|
637
|
-
return value;
|
|
638
|
-
}
|
|
639
|
-
export { SignalCompat };
|
|
640
|
-
export default SignalCompat;
|
package/dist/orm/compatEnv.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export function isCompatEnv (): boolean
|
package/dist/orm/compatEnv.js
DELETED