update (path, diff) {
    const node = this.get(path[0])
    let oldValue = this._get(path)
    let newValue
    if (diff._isOperation) {
      // ATTENTION: array operations are done inplace
      if (diff._isArrayOperation) {
        const tmp = oldValue
        oldValue = Array.from(oldValue)
        newValue = diff.apply(tmp)
      // ATTENTION: coordinate operations are done inplace
      } else if (diff._isCoordinateOperation) {
        const tmp = oldValue
        oldValue = oldValue.clone()
        newValue = diff.apply(tmp)
      } else {
        newValue = diff.apply(oldValue)
      }
    } else {
      diff = this._normalizeDiff(oldValue, diff)
      if (isString(oldValue)) {
        switch (diff.type) {
          case 'delete': {
            newValue = oldValue.split('').splice(diff.start, diff.end - diff.start).join('')
            break
          }
          case 'insert': {
            newValue = [oldValue.substring(0, diff.start), diff.text, oldValue.substring(diff.start)].join('')
            break
          }
          default:
            throw new Error('Unknown diff type')
        }
      } else if (isArray(oldValue)) {
        newValue = oldValue.slice(0)
        switch (diff.type) {
          case 'delete': {
            newValue.splice(diff.pos, 1)
            break
          }
          case 'insert': {
            newValue.splice(diff.pos, 0, diff.value)
            break
          }
          default:
            throw new Error('Unknown diff type')
        }
      } else if (oldValue._isCoordinate) {
        switch (diff.type) {
          case 'shift': {
            // ATTENTION: in this case we do not want to create a new value
            oldValue = { path: oldValue.path, offset: oldValue.offset }
            newValue = oldValue
            newValue.offset += diff.value
            break
          }
          default:
            throw new Error('Unknown diff type')
        }
      } else {
        throw new Error('Diff is not supported:', JSON.stringify(diff))
      }
    }
    this._set(path, newValue)

    var change = {
      type: 'update',
      node: node,
      path: path,
      newValue: newValue,
      oldValue: oldValue
    }

    if (this.__QUEUE_INDEXING__) {
      this.queue.push(change)
    } else {
      this._updateIndexes(change)
    }

    return oldValue
  }
Update a property incrementally.

    @param {Array} property path
    @param {Object} diff
    @returns {any} The value before applying the update.