11import jsonpatch , { Operation } from 'fast-json-patch'
2- import jp from 'jsonpath'
2+ import { JSONPath } from 'jsonpath-plus '
33
44// Export to help dependencies because this is used in our interface.
55export { Operation } from 'fast-json-patch'
@@ -101,10 +101,14 @@ export class Basin<T> {
101101 delete cursor . d
102102 }
103103
104- const expressions = jp . parse ( cursor . jsonPath ! )
105- for ( const expression of expressions ) {
106- if ( expression . expression . type !== 'root' ) {
107- this . _keys . set ( label , expression . expression . value )
104+ if ( ! cursor . jsonPath ! . startsWith ( '$' ) ) {
105+ cursor . jsonPath = '$.' + cursor . jsonPath
106+ }
107+
108+ const pathArray = JSONPath . toPathArray ( cursor . jsonPath ! )
109+ for ( const segment of pathArray ) {
110+ if ( segment !== '$' ) {
111+ this . _keys . set ( label , segment )
108112 break
109113 }
110114 }
@@ -123,9 +127,9 @@ export class Basin<T> {
123127 const jsonPath = cursor . jsonPath !
124128 if ( typeof position !== 'number' ) {
125129 // Set the value.
126- jp . value ( this . items , jsonPath , value )
130+ jpValue ( this . items , jsonPath , value )
127131 } else {
128- jp . apply ( this . items , jsonPath , ( currentValue : string ) => {
132+ jpApply ( this . items , jsonPath , ( currentValue : string ) => {
129133 if ( Array . isArray ( currentValue ) ) {
130134 if ( cursor . deleteCount !== undefined ) {
131135 // Delete
@@ -156,4 +160,32 @@ export class Basin<T> {
156160 const key = this . _keys . get ( cursorLabel ) !
157161 return this . items [ key ]
158162 }
163+ }
164+
165+ function jpValue ( obj : any , path : string , value : any ) : void {
166+ const results : any [ ] = JSONPath ( { path, json : obj , resultType : 'all' } )
167+ if ( results . length > 0 ) {
168+ results [ 0 ] . parent [ results [ 0 ] . parentProperty ] = value
169+ } else {
170+ // Path doesn't exist yet — create intermediate objects and set the value.
171+ const pathArray = JSONPath . toPathArray ( path )
172+ let current = obj
173+ for ( let i = 1 ; i < pathArray . length - 1 ; i ++ ) {
174+ const key = pathArray [ i ]
175+ if ( current [ key ] === undefined ) {
176+ current [ key ] = { }
177+ }
178+ current = current [ key ]
179+ }
180+ if ( pathArray . length > 1 ) {
181+ current [ pathArray [ pathArray . length - 1 ] ] = value
182+ }
183+ }
184+ }
185+
186+ function jpApply ( obj : any , path : string , fn : ( value : any ) => any ) : void {
187+ const results : any [ ] = JSONPath ( { path, json : obj , resultType : 'all' } )
188+ for ( const result of results ) {
189+ result . parent [ result . parentProperty ] = fn ( result . value )
190+ }
159191}
0 commit comments