rdb-client
Version:
Rdb in the browser
1,713 lines (1,456 loc) • 118 kB
JavaScript
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function getAugmentedNamespace(n) {
if (n.__esModule) return n;
var a = Object.defineProperty({}, '__esModule', {value: true});
Object.keys(n).forEach(function (k) {
var d = Object.getOwnPropertyDescriptor(n, k);
Object.defineProperty(a, k, d.get ? d : {
enumerable: true,
get: function () {
return n[k];
}
});
});
return a;
}
var constants = {
PATH_SEPARATOR: '.',
TARGET: Symbol('target'),
UNSUBSCRIBE: Symbol('unsubscribe')
};
const isBuiltin$2 = {
withMutableMethods: value => {
return value instanceof Date ||
value instanceof Set ||
value instanceof Map ||
value instanceof WeakSet ||
value instanceof WeakMap;
},
withoutMutableMethods: value => (typeof value === 'object' ? value === null : typeof value !== 'function') || value instanceof RegExp
};
var isBuiltin_1 = isBuiltin$2;
var isArray$3 = Array.isArray;
var isSymbol$3 = value => typeof value === 'symbol';
const {PATH_SEPARATOR} = constants;
const isArray$2 = isArray$3;
const isSymbol$2 = isSymbol$3;
var path$3 = {
after: (path, subPath) => {
if (isArray$2(path)) {
return path.slice(subPath.length);
}
if (subPath === '') {
return path;
}
return path.slice(subPath.length + 1);
},
concat: (path, key) => {
if (isArray$2(path)) {
path = path.slice();
if (key) {
path.push(key);
}
return path;
}
if (key && key.toString !== undefined) {
if (path !== '') {
path += PATH_SEPARATOR;
}
if (isSymbol$2(key)) {
return path + key.toString();
}
return path + key;
}
return path;
},
initial: path => {
if (isArray$2(path)) {
return path.slice(0, -1);
}
if (path === '') {
return path;
}
const index = path.lastIndexOf(PATH_SEPARATOR);
if (index === -1) {
return '';
}
return path.slice(0, index);
},
last: path => {
if (isArray$2(path)) {
return path[path.length - 1] || '';
}
if (path === '') {
return path;
}
const index = path.lastIndexOf(PATH_SEPARATOR);
if (index === -1) {
return path;
}
return path.slice(index + 1);
},
walk: (path, callback) => {
if (isArray$2(path)) {
path.forEach(key => callback(key));
} else if (path !== '') {
let position = 0;
let index = path.indexOf(PATH_SEPARATOR);
if (index === -1) {
callback(path);
} else {
while (position < path.length) {
if (index === -1) {
index = path.length;
}
callback(path.slice(position, index));
position = index + 1;
index = path.indexOf(PATH_SEPARATOR, position);
}
}
}
},
get(object, path) {
this.walk(path, key => {
if (object) {
object = object[key];
}
});
return object;
}
};
var isIterator$1 = value => typeof value === 'object' && typeof value.next === 'function';
const {TARGET: TARGET$1} = constants;
// eslint-disable-next-line max-params
var wrapIterator$1 = (iterator, target, thisArg, applyPath, prepareValue) => {
const originalNext = iterator.next;
if (target.name === 'entries') {
iterator.next = function () {
const result = originalNext.call(this);
if (result.done === false) {
result.value[0] = prepareValue(
result.value[0],
target,
result.value[0],
applyPath
);
result.value[1] = prepareValue(
result.value[1],
target,
result.value[0],
applyPath
);
}
return result;
};
} else if (target.name === 'values') {
const keyIterator = thisArg[TARGET$1].keys();
iterator.next = function () {
const result = originalNext.call(this);
if (result.done === false) {
result.value = prepareValue(
result.value,
target,
keyIterator.next().value,
applyPath
);
}
return result;
};
} else {
iterator.next = function () {
const result = originalNext.call(this);
if (result.done === false) {
result.value = prepareValue(
result.value,
target,
result.value,
applyPath
);
}
return result;
};
}
return iterator;
};
const isSymbol$1 = isSymbol$3;
var ignoreProperty$1 = (cache, options, property) => {
return cache.isUnsubscribed ||
(options.ignoreSymbols && isSymbol$1(property)) ||
(options.ignoreUnderscores && property.charAt(0) === '_') ||
('ignoreKeys' in options && options.ignoreKeys.includes(property));
};
const path$2 = path$3;
/**
* @class Cache
* @private
*/
class Cache$1 {
constructor(equals) {
this._equals = equals;
this._proxyCache = new WeakMap();
this._pathCache = new WeakMap();
this.isUnsubscribed = false;
}
_getDescriptorCache() {
if (this._descriptorCache === undefined) {
this._descriptorCache = new WeakMap();
}
return this._descriptorCache;
}
_getProperties(target) {
const descriptorCache = this._getDescriptorCache();
let properties = descriptorCache.get(target);
if (properties === undefined) {
properties = {};
descriptorCache.set(target, properties);
}
return properties;
}
_getOwnPropertyDescriptor(target, property) {
if (this.isUnsubscribed) {
return Reflect.getOwnPropertyDescriptor(target, property);
}
const properties = this._getProperties(target);
let descriptor = properties[property];
if (descriptor === undefined) {
descriptor = Reflect.getOwnPropertyDescriptor(target, property);
properties[property] = descriptor;
}
return descriptor;
}
getProxy(target, path, handler, proxyTarget) {
if (this.isUnsubscribed) {
return target;
}
this._pathCache.set(target, path);
let proxy = this._proxyCache.get(target);
if (proxy === undefined) {
proxy = target[proxyTarget] === undefined ?
new Proxy(target, handler) :
target;
this._proxyCache.set(target, proxy);
}
return proxy;
}
getPath(target) {
return this.isUnsubscribed ? undefined : this._pathCache.get(target);
}
isDetached(target, object) {
return !Object.is(target, path$2.get(object, this.getPath(target)));
}
defineProperty(target, property, descriptor) {
if (!Reflect.defineProperty(target, property, descriptor)) {
return false;
}
if (!this.isUnsubscribed) {
this._getProperties(target)[property] = descriptor;
}
return true;
}
setProperty(target, property, value, receiver, previous) { // eslint-disable-line max-params
if (!this._equals(previous, value) || !(property in target)) {
const descriptor = this._getOwnPropertyDescriptor(target, property);
if (descriptor !== undefined && 'set' in descriptor) {
return Reflect.set(target, property, value, receiver);
}
return Reflect.set(target, property, value);
}
return true;
}
deleteProperty(target, property, previous) {
if (Reflect.deleteProperty(target, property)) {
if (!this.isUnsubscribed) {
const properties = this._getDescriptorCache().get(target);
if (properties) {
delete properties[property];
this._pathCache.delete(previous);
}
}
return true;
}
return false;
}
isSameDescriptor(a, target, property) {
const b = this._getOwnPropertyDescriptor(target, property);
return a !== undefined &&
b !== undefined &&
Object.is(a.value, b.value) &&
(a.writable || false) === (b.writable || false) &&
(a.enumerable || false) === (b.enumerable || false) &&
(a.configurable || false) === (b.configurable || false) &&
a.get === b.get &&
a.set === b.set;
}
isGetInvariant(target, property) {
const descriptor = this._getOwnPropertyDescriptor(target, property);
return descriptor !== undefined &&
descriptor.configurable !== true &&
descriptor.writable !== true;
}
unsubscribe() {
this._descriptorCache = null;
this._pathCache = null;
this._proxyCache = null;
this.isUnsubscribed = true;
}
}
var cache = Cache$1;
var isObject$2 = value => toString.call(value) === '[object Object]';
var isDiffCertain$1 = () => true;
var isDiffArrays$1 = (clone, value) => {
return clone.length !== value.length || clone.some((item, index) => value[index] !== item);
};
const IMMUTABLE_OBJECT_METHODS$2 = new Set([
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'toLocaleString',
'toString',
'valueOf'
]);
var object = {IMMUTABLE_OBJECT_METHODS: IMMUTABLE_OBJECT_METHODS$2};
const isDiffCertain = isDiffCertain$1;
const isDiffArrays = isDiffArrays$1;
const {IMMUTABLE_OBJECT_METHODS: IMMUTABLE_OBJECT_METHODS$1} = object;
const IMMUTABLE_ARRAY_METHODS = new Set([
'concat',
'includes',
'indexOf',
'join',
'keys',
'lastIndexOf'
]);
const MUTABLE_ARRAY_METHODS$1 = {
push: isDiffCertain,
pop: isDiffCertain,
shift: isDiffCertain,
unshift: isDiffCertain,
copyWithin: isDiffArrays,
reverse: isDiffArrays,
sort: isDiffArrays,
splice: isDiffArrays,
flat: isDiffArrays,
fill: isDiffArrays
};
const HANDLED_ARRAY_METHODS$1 = new Set([...IMMUTABLE_OBJECT_METHODS$1]
.concat([...IMMUTABLE_ARRAY_METHODS])
.concat(Object.keys(MUTABLE_ARRAY_METHODS$1)));
var array = {MUTABLE_ARRAY_METHODS: MUTABLE_ARRAY_METHODS$1, HANDLED_ARRAY_METHODS: HANDLED_ARRAY_METHODS$1};
var isDiffSets$1 = (clone, value) => {
if (clone.size !== value.size) {
return true;
}
for (const element of clone) {
if (!value.has(element)) {
return true;
}
}
return false;
};
const isDiffSets = isDiffSets$1;
const COLLECTION_ITERATOR_METHODS$1 = [
'keys',
'values',
'entries'
];
const IMMUTABLE_SET_METHODS$1 = new Set([
'has',
'toString'
]);
const MUTABLE_SET_METHODS$1 = {
add: isDiffSets,
clear: isDiffSets,
delete: isDiffSets,
forEach: isDiffSets
};
const HANDLED_SET_METHODS$1 = new Set([...IMMUTABLE_SET_METHODS$1]
.concat(Object.keys(MUTABLE_SET_METHODS$1))
.concat(COLLECTION_ITERATOR_METHODS$1));
var set = {
IMMUTABLE_SET_METHODS: IMMUTABLE_SET_METHODS$1,
MUTABLE_SET_METHODS: MUTABLE_SET_METHODS$1,
HANDLED_SET_METHODS: HANDLED_SET_METHODS$1,
COLLECTION_ITERATOR_METHODS: COLLECTION_ITERATOR_METHODS$1
};
var isDiffMaps$1 = (clone, value) => {
if (clone.size !== value.size) {
return true;
}
let bValue;
for (const [key, aValue] of clone) {
bValue = value.get(key);
if (bValue !== aValue || (bValue === undefined && !value.has(key))) {
return true;
}
}
return false;
};
const {IMMUTABLE_SET_METHODS, COLLECTION_ITERATOR_METHODS} = set;
const isDiffMaps = isDiffMaps$1;
const IMMUTABLE_MAP_METHODS = new Set([...IMMUTABLE_SET_METHODS].concat(['get']));
const MUTABLE_MAP_METHODS$1 = {
set: isDiffMaps,
clear: isDiffMaps,
delete: isDiffMaps,
forEach: isDiffMaps
};
const HANDLED_MAP_METHODS$1 = new Set([...IMMUTABLE_MAP_METHODS]
.concat(Object.keys(MUTABLE_MAP_METHODS$1))
.concat(COLLECTION_ITERATOR_METHODS));
var map = {MUTABLE_MAP_METHODS: MUTABLE_MAP_METHODS$1, HANDLED_MAP_METHODS: HANDLED_MAP_METHODS$1};
const path$1 = path$3;
const isArray$1 = isArray$3;
const isObject$1 = isObject$2;
const {MUTABLE_ARRAY_METHODS} = array;
const {MUTABLE_SET_METHODS} = set;
const {MUTABLE_MAP_METHODS} = map;
const {IMMUTABLE_OBJECT_METHODS} = object;
var cloneObject = class CloneObject {
constructor(value, path, argumentsList, hasOnValidate) {
this._path = path;
this._isChanged = false;
this._clonedCache = new Set();
this._hasOnValidate = hasOnValidate;
this._changes = hasOnValidate ? [] : null;
this.clone = path === undefined ? value : this._shallowClone(value);
}
static isHandledMethod(name) {
return IMMUTABLE_OBJECT_METHODS.has(name);
}
_shallowClone(value) {
let clone = value;
if (isObject$1(value)) {
clone = {...value};
} else if (isArray$1(value)) {
clone = [...value];
} else if (value instanceof Date) {
clone = new Date(value);
} else if (value instanceof Set) {
clone = new Set([...value].map(item => this._shallowClone(item)));
} else if (value instanceof Map) {
clone = new Map();
for (const [key, item] of value.entries()) {
clone.set(key, this._shallowClone(item));
}
}
this._clonedCache.add(clone);
return clone;
}
preferredThisArg(isHandledMethod, name, thisArg, thisProxyTarget) {
if (isHandledMethod) {
if (isArray$1(thisProxyTarget)) {
this._onIsChanged = MUTABLE_ARRAY_METHODS[name];
} else if (thisProxyTarget instanceof Set) {
this._onIsChanged = MUTABLE_SET_METHODS[name];
} else if (thisProxyTarget instanceof Map) {
this._onIsChanged = MUTABLE_MAP_METHODS[name];
}
return thisProxyTarget;
}
return thisArg;
}
update(fullPath, property, value) {
const changePath = path$1.after(fullPath, this._path);
if (property !== 'length') {
let object = this.clone;
path$1.walk(changePath, key => {
if (object && object[key]) {
if (!this._clonedCache.has(object[key])) {
object[key] = this._shallowClone(object[key]);
}
object = object[key];
}
});
if (this._hasOnValidate) {
this._changes.push({
path: changePath,
property,
previous: value
});
}
if (object && object[property]) {
object[property] = value;
}
}
this._isChanged = true;
}
undo(object) {
let change;
for (let index = this._changes.length - 1; index !== -1; index--) {
change = this._changes[index];
path$1.get(object, change.path)[change.property] = change.previous;
}
}
isChanged(value) {
return this._onIsChanged === undefined ?
this._isChanged :
this._onIsChanged(this.clone, value);
}
};
const CloneObject$6 = cloneObject;
const {HANDLED_ARRAY_METHODS} = array;
var cloneArray = class CloneArray extends CloneObject$6 {
static isHandledMethod(name) {
return HANDLED_ARRAY_METHODS.has(name);
}
};
const CloneObject$5 = cloneObject;
var cloneDate = class CloneDate extends CloneObject$5 {
undo(object) {
object.setTime(this.clone.getTime());
}
isChanged(value, equals) {
return !equals(this.clone.valueOf(), value.valueOf());
}
};
const CloneObject$4 = cloneObject;
const {HANDLED_SET_METHODS} = set;
var cloneSet = class CloneSet extends CloneObject$4 {
static isHandledMethod(name) {
return HANDLED_SET_METHODS.has(name);
}
undo(object) {
this.clone.forEach(value => {
object.add(value);
});
object.forEach(value => {
if (!this.clone.has(value)) {
object.delete(value);
}
});
}
};
const CloneObject$3 = cloneObject;
const {HANDLED_MAP_METHODS} = map;
var cloneMap = class CloneMap extends CloneObject$3 {
static isHandledMethod(name) {
return HANDLED_MAP_METHODS.has(name);
}
undo(object) {
for (const [key, value] of this.clone.entries()) {
object.set(key, value);
}
for (const key of object.keys()) {
if (!this.clone.has(key)) {
object.delete(key);
}
}
}
};
const CloneObject$2 = cloneObject;
var cloneWeakset = class CloneWeakSet extends CloneObject$2 {
constructor(value, path, argumentsList, hasOnValidate) {
super(undefined, path, argumentsList, hasOnValidate);
this._arg1 = argumentsList[0];
this._weakValue = value.has(this._arg1);
}
isChanged(value) {
return this._weakValue !== value.has(this._arg1);
}
undo(object) {
if (this._weakValue && !object.has(this._arg1)) {
object.add(this._arg1);
} else {
object.delete(this._arg1);
}
}
};
const CloneObject$1 = cloneObject;
var cloneWeakmap = class CloneWeakMap extends CloneObject$1 {
constructor(value, path, argumentsList, hasOnValidate) {
super(undefined, path, argumentsList, hasOnValidate);
this._weakKey = argumentsList[0];
this._weakHas = value.has(this._weakKey);
this._weakValue = value.get(this._weakKey);
}
isChanged(value) {
return this._weakValue !== value.get(this._weakKey);
}
undo(object) {
const weakHas = object.has(this._weakKey);
if (this._weakHas && !weakHas) {
object.set(this._weakKey, this._weakValue);
} else if (!this._weakHas && weakHas) {
object.delete(this._weakKey);
} else if (this._weakValue !== object.get(this._weakKey)) {
object.set(this._weakKey, this._weakValue);
}
}
};
const isArray = isArray$3;
const isBuiltin$1 = isBuiltin_1;
const isObject = isObject$2;
const CloneObject = cloneObject;
const CloneArray = cloneArray;
const CloneDate = cloneDate;
const CloneSet = cloneSet;
const CloneMap = cloneMap;
const CloneWeakSet = cloneWeakset;
const CloneWeakMap = cloneWeakmap;
class SmartClone$1 {
constructor(hasOnValidate) {
this._stack = [];
this._hasOnValidate = hasOnValidate;
}
static isHandledType(value) {
return isObject(value) ||
isArray(value) ||
isBuiltin$1.withMutableMethods(value);
}
static isHandledMethod(target, name) {
if (isObject(target)) {
return CloneObject.isHandledMethod(name);
}
if (isArray(target)) {
return CloneArray.isHandledMethod(name);
}
if (target instanceof Set) {
return CloneSet.isHandledMethod(name);
}
if (target instanceof Map) {
return CloneMap.isHandledMethod(name);
}
return isBuiltin$1.withMutableMethods(target);
}
get isCloning() {
return this._stack.length !== 0;
}
start(value, path, argumentsList) {
let CloneClass = CloneObject;
if (isArray(value)) {
CloneClass = CloneArray;
} else if (value instanceof Date) {
CloneClass = CloneDate;
} else if (value instanceof Set) {
CloneClass = CloneSet;
} else if (value instanceof Map) {
CloneClass = CloneMap;
} else if (value instanceof WeakSet) {
CloneClass = CloneWeakSet;
} else if (value instanceof WeakMap) {
CloneClass = CloneWeakMap;
}
this._stack.push(new CloneClass(value, path, argumentsList, this._hasOnValidate));
}
update(fullPath, property, value) {
this._stack[this._stack.length - 1].update(fullPath, property, value);
}
preferredThisArg(target, thisArg, thisProxyTarget) {
const {name} = target;
const isHandledMethod = SmartClone$1.isHandledMethod(thisProxyTarget, name);
return this._stack[this._stack.length - 1]
.preferredThisArg(isHandledMethod, name, thisArg, thisProxyTarget);
}
isChanged(isMutable, value, equals) {
return this._stack[this._stack.length - 1].isChanged(isMutable, value, equals);
}
undo(object) {
if (this._previousClone !== undefined) {
this._previousClone.undo(object);
}
}
stop() {
this._previousClone = this._stack.pop();
return this._previousClone.clone;
}
}
var smartClone = SmartClone$1;
const {TARGET, UNSUBSCRIBE} = constants;
const isBuiltin = isBuiltin_1;
const path = path$3;
const isSymbol = isSymbol$3;
const isIterator = isIterator$1;
const wrapIterator = wrapIterator$1;
const ignoreProperty = ignoreProperty$1;
const Cache = cache;
const SmartClone = smartClone;
const defaultOptions = {
equals: Object.is,
isShallow: false,
pathAsArray: false,
ignoreSymbols: false,
ignoreUnderscores: false,
ignoreDetached: false,
details: false
};
const onChange$1 = (object, onChange, options = {}) => {
options = {
...defaultOptions,
...options
};
const proxyTarget = Symbol('ProxyTarget');
const {equals, isShallow, ignoreDetached, details} = options;
const cache = new Cache(equals);
const hasOnValidate = typeof options.onValidate === 'function';
const smartClone = new SmartClone(hasOnValidate);
// eslint-disable-next-line max-params
const validate = (target, property, value, previous, applyData) => {
return !hasOnValidate ||
smartClone.isCloning ||
options.onValidate(path.concat(cache.getPath(target), property), value, previous, applyData) === true;
};
const handleChangeOnTarget = (target, property, value, previous) => {
if (
!ignoreProperty(cache, options, property) &&
!(ignoreDetached && cache.isDetached(target, object))
) {
handleChange(cache.getPath(target), property, value, previous);
}
};
// eslint-disable-next-line max-params
const handleChange = (changePath, property, value, previous, applyData) => {
if (smartClone.isCloning) {
smartClone.update(changePath, property, previous);
} else {
onChange(path.concat(changePath, property), value, previous, applyData);
}
};
const getProxyTarget = value => {
return value ?
(value[proxyTarget] || value) :
value;
};
const prepareValue = (value, target, property, basePath) => {
if (
isBuiltin.withoutMutableMethods(value) ||
property === 'constructor' ||
(isShallow && !SmartClone.isHandledMethod(target, property)) ||
ignoreProperty(cache, options, property) ||
cache.isGetInvariant(target, property) ||
(ignoreDetached && cache.isDetached(target, object))
) {
return value;
}
if (basePath === undefined) {
basePath = cache.getPath(target);
}
return cache.getProxy(value, path.concat(basePath, property), handler, proxyTarget);
};
const handler = {
get(target, property, receiver) {
if (isSymbol(property)) {
if (property === proxyTarget || property === TARGET) {
return target;
}
if (
property === UNSUBSCRIBE &&
!cache.isUnsubscribed &&
cache.getPath(target).length === 0
) {
cache.unsubscribe();
return target;
}
}
const value = isBuiltin.withMutableMethods(target) ?
Reflect.get(target, property) :
Reflect.get(target, property, receiver);
return prepareValue(value, target, property);
},
set(target, property, value, receiver) {
value = getProxyTarget(value);
const reflectTarget = target[proxyTarget] || target;
const previous = reflectTarget[property];
if (equals(previous, value) && property in target) {
return true;
}
const isValid = validate(target, property, value, previous);
if (
isValid &&
cache.setProperty(reflectTarget, property, value, receiver, previous)
) {
handleChangeOnTarget(target, property, target[property], previous);
return true;
}
return !isValid;
},
defineProperty(target, property, descriptor) {
if (!cache.isSameDescriptor(descriptor, target, property)) {
const previous = target[property];
if (
validate(target, property, descriptor.value, previous) &&
cache.defineProperty(target, property, descriptor, previous)
) {
handleChangeOnTarget(target, property, descriptor.value, previous);
}
}
return true;
},
deleteProperty(target, property) {
if (!Reflect.has(target, property)) {
return true;
}
const previous = Reflect.get(target, property);
if (
validate(target, property, undefined, previous) &&
cache.deleteProperty(target, property, previous)
) {
handleChangeOnTarget(target, property, undefined, previous);
return true;
}
return false;
},
apply(target, thisArg, argumentsList) {
const thisProxyTarget = thisArg[proxyTarget] || thisArg;
if (cache.isUnsubscribed) {
return Reflect.apply(target, thisProxyTarget, argumentsList);
}
if (
(details === false ||
(details !== true && !details.includes(target.name))) &&
SmartClone.isHandledType(thisProxyTarget)
) {
let applyPath = path.initial(cache.getPath(target));
const isHandledMethod = SmartClone.isHandledMethod(thisProxyTarget, target.name);
smartClone.start(thisProxyTarget, applyPath, argumentsList);
let result = Reflect.apply(
target,
smartClone.preferredThisArg(target, thisArg, thisProxyTarget),
isHandledMethod ?
argumentsList.map(argument => getProxyTarget(argument)) :
argumentsList
);
const isChanged = smartClone.isChanged(thisProxyTarget, equals);
const previous = smartClone.stop();
if (SmartClone.isHandledType(result) && isHandledMethod) {
if (thisArg instanceof Map && target.name === 'get') {
applyPath = path.concat(applyPath, argumentsList[0]);
}
result = cache.getProxy(result, applyPath, handler);
}
if (isChanged) {
const applyData = {
name: target.name,
args: argumentsList,
result
};
const changePath = smartClone.isCloning ?
path.initial(applyPath) :
applyPath;
const property = smartClone.isCloning ?
path.last(applyPath) :
'';
if (validate(path.get(object, changePath), property, thisProxyTarget, previous, applyData)) {
handleChange(changePath, property, thisProxyTarget, previous, applyData);
} else {
smartClone.undo(thisProxyTarget);
}
}
if (
(thisArg instanceof Map || thisArg instanceof Set) &&
isIterator(result)
) {
return wrapIterator(result, target, thisArg, applyPath, prepareValue);
}
return result;
}
return Reflect.apply(target, thisArg, argumentsList);
}
};
const proxy = cache.getProxy(object, options.pathAsArray ? [] : '', handler);
onChange = onChange.bind(proxy);
if (hasOnValidate) {
options.onValidate = options.onValidate.bind(proxy);
}
return proxy;
};
onChange$1.target = proxy => (proxy && proxy[TARGET]) || proxy;
onChange$1.unsubscribe = proxy => proxy[UNSUBSCRIBE] || proxy;
var onChange_1 = onChange$1;
var rfc6902 = {};
var pointer = {};
Object.defineProperty(pointer, "__esModule", { value: true });
pointer.Pointer = void 0;
/**
Unescape token part of a JSON Pointer string
`token` should *not* contain any '/' characters.
> Evaluation of each reference token begins by decoding any escaped
> character sequence. This is performed by first transforming any
> occurrence of the sequence '~1' to '/', and then transforming any
> occurrence of the sequence '~0' to '~'. By performing the
> substitutions in this order, an implementation avoids the error of
> turning '~01' first into '~1' and then into '/', which would be
> incorrect (the string '~01' correctly becomes '~1' after
> transformation).
Here's my take:
~1 is unescaped with higher priority than ~0 because it is a lower-order escape character.
I say "lower order" because '/' needs escaping due to the JSON Pointer serialization technique.
Whereas, '~' is escaped because escaping '/' uses the '~' character.
*/
function unescape$1(token) {
return token.replace(/~1/g, '/').replace(/~0/g, '~');
}
/** Escape token part of a JSON Pointer string
> '~' needs to be encoded as '~0' and '/'
> needs to be encoded as '~1' when these characters appear in a
> reference token.
This is the exact inverse of `unescape()`, so the reverse replacements must take place in reverse order.
*/
function escape(token) {
return token.replace(/~/g, '~0').replace(/\//g, '~1');
}
/**
JSON Pointer representation
*/
var Pointer = /** @class */ (function () {
function Pointer(tokens) {
if (tokens === void 0) { tokens = ['']; }
this.tokens = tokens;
}
/**
`path` *must* be a properly escaped string.
*/
Pointer.fromJSON = function (path) {
var tokens = path.split('/').map(unescape$1);
if (tokens[0] !== '')
throw new Error("Invalid JSON Pointer: " + path);
return new Pointer(tokens);
};
Pointer.prototype.toString = function () {
return this.tokens.map(escape).join('/');
};
/**
Returns an object with 'parent', 'key', and 'value' properties.
In the special case that this Pointer's path == "",
this object will be {parent: null, key: '', value: object}.
Otherwise, parent and key will have the property such that parent[key] == value.
*/
Pointer.prototype.evaluate = function (object) {
var parent = null;
var key = '';
var value = object;
for (var i = 1, l = this.tokens.length; i < l; i++) {
parent = value;
key = this.tokens[i];
// not sure if this the best way to handle non-existant paths...
value = (parent || {})[key];
}
return { parent: parent, key: key, value: value };
};
Pointer.prototype.get = function (object) {
return this.evaluate(object).value;
};
Pointer.prototype.set = function (object, value) {
var cursor = object;
for (var i = 1, l = this.tokens.length - 1, token = this.tokens[i]; i < l; i++) {
// not sure if this the best way to handle non-existant paths...
cursor = (cursor || {})[token];
}
if (cursor) {
cursor[this.tokens[this.tokens.length - 1]] = value;
}
};
Pointer.prototype.push = function (token) {
// mutable
this.tokens.push(token);
};
/**
`token` should be a String. It'll be coerced to one anyway.
immutable (shallowly)
*/
Pointer.prototype.add = function (token) {
var tokens = this.tokens.concat(String(token));
return new Pointer(tokens);
};
return Pointer;
}());
pointer.Pointer = Pointer;
var patch = {};
var util = {};
(function (exports) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.clone = exports.objectType = exports.hasOwnProperty = void 0;
exports.hasOwnProperty = Object.prototype.hasOwnProperty;
function objectType(object) {
if (object === undefined) {
return 'undefined';
}
if (object === null) {
return 'null';
}
if (Array.isArray(object)) {
return 'array';
}
return typeof object;
}
exports.objectType = objectType;
/**
Recursively copy a value.
@param source - should be a JavaScript primitive, Array, or (plain old) Object.
@returns copy of source where every Array and Object have been recursively
reconstructed from their constituent elements
*/
function clone(source) {
// loose-equality checking for null is faster than strict checking for each of null/undefined/true/false
// checking null first, then calling typeof, is faster than vice-versa
if (source == null || typeof source != 'object') {
// short-circuiting is faster than a single return
return source;
}
// x.constructor == Array is the fastest way to check if x is an Array
if (source.constructor == Array) {
// construction via imperative for-loop is faster than source.map(arrayVsObject)
var length_1 = source.length;
// setting the Array length during construction is faster than just `[]` or `new Array()`
var arrayTarget = new Array(length_1);
for (var i = 0; i < length_1; i++) {
arrayTarget[i] = clone(source[i]);
}
return arrayTarget;
}
// Object
var objectTarget = {};
// declaring the variable (with const) inside the loop is faster
for (var key in source) {
// hasOwnProperty costs a bit of performance, but it's semantically necessary
// using a global helper is MUCH faster than calling source.hasOwnProperty(key)
if (exports.hasOwnProperty.call(source, key)) {
objectTarget[key] = clone(source[key]);
}
}
return objectTarget;
}
exports.clone = clone;
}(util));
var equal = {};
Object.defineProperty(equal, "__esModule", { value: true });
equal.compare = void 0;
var util_1$2 = util;
/**
Evaluate `left === right`, treating `left` and `right` as ordered lists.
@returns true iff `left` and `right` have identical lengths, and every element
of `left` is equal to the corresponding element of `right`. Equality is
determined recursivly, via `compare`.
*/
function compareArrays(left, right) {
var length = left.length;
if (length !== right.length) {
return false;
}
for (var i = 0; i < length; i++) {
if (!compare(left[i], right[i])) {
return false;
}
}
return true;
}
/**
Evaluate `left === right`, treating `left` and `right` as property maps.
@returns true iff every property in `left` has a value equal to the value of the
corresponding property in `right`, and vice-versa, stopping as soon as
possible. Equality is determined recursivly, via `compare`.
*/
function compareObjects(left, right) {
var left_keys = Object.keys(left);
var right_keys = Object.keys(right);
var length = left_keys.length;
// quick exit if the number of keys don't match up
if (length !== right_keys.length) {
return false;
}
// we don't know for sure that Set(left_keys) is equal to Set(right_keys),
// much less that their values in left and right are equal, but if right
// contains each key in left, we know it can't have any additional keys
for (var i = 0; i < length; i++) {
var key = left_keys[i];
if (!util_1$2.hasOwnProperty.call(right, key) || !compare(left[key], right[key])) {
return false;
}
}
return true;
}
/**
`compare()` returns true if `left` and `right` are materially equal
(i.e., would produce equivalent JSON), false otherwise.
> Here, "equal" means that the value at the target location and the
> value conveyed by "value" are of the same JSON type, and that they
> are considered equal by the following rules for that type:
> o strings: are considered equal if they contain the same number of
> Unicode characters and their code points are byte-by-byte equal.
> o numbers: are considered equal if their values are numerically
> equal.
> o arrays: are considered equal if they contain the same number of
> values, and if each value can be considered equal to the value at
> the corresponding position in the other array, using this list of
> type-specific rules.
> o objects: are considered equal if they contain the same number of
> members, and if each member can be considered equal to a member in
> the other object, by comparing their keys (as strings) and their
> values (using this list of type-specific rules).
> o literals (false, true, and null): are considered equal if they are
> the same.
*/
function compare(left, right) {
// strict equality handles literals, numbers, and strings (a sufficient but not necessary cause)
if (left === right) {
return true;
}
var left_type = util_1$2.objectType(left);
var right_type = util_1$2.objectType(right);
// check arrays
if (left_type == 'array' && right_type == 'array') {
return compareArrays(left, right);
}
// check objects
if (left_type == 'object' && right_type == 'object') {
return compareObjects(left, right);
}
// mismatched arrays & objects, etc., are always inequal
return false;
}
equal.compare = compare;
var __extends = (commonjsGlobal && commonjsGlobal.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(patch, "__esModule", { value: true });
patch.apply = patch.InvalidOperationError = patch.test = patch.copy = patch.move = patch.replace = patch.remove = patch.add = patch.TestError = patch.MissingError = void 0;
var pointer_1$1 = pointer;
var util_1$1 = util;
var equal_1$1 = equal;
var MissingError = /** @class */ (function (_super) {
__extends(MissingError, _super);
function MissingError(path) {
var _this = _super.call(this, "Value required at path: " + path) || this;
_this.path = path;
_this.name = 'MissingError';
return _this;
}
return MissingError;
}(Error));
patch.MissingError = MissingError;
var TestError = /** @class */ (function (_super) {
__extends(TestError, _super);
function TestError(actual, expected) {
var _this = _super.call(this, "Test failed: " + actual + " != " + expected) || this;
_this.actual = actual;
_this.expected = expected;
_this.name = 'TestError';
return _this;
}
return TestError;
}(Error));
patch.TestError = TestError;
function _add(object, key, value) {
if (Array.isArray(object)) {
// `key` must be an index
if (key == '-') {
object.push(value);
}
else {
var index = parseInt(key, 10);
object.splice(index, 0, value);
}
}
else {
object[key] = value;
}
}
function _remove(object, key) {
if (Array.isArray(object)) {
// '-' syntax doesn't make sense when removing
var index = parseInt(key, 10);
object.splice(index, 1);
}
else {
// not sure what the proper behavior is when path = ''
delete object[key];
}
}
/**
> o If the target location specifies an array index, a new value is
> inserted into the array at the specified index.
> o If the target location specifies an object member that does not
> already exist, a new member is added to the object.
> o If the target location specifies an object member that does exist,
> that member's value is replaced.
*/
function add(object, operation) {
var endpoint = pointer_1$1.Pointer.fromJSON(operation.path).evaluate(object);
// it's not exactly a "MissingError" in the same way that `remove` is -- more like a MissingParent, or something
if (endpoint.parent === undefined) {
return new MissingError(operation.path);
}
_add(endpoint.parent, endpoint.key, util_1$1.clone(operation.value));
return null;
}
patch.add = add;
/**
> The "remove" operation removes the value at the target location.
> The target location MUST exist for the operation to be successful.
*/
function remove(object, operation) {
// endpoint has parent, key, and value properties
var endpoint = pointer_1$1.Pointer.fromJSON(operation.path).evaluate(object);
if (endpoint.value === undefined) {
return new MissingError(operation.path);
}
// not sure what the proper behavior is when path = ''
_remove(endpoint.parent, endpoint.key);
return null;
}
patch.remove = remove;
/**
> The "replace" operation replaces the value at the target location
> with a new value. The operation object MUST contain a "value" member
> whose content specifies the replacement value.
> The target location MUST exist for the operation to be successful.
> This operation is functionally identical to a "remove" operation for
> a value, followed immediately by an "add" operation at the same
> location with the replacement value.
Even more simply, it's like the add operation with an existence check.
*/
function replace(object, operation) {
var endpoint = pointer_1$1.Pointer.fromJSON(operation.path).evaluate(object);
if (endpoint.parent === null) {
return new MissingError(operation.path);
}
// this existence check treats arrays as a special case
if (Array.isArray(endpoint.parent)) {
if (parseInt(endpoint.key, 10) >= endpoint.parent.length) {
return new MissingError(operation.path);
}
}
else if (endpoint.value === undefined) {
return new MissingError(operation.path);
}
endpoint.parent[endpoint.key] = operation.value;
return null;
}
patch.replace = replace;
/**
> The "move" operation removes the value at a specified location and
> adds it to the target location.
> The operation object MUST contain a "from" member, which is a string
> containing a JSON Pointer value that references the location in the
> target document to move the value from.
> This operation is functionally identical to a "remove" operation on
> the "from" location, followed immediately by an "add" operation at
> the target location with the value that was just removed.
> The "from" location MUST NOT be a proper prefix of the "path"
> location; i.e., a location cannot be moved into one of its children.
TODO: throw if the check described in the previous paragraph fails.
*/
function move(object, operation) {
var from_endpoint = pointer_1$1.Pointer.fromJSON(operation.from).evaluate(object);
if (from_endpoint.value === undefined) {
return new MissingError(operation.from);
}
var endpoint = pointer_1$1.Pointer.fromJSON(operation.path).evaluate(object);
if (endpoint.parent === undefined) {
return new MissingError(operation.path);
}
_remove(from_endpoint.parent, from_endpoint.key);
_add(endpoint.parent, endpoint.key, from_endpoint.value);
return null;
}
patch.move = move;
/**
> The "copy" operation copies the value at a specified location to the
> target location.
> The operation object MUST contain a "from" member, which is a string
> containing a JSON Pointer value that references the location in the
> target document to copy the value from.
> The "from" location MUST exist for the operation to be successful.
> This operation is functionally identical to an "add" operation at the
> target location using the value specified in the "from" member.
Alternatively, it's like 'move' without the 'remove'.
*/
function copy(object, operation) {
var from_endpoint = pointer_1$1.Pointer.fromJSON(operation.from).evaluate(object);
if (from_endpoint.value === undefined) {
return new MissingError(operation.from);
}
var endpoint = pointer_1$1.Pointer.fromJSON(operation.path).evaluate(object);
if (endpoint.parent === undefined) {
return new MissingError(operation.path);
}
_add(endpoint.parent, endpoint.key, util_1$1.clone(from_endpoint.value));
return null;
}
patch.copy = copy;
/**
> The "test" operation tests that a value at the target location is
> equal to a specified value.
> The operation object MUST contain a "value" member that conveys the
> value to be compared to the target location's value.
> The target location MUST be equal to the "value" value for the
> operation to be considered successful.
*/
function test(object, operation) {
var endpoint = pointer_1$1.Pointer.fromJSON(operation.path).evaluate(object);
var result = equal_1$1.compare(endpoint.value, operation.value);
if (!result) {
return new TestError(endpoint.value, operation.value);
}
return null;
}
patch.test = test;
var InvalidOperationError = /** @class */ (function (_super) {
__extends(InvalidOperationError, _super);
function InvalidOperationError(operation) {
var _this = _super.call(this, "Invalid operation: " + operation.op) || this;
_this.operation = operation;
_this.name = 'InvalidOperationError';
return _this;
}
return InvalidOperationError;
}(Error));
patch.InvalidOperationError = InvalidOperationError;
/**
Switch on `operation.op`, applying the corresponding patch function for each
case to `object`.
*/
function apply(object, operation) {
// not sure why TypeScript can't infer typesafety of:
// {add, remove, replace, move, copy, test}[operation.op](object, operation)
// (seems like a bug)
switch (operation.op) {
case 'add': return add(object, operation);
case 'remove': return remove(object, operation);
case 'replace': return replace(object, operation);
case 'move': return move(object, operation);
case 'copy': return copy(object, operation);
case 'test': return test(object, operation);
}
return new InvalidOperationError(operation);
}
patch.apply = apply;
var diff = {};
Object.defineProperty(diff, "__esModule", { value: true });
diff.diffAny = diff.diffObjects = diff.diffArrays = diff.intersection = diff.subtract = diff.isDestructive = void 0;
var equal_1 = equal;
var util_1 = util;
function isDestructive(_a) {
var op = _a.op;
return op === 'remove' || op === 'replace' || op === 'copy' || op === 'move';
}
diff.isDestructive = isDestructive;
/**
List the keys in `minuend` that are not in `subtrahend`.
A key is only considered if it is both 1) an own-property (o.hasOwnProperty(k))
of the object, and 2) has a value that is not undefined. This is to match JSON
semantics, where JSON object serialization drops keys with undefined values.
@param minuend Object of interest
@param subtrahend Object of comparison
@returns Array of keys that are in `minuend` but not in `subtrahend`.
*/
function subtract(minuend, subtrahend) {
// initialize empty object; we only care about the keys, the values can be anything
var obj = {};
// build up obj with all the properties of minuend
for (var add_key in minuend) {
if (util_1.hasOwnProperty.call(minuend, add_key) && minuend[add_key] !== undefined) {
obj[add_key] = 1;
}
}
// now delete all the properties of subtrahend from obj
// (deleting a missing key has no effect)
for (var del_key in subtrahend) {
if (util_1.hasOwnProperty.call(subtrahend, del_key) && subtrahend[del_key] !== undefined) {
delete obj[del_key];
}
}
// finally, extract whatever keys remain in obj
return Object.keys(obj);
}
diff.subtract = subtract;
/**
List the keys that shared by all `objects`.
The semantics of what constitutes a "key" is described in {@link subtract}.
@param objects Array of objects to compare
@returns Array of keys that are in ("own-properties" of) every object in `objects`.
*/
function intersection(objects) {
var length = objects.length;
// prepare empty counter to keep track of how many objects each key occurred in
var counter = {};
// go through each object and increment the counter for each key in that object
for (var i = 0; i < length; i++) {
var object = objects[i];
for (var key in object) {
if (util_1.hasOwnProperty.call(object, key) && object[key] !== undefined) {
counter[key] = (counter[key] || 0) + 1;
}
}
}
// now delete all keys from the counter that were not seen in every object
for (var key in counter) {
if (counter[key] < length) {
delete counter[key];
}
}
// finally, extract whatever keys remain in the counter
return Object.keys(counter);
}
diff.intersection = intersection;
function isArrayAdd(array_operation) {
return array_operation.op === 'add';
}
function isArrayRemove(array_operation) {
return array_operation.op === 'remove';
}
function appendArrayOperation(base, operation) {
return {
// the new operation must be pushed on the end
operations: base.operations.concat(operation),
cost: base.cost + 1,
};
}
/**
Calculate the shortest sequence of operations to get from `input` to `output`,
using a dynamic programming implementation of the Levenshtein distance algorithm.
To get from the input ABC to the output AZ we could just delete all the input
and say "insert A, insert Z" and be done with it. That's what we do if the
input is empty. But we can be smarter.
output
A Z
- -
[0] 1 2
input A | 1 [0] 1
B | 2 [1] 1
C | 3 2 [2]
1) start at 0,0 (+0)
2) keep A (+0)
3) remove B (+1)
4) replace C with Z (+1)
If the `input` (source) is empty, they'll all be in the top row, resulting in an
array of 'add' operations.
If the `output` (target) is empty, everything will be in the left column,
resulting in an array of 'remove' operations.
@returns A list of add/remove/replace operations.
*/
function diffArrays(input, output, ptr, diff) {
if (diff === void 0) { diff = diffAny; }
// set up cost matrix (very simple initialization: just a map)
var memo = {
'0,0': { operations: [], cost: 0 },
};
/**
Calculate the cheapest sequence of operations required to get from
input.slice(0, i) to output.slice(0, j).
There may be other valid sequences with the same cost, but none cheaper.
@param i The row in the layout above
@param j The column in the layout above
@returns An object containing a list of operations, along with the total cost
of applying them (+1 for each add/remove/replace operation)
*/
function dist(i, j) {
// memoized
var memo_key = i + "," + j;
var memoized = memo[memo_key];
if (memoized === undefined) {
if (i > 0 && j > 0 && equal_1.compare(input[i - 1], output[j - 1])) {
// equal (no operations => no cost)
memoized = dist(i - 1, j - 1);
}
else {
var alternati