3.1.1 • Published 6 years ago

@warren-bank/immutable-jsonpath v3.1.1

Weekly downloads
158
License
GPL-2.0
Repository
github
Last release
6 years ago

immutable-jsonpath

Summary:

jsonpath enhancement: extends class prototype with immutable assignment of value to pathExpression

Installation:

npm install --save 'jsonpath'
npm install --save '@warren-bank/immutable-jsonpath'

Methods:


jsonpath.assign(obj, pathExpression, newValue)

Returns a clone of obj having the following properties:

  • every node traversed between the root ($) and the target path node (pathExpression) are also cloned
  • the target path node (pathExpression) is replaced by newValue
const jsonpath = require('jsonpath')

// apply enhancement to jsonpath class prototype
require('@warren-bank/immutable-jsonpath')(jsonpath)

const deepFreeze = require('deep-freeze')
deepFreeze(data)

const newData = jsonpath.assign(data, '$.store.bicycle.color', 'blue')

// cloned Objects
expect(newData).not.toBe(data)
expect(newData.store).not.toBe(data.store)
expect(newData.store.bicycle).not.toBe(data.store.bicycle)
expect(newData.store.bicycle.color).not.toBe(data.store.bicycle.color)

// not cloned
expect(newData.store.book).toBe(data.store.book)

jsonpath.update(obj, pathExpression, operation, ...data)

Returns a clone of obj having the following properties:

  • every node traversed between the root ($) and the target path node (pathExpression) are also cloned
  • the clone of the target path node (pathExpression) is a collection data type:
    • Array or Object
  • the clone of the target path node (pathExpression) has been updated by an operation
    • operation is a string
    • data contains parameters to configure the behavior of the operation
      • its length and data types are dependent upon the particular operation

considerations:

  • this can be thought of as a convenience method

    • to update a collection (ie: Array, Object) at pathExpression in obj
      • a common pattern may emerge:
        let old_val = jsonpath.value(obj, pathExpression)
        let new_val = {...old_val}
        // mutate new_val
        // assign new_val to `pathExpression` in `obj` resulting in a clone of the Object
        let new_obj = jsonpath.assign(obj, pathExpression, new_val)
      • this can become tedious
      • the way new_val is mutated in the vast majority of cases is fairly predictable
      • much of this boilerplate can be performed by a helper function
  • my first inclination was to borrow the API convention used by immutability-helper

    • instead, I decided to simplify the API and only focus on the primary use cases
      • anything more complicated can follow the above pattern and take complete control of the update operation

operations:

  • to perform on an Array:

    • delete
      • removes 1+ elements from Array beginning at a start index
      • data:
        • <integer>start
          • index of first element to delete
          • a negative value is subtracted from the length of the Array
        • <integer>deleteCount
          • count of elements to delete at start
          • default = 1
      • notes:
        • data can be passed to the function as either:
          • a single Array value
          • individual arguments
      • example:
        const data  = {path: {to: {arr: ["a","b","c"]}}}
        const clone = jsonpath.update(data, '$.path.to.arr', 'delete', 1)
        expect(clone.path.to.arr).toEqual(["a","c"])
    • shift
      • removes the first element from Array
      • note:
        • the element is discarded
      • example:
        const data  = {path: {to: {arr: ["a","b","c"]}}}
        const clone = jsonpath.update(data, '$.path.to.arr', 'shift')
        expect(clone.path.to.arr).toEqual(["b","c"])
    • pop
      • removes the last element from Array
      • note:
        • the element is discarded
      • example:
        const data  = {path: {to: {arr: ["a","b","c"]}}}
        const clone = jsonpath.update(data, '$.path.to.arr', 'pop')
        expect(clone.path.to.arr).toEqual(["a","b"])
    • unshift
      • inserts 1 element to the beginning of the Array
      • data:
        • <Any>value
      • example:
        const data  = {path: {to: {arr: ["a","b","c"]}}}
        const clone = jsonpath.update(data, '$.path.to.arr', 'unshift', '0')
        expect(clone.path.to.arr).toEqual(["0","a","b","c"])
    • push
      • inserts 1 element to the end of the Array
      • data:
        • <Any>value
      • example:
        const data  = {path: {to: {arr: ["a","b","c"]}}}
        const clone = jsonpath.update(data, '$.path.to.arr', 'push', '4')
        expect(clone.path.to.arr).toEqual(["a","b","c","4"])
    • concat_start
      • concatenates the elements of an input Array to the beginning of the Array
      • data:
        • <Array>value
      • example:
        const data  = {path: {to: {arr: ["a","b","c"]}}}
        const clone = jsonpath.update(data, '$.path.to.arr', 'concat_start', ["0","1","2"])
        expect(clone.path.to.arr).toEqual(["0","1","2","a","b","c"])
    • concat_end
      • concatenates the elements of an input Array to the end of the Array
      • data:
        • <Array>value
      • example:
        const data  = {path: {to: {arr: ["a","b","c"]}}}
        const clone = jsonpath.update(data, '$.path.to.arr', 'concat_end', ["4","5","6"])
        expect(clone.path.to.arr).toEqual(["a","b","c","4","5","6"])
    • slice
      • replaces the Array with a contiguous subset of its elements
      • same input parameters as Array.slice
      • data:
        • <integer>start
          • index of first element to extract into subset
          • a negative value is subtracted from the length of the Array
        • <integer>end
          • index of first element (following start) to exclude from contiguous subset
          • a negative value is subtracted from the length of the Array
          • default = length of the Array
      • notes:
        • data can be passed to the function as either:
          • a single Array value
          • individual arguments
      • example:
        const data  = {path: {to: {arr: ["a","b","c"]}}}
        const clone = jsonpath.update(data, '$.path.to.arr', 'slice', 0, 2)
        expect(clone.path.to.arr).toEqual(["a","b"])
    • splice
      • changes the contents of the Array by removing existing elements and/or adding new elements
      • same input parameters as Array.splice
      • data:
        • <integer>start
          • index of element at which to start changing the Array
          • a negative value is subtracted from the length of the Array
        • <integer>deleteCount
          • count of elements to delete, beginning at start
          • default = all elements following start
        • <Any>item1, <Any>item2, ...
          • elements to add to the Array, beginning at start
      • notes:
        • data can be passed to the function as either:
          • a single Array value
          • individual arguments
      • example:
        const data  = {path: {to: {arr: ["a","b","c"]}}}
        const clone = jsonpath.update(data, '$.path.to.arr', 'splice', 2, 1, "3")
        expect(clone.path.to.arr).toEqual(["a","b","3"])
    • filter
      • replaces the Array with a filtered subset of elements
      • similar behavior to Array.filter
      • data:
        • <Function>callback
          • parameters passed to callback:
            • element
              • current element being processed
            • index
              • index of the current element being processed
          • return value from callback:
            • boolean
              • true indicates that element is included in resulting subset
      • example:
        const data  = {path: {to: {arr: ["a","b","c"]}}}
        const fn    = element => element === 'b'
        const clone = jsonpath.update(data, '$.path.to.arr', 'filter', fn)
        expect(clone.path.to.arr).toEqual(["b"])
    • map
      • replaces the Array with a new Array
        • same length as original Array
        • elements are mapped by a callback function
      • similar behavior to Array.map
      • data:
        • <Function>callback
          • parameters passed to callback:
            • element
              • current element being processed
            • index
              • index of the current element being processed
          • return value from callback:
            • mapped value of element
      • example:
        const data  = {path: {to: {arr: ["a","b","c"]}}}
        const fn    = element => `(${element})`
        const clone = jsonpath.update(data, '$.path.to.arr', 'map', fn)
        expect(clone.path.to.arr).toEqual(["(a)","(b)","(c)"])
  • to perform on an Object:

    • delete
      • removes a single attribute
      • data:
        • <string>key
          • attribute key to remove from the Object
      • example:
        const data  = {path: {to: {obj: {a:"a", b:"b", c:"c"}}}}
        const clone = jsonpath.update(data, '$.path.to.obj', 'delete', 'b')
        expect(clone.path.to.obj).toEqual({a:"a", c:"c"})
    • add
      • merges data from an input Object into the Object
      • data:
        • <Object>value
      • example:
        const data  = {path: {to: {obj: {a:"a", b:"b", c:"c"}}}}
        const clone = jsonpath.update(data, '$.path.to.obj', 'add', {d:"d", e:"e"})
        expect(clone.path.to.obj).toEqual({a:"a", b:"b", c:"c", d:"d", e:"e"})
    • subtract
      • removes 1+ attributes
      • data:
        • <Object | Array>value
          • collection of attribute keys to remove from the Object
      • example:
        const data  = {path: {to: {obj: {a:"a", b:"b", c:"c"}}}}
        const clone = jsonpath.update(data, '$.path.to.obj', 'subtract', ["a","c"])
        expect(clone.path.to.obj).toEqual({b:"b"})

More Examples:


Browser Build (transpiled to ES5):


Legal:

3.1.1

6 years ago

3.1.0

6 years ago

3.0.0

6 years ago

2.1.1

6 years ago

2.1.0

6 years ago

2.0.0

6 years ago

1.0.0

6 years ago