@ng-org/orm 0.1.2-alpha.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/README.md +347 -0
- package/dist/connector/applyPatches.d.ts +106 -0
- package/dist/connector/applyPatches.d.ts.map +1 -0
- package/dist/connector/applyPatches.js +317 -0
- package/dist/connector/applyPatches.test.d.ts +2 -0
- package/dist/connector/applyPatches.test.d.ts.map +1 -0
- package/dist/connector/applyPatches.test.js +772 -0
- package/dist/connector/createSignalObjectForShape.d.ts +14 -0
- package/dist/connector/createSignalObjectForShape.d.ts.map +1 -0
- package/dist/connector/createSignalObjectForShape.js +24 -0
- package/dist/connector/initNg.d.ts +14 -0
- package/dist/connector/initNg.d.ts.map +1 -0
- package/dist/connector/initNg.js +16 -0
- package/dist/connector/ormConnectionHandler.d.ts +47 -0
- package/dist/connector/ormConnectionHandler.d.ts.map +1 -0
- package/dist/connector/ormConnectionHandler.js +240 -0
- package/dist/frontendAdapters/react/index.d.ts +3 -0
- package/dist/frontendAdapters/react/index.d.ts.map +1 -0
- package/dist/frontendAdapters/react/index.js +2 -0
- package/dist/frontendAdapters/react/useShape.d.ts +6 -0
- package/dist/frontendAdapters/react/useShape.d.ts.map +1 -0
- package/dist/frontendAdapters/react/useShape.js +24 -0
- package/dist/frontendAdapters/svelte/index.d.ts +3 -0
- package/dist/frontendAdapters/svelte/index.d.ts.map +1 -0
- package/dist/frontendAdapters/svelte/index.js +2 -0
- package/dist/frontendAdapters/svelte/useShape.svelte.d.ts +14 -0
- package/dist/frontendAdapters/svelte/useShape.svelte.d.ts.map +1 -0
- package/dist/frontendAdapters/svelte/useShape.svelte.js +22 -0
- package/dist/frontendAdapters/vue/index.d.ts +3 -0
- package/dist/frontendAdapters/vue/index.d.ts.map +1 -0
- package/dist/frontendAdapters/vue/index.js +2 -0
- package/dist/frontendAdapters/vue/useShape.d.ts +5 -0
- package/dist/frontendAdapters/vue/useShape.d.ts.map +1 -0
- package/dist/frontendAdapters/vue/useShape.js +22 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/types.d.ts +13 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/package.json +90 -0
- package/src/connector/applyPatches.test.ts +842 -0
- package/src/connector/applyPatches.ts +404 -0
- package/src/connector/createSignalObjectForShape.ts +35 -0
- package/src/connector/initNg.ts +30 -0
- package/src/connector/ormConnectionHandler.ts +300 -0
- package/src/frontendAdapters/react/index.ts +2 -0
- package/src/frontendAdapters/react/useShape.ts +36 -0
- package/src/frontendAdapters/svelte/index.ts +2 -0
- package/src/frontendAdapters/svelte/useShape.svelte.ts +46 -0
- package/src/frontendAdapters/vue/index.ts +2 -0
- package/src/frontendAdapters/vue/useShape.ts +33 -0
- package/src/index.ts +14 -0
- package/src/types.ts +26 -0
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
// Copyright (c) 2025 Laurin Weger, Par le Peuple, NextGraph.org developers
|
|
2
|
+
// All rights reserved.
|
|
3
|
+
// Licensed under the Apache License, Version 2.0
|
|
4
|
+
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
|
|
5
|
+
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
|
|
6
|
+
// at your option. All files in the project carrying such
|
|
7
|
+
// notice may not be copied, modified, or distributed except
|
|
8
|
+
// according to those terms.
|
|
9
|
+
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
10
|
+
|
|
11
|
+
import { batch } from "@ng-org/alien-deepsignals";
|
|
12
|
+
|
|
13
|
+
export type Patch = {
|
|
14
|
+
/** Property path (array indices, object keys, synthetic Set entry ids) from the root to the mutated location. */
|
|
15
|
+
path: string;
|
|
16
|
+
valType?: string & {};
|
|
17
|
+
value?: unknown;
|
|
18
|
+
} & (
|
|
19
|
+
| SetAddPatch
|
|
20
|
+
| SetRemovePatch
|
|
21
|
+
| ObjectAddPatch
|
|
22
|
+
| RemovePatch
|
|
23
|
+
| LiteralAddPatch
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
export interface SetAddPatch {
|
|
27
|
+
/** Mutation kind applied at the resolved `path`. */
|
|
28
|
+
op: "add";
|
|
29
|
+
valType: "set";
|
|
30
|
+
/**
|
|
31
|
+
* New value for set mutations:
|
|
32
|
+
* - A single primitive
|
|
33
|
+
* - An array of primitives
|
|
34
|
+
*/
|
|
35
|
+
value: number | string | boolean | (number | string | boolean)[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface SetRemovePatch {
|
|
39
|
+
/** Mutation kind applied at the resolved `path`. */
|
|
40
|
+
op: "remove";
|
|
41
|
+
valType: "set";
|
|
42
|
+
/**
|
|
43
|
+
* The value(s) to be removed from the set. Either:
|
|
44
|
+
* - A single primitive
|
|
45
|
+
* - An array of primitives
|
|
46
|
+
*/
|
|
47
|
+
value: number | string | boolean | (number | string | boolean)[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface ObjectAddPatch {
|
|
51
|
+
/** Mutation kind applied at the resolved `path`. */
|
|
52
|
+
op: "add";
|
|
53
|
+
valType: "object";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface RemovePatch {
|
|
57
|
+
/** Mutation kind applied at the resolved `path`. */
|
|
58
|
+
op: "remove";
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface LiteralAddPatch {
|
|
62
|
+
/** Mutation kind applied at the resolved `path`. */
|
|
63
|
+
op: "add";
|
|
64
|
+
/** The literal value to be added at the resolved `path` */
|
|
65
|
+
value: string | number | boolean;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function isPrimitive(v: unknown): v is string | number | boolean {
|
|
69
|
+
return (
|
|
70
|
+
typeof v === "string" || typeof v === "number" || typeof v === "boolean"
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Parse a combined identifier of the form "graph|subject".
|
|
76
|
+
* If there is no pipe, returns { graph: undefined, id: input }.
|
|
77
|
+
*/
|
|
78
|
+
function parseGraphId(input: string): { graph?: string; id: string } {
|
|
79
|
+
if (typeof input !== "string") return { id: String(input) } as any;
|
|
80
|
+
const idx = input.indexOf("|");
|
|
81
|
+
if (idx === -1) return { id: input };
|
|
82
|
+
const graph = input.slice(0, idx);
|
|
83
|
+
const id = input.slice(idx + 1);
|
|
84
|
+
return { graph, id };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Find an object in a Set by its @id property.
|
|
89
|
+
* Returns the object if found, otherwise undefined.
|
|
90
|
+
*/
|
|
91
|
+
function findInSetBySegment(set: Set<any>, seg: string): any | undefined {
|
|
92
|
+
// TODO: We could optimize that by leveraging key @id to object mapping in sets of deepSignals.
|
|
93
|
+
|
|
94
|
+
const { graph, id } = parseGraphId(seg);
|
|
95
|
+
|
|
96
|
+
for (const item of set) {
|
|
97
|
+
if (typeof item !== "object" || item === null) continue;
|
|
98
|
+
// If graph was provided, require both to match
|
|
99
|
+
if (graph && item["@graph"] === graph && item["@id"] === id)
|
|
100
|
+
return item;
|
|
101
|
+
// Match by @id only when no graph part is provided
|
|
102
|
+
if (!graph && item["@id"] === id) return item;
|
|
103
|
+
}
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Apply a diff to an object.
|
|
109
|
+
*
|
|
110
|
+
* The syntax is inspired by RFC 6902 but it is not compatible.
|
|
111
|
+
*
|
|
112
|
+
* It supports Sets for multi-valued properties:
|
|
113
|
+
* - Primitive values are added as Sets (Set<string | number | boolean>)
|
|
114
|
+
* - Multi-valued objects are stored in Sets, accessed by their @id property
|
|
115
|
+
* - Single objects are plain objects with an @id property
|
|
116
|
+
*
|
|
117
|
+
* Path traversal:
|
|
118
|
+
* - When traversing through a Set, the path segment is treated as an @id to find the object
|
|
119
|
+
* - When traversing through a plain object, the path segment is a property name
|
|
120
|
+
*
|
|
121
|
+
* @example operations
|
|
122
|
+
* ```jsonc
|
|
123
|
+
* // === SINGLE OBJECT ===
|
|
124
|
+
* // Creating a single object (has @id at same level)
|
|
125
|
+
* { "op": "add", "path": "/urn:example:person1/address", "valType": "object" }
|
|
126
|
+
* { "op": "add", "path": "/urn:example:person1/address/@id", "value": "urn:test:address1" }
|
|
127
|
+
* // Adding primitives to single object
|
|
128
|
+
* { "op": "add", "path": "/urn:example:person1/address/street", "value": "1st street" }
|
|
129
|
+
* { "op": "add", "path": "/urn:example:person1/address/country", "value": "Greece" }
|
|
130
|
+
* // Remove a primitive from object
|
|
131
|
+
* { "op": "remove", "path": "/urn:example:person1/address/street" }
|
|
132
|
+
* // Remove the entire object
|
|
133
|
+
* { "op": "remove", "path": "/urn:example:person1/address" }
|
|
134
|
+
*
|
|
135
|
+
* // === MULTI-VALUED OBJECTS (Set) ===
|
|
136
|
+
* // Creating a multi-object container (NO @id at this level -> creates Set)
|
|
137
|
+
* { "op": "add", "path": "/urn:example:person1/children", "valType": "object" }
|
|
138
|
+
* // Adding an object to the Set (path includes object's @id)
|
|
139
|
+
* { "op": "add", "path": "/urn:example:person1/children/urn:example:child1", "valType": "object" }
|
|
140
|
+
* { "op": "add", "path": "/urn:example:person1/children/urn:example:child1/@id", "value": "urn:example:child1" }
|
|
141
|
+
* // Adding properties to object in Set
|
|
142
|
+
* { "op": "add", "path": "/urn:example:person1/children/urn:example:child1/name", "value": "Alice" }
|
|
143
|
+
* // Remove an object from Set
|
|
144
|
+
* { "op": "remove", "path": "/urn:example:person1/children/urn:example:child1" }
|
|
145
|
+
* // Remove all objects (the Set itself)
|
|
146
|
+
* { "op": "remove", "path": "/urn:example:person1/children" }
|
|
147
|
+
*
|
|
148
|
+
* // === PRIMITIVE SETS ===
|
|
149
|
+
* // Add primitive types to Sets
|
|
150
|
+
* { "op": "add", "valType": "set", "path": "/urn:example:person1/tags", "value": [1,2,3] }
|
|
151
|
+
* // Remove primitive types from a Set
|
|
152
|
+
* { "op": "remove", "valType": "set", "path": "/urn:example:person1/tags", "value": [1,2] }
|
|
153
|
+
* ```
|
|
154
|
+
*
|
|
155
|
+
* @param currentState The object before the patch
|
|
156
|
+
* @param patches An array of patches to apply to the object.
|
|
157
|
+
* @param ensurePathExists If true, create nested objects along the path if the path does not exist.
|
|
158
|
+
*
|
|
159
|
+
* @note When creating new objects, this function pre-scans upcoming patches to find @id and @graph
|
|
160
|
+
* values that will be assigned to the object. This prevents the signal library's propGenerator
|
|
161
|
+
* from being triggered before these identity fields are set, which would cause it to generate
|
|
162
|
+
* random IDs unnecessarily.
|
|
163
|
+
*/
|
|
164
|
+
export function applyPatches(
|
|
165
|
+
currentState: Record<string, any>,
|
|
166
|
+
patches: Patch[],
|
|
167
|
+
ensurePathExists: boolean = false
|
|
168
|
+
) {
|
|
169
|
+
for (let patchIndex = 0; patchIndex < patches.length; patchIndex++) {
|
|
170
|
+
const patch = patches[patchIndex];
|
|
171
|
+
if (!patch.path.startsWith("/")) continue;
|
|
172
|
+
const pathParts = patch.path
|
|
173
|
+
.slice(1)
|
|
174
|
+
.split("/")
|
|
175
|
+
.filter(Boolean)
|
|
176
|
+
.map(decodePathSegment);
|
|
177
|
+
|
|
178
|
+
if (pathParts.length === 0) {
|
|
179
|
+
console.warn("[applyDiff] No path specified for patch", patch);
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
const lastKey = pathParts[pathParts.length - 1];
|
|
183
|
+
let parentVal: any = currentState;
|
|
184
|
+
let parentMissing = false;
|
|
185
|
+
// Traverse only intermediate segments (to leaf object at path)
|
|
186
|
+
for (let i = 0; i < pathParts.length - 1; i++) {
|
|
187
|
+
const seg = pathParts[i];
|
|
188
|
+
// Handle Sets: if parentVal is a Set, find object by path segment.
|
|
189
|
+
if (parentVal instanceof Set) {
|
|
190
|
+
const foundObj = findInSetBySegment(parentVal, seg);
|
|
191
|
+
if (foundObj) {
|
|
192
|
+
parentVal = foundObj;
|
|
193
|
+
} else if (ensurePathExists) {
|
|
194
|
+
// Create new object in the set.
|
|
195
|
+
const newObj = {};
|
|
196
|
+
parentVal.add(newObj);
|
|
197
|
+
parentVal = newObj;
|
|
198
|
+
} else {
|
|
199
|
+
parentMissing = true;
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Handle regular objects
|
|
206
|
+
if (
|
|
207
|
+
parentVal != null &&
|
|
208
|
+
typeof parentVal === "object" &&
|
|
209
|
+
Object.prototype.hasOwnProperty.call(parentVal, seg)
|
|
210
|
+
) {
|
|
211
|
+
parentVal = parentVal[seg];
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
if (ensurePathExists) {
|
|
215
|
+
if (parentVal != null && typeof parentVal === "object") {
|
|
216
|
+
// Check if we need to create an object or a set:
|
|
217
|
+
if (pathParts[i + 1]?.includes("|")) {
|
|
218
|
+
// The next path segment is an IRI, that means the new element must be a set of objects. Create a set.
|
|
219
|
+
parentVal[seg] = new Set();
|
|
220
|
+
} else {
|
|
221
|
+
// Create a new object
|
|
222
|
+
parentVal[seg] = {};
|
|
223
|
+
}
|
|
224
|
+
parentVal = parentVal[seg];
|
|
225
|
+
} else {
|
|
226
|
+
parentMissing = true;
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
} else {
|
|
230
|
+
parentMissing = true;
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (parentMissing) {
|
|
236
|
+
console.warn(
|
|
237
|
+
`[applyDiff] Skipping patch due to missing parent path segment(s): ${patch.path}`
|
|
238
|
+
);
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// parentVal now should be an object or Set into which we apply lastKey
|
|
243
|
+
if (
|
|
244
|
+
parentVal == null ||
|
|
245
|
+
(typeof parentVal !== "object" && !(parentVal instanceof Set))
|
|
246
|
+
) {
|
|
247
|
+
console.warn(
|
|
248
|
+
`[applyDiff] Skipping patch because parent is not an object or Set: ${patch.path}`
|
|
249
|
+
);
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
const key = lastKey;
|
|
253
|
+
|
|
254
|
+
// Special handling when parent is a Set
|
|
255
|
+
if (parentVal instanceof Set) {
|
|
256
|
+
// The key represents the identifier of an object within the Set
|
|
257
|
+
const targetObj = findInSetBySegment(parentVal, key);
|
|
258
|
+
|
|
259
|
+
// Handle object creation in a Set
|
|
260
|
+
if (patch.op === "add" && patch.valType === "object") {
|
|
261
|
+
if (!targetObj) {
|
|
262
|
+
// Determine if this will be a single object or nested Set
|
|
263
|
+
const hasId = patches[patchIndex + 2]?.path.endsWith("@id");
|
|
264
|
+
const newLeaf: any = hasId ? {} : new Set();
|
|
265
|
+
// Pre-assign identity so subsequent patches can find this object
|
|
266
|
+
if (hasId) {
|
|
267
|
+
const { graph, id } = parseGraphId(key);
|
|
268
|
+
newLeaf["@id"] = id;
|
|
269
|
+
const graphPatch = patches[patchIndex + 1];
|
|
270
|
+
if (graphPatch?.path.endsWith("@graph")) {
|
|
271
|
+
newLeaf["@graph"] = graphPatch.value ?? graph;
|
|
272
|
+
} else if (graph) {
|
|
273
|
+
newLeaf["@graph"] = graph;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
parentVal.add(newLeaf);
|
|
277
|
+
}
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Handle remove from Set
|
|
282
|
+
if (patch.op === "remove" && patch.valType !== "set") {
|
|
283
|
+
if (targetObj) {
|
|
284
|
+
parentVal.delete(targetObj);
|
|
285
|
+
}
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// All other operations require the target object to exist
|
|
290
|
+
if (!targetObj) {
|
|
291
|
+
console.warn(
|
|
292
|
+
`[applyDiff] Target object with @id=${key} not found in Set for path: ${patch.path}`
|
|
293
|
+
);
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// This shouldn't happen - we handle all intermediate segments in the traversal loop
|
|
298
|
+
console.warn(
|
|
299
|
+
`[applyDiff] Unexpected: reached end of path with Set as parent: ${patch.path}`
|
|
300
|
+
);
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Regular object handling (parentVal is a plain object, not a Set)
|
|
305
|
+
// Handle primitive set additions
|
|
306
|
+
if (patch.op === "add" && patch.valType === "set") {
|
|
307
|
+
const existing = parentVal[key];
|
|
308
|
+
const raw = (patch as SetAddPatch).value;
|
|
309
|
+
if (raw == null) continue;
|
|
310
|
+
|
|
311
|
+
// Normalize to array of primitives
|
|
312
|
+
const toAdd: (string | number | boolean)[] = Array.isArray(raw)
|
|
313
|
+
? raw.filter(isPrimitive)
|
|
314
|
+
: isPrimitive(raw)
|
|
315
|
+
? [raw]
|
|
316
|
+
: [];
|
|
317
|
+
|
|
318
|
+
if (!toAdd.length) continue;
|
|
319
|
+
|
|
320
|
+
// Ensure we have a Set, create or add to existing
|
|
321
|
+
if (existing instanceof Set) {
|
|
322
|
+
for (const v of toAdd) existing.add(v);
|
|
323
|
+
} else {
|
|
324
|
+
// Create new Set (replaces any incompatible existing value)
|
|
325
|
+
parentVal[key] = new Set(toAdd);
|
|
326
|
+
}
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Handle primitive set removals
|
|
331
|
+
if (patch.op === "remove" && patch.valType === "set") {
|
|
332
|
+
const existing = parentVal[key];
|
|
333
|
+
const raw = (patch as SetRemovePatch).value;
|
|
334
|
+
if (raw == null) continue;
|
|
335
|
+
|
|
336
|
+
const toRemove: (string | number | boolean)[] = Array.isArray(raw)
|
|
337
|
+
? raw
|
|
338
|
+
: [raw];
|
|
339
|
+
|
|
340
|
+
if (existing instanceof Set) {
|
|
341
|
+
for (const v of toRemove) existing.delete(v);
|
|
342
|
+
}
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Add object (if it does not exist yet).
|
|
347
|
+
// Distinguish between single objects and multi-object containers:
|
|
348
|
+
// - If an @id patch follows for this path, it's a single object -> create {}
|
|
349
|
+
// - If no @id patch follows, it's a container for multi-valued objects -> create set.
|
|
350
|
+
if (patch.op === "add" && patch.valType === "object") {
|
|
351
|
+
const leafVal = parentVal[key];
|
|
352
|
+
const hasId = patches.at(patchIndex + 2)?.path.endsWith("@id");
|
|
353
|
+
|
|
354
|
+
// If the leafVal does not exist and it should be a set, create.
|
|
355
|
+
if (!hasId && !leafVal) {
|
|
356
|
+
parentVal[key] = new Set();
|
|
357
|
+
} else if (!(typeof leafVal === "object")) {
|
|
358
|
+
// If the leave does not exist yet (as object), create it.
|
|
359
|
+
const newLeaf: Record<string, any> = {};
|
|
360
|
+
const graphPatch = patches.at(patchIndex + 1);
|
|
361
|
+
if (graphPatch?.path.endsWith("@graph")) {
|
|
362
|
+
newLeaf["@graph"] = graphPatch.value;
|
|
363
|
+
}
|
|
364
|
+
const idPatch = patches.at(patchIndex + 2);
|
|
365
|
+
if (idPatch?.path.endsWith("@id")) {
|
|
366
|
+
newLeaf["@id"] = idPatch.value;
|
|
367
|
+
}
|
|
368
|
+
parentVal[key] = newLeaf;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Literal add
|
|
375
|
+
if (
|
|
376
|
+
patch.op === "add" &&
|
|
377
|
+
!(patch.path.endsWith("@id") || patch.path.endsWith("@graph"))
|
|
378
|
+
) {
|
|
379
|
+
parentVal[key] = (patch as LiteralAddPatch).value;
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Generic remove (property or value)
|
|
384
|
+
if (patch.op === "remove") {
|
|
385
|
+
if (Object.prototype.hasOwnProperty.call(parentVal, key)) {
|
|
386
|
+
delete parentVal[key];
|
|
387
|
+
}
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* See documentation for applyDiff
|
|
395
|
+
*/
|
|
396
|
+
export function applyPatchesToDeepSignal(currentState: object, patch: Patch[]) {
|
|
397
|
+
batch(() => {
|
|
398
|
+
applyPatches(currentState as Record<string, any>, patch, true);
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function decodePathSegment(segment: string): string {
|
|
403
|
+
return segment.replace("~1", "/").replace("~0", "~");
|
|
404
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Copyright (c) 2025 Laurin Weger, Par le Peuple, NextGraph.org developers
|
|
2
|
+
// All rights reserved.
|
|
3
|
+
// Licensed under the Apache License, Version 2.0
|
|
4
|
+
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
|
|
5
|
+
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
|
|
6
|
+
// at your option. All files in the project carrying such
|
|
7
|
+
// notice may not be copied, modified, or distributed except
|
|
8
|
+
// according to those terms.
|
|
9
|
+
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
10
|
+
|
|
11
|
+
import type { Diff, Scope } from "../types.ts";
|
|
12
|
+
import type { ShapeType, BaseType } from "@ng-org/shex-orm";
|
|
13
|
+
import { OrmConnection } from "./ormConnectionHandler.ts";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
*
|
|
17
|
+
* @param shapeType
|
|
18
|
+
* @param scope
|
|
19
|
+
* @returns
|
|
20
|
+
*/
|
|
21
|
+
export function createSignalObjectForShape<T extends BaseType>(
|
|
22
|
+
shapeType: ShapeType<T>,
|
|
23
|
+
scope?: Scope
|
|
24
|
+
) {
|
|
25
|
+
const connection: OrmConnection<T> = OrmConnection.getConnection(
|
|
26
|
+
shapeType,
|
|
27
|
+
scope || ""
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
signalObject: connection.signalObject,
|
|
32
|
+
stop: connection.release,
|
|
33
|
+
readyPromise: connection.readyPromise,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Copyright (c) 2025 Laurin Weger, Par le Peuple, NextGraph.org developers
|
|
2
|
+
// All rights reserved.
|
|
3
|
+
// Licensed under the Apache License, Version 2.0
|
|
4
|
+
// <LICENSE-APACHE2 or http://www.apache.org/licenses/LICENSE-2.0>
|
|
5
|
+
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
|
|
6
|
+
// at your option. All files in the project carrying such
|
|
7
|
+
// notice may not be copied, modified, or distributed except
|
|
8
|
+
// according to those terms.
|
|
9
|
+
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
10
|
+
|
|
11
|
+
import * as NG from "@ng-org/lib-wasm";
|
|
12
|
+
|
|
13
|
+
type Session = {
|
|
14
|
+
session_id: string | number;
|
|
15
|
+
protected_store_id: string;
|
|
16
|
+
private_store_id: string;
|
|
17
|
+
public_store_id: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
let resolveNgSession: (value: { ng: typeof NG; session: Session }) => void;
|
|
21
|
+
|
|
22
|
+
export const ngSession = new Promise<{ ng: typeof NG; session: Session }>(
|
|
23
|
+
(resolve) => {
|
|
24
|
+
resolveNgSession = resolve;
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
export function initNgSignals(ngImpl: typeof NG, session: Session) {
|
|
29
|
+
resolveNgSession({ ng: ngImpl, session });
|
|
30
|
+
}
|