@mml-io/networked-dom-document 0.15.0 → 0.16.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.
@@ -0,0 +1,167 @@
1
+ import { Pointer } from "./pointer";
2
+ /**
3
+ All diff* functions should return a list of operations, often empty.
4
+
5
+ Each operation should be an object with two to four fields:
6
+ * `op`: the name of the operation; one of "add", "remove", "replace", "move",
7
+ "copy", or "test".
8
+ * `path`: a JSON pointer string
9
+ * `from`: a JSON pointer string
10
+ * `value`: a JSON value
11
+
12
+ The different operations have different arguments.
13
+ * "add": [`path`, `value`]
14
+ * "remove": [`path`]
15
+ * "replace": [`path`, `value`]
16
+ * "move": [`from`, `path`]
17
+ * "copy": [`from`, `path`]
18
+ * "test": [`path`, `value`]
19
+
20
+ Currently this only really differentiates between Arrays, Objects, and
21
+ Everything Else, which is pretty much just what JSON substantially
22
+ differentiates between.
23
+ */
24
+ export interface AddOperation {
25
+ op: "add";
26
+ path: string;
27
+ value: any;
28
+ }
29
+ export interface RemoveOperation {
30
+ op: "remove";
31
+ path: string;
32
+ }
33
+ export interface ReplaceOperation {
34
+ op: "replace";
35
+ path: string;
36
+ value: any;
37
+ }
38
+ export interface MoveOperation {
39
+ op: "move";
40
+ from: string;
41
+ path: string;
42
+ }
43
+ export interface CopyOperation {
44
+ op: "copy";
45
+ from: string;
46
+ path: string;
47
+ }
48
+ export interface TestOperation {
49
+ op: "test";
50
+ path: string;
51
+ value: any;
52
+ }
53
+ export type Operation = AddOperation | RemoveOperation | ReplaceOperation | MoveOperation | CopyOperation | TestOperation;
54
+ export declare function isDestructive({ op }: Operation): boolean;
55
+ export type Diff = (input: any, output: any, ptr: Pointer) => Operation[];
56
+ /**
57
+ VoidableDiff exists to allow the user to provide a partial diff(...) function,
58
+ falling back to the built-in diffAny(...) function if the user-provided function
59
+ returns void.
60
+ */
61
+ export type VoidableDiff = (input: any, output: any, ptr: Pointer) => Operation[] | void;
62
+ /**
63
+ Produce an 'application/json-patch+json'-type list of tests, to verify that
64
+ existing values in an object are identical to the those captured at some
65
+ checkpoint (whenever this function is called).
66
+
67
+ This does not alter `input` or `output` unless they have a property getter with
68
+ side-effects (which is not a good idea anyway).
69
+
70
+ Returns list of test operations.
71
+ */
72
+ export declare function createTests(input: any, patch: Operation[]): TestOperation[];
73
+ /**
74
+ Produce a 'application/json-patch+json'-type patch to get from one object to
75
+ another.
76
+
77
+ This does not alter `input` or `output` unless they have a property getter with
78
+ side-effects (which is not a good idea anyway).
79
+
80
+ `diff` is called on each pair of comparable non-primitive nodes in the
81
+ `input`/`output` object trees, producing nested patches. Return `undefined`
82
+ to fall back to default behaviour.
83
+
84
+ Returns list of operations to perform on `input` to produce `output`.
85
+ */
86
+ export declare function createPatch(input: any, output: any, diff?: VoidableDiff): Operation[];
87
+ /**
88
+ List the keys in `minuend` that are not in `subtrahend`.
89
+
90
+ A key is only considered if it is both 1) an own-property (o.hasOwnProperty(k))
91
+ of the object, and 2) has a value that is not undefined. This is to match JSON
92
+ semantics, where JSON object serialization drops keys with undefined values.
93
+
94
+ @param minuend Object of interest
95
+ @param subtrahend Object of comparison
96
+ @returns Array of keys that are in `minuend` but not in `subtrahend`.
97
+ */
98
+ export declare function subtract(minuend: {
99
+ [index: string]: any;
100
+ }, subtrahend: {
101
+ [index: string]: any;
102
+ }): string[];
103
+ /**
104
+ List the keys that shared by all `objects`.
105
+
106
+ The semantics of what constitutes a "key" is described in {@link subtract}.
107
+
108
+ @param objects Array of objects to compare
109
+ @returns Array of keys that are in ("own-properties" of) every object in `objects`.
110
+ */
111
+ export declare function intersection(objects: ArrayLike<{
112
+ [index: string]: any;
113
+ }>): string[];
114
+ /**
115
+ Calculate the shortest sequence of operations to get from `input` to `output`,
116
+ using a dynamic programming implementation of the Levenshtein distance algorithm.
117
+
118
+ To get from the input ABC to the output AZ we could just delete all the input
119
+ and say "insert A, insert Z" and be done with it. That's what we do if the
120
+ input is empty. But we can be smarter.
121
+
122
+ output
123
+ A Z
124
+ - -
125
+ [0] 1 2
126
+ input A | 1 [0] 1
127
+ B | 2 [1] 1
128
+ C | 3 2 [2]
129
+
130
+ 1) start at 0,0 (+0)
131
+ 2) keep A (+0)
132
+ 3) remove B (+1)
133
+ 4) replace C with Z (+1)
134
+
135
+ If the `input` (source) is empty, they'll all be in the top row, resulting in an
136
+ array of 'add' operations.
137
+ If the `output` (target) is empty, everything will be in the left column,
138
+ resulting in an array of 'remove' operations.
139
+
140
+ @returns A list of add/remove/replace operations.
141
+ */
142
+ export declare function diffArrays<T>(input: T[], output: T[], ptr: Pointer, diff?: Diff): Operation[];
143
+ export declare function diffObjects(input: any, output: any, ptr: Pointer, diff?: Diff): Operation[];
144
+ /**
145
+ `diffAny()` returns an empty array if `input` and `output` are materially equal
146
+ (i.e., would produce equivalent JSON); otherwise it produces an array of patches
147
+ that would transform `input` into `output`.
148
+
149
+ > Here, "equal" means that the value at the target location and the
150
+ > value conveyed by "value" are of the same JSON type, and that they
151
+ > are considered equal by the following rules for that type:
152
+ > o strings: are considered equal if they contain the same number of
153
+ > Unicode characters and their code points are byte-by-byte equal.
154
+ > o numbers: are considered equal if their values are numerically
155
+ > equal.
156
+ > o arrays: are considered equal if they contain the same number of
157
+ > values, and if each value can be considered equal to the value at
158
+ > the corresponding position in the other array, using this list of
159
+ > type-specific rules.
160
+ > o objects: are considered equal if they contain the same number of
161
+ > members, and if each member can be considered equal to a member in
162
+ > the other object, by comparing their keys (as strings) and their
163
+ > values (using this list of type-specific rules).
164
+ > o literals (false, true, and null): are considered equal if they are
165
+ > the same.
166
+ */
167
+ export declare function diffAny(input: any, output: any, ptr: Pointer, diff?: Diff): Operation[];
@@ -0,0 +1,4 @@
1
+ export { Pointer } from "./pointer";
2
+ export { applyPatch } from "./patch";
3
+ export type { Operation, TestOperation } from "./diff";
4
+ export { createPatch, createTests } from "./diff";
@@ -0,0 +1,102 @@
1
+ import { AddOperation, CopyOperation, MoveOperation, Operation, RemoveOperation, ReplaceOperation, TestOperation } from "./diff";
2
+ export declare class MissingError extends Error {
3
+ path: string;
4
+ constructor(path: string);
5
+ }
6
+ export declare class TestError extends Error {
7
+ actual: any;
8
+ expected: any;
9
+ constructor(actual: any, expected: any);
10
+ }
11
+ /**
12
+ Apply a 'application/json-patch+json'-type patch to an object.
13
+
14
+ `patch` *must* be an array of operations.
15
+
16
+ > Operation objects MUST have exactly one "op" member, whose value
17
+ > indicates the operation to perform. Its value MUST be one of "add",
18
+ > "remove", "replace", "move", "copy", or "test"; other values are
19
+ > errors.
20
+
21
+ This method mutates the target object in-place.
22
+
23
+ @returns list of results, one for each operation: `null` indicated success,
24
+ otherwise, the result will be an instance of one of the Error classes:
25
+ MissingError, InvalidOperationError, or TestError.
26
+ */
27
+ export declare function applyPatch(object: any, patch: Operation[]): (MissingError | TestError | InvalidOperationError | null)[];
28
+ /**
29
+ > o If the target location specifies an array index, a new value is
30
+ > inserted into the array at the specified index.
31
+ > o If the target location specifies an object member that does not
32
+ > already exist, a new member is added to the object.
33
+ > o If the target location specifies an object member that does exist,
34
+ > that member's value is replaced.
35
+ */
36
+ export declare function add(object: any, operation: AddOperation): MissingError | null;
37
+ /**
38
+ > The "remove" operation removes the value at the target location.
39
+ > The target location MUST exist for the operation to be successful.
40
+ */
41
+ export declare function remove(object: any, operation: RemoveOperation): MissingError | null;
42
+ /**
43
+ > The "replace" operation replaces the value at the target location
44
+ > with a new value. The operation object MUST contain a "value" member
45
+ > whose content specifies the replacement value.
46
+ > The target location MUST exist for the operation to be successful.
47
+
48
+ > This operation is functionally identical to a "remove" operation for
49
+ > a value, followed immediately by an "add" operation at the same
50
+ > location with the replacement value.
51
+
52
+ Even more simply, it's like the add operation with an existence check.
53
+ */
54
+ export declare function replace(object: any, operation: ReplaceOperation): MissingError | null;
55
+ /**
56
+ > The "move" operation removes the value at a specified location and
57
+ > adds it to the target location.
58
+ > The operation object MUST contain a "from" member, which is a string
59
+ > containing a JSON Pointer value that references the location in the
60
+ > target document to move the value from.
61
+ > This operation is functionally identical to a "remove" operation on
62
+ > the "from" location, followed immediately by an "add" operation at
63
+ > the target location with the value that was just removed.
64
+
65
+ > The "from" location MUST NOT be a proper prefix of the "path"
66
+ > location; i.e., a location cannot be moved into one of its children.
67
+
68
+ TODO: throw if the check described in the previous paragraph fails.
69
+ */
70
+ export declare function move(object: any, operation: MoveOperation): MissingError | null;
71
+ /**
72
+ > The "copy" operation copies the value at a specified location to the
73
+ > target location.
74
+ > The operation object MUST contain a "from" member, which is a string
75
+ > containing a JSON Pointer value that references the location in the
76
+ > target document to copy the value from.
77
+ > The "from" location MUST exist for the operation to be successful.
78
+
79
+ > This operation is functionally identical to an "add" operation at the
80
+ > target location using the value specified in the "from" member.
81
+
82
+ Alternatively, it's like 'move' without the 'remove'.
83
+ */
84
+ export declare function copy(object: any, operation: CopyOperation): MissingError | null;
85
+ /**
86
+ > The "test" operation tests that a value at the target location is
87
+ > equal to a specified value.
88
+ > The operation object MUST contain a "value" member that conveys the
89
+ > value to be compared to the target location's value.
90
+ > The target location MUST be equal to the "value" value for the
91
+ > operation to be considered successful.
92
+ */
93
+ export declare function test(object: any, operation: TestOperation): TestError | null;
94
+ export declare class InvalidOperationError extends Error {
95
+ operation: Operation;
96
+ constructor(operation: Operation);
97
+ }
98
+ /**
99
+ Switch on `operation.op`, applying the corresponding patch function for each
100
+ case to `object`.
101
+ */
102
+ export declare function apply(object: any, operation: Operation): MissingError | InvalidOperationError | TestError | null;
@@ -0,0 +1,33 @@
1
+ export interface PointerEvaluation {
2
+ parent: any;
3
+ key: string;
4
+ value: any;
5
+ }
6
+ /**
7
+ JSON Pointer representation
8
+ */
9
+ export declare class Pointer {
10
+ tokens: string[];
11
+ constructor(tokens?: string[]);
12
+ /**
13
+ `path` *must* be a properly escaped string.
14
+ */
15
+ static fromJSON(path: string): Pointer;
16
+ toString(): string;
17
+ /**
18
+ Returns an object with 'parent', 'key', and 'value' properties.
19
+ In the special case that this Pointer's path == "",
20
+ this object will be {parent: null, key: '', value: object}.
21
+ Otherwise, parent and key will have the property such that parent[key] == value.
22
+ */
23
+ evaluate(object: any): PointerEvaluation;
24
+ get(object: any): any;
25
+ set(object: any, value: any): void;
26
+ push(token: string): void;
27
+ /**
28
+ `token` should be a String. It'll be coerced to one anyway.
29
+
30
+ immutable (shallowly)
31
+ */
32
+ add(token: string): Pointer;
33
+ }
@@ -0,0 +1,10 @@
1
+ export declare const hasOwnProperty: (v: PropertyKey) => boolean;
2
+ export declare function objectType(object: any): "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | "null" | "array";
3
+ /**
4
+ Recursively copy a value.
5
+
6
+ @param source - should be a JavaScript primitive, Array, Date, or (plain old) Object.
7
+ @returns copy of source where every Array and Object have been recursively
8
+ reconstructed from their constituent elements
9
+ */
10
+ export declare function clone<T>(source: T): T;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mml-io/networked-dom-document",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -19,9 +19,8 @@
19
19
  "test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest"
20
20
  },
21
21
  "dependencies": {
22
- "@mml-io/networked-dom-protocol": "^0.15.0",
23
- "@mml-io/observable-dom-common": "^0.15.0",
24
- "rfc6902": "5.1.1"
22
+ "@mml-io/networked-dom-protocol": "^0.16.0",
23
+ "@mml-io/observable-dom-common": "^0.16.0"
25
24
  },
26
- "gitHead": "09c8250150fbb464d6b94f27976078366885b858"
25
+ "gitHead": "b63e712f9e21e9f165ba3845e4c8b5f66af064b1"
27
26
  }