42
42
var REMOVE = 'remove' ;
43
43
var REPLACE = 'replace' ;
44
44
var ADD = 'add' ;
45
+ var MOVE = 'move' ;
45
46
46
47
function diffApply ( obj , diff , pathConverter ) {
47
48
if ( ! obj || typeof obj != 'object' ) {
@@ -57,23 +58,40 @@ function diffApply(obj, diff, pathConverter) {
57
58
var thisDiff = diff [ i ] ;
58
59
var subObject = obj ;
59
60
var thisOp = thisDiff . op ;
60
- var thisPath = thisDiff . path ;
61
- if ( pathConverter ) {
62
- thisPath = pathConverter ( thisPath ) ;
63
- if ( ! Array . isArray ( thisPath ) ) {
64
- throw new Error ( 'pathConverter must return an array' ) ;
61
+
62
+ var thisPath = transformPath ( pathConverter , thisDiff . path ) ;
63
+ var thisFromPath = thisDiff . from && transformPath ( pathConverter , thisDiff . from ) ;
64
+ var toPath , toPathCopy , lastToProp , subToObject , valueToMove ;
65
+
66
+ if ( thisFromPath ) {
67
+ // MOVE only, "fromPath" is effectively path and "path" is toPath
68
+ toPath = thisPath ;
69
+ thisPath = thisFromPath ;
70
+
71
+ toPathCopy = toPath . slice ( ) ;
72
+ lastToProp = toPathCopy . pop ( ) ;
73
+ prototypeCheck ( lastToProp ) ;
74
+ if ( lastToProp == null ) {
75
+ return false ;
65
76
}
66
- } else {
67
- if ( ! Array . isArray ( thisPath ) ) {
68
- throw new Error ( 'diff path must be an array, consider supplying a path converter' ) ;
77
+
78
+ var thisToProp ;
79
+ while ( ( ( thisToProp = toPathCopy . shift ( ) ) ) != null ) {
80
+ prototypeCheck ( thisToProp ) ;
81
+ if ( ! ( thisToProp in subToObject ) ) {
82
+ subToObject [ thisToProp ] = { } ;
83
+ }
84
+ subToObject = subToObject [ thisToProp ] ;
69
85
}
70
86
}
87
+
71
88
var pathCopy = thisPath . slice ( ) ;
72
89
var lastProp = pathCopy . pop ( ) ;
73
90
prototypeCheck ( lastProp ) ;
74
91
if ( lastProp == null ) {
75
92
return false ;
76
93
}
94
+
77
95
var thisProp ;
78
96
while ( ( ( thisProp = pathCopy . shift ( ) ) ) != null ) {
79
97
prototypeCheck ( thisProp ) ;
@@ -82,21 +100,50 @@ function diffApply(obj, diff, pathConverter) {
82
100
}
83
101
subObject = subObject [ thisProp ] ;
84
102
}
85
- if ( thisOp === REMOVE || thisOp === REPLACE ) {
103
+ if ( thisOp === REMOVE || thisOp === REPLACE || thisOp === MOVE ) {
104
+ var path = thisOp === MOVE ? thisDiff . from : thisDiff . path ;
86
105
if ( ! subObject . hasOwnProperty ( lastProp ) ) {
87
- throw new Error ( [ 'expected to find property' , thisDiff . path , 'in object' , obj ] . join ( ' ' ) ) ;
106
+ throw new Error ( [ 'expected to find property' , path , 'in object' , obj ] . join ( ' ' ) ) ;
88
107
}
89
108
}
90
- if ( thisOp === REMOVE ) {
109
+ if ( thisOp === REMOVE || thisOp === MOVE ) {
110
+ if ( thisOp === MOVE ) {
111
+ valueToMove = subObject [ lastProp ] ;
112
+ }
91
113
Array . isArray ( subObject ) ? subObject . splice ( lastProp , 1 ) : delete subObject [ lastProp ] ;
92
114
}
93
115
if ( thisOp === REPLACE || thisOp === ADD ) {
94
116
subObject [ lastProp ] = thisDiff . value ;
95
117
}
118
+
119
+ if ( thisOp === MOVE ) {
120
+ subObject [ lastToProp ] = valueToMove ;
121
+ }
96
122
}
97
123
return subObject ;
98
124
}
99
125
126
+ function transformPath ( pathConverter , thisPath ) {
127
+ if ( pathConverter ) {
128
+ thisPath = pathConverter ( thisPath ) ;
129
+ if ( ! Array . isArray ( thisPath ) ) {
130
+ throw new Error ( [
131
+ 'pathConverter must return an array, returned:' ,
132
+ thisPath ,
133
+ ] . join ( ' ' ) ) ;
134
+ }
135
+ } else {
136
+ if ( ! Array . isArray ( thisPath ) ) {
137
+ throw new Error ( [
138
+ 'diff path' ,
139
+ thisPath ,
140
+ 'must be an array, consider supplying a path converter' ]
141
+ . join ( ' ' ) ) ;
142
+ }
143
+ }
144
+ return thisPath ;
145
+ }
146
+
100
147
function jsonPatchPathConverter ( stringPath ) {
101
148
return stringPath . split ( '/' ) . slice ( 1 ) ;
102
149
}
0 commit comments