@fluidframework/ai-collab 2.10.0-306579
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/.eslintrc.cjs +26 -0
- package/CHANGELOG.md +9 -0
- package/LICENSE +21 -0
- package/README.md +280 -0
- package/alpha.d.ts +11 -0
- package/api-extractor/api-extractor-lint-alpha.cjs.json +5 -0
- package/api-extractor/api-extractor-lint-alpha.esm.json +5 -0
- package/api-extractor/api-extractor-lint-bundle.json +5 -0
- package/api-extractor/api-extractor-lint-index.cjs.json +5 -0
- package/api-extractor/api-extractor-lint-index.esm.json +5 -0
- package/api-extractor/api-extractor-lint-public.cjs.json +5 -0
- package/api-extractor/api-extractor-lint-public.esm.json +5 -0
- package/api-extractor-lint.json +4 -0
- package/api-extractor.json +4 -0
- package/api-report/ai-collab.alpha.api.md +164 -0
- package/api-report/ai-collab.beta.api.md +7 -0
- package/api-report/ai-collab.public.api.md +7 -0
- package/biome.jsonc +4 -0
- package/dist/aiCollab.d.ts +65 -0
- package/dist/aiCollab.d.ts.map +1 -0
- package/dist/aiCollab.js +81 -0
- package/dist/aiCollab.js.map +1 -0
- package/dist/aiCollabApi.d.ts +173 -0
- package/dist/aiCollabApi.d.ts.map +1 -0
- package/dist/aiCollabApi.js +7 -0
- package/dist/aiCollabApi.js.map +1 -0
- package/dist/alpha.d.ts +41 -0
- package/dist/explicit-strategy/agentEditReducer.d.ts +12 -0
- package/dist/explicit-strategy/agentEditReducer.d.ts.map +1 -0
- package/dist/explicit-strategy/agentEditReducer.js +394 -0
- package/dist/explicit-strategy/agentEditReducer.js.map +1 -0
- package/dist/explicit-strategy/agentEditTypes.d.ts +158 -0
- package/dist/explicit-strategy/agentEditTypes.d.ts.map +1 -0
- package/dist/explicit-strategy/agentEditTypes.js +50 -0
- package/dist/explicit-strategy/agentEditTypes.js.map +1 -0
- package/dist/explicit-strategy/idGenerator.d.ts +22 -0
- package/dist/explicit-strategy/idGenerator.d.ts.map +1 -0
- package/dist/explicit-strategy/idGenerator.js +74 -0
- package/dist/explicit-strategy/idGenerator.js.map +1 -0
- package/dist/explicit-strategy/index.d.ts +51 -0
- package/dist/explicit-strategy/index.d.ts.map +1 -0
- package/dist/explicit-strategy/index.js +223 -0
- package/dist/explicit-strategy/index.js.map +1 -0
- package/dist/explicit-strategy/jsonTypes.d.ts +23 -0
- package/dist/explicit-strategy/jsonTypes.d.ts.map +1 -0
- package/dist/explicit-strategy/jsonTypes.js +7 -0
- package/dist/explicit-strategy/jsonTypes.js.map +1 -0
- package/dist/explicit-strategy/promptGeneration.d.ts +51 -0
- package/dist/explicit-strategy/promptGeneration.d.ts.map +1 -0
- package/dist/explicit-strategy/promptGeneration.js +218 -0
- package/dist/explicit-strategy/promptGeneration.js.map +1 -0
- package/dist/explicit-strategy/typeGeneration.d.ts +15 -0
- package/dist/explicit-strategy/typeGeneration.d.ts.map +1 -0
- package/dist/explicit-strategy/typeGeneration.js +264 -0
- package/dist/explicit-strategy/typeGeneration.js.map +1 -0
- package/dist/explicit-strategy/utils.d.ts +37 -0
- package/dist/explicit-strategy/utils.d.ts.map +1 -0
- package/dist/explicit-strategy/utils.js +47 -0
- package/dist/explicit-strategy/utils.js.map +1 -0
- package/dist/implicit-strategy/index.d.ts +8 -0
- package/dist/implicit-strategy/index.d.ts.map +1 -0
- package/dist/implicit-strategy/index.js +18 -0
- package/dist/implicit-strategy/index.js.map +1 -0
- package/dist/implicit-strategy/sharedTreeBranchManager.d.ts +63 -0
- package/dist/implicit-strategy/sharedTreeBranchManager.d.ts.map +1 -0
- package/dist/implicit-strategy/sharedTreeBranchManager.js +212 -0
- package/dist/implicit-strategy/sharedTreeBranchManager.js.map +1 -0
- package/dist/implicit-strategy/sharedTreeDiff.d.ts +102 -0
- package/dist/implicit-strategy/sharedTreeDiff.d.ts.map +1 -0
- package/dist/implicit-strategy/sharedTreeDiff.js +522 -0
- package/dist/implicit-strategy/sharedTreeDiff.js.map +1 -0
- package/dist/implicit-strategy/utils.d.ts +21 -0
- package/dist/implicit-strategy/utils.d.ts.map +1 -0
- package/dist/implicit-strategy/utils.js +49 -0
- package/dist/implicit-strategy/utils.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/package.json +3 -0
- package/dist/public.d.ts +19 -0
- package/eslintrc.cjs +11 -0
- package/internal.d.ts +11 -0
- package/lib/aiCollab.d.ts +65 -0
- package/lib/aiCollab.d.ts.map +1 -0
- package/lib/aiCollab.js +77 -0
- package/lib/aiCollab.js.map +1 -0
- package/lib/aiCollabApi.d.ts +173 -0
- package/lib/aiCollabApi.d.ts.map +1 -0
- package/lib/aiCollabApi.js +6 -0
- package/lib/aiCollabApi.js.map +1 -0
- package/lib/alpha.d.ts +41 -0
- package/lib/explicit-strategy/agentEditReducer.d.ts +12 -0
- package/lib/explicit-strategy/agentEditReducer.d.ts.map +1 -0
- package/lib/explicit-strategy/agentEditReducer.js +390 -0
- package/lib/explicit-strategy/agentEditReducer.js.map +1 -0
- package/lib/explicit-strategy/agentEditTypes.d.ts +158 -0
- package/lib/explicit-strategy/agentEditTypes.d.ts.map +1 -0
- package/lib/explicit-strategy/agentEditTypes.js +47 -0
- package/lib/explicit-strategy/agentEditTypes.js.map +1 -0
- package/lib/explicit-strategy/idGenerator.d.ts +22 -0
- package/lib/explicit-strategy/idGenerator.d.ts.map +1 -0
- package/lib/explicit-strategy/idGenerator.js +70 -0
- package/lib/explicit-strategy/idGenerator.js.map +1 -0
- package/lib/explicit-strategy/index.d.ts +51 -0
- package/lib/explicit-strategy/index.d.ts.map +1 -0
- package/lib/explicit-strategy/index.js +219 -0
- package/lib/explicit-strategy/index.js.map +1 -0
- package/lib/explicit-strategy/jsonTypes.d.ts +23 -0
- package/lib/explicit-strategy/jsonTypes.d.ts.map +1 -0
- package/lib/explicit-strategy/jsonTypes.js +6 -0
- package/lib/explicit-strategy/jsonTypes.js.map +1 -0
- package/lib/explicit-strategy/promptGeneration.d.ts +51 -0
- package/lib/explicit-strategy/promptGeneration.d.ts.map +1 -0
- package/lib/explicit-strategy/promptGeneration.js +208 -0
- package/lib/explicit-strategy/promptGeneration.js.map +1 -0
- package/lib/explicit-strategy/typeGeneration.d.ts +15 -0
- package/lib/explicit-strategy/typeGeneration.d.ts.map +1 -0
- package/lib/explicit-strategy/typeGeneration.js +260 -0
- package/lib/explicit-strategy/typeGeneration.js.map +1 -0
- package/lib/explicit-strategy/utils.d.ts +37 -0
- package/lib/explicit-strategy/utils.d.ts.map +1 -0
- package/lib/explicit-strategy/utils.js +41 -0
- package/lib/explicit-strategy/utils.js.map +1 -0
- package/lib/implicit-strategy/index.d.ts +8 -0
- package/lib/implicit-strategy/index.d.ts.map +1 -0
- package/lib/implicit-strategy/index.js +8 -0
- package/lib/implicit-strategy/index.js.map +1 -0
- package/lib/implicit-strategy/sharedTreeBranchManager.d.ts +63 -0
- package/lib/implicit-strategy/sharedTreeBranchManager.d.ts.map +1 -0
- package/lib/implicit-strategy/sharedTreeBranchManager.js +213 -0
- package/lib/implicit-strategy/sharedTreeBranchManager.js.map +1 -0
- package/lib/implicit-strategy/sharedTreeDiff.d.ts +102 -0
- package/lib/implicit-strategy/sharedTreeDiff.d.ts.map +1 -0
- package/lib/implicit-strategy/sharedTreeDiff.js +515 -0
- package/lib/implicit-strategy/sharedTreeDiff.js.map +1 -0
- package/lib/implicit-strategy/utils.d.ts +21 -0
- package/lib/implicit-strategy/utils.d.ts.map +1 -0
- package/lib/implicit-strategy/utils.js +43 -0
- package/lib/implicit-strategy/utils.js.map +1 -0
- package/lib/index.d.ts +16 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +15 -0
- package/lib/index.js.map +1 -0
- package/lib/public.d.ts +19 -0
- package/lib/tsdoc-metadata.json +11 -0
- package/mocharc.cjs +14 -0
- package/package.json +165 -0
- package/prettier.config.cjs +8 -0
- package/src/aiCollab.ts +86 -0
- package/src/aiCollabApi.ts +184 -0
- package/src/explicit-strategy/agentEditReducer.ts +498 -0
- package/src/explicit-strategy/agentEditTypes.ts +177 -0
- package/src/explicit-strategy/idGenerator.ts +90 -0
- package/src/explicit-strategy/index.ts +364 -0
- package/src/explicit-strategy/jsonTypes.ts +27 -0
- package/src/explicit-strategy/promptGeneration.ts +294 -0
- package/src/explicit-strategy/typeGeneration.ts +374 -0
- package/src/explicit-strategy/utils.ts +60 -0
- package/src/implicit-strategy/README.md +4 -0
- package/src/implicit-strategy/index.ts +21 -0
- package/src/implicit-strategy/sharedTreeBranchManager.ts +294 -0
- package/src/implicit-strategy/sharedTreeDiff.ts +735 -0
- package/src/implicit-strategy/utils.ts +54 -0
- package/src/index.ts +39 -0
- package/tsconfig.cjs.json +7 -0
- package/tsconfig.json +12 -0
- package/tsdoc.json +4 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Subset of Map interface.
|
|
8
|
+
*
|
|
9
|
+
* @remarks originally from tree/src/util/utils.ts
|
|
10
|
+
*/
|
|
11
|
+
export interface MapGetSet<K, V> {
|
|
12
|
+
get(key: K): V | undefined;
|
|
13
|
+
set(key: K, value: V): void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* TBD
|
|
18
|
+
*/
|
|
19
|
+
export function fail(message: string): never {
|
|
20
|
+
throw new Error(message);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Map one iterable to another by transforming each element one at a time
|
|
25
|
+
* @param iterable - the iterable to transform
|
|
26
|
+
* @param map - the transformation function to run on each element of the iterable
|
|
27
|
+
* @returns a new iterable of elements which have been transformed by the `map` function
|
|
28
|
+
*
|
|
29
|
+
* @remarks originally from tree/src/util/utils.ts
|
|
30
|
+
*/
|
|
31
|
+
export function* mapIterable<T, U>(
|
|
32
|
+
iterable: Iterable<T>,
|
|
33
|
+
map: (t: T) => U,
|
|
34
|
+
): IterableIterator<U> {
|
|
35
|
+
for (const t of iterable) {
|
|
36
|
+
yield map(t);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Retrieve a value from a map with the given key, or create a new entry if the key is not in the map.
|
|
42
|
+
* @param map - The map to query/update
|
|
43
|
+
* @param key - The key to lookup in the map
|
|
44
|
+
* @param defaultValue - a function which returns a default value. This is called and used to set an initial value for the given key in the map if none exists
|
|
45
|
+
* @returns either the existing value for the given key, or the newly-created value (the result of `defaultValue`)
|
|
46
|
+
*
|
|
47
|
+
* @remarks originally from tree/src/util/utils.ts
|
|
48
|
+
*/
|
|
49
|
+
export function getOrCreate<K, V>(
|
|
50
|
+
map: MapGetSet<K, V>,
|
|
51
|
+
key: K,
|
|
52
|
+
defaultValue: (key: K) => V,
|
|
53
|
+
): V {
|
|
54
|
+
let value = map.get(key);
|
|
55
|
+
if (value === undefined) {
|
|
56
|
+
value = defaultValue(key);
|
|
57
|
+
map.set(key, value);
|
|
58
|
+
}
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export {
|
|
7
|
+
type DifferenceCreate,
|
|
8
|
+
type DifferenceChange,
|
|
9
|
+
type DifferenceMove,
|
|
10
|
+
type DifferenceRemove,
|
|
11
|
+
type Difference,
|
|
12
|
+
type ObjectPath,
|
|
13
|
+
type Options,
|
|
14
|
+
sharedTreeDiff,
|
|
15
|
+
createMergableIdDiffSeries,
|
|
16
|
+
createMergableDiffSeries,
|
|
17
|
+
} from "./sharedTreeDiff.js";
|
|
18
|
+
|
|
19
|
+
export { SharedTreeBranchManager } from "./sharedTreeBranchManager.js";
|
|
20
|
+
|
|
21
|
+
export { sharedTreeTraverse, isTreeArrayNode, isTreeMapNode } from "./utils.js";
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
ImplicitFieldSchema,
|
|
8
|
+
TreeArrayNode,
|
|
9
|
+
TreeMapNode,
|
|
10
|
+
TreeViewConfiguration,
|
|
11
|
+
} from "@fluidframework/tree";
|
|
12
|
+
import {
|
|
13
|
+
// TODO: Migrate to newer branching API (`TreeContext`)
|
|
14
|
+
// eslint-disable-next-line import/no-deprecated
|
|
15
|
+
getBranch,
|
|
16
|
+
type BranchableTree,
|
|
17
|
+
type TreeBranchFork,
|
|
18
|
+
type TreeViewAlpha,
|
|
19
|
+
// eslint-disable-next-line import/no-internal-modules -- This package depends on the branching APIs in Tree which are currently alpha
|
|
20
|
+
} from "@fluidframework/tree/alpha";
|
|
21
|
+
import type { z } from "zod";
|
|
22
|
+
|
|
23
|
+
import {
|
|
24
|
+
createMergableDiffSeries,
|
|
25
|
+
createMergableIdDiffSeries,
|
|
26
|
+
sharedTreeDiff,
|
|
27
|
+
type Difference,
|
|
28
|
+
type ObjectPath,
|
|
29
|
+
} from "./sharedTreeDiff.js";
|
|
30
|
+
import { isTreeMapNode, isTreeArrayNode, sharedTreeTraverse } from "./utils.js";
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Manages determining the differences between two branches of a SharedTree represented as an actual tree node or a plain javascript object
|
|
34
|
+
* and applies said differences to the original SharedTree branch.
|
|
35
|
+
*
|
|
36
|
+
* @alpha
|
|
37
|
+
*/
|
|
38
|
+
export class SharedTreeBranchManager {
|
|
39
|
+
private readonly objectSchema?: z.Schema | undefined;
|
|
40
|
+
private readonly nodeIdAttributeName?: string | undefined;
|
|
41
|
+
|
|
42
|
+
public constructor(params?: { objectSchema?: z.Schema; nodeIdAttributeName?: string }) {
|
|
43
|
+
this.objectSchema = params?.objectSchema;
|
|
44
|
+
this.nodeIdAttributeName = params?.nodeIdAttributeName;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Compares the differences between either two objects or a TreeNode and a plain object.
|
|
49
|
+
* TODO: Should allow comparing two tree nodes? Should we allow comparing two plain objects? Or just leave as tree node vs object?
|
|
50
|
+
*/
|
|
51
|
+
public compare(
|
|
52
|
+
obj: Record<string, unknown> | TreeArrayNode,
|
|
53
|
+
newObj: Record<string, unknown> | unknown[],
|
|
54
|
+
): Difference[] {
|
|
55
|
+
// By validating that the incoming object matches the schema, we can confirm that any property
|
|
56
|
+
// deletions/updates/additions are valid.
|
|
57
|
+
if (this.objectSchema !== undefined) {
|
|
58
|
+
const res = this.objectSchema.safeParse(newObj);
|
|
59
|
+
if (res.success === false) {
|
|
60
|
+
throw new TypeError("Invalid data");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const diffTotality = sharedTreeDiff(obj as Record<string, unknown> | unknown[], newObj, {
|
|
65
|
+
useObjectIds:
|
|
66
|
+
this.nodeIdAttributeName === undefined
|
|
67
|
+
? undefined
|
|
68
|
+
: { idAttributeName: this.nodeIdAttributeName },
|
|
69
|
+
cyclesFix: true,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
if (this.nodeIdAttributeName !== undefined) {
|
|
73
|
+
return createMergableIdDiffSeries(obj, diffTotality, this.nodeIdAttributeName);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return createMergableDiffSeries(diffTotality);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Produces a set of differences based on two versions of an object, applies the changes to the first one,
|
|
81
|
+
* and returns the set of differences.
|
|
82
|
+
*/
|
|
83
|
+
public mergeObject(
|
|
84
|
+
obj: Record<string, unknown> | TreeArrayNode,
|
|
85
|
+
llmResponse: Record<string, unknown> | unknown[],
|
|
86
|
+
): Difference[] {
|
|
87
|
+
const differences = this.compare(obj, llmResponse);
|
|
88
|
+
this.mergeDiffs(differences, obj);
|
|
89
|
+
return differences;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* produces a diff between two objects and merges the differences.
|
|
94
|
+
*/
|
|
95
|
+
public checkoutNewMergedBranch<T extends ImplicitFieldSchema>(
|
|
96
|
+
treeView: TreeViewAlpha<T>,
|
|
97
|
+
treeViewConfiguration: TreeViewConfiguration<T>,
|
|
98
|
+
absolutePathToObjectNode: ObjectPath,
|
|
99
|
+
llmResponse: Record<string, unknown> | unknown[],
|
|
100
|
+
): {
|
|
101
|
+
differences: Difference[];
|
|
102
|
+
originalBranch: BranchableTree;
|
|
103
|
+
forkBranch: TreeBranchFork;
|
|
104
|
+
forkView: TreeViewAlpha<T>;
|
|
105
|
+
newBranchTargetNode: Record<string, unknown> | TreeArrayNode;
|
|
106
|
+
} {
|
|
107
|
+
// eslint-disable-next-line import/no-deprecated
|
|
108
|
+
const originalBranch = getBranch(treeView);
|
|
109
|
+
const forkBranch = originalBranch.branch();
|
|
110
|
+
const forkView = forkBranch.viewWith(treeViewConfiguration) as TreeViewAlpha<T>;
|
|
111
|
+
|
|
112
|
+
console.log("traveling to absolute path from root:", absolutePathToObjectNode);
|
|
113
|
+
const newBranchTargetNode = sharedTreeTraverse(
|
|
114
|
+
forkView.root as unknown as TreeMapNode | TreeArrayNode | Record<string, unknown>,
|
|
115
|
+
absolutePathToObjectNode,
|
|
116
|
+
) as Record<string, unknown> | TreeArrayNode;
|
|
117
|
+
|
|
118
|
+
console.log(
|
|
119
|
+
"initiating compare between old and new branch target nodes",
|
|
120
|
+
{ ...newBranchTargetNode },
|
|
121
|
+
{ ...llmResponse },
|
|
122
|
+
);
|
|
123
|
+
console.log("newBranchTargetNode", { ...newBranchTargetNode });
|
|
124
|
+
console.log("llmResponse", { ...llmResponse });
|
|
125
|
+
|
|
126
|
+
const differences = this.compare(newBranchTargetNode, llmResponse);
|
|
127
|
+
// const differences = [];
|
|
128
|
+
this.mergeDiffs(differences, newBranchTargetNode);
|
|
129
|
+
|
|
130
|
+
return { differences, originalBranch, forkBranch, forkView, newBranchTargetNode };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Creates a forked branch of a tree view.
|
|
135
|
+
*/
|
|
136
|
+
public checkoutNewMergedBranchV2<T extends ImplicitFieldSchema>(
|
|
137
|
+
treeView: TreeViewAlpha<T>,
|
|
138
|
+
treeViewConfiguration: TreeViewConfiguration<T>,
|
|
139
|
+
absolutePathToObjectNode: ObjectPath,
|
|
140
|
+
// differences: Difference[],
|
|
141
|
+
): {
|
|
142
|
+
originalBranch: BranchableTree;
|
|
143
|
+
forkBranch: TreeBranchFork;
|
|
144
|
+
forkView: TreeViewAlpha<T>;
|
|
145
|
+
newBranchTargetNode: Record<string, unknown> | TreeArrayNode;
|
|
146
|
+
} {
|
|
147
|
+
// eslint-disable-next-line import/no-deprecated
|
|
148
|
+
const originalBranch = getBranch(treeView);
|
|
149
|
+
const forkBranch = originalBranch.branch();
|
|
150
|
+
const forkView = forkBranch.viewWith(treeViewConfiguration) as TreeViewAlpha<T>;
|
|
151
|
+
const newBranchTargetNode = sharedTreeTraverse(
|
|
152
|
+
forkView.root as TreeMapNode | TreeArrayNode | Record<string, unknown>,
|
|
153
|
+
absolutePathToObjectNode,
|
|
154
|
+
) as Record<string, unknown> | TreeArrayNode;
|
|
155
|
+
// this.mergeDiffs(differences, newBranchTargetNode);
|
|
156
|
+
return { originalBranch, forkBranch, forkView, newBranchTargetNode };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Handles applying an array of differences to an object in the proper order and making any necessary adjustments as each diff
|
|
161
|
+
* is applied.
|
|
162
|
+
*
|
|
163
|
+
* @returns an array of differences that were not applied due to some kind of conflict or error.
|
|
164
|
+
*/
|
|
165
|
+
public mergeDiffs(
|
|
166
|
+
diffs: Difference[],
|
|
167
|
+
objectToUpdate: Record<string, unknown> | TreeArrayNode,
|
|
168
|
+
): Set<Difference> {
|
|
169
|
+
const unappliedDiffs = new Set<Difference>();
|
|
170
|
+
|
|
171
|
+
for (const diff of diffs) {
|
|
172
|
+
const isDiffApplied = this.applyDiff(diff, objectToUpdate);
|
|
173
|
+
|
|
174
|
+
if (isDiffApplied === false) {
|
|
175
|
+
unappliedDiffs.add(diff);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return unappliedDiffs;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Applies an individual diff to the objectToUpdate.
|
|
184
|
+
*/
|
|
185
|
+
public applyDiff(
|
|
186
|
+
diff: Difference,
|
|
187
|
+
objectToUpdate: Record<string, unknown> | TreeArrayNode,
|
|
188
|
+
): boolean {
|
|
189
|
+
const targetObject: unknown = getTargetObjectFromPath(diff.path, objectToUpdate);
|
|
190
|
+
|
|
191
|
+
if (isTreeMapNode(targetObject)) {
|
|
192
|
+
switch (diff.type) {
|
|
193
|
+
case "CHANGE":
|
|
194
|
+
case "CREATE": {
|
|
195
|
+
// This code is doing non-schema aware editing, which is not a supported feature of this API.
|
|
196
|
+
// Casting to any is a way to get this unsupported and rather unsafe operation to compile.
|
|
197
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
|
|
198
|
+
targetObject.set(diff.path[diff.path.length - 1] as string, diff.value as any);
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
case "REMOVE": {
|
|
202
|
+
targetObject.delete(diff.path[diff.path.length - 1] as string);
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
default: {
|
|
206
|
+
throw new TypeError("Unsupported diff type for Map Tree Node");
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
} else if (isTreeArrayNode(targetObject)) {
|
|
210
|
+
const targetIndex = diff.path[diff.path.length - 1] as number;
|
|
211
|
+
const isTargetIndexValid = targetIndex >= 0 && targetIndex <= targetObject.length - 1;
|
|
212
|
+
switch (diff.type) {
|
|
213
|
+
case "CHANGE":
|
|
214
|
+
case "CREATE": {
|
|
215
|
+
if (isTargetIndexValid) {
|
|
216
|
+
// This code is doing non-schema aware editing, which is not a supported feature of this API.
|
|
217
|
+
// Casting to any is a way to get this unsupported and rather unsafe operation to compile.
|
|
218
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
|
|
219
|
+
targetObject.insertAt(targetIndex, diff.value as any);
|
|
220
|
+
return true;
|
|
221
|
+
} else {
|
|
222
|
+
// This code is doing non-schema aware editing, which is not a supported feature of this API.
|
|
223
|
+
// Casting to any is a way to get this unsupported and rather unsafe operation to compile.
|
|
224
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
|
|
225
|
+
targetObject.insertAtEnd(diff.value as any);
|
|
226
|
+
console.warn(
|
|
227
|
+
"CREATE diff specified an invalid index, defaulting to pushing to end of array",
|
|
228
|
+
);
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
case "MOVE": {
|
|
233
|
+
if (isTargetIndexValid) {
|
|
234
|
+
if (diff.newIndex > targetIndex) {
|
|
235
|
+
// forward move must use i + 1
|
|
236
|
+
targetObject.moveToIndex(diff.newIndex + 1, targetIndex);
|
|
237
|
+
} else if (diff.newIndex < targetIndex) {
|
|
238
|
+
// backwards move, using i directly is fine
|
|
239
|
+
targetObject.moveToIndex(diff.newIndex, targetIndex);
|
|
240
|
+
}
|
|
241
|
+
return true;
|
|
242
|
+
} else {
|
|
243
|
+
console.warn("MOVE diff specified an invalid index, ignoring.");
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
case "REMOVE": {
|
|
248
|
+
if (isTargetIndexValid) {
|
|
249
|
+
targetObject.removeAt(targetIndex);
|
|
250
|
+
return true;
|
|
251
|
+
} else {
|
|
252
|
+
console.warn("REMOVE diff specified an invalid index, ignoring.");
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
default: {
|
|
257
|
+
throw new TypeError("Unsupported diff type for Array Tree Node");
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
} else if (typeof targetObject === "object" && targetObject !== null) {
|
|
261
|
+
switch (diff.type) {
|
|
262
|
+
case "CHANGE":
|
|
263
|
+
case "CREATE": {
|
|
264
|
+
targetObject[diff.path[diff.path.length - 1] as string] = diff.value;
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
case "REMOVE": {
|
|
268
|
+
// We can't use the delete keyword on a tree node.
|
|
269
|
+
targetObject[diff.path[diff.path.length - 1] as string] = undefined;
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
default: {
|
|
273
|
+
throw new TypeError("Unsupported diff type for Object Tree Node");
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
} else {
|
|
277
|
+
throw new TypeError("Unsupported object type for diff application");
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Returns the target object that the given diff should be applied to.
|
|
284
|
+
*/
|
|
285
|
+
function getTargetObjectFromPath(
|
|
286
|
+
path: ObjectPath,
|
|
287
|
+
object: Record<string, unknown> | TreeArrayNode,
|
|
288
|
+
): unknown {
|
|
289
|
+
let targetObject: unknown = object;
|
|
290
|
+
if (path.length > 1) {
|
|
291
|
+
targetObject = sharedTreeTraverse(object, path.slice(0, -1));
|
|
292
|
+
}
|
|
293
|
+
return targetObject;
|
|
294
|
+
}
|