Skip to content

Commit 0711abf

Browse files
committed
feat: add support for copy
1 parent 4cf94f8 commit 0711abf

File tree

2 files changed

+66
-45
lines changed

2 files changed

+66
-45
lines changed

src/__tests__/new.test.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,14 +137,58 @@ describe('JSONPatchOT', () => {
137137
]);
138138
});
139139

140+
it('should handle array index changes with accepted copies', () => {
141+
// [0, 1, 2, 3, 4, 5, 6]; <- Starting array
142+
const acceptedOps: Operation[] = [
143+
{op: OpType.copy, path: '/array/3', from: '/someval'},
144+
{op: OpType.copy, path: '/array/5', from: '/someval'},
145+
];
146+
147+
// [0, 1, 2, val, 3, val, 4, 5, 6]; <- Array after accepted copies
148+
149+
// Actions to double some specific values
150+
const proposedOps: Operation[] = [
151+
{op: OpType.replace, path: '/array/3', value: 6}, // 3 -> 6
152+
{op: OpType.replace, path: '/array/4', value: 8}, // 4 -> 8
153+
{op: OpType.replace, path: '/array/6', value: 12}, // 6 -> 12
154+
];
155+
156+
expect(JSONPatchOT(acceptedOps, proposedOps)).toEqual([
157+
{op: OpType.replace, path: '/array/4', value: 6},
158+
{op: OpType.replace, path: '/array/6', value: 8},
159+
{op: OpType.replace, path: '/array/8', value: 12},
160+
]);
161+
});
162+
163+
// it('should handle array index changes with accepted moves to and out of an array', () => {
164+
// // [0, 1, 2, 3, 4, 5, 6]; <- Starting array
165+
// const acceptedOps: Operation[] = [
166+
// // {op: OpType.move, path: '/array/3', from: '/someval'}, //acts like an add
167+
// {op: OpType.move, path: '/someval', from: '/array/5'}, // acts like a remove
168+
// ];
169+
170+
// // [0, 1, 2, val, 3, 5, 6]; <- Array after accepted copies
171+
172+
// // Actions to double some specific values
173+
// const proposedOps: Operation[] = [
174+
// {op: OpType.replace, path: '/array/5', value: 6}, // 3 -> 6
175+
// ];
176+
177+
// expect(JSONPatchOT(acceptedOps, proposedOps)).toEqual([
178+
// {op: OpType.replace, path: '/array/4', value: 6},
179+
// //{op: OpType.replace, path: '/array/6', value: 8}, <- removed
180+
// {op: OpType.replace, path: '/array/8', value: 12},
181+
// ]);
182+
// });
183+
140184
it('should handle array index changes with accepted adds and removes', () => {
141185
// [0, 1, 2, 3, 4, 5, 6]; <- Starting array
142186
const acceptedOps: Operation[] = [
143187
{op: OpType.remove, path: '/array/1'},
144188
{op: OpType.add, path: '/array/3', value: 30},
145189
];
146190

147-
// [0, 2, 3, 30, 4, 5, 6]; <- Array after accepted adds
191+
// [0, 2, 3, 30, 4, 5, 6]; <- Array after accepted add and remove
148192

149193
// Actions to double some specific values
150194
const proposedOps: Operation[] = [

src/index.ts

Lines changed: 21 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -58,40 +58,36 @@ export type Operation =
5858
import {isValidIndex, replacePathIndices} from './utils';
5959

6060
const shiftIndices = function(acceptedOp: Operation, proposedOps: Operation[], isAdd: boolean = false): void {
61-
// shift indexes
6261
const lastSlash = acceptedOp.path.lastIndexOf('/');
6362

64-
if (lastSlash > -1) {
65-
const index = acceptedOp.path.substr(lastSlash + 1);
66-
const arrayPath = acceptedOp.path.substr(0, lastSlash + 1);
63+
if (lastSlash === -1) return;
6764

68-
if (isValidIndex(index)) {
69-
const propChangesLen = proposedOps.length;
70-
let currentIndex = 0;
65+
const index = acceptedOp.path.substr(lastSlash + 1);
66+
const arrayPath = acceptedOp.path.substr(0, lastSlash + 1);
7167

72-
while (currentIndex < propChangesLen) {
73-
const proposedOp = proposedOps[currentIndex];
74-
currentIndex++;
68+
if (!isValidIndex(index)) return;
7569

76-
if (proposedOp.path.indexOf(arrayPath) === 0) {
77-
//item from the same array
78-
proposedOp.path = replacePathIndices(proposedOp.path, arrayPath, index, isAdd);
79-
}
70+
proposedOps.forEach((proposedOp) => {
71+
const pathOfSameArray = proposedOp.path.indexOf(arrayPath) === 0;
8072

81-
if (proposedOp.from && proposedOp.from.indexOf(arrayPath) === 0) {
82-
//item from the same array
83-
proposedOp.from = replacePathIndices(proposedOp.from, arrayPath, index, isAdd);
84-
}
85-
}
73+
if (pathOfSameArray) {
74+
proposedOp.path = replacePathIndices(proposedOp.path, arrayPath, index, isAdd);
8675
}
87-
}
76+
77+
const hasFromOp = proposedOp.op === OpType.move || proposedOp.op === OpType.copy ? proposedOp : null;
78+
const fromOfSameArray = hasFromOp && hasFromOp.from && hasFromOp.from.indexOf(arrayPath) === 0;
79+
80+
if (hasFromOp && fromOfSameArray) {
81+
hasFromOp.from = replacePathIndices(hasFromOp.from, arrayPath, index, isAdd);
82+
}
83+
});
8884
};
8985

9086
const removeOperations = function(
9187
acceptedOp: Operation,
9288
proposedOps: Operation[],
9389
options: Options,
94-
skipCondition?: Function,
90+
skipCondition?: (acceptedOp: Operation, proposedOp: Operation) => boolean,
9591
) {
9692
const {acceptedWinsOnEqualPath} = options;
9793
let currentIndex = 0;
@@ -104,10 +100,9 @@ const removeOperations = function(
104100
const matchesPathToPath =
105101
(acceptedWinsOnEqualPath && acceptedOp.path === proposedOp.path) ||
106102
proposedOp.path.indexOf(acceptedOp.path + '/') === 0;
103+
const shouldSkip = !!(skipCondition && skipCondition(acceptedOp, proposedOp));
107104

108-
if (skipCondition && skipCondition(acceptedOp, proposedOp)) {
109-
110-
} else if (matchesFromToPath || matchesPathToPath) {
105+
if (!shouldSkip && (matchesFromToPath || matchesPathToPath)) {
111106
proposedOps.splice(currentIndex, 1);
112107
currentIndex--;
113108
}
@@ -117,29 +112,10 @@ const removeOperations = function(
117112
};
118113

119114
const removeTransformer = function(acceptedOp: Operation, proposedOps: Operation[]): void {
120-
removeOperations(acceptedOp, proposedOps, {acceptedWinsOnEqualPath: true}, function (acceptedOp, proposedOp) {
115+
removeOperations(acceptedOp, proposedOps, {acceptedWinsOnEqualPath: true}, function(acceptedOp, proposedOp) {
121116
return (proposedOp.op === 'add' || proposedOp.op === 'test') && acceptedOp.path === proposedOp.path;
122117
});
123118
shiftIndices(acceptedOp, proposedOps);
124-
/*let currentIndex = 0;
125-
let proposedOp;
126-
127-
while ((proposedOp = proposedOps[currentIndex])) {
128-
const matchesFromToPath =
129-
proposedOp.from && (proposedOp.from === acceptedOp.path || proposedOp.from.indexOf(acceptedOp.path + '/') === 0);
130-
const matchesPathToPath =
131-
acceptedOp.path === proposedOp.path || proposedOp.path.indexOf(acceptedOp.path + '/') === 0;
132-
133-
if ((proposedOp.op === 'add' || proposedOp.op === 'test') && acceptedOp.path === proposedOp.path) {
134-
// do nothing ? (tomalec)
135-
} else if (matchesFromToPath || matchesPathToPath) {
136-
proposedOps.splice(currentIndex, 1);
137-
currentIndex--;
138-
}
139-
currentIndex++;
140-
}
141-
142-
shiftIndices(acceptedOp, proposedOps);*/
143119
};
144120

145121
const replaceTransformer = function(acceptedOp: Operation, proposedOps: Operation[], options: Options): void {
@@ -155,6 +131,7 @@ const transformAgainst = {
155131
remove: removeTransformer,
156132
replace: replaceTransformer,
157133
add: addTransformer,
134+
copy: addTransformer,
158135
};
159136

160137
const reduceJSONPatches = function(proposedOps: Operation[], acceptedOp: Operation, options: Options) {

0 commit comments

Comments
 (0)