2
2
3
3
var equal = require ( "deep-equal" ) ;
4
4
5
+ var diffMatchPatchInstance ;
6
+
7
+ function replaceOp ( path , isObject , input , output , json1 ) {
8
+ var op ;
9
+ if ( json1 ) {
10
+ op = json1 . replaceOp ( path , input , output ) ;
11
+ } else {
12
+ op = { p : path } ;
13
+ op [ isObject ? "od" : "ld" ] = input ;
14
+ op [ isObject ? "oi" : "li" ] = output ;
15
+ }
16
+ return [ op ] ;
17
+ }
18
+
5
19
/**
6
20
* Convert a number of string patches to OT operations.
7
21
* @param {JsonMLPath } path Base path for patches to apply to.
8
22
* @param {string } oldValue Old value.
9
23
* @param {string } newValue New value.
10
24
* @return {Ops } List of resulting operations.
11
25
*/
12
- function patchesToOps ( path , oldValue , newValue , diffMatchPatch , diffMatchPatchInstance ) {
26
+ function patchesToOps ( path , oldValue , newValue , diffMatchPatch , json1 , textUnicode ) {
13
27
const ops = [ ] ;
14
28
15
29
var patches = diffMatchPatchInstance . patch_make ( oldValue , newValue ) ;
@@ -19,10 +33,20 @@ function patchesToOps(path, oldValue, newValue, diffMatchPatch, diffMatchPatchIn
19
33
patch . diffs . forEach ( function ( [ type , value ] ) {
20
34
switch ( type ) {
21
35
case diffMatchPatch . DIFF_DELETE :
22
- ops . push ( { sd : value , p : [ ...path , offset ] } ) ;
36
+ if ( textUnicode ) {
37
+ var unicodeOp = textUnicode . remove ( offset , value ) ;
38
+ ops . push ( json1 . editOp ( path , textUnicode . type , unicodeOp ) ) ;
39
+ } else {
40
+ ops . push ( { sd : value , p : [ ...path , offset ] } ) ;
41
+ }
23
42
break ;
24
43
case diffMatchPatch . DIFF_INSERT :
25
- ops . push ( { si : value , p : [ ...path , offset ] } ) ;
44
+ if ( textUnicode ) {
45
+ var unicodeOp = textUnicode . insert ( offset , value ) ;
46
+ ops . push ( json1 . editOp ( path , textUnicode . type , unicodeOp ) ) ;
47
+ } else {
48
+ ops . push ( { si : value , p : [ ...path , offset ] } ) ;
49
+ }
26
50
// falls through intentionally
27
51
case diffMatchPatch . DIFF_EQUAL :
28
52
offset += value . length ;
@@ -35,9 +59,11 @@ function patchesToOps(path, oldValue, newValue, diffMatchPatch, diffMatchPatchIn
35
59
return ops ;
36
60
}
37
61
38
- var diffMatchPatchInstance ;
39
-
40
- var optimize = function ( ops ) {
62
+ var optimize = function ( ops , options ) {
63
+ if ( options && options . json1 ) {
64
+ var compose = options . json1 . type . compose ;
65
+ return ops . reduce ( compose , null ) ;
66
+ }
41
67
/*
42
68
Optimization loop where we attempt to find operations that needlessly inserts and deletes identical objects right
43
69
after each other, and then consolidate them.
@@ -76,27 +102,41 @@ var optimize = function(ops) {
76
102
return ops ;
77
103
}
78
104
79
- var diff = function ( input , output , path = [ ] , diffMatchPatch ) {
105
+ var diff = function ( input , output , path = [ ] , options ) {
106
+ var diffMatchPatch = options && options . diffMatchPatch ;
107
+ var json1 = options && options . json1 ;
108
+ var textUnicode = options && options . textUnicode ;
109
+
80
110
// If the last element of the path is a string, that means we're looking at a key, rather than
81
111
// a number index. Objects use keys, so the target for our insertion/deletion is an object.
82
112
var isObject = typeof path [ path . length - 1 ] === "string" || path . length === 0 ;
83
113
84
114
// If input and output are equal, no operations are needed.
85
- if ( equal ( input , output ) ) {
115
+ if ( equal ( input , output ) && Array . isArray ( input ) === Array . isArray ( output ) ) {
86
116
return [ ] ;
87
117
}
88
118
89
119
// If there is no output, we need to delete the current data (input).
90
120
if ( typeof output === "undefined" ) {
91
- var op = { p : path } ;
92
- op [ isObject ? "od" : "ld" ] = input ;
121
+ var op ;
122
+ if ( json1 ) {
123
+ op = json1 . removeOp ( path , output ) ;
124
+ } else {
125
+ op = { p : path } ;
126
+ op [ isObject ? "od" : "ld" ] = input ;
127
+ }
93
128
return [ op ] ;
94
129
}
95
130
96
131
// If there is no input, we need to add the new data (output).
97
132
if ( typeof input === "undefined" ) {
98
- var op = { p : path } ;
99
- op [ isObject ? "oi" : "li" ] = output ;
133
+ var op ;
134
+ if ( json1 ) {
135
+ op = json1 . insertOp ( path , output ) ;
136
+ } else {
137
+ op = { p : path } ;
138
+ op [ isObject ? "oi" : "li" ] = output ;
139
+ }
100
140
return [ op ] ;
101
141
}
102
142
@@ -108,17 +148,14 @@ var diff = function(input, output, path=[], diffMatchPatch) {
108
148
diffMatchPatchInstance = new diffMatchPatch ( ) ;
109
149
}
110
150
111
- return patchesToOps ( path , input , output , diffMatchPatch , diffMatchPatchInstance ) ;
151
+ return patchesToOps ( path , input , output , diffMatchPatch , json1 , textUnicode ) ;
112
152
}
113
153
114
154
var primitiveTypes = [ "string" , "number" , "boolean" ] ;
115
155
// If either of input/output is a primitive type, there is no need to perform deep recursive calls to
116
156
// figure out what to do. We can just replace the objects.
117
157
if ( primitiveTypes . includes ( typeof output ) || primitiveTypes . includes ( typeof input ) ) {
118
- var op = { p : path } ;
119
- op [ isObject ? "od" : "ld" ] = input ;
120
- op [ isObject ? "oi" : "li" ] = output ;
121
- return [ op ] ;
158
+ return replaceOp ( path , isObject , input , output , json1 ) ;
122
159
}
123
160
124
161
if ( Array . isArray ( output ) && Array . isArray ( input ) ) {
@@ -127,23 +164,23 @@ var diff = function(input, output, path=[], diffMatchPatch) {
127
164
var minLen = Math . min ( inputLen , outputLen ) ;
128
165
var ops = [ ] ;
129
166
for ( var i = 0 ; i < minLen ; ++ i ) {
130
- var newOps = diff ( input [ i ] , output [ i ] , [ ...path , i ] , diffMatchPatch ) ;
167
+ var newOps = diff ( input [ i ] , output [ i ] , [ ...path , i ] , options ) ;
131
168
newOps . forEach ( function ( op ) {
132
169
ops . push ( op ) ;
133
170
} ) ;
134
171
}
135
172
if ( outputLen > inputLen ) {
136
173
// deal with array insert
137
174
for ( var i = minLen ; i < outputLen ; i ++ ) {
138
- var newOps = diff ( undefined , output [ i ] , [ ...path , i ] , diffMatchPatch ) ;
175
+ var newOps = diff ( undefined , output [ i ] , [ ...path , i ] , options ) ;
139
176
newOps . forEach ( function ( op ) {
140
177
ops . push ( op ) ;
141
178
} ) ;
142
179
}
143
180
} else if ( outputLen < inputLen ) {
144
181
// deal with array delete
145
182
for ( var i = minLen ; i < inputLen ; i ++ ) {
146
- var newOps = diff ( input [ i ] , undefined , [ ...path , minLen ] , diffMatchPatch ) ;
183
+ var newOps = diff ( input [ i ] , undefined , [ ...path , minLen ] , options ) ;
147
184
newOps . forEach ( function ( op ) {
148
185
ops . push ( op ) ;
149
186
} ) ;
@@ -152,23 +189,21 @@ var diff = function(input, output, path=[], diffMatchPatch) {
152
189
return ops ;
153
190
} else if ( Array . isArray ( output ) || Array . isArray ( input ) ) {
154
191
// deal with array/object
155
- var op = { p : path } ;
156
- op [ isObject ? "od" : "ld" ] = input ;
157
- op [ isObject ? "oi" : "li" ] = output ;
158
- return [ op ] ;
192
+ return replaceOp ( path , isObject , input , output , json1 ) ;
159
193
}
160
194
161
195
var ops = [ ] ;
162
196
var keys = new Set ( [ ...Object . keys ( input ) , ...Object . keys ( output ) ] ) ;
163
197
keys . forEach ( function ( key ) {
164
- var newOps = diff ( input [ key ] , output [ key ] , [ ...path , key ] , diffMatchPatch ) ;
198
+ var newOps = diff ( input [ key ] , output [ key ] , [ ...path , key ] , options ) ;
165
199
ops = ops . concat ( newOps ) ;
166
200
} ) ;
167
201
return ops ;
168
202
}
169
203
170
- var optimizedDiff = function ( input , output , diffMatchPatch ) {
171
- return optimize ( diff ( input , output , [ ] , diffMatchPatch ) ) ;
204
+ var optimizedDiff = function ( input , output , diffMatchPatch , json1 , textUnicode ) {
205
+ var options = { diffMatchPatch, json1, textUnicode } ;
206
+ return optimize ( diff ( input , output , [ ] , options ) , options ) ;
172
207
}
173
208
174
209
module . exports = optimizedDiff ;
0 commit comments