@jay-framework/serialization 0.5.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/dist/index.d.ts +9 -0
- package/dist/index.js +29 -0
- package/package.json +34 -0
- package/readme.md +69 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { JSONPatch, ArrayContexts } from '@jay-framework/json-patch';
|
|
2
|
+
|
|
3
|
+
type Deserialize<T extends object> = (jsonPatch: JSONPatch) => [T, Deserialize<T>];
|
|
4
|
+
declare function deserialize<T extends object>(jsonPatch: JSONPatch): [T, Deserialize<T>];
|
|
5
|
+
|
|
6
|
+
type Serialize<T extends object> = (entity: any, contexts?: ArrayContexts) => [JSONPatch, Serialize<T>];
|
|
7
|
+
declare function serialize<T extends object>(entity: any, contexts?: ArrayContexts): [JSONPatch, Serialize<T>];
|
|
8
|
+
|
|
9
|
+
export { type Deserialize, type Serialize, deserialize, serialize };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ADD, REPLACE, patch, diff } from "@jay-framework/json-patch";
|
|
2
|
+
function deserialize(jsonPatch) {
|
|
3
|
+
return _deserialize(void 0)(jsonPatch);
|
|
4
|
+
}
|
|
5
|
+
function _deserialize(obj) {
|
|
6
|
+
return (jsonPatch) => {
|
|
7
|
+
if (jsonPatch.length === 1 && jsonPatch[0].path.length === 0 && (jsonPatch[0].op === ADD || jsonPatch[0].op === REPLACE)) {
|
|
8
|
+
obj = jsonPatch[0].value;
|
|
9
|
+
return [obj, _deserialize(obj)];
|
|
10
|
+
}
|
|
11
|
+
if (!obj)
|
|
12
|
+
obj = {};
|
|
13
|
+
let newObj = patch(obj, jsonPatch);
|
|
14
|
+
return [newObj, _deserialize(newObj)];
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function serialize(entity, contexts) {
|
|
18
|
+
return _serialize(void 0, contexts)(entity);
|
|
19
|
+
}
|
|
20
|
+
function _serialize(lastEntity, contexts) {
|
|
21
|
+
return (entity) => {
|
|
22
|
+
let patch2 = diff(entity, lastEntity, contexts);
|
|
23
|
+
return [patch2[0], _serialize(entity, contexts)];
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export {
|
|
27
|
+
deserialize,
|
|
28
|
+
serialize
|
|
29
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jay-framework/serialization",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"readme.md"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "npm run build:js && npm run build:types",
|
|
13
|
+
"build:watch": "npm run build:js -- --watch & npm run build:types -- --watch",
|
|
14
|
+
"build:js": "vite build",
|
|
15
|
+
"build:types": "tsup lib/index.ts --dts-only --format esm",
|
|
16
|
+
"build:check-types": "tsc",
|
|
17
|
+
"clean": "rimraf dist",
|
|
18
|
+
"confirm": "npm run clean && npm run build && npm run build:check-types && npm run test",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"test:watch": "vitest"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@jay-framework/json-patch": "workspace:^"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@jay-framework/dev-environment": "workspace:^",
|
|
27
|
+
"@types/node": "^20.11.5",
|
|
28
|
+
"rimraf": "^5.0.5",
|
|
29
|
+
"tsup": "^8.0.1",
|
|
30
|
+
"typescript": "^5.3.3",
|
|
31
|
+
"vite": "^5.0.11",
|
|
32
|
+
"vitest": "^1.2.1"
|
|
33
|
+
}
|
|
34
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Jay Serialization
|
|
2
|
+
|
|
3
|
+
A **stateful serialization** implementation that serializes an **object** into a **diff** to be applied to another
|
|
4
|
+
**object** on the other side.
|
|
5
|
+
|
|
6
|
+
The algorithm is useful when two parties have frequent updates of an updated object sent from party `A` to party `B`.
|
|
7
|
+
|
|
8
|
+
1. Party `A` calls the `serialize` function which produces a `JSONPatch` and a new `seralize`
|
|
9
|
+
function to compute the next patch.
|
|
10
|
+
2. Party `B` receives the `JSONPatch`, using `deserialize` gets the updated object and a new `deserialize` function
|
|
11
|
+
to apply the next patch.
|
|
12
|
+
|
|
13
|
+
## Signature
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
export type Serialize<T extends object> = (
|
|
17
|
+
entity: any,
|
|
18
|
+
contexts?: ArrayContexts,
|
|
19
|
+
) => [JSONPatch, Serialize<T>];
|
|
20
|
+
declare function serialize<T extends object>(
|
|
21
|
+
entity: any,
|
|
22
|
+
contexts?: ArrayContexts,
|
|
23
|
+
): [JSONPatch, Serialize<T>];
|
|
24
|
+
|
|
25
|
+
export type Deserialize<T extends object> = (jsonPatch: JSONPatch) => [T, Deserialize<T>];
|
|
26
|
+
declare function deserialize<T extends object>(jsonPatch: JSONPatch): [T, Deserialize<T>];
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## library notes
|
|
30
|
+
|
|
31
|
+
- The library assumes the object to serialize and deserialize are immutable objects.
|
|
32
|
+
It always creates new instances in deserialization.
|
|
33
|
+
- The library serialization always serializes the first object in full on the path `[]`,
|
|
34
|
+
which is then deserialized as is.
|
|
35
|
+
- It is using the `@jay-framework/json-patch` library to compute and apply the `JSONPatch`es.
|
|
36
|
+
- The `ArrayContexts` parameter is the same from the `@jay-framework/json-patch` library.
|
|
37
|
+
- The library is used by `@jay-framework/secure` for the worker - main context communication.
|
|
38
|
+
- The library can also be used for server - client communication if also using global object version management,
|
|
39
|
+
such as optimistic locking.
|
|
40
|
+
|
|
41
|
+
## examples
|
|
42
|
+
|
|
43
|
+
Serialization:
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
let [patch, nextSerialize] = serialize({ a: 1, b: 2, c: 'abcd', d: true });
|
|
47
|
+
expect(patch).toEqual([{ op: ADD, path: [], value: { a: 1, b: 2, c: 'abcd', d: true } }]);
|
|
48
|
+
|
|
49
|
+
[patch, nextSerialize] = nextSerialize({ a: 11, b: 2, c: 'abcd', d: true });
|
|
50
|
+
expect(patch).toEqual([{ op: REPLACE, path: ['a'], value: 11 }]);
|
|
51
|
+
|
|
52
|
+
[patch, nextSerialize] = nextSerialize({ a: 11, b: 12, c: 'abcd', d: true });
|
|
53
|
+
expect(patch).toEqual([{ op: REPLACE, path: ['b'], value: 12 }]);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Deserialization:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
let [target, nextSerialize] = deserialize([
|
|
60
|
+
{ op: ADD, path: [], value: { a: 1, b: 2, c: 'abcd', d: true } },
|
|
61
|
+
]);
|
|
62
|
+
expect(target).toEqual({ a: 1, b: 2, c: 'abcd', d: true });
|
|
63
|
+
|
|
64
|
+
[target, nextSerialize] = nextSerialize([{ op: REPLACE, path: ['a'], value: 11 }]);
|
|
65
|
+
expect(target).toEqual({ a: 11, b: 2, c: 'abcd', d: true });
|
|
66
|
+
|
|
67
|
+
[target, nextSerialize] = nextSerialize([{ op: REPLACE, path: ['b'], value: 12 }]);
|
|
68
|
+
expect(target).toEqual({ a: 11, b: 12, c: 'abcd', d: true });
|
|
69
|
+
```
|