Comparing version 3.0.2 to 4.0.0
251
index.d.ts
@@ -1,144 +0,143 @@ | ||
declare namespace onChange { | ||
interface Options { | ||
/** | ||
Deep changes will not trigger the callback. Only changes to the immediate properties of the original object. | ||
export interface Options { | ||
/** | ||
Deep changes will not trigger the callback. Only changes to the immediate properties of the original object. | ||
@default false | ||
@default false | ||
@example | ||
``` | ||
const onChange = require('on-change'); | ||
@example | ||
``` | ||
import onChange from 'on-change'; | ||
const object = { | ||
a: { | ||
b: false | ||
} | ||
}; | ||
const object = { | ||
a: { | ||
b: false | ||
} | ||
}; | ||
let i = 0; | ||
const watchedObject = onChange(object, () => { | ||
console.log('Object changed:', ++i); | ||
}, {isShallow: true}); | ||
let index = 0; | ||
const watchedObject = onChange(object, () => { | ||
console.log('Object changed:', ++index); | ||
}, {isShallow: true}); | ||
watchedObject.a.b = true; | ||
// Nothing happens | ||
watchedObject.a.b = true; | ||
// Nothing happens | ||
watchedObject.a = true; | ||
//=> 'Object changed: 1' | ||
``` | ||
*/ | ||
isShallow?: boolean; | ||
watchedObject.a = true; | ||
//=> 'Object changed: 1' | ||
``` | ||
*/ | ||
readonly isShallow?: boolean; | ||
/** | ||
The function receives two arguments to be compared for equality. Should return `true` if the two values are determined to be equal. | ||
/** | ||
The function receives two arguments to be compared for equality. Should return `true` if the two values are determined to be equal. | ||
@default Object.is | ||
@default Object.is | ||
@example | ||
``` | ||
const onChange = require('on-change'); | ||
@example | ||
``` | ||
import onChange from 'on-change'; | ||
const object = { | ||
a: { | ||
b: false | ||
} | ||
}; | ||
const object = { | ||
a: { | ||
b: false | ||
} | ||
}; | ||
let i = 0; | ||
const watchedObject = onChange(object, () => { | ||
console.log('Object changed:', ++i); | ||
}, {equals: (a, b) => a === b}); | ||
let index = 0; | ||
const watchedObject = onChange(object, () => { | ||
console.log('Object changed:', ++index); | ||
}, {equals: (a, b) => a === b}); | ||
watchedObject.a.b = 0; | ||
// Nothing happens | ||
watchedObject.a.b = 0; | ||
// Nothing happens | ||
watchedObject.a = true; | ||
//=> 'Object changed: 1' | ||
``` | ||
*/ | ||
equals?: (a: unknown, b: unknown) => boolean; | ||
watchedObject.a = true; | ||
//=> 'Object changed: 1' | ||
``` | ||
*/ | ||
equals?: (a: unknown, b: unknown) => boolean; | ||
/** | ||
Setting properties as `Symbol` won't trigger the callback. | ||
/** | ||
Setting properties as `Symbol` won't trigger the callback. | ||
@default false | ||
*/ | ||
ignoreSymbols?: boolean; | ||
@default false | ||
*/ | ||
readonly ignoreSymbols?: boolean; | ||
/** | ||
Setting properties in this array won't trigger the callback. | ||
/** | ||
Setting properties in this array won't trigger the callback. | ||
@default undefined | ||
*/ | ||
ignoreKeys?: Array<string|symbol>; | ||
@default undefined | ||
*/ | ||
readonly ignoreKeys?: ReadonlyArray<string | symbol>; | ||
/** | ||
Setting properties with an underscore as the first character won't trigger the callback. | ||
/** | ||
Setting properties with an underscore as the first character won't trigger the callback. | ||
@default false | ||
*/ | ||
ignoreUnderscores?: boolean; | ||
@default false | ||
*/ | ||
readonly ignoreUnderscores?: boolean; | ||
/** | ||
The path will be provided as an array of keys instead of a delimited string. | ||
/** | ||
The path will be provided as an array of keys instead of a delimited string. | ||
@default false | ||
*/ | ||
pathAsArray?: boolean; | ||
@default false | ||
*/ | ||
readonly pathAsArray?: boolean; | ||
/** | ||
Ignore changes to objects that become detached from the watched object. | ||
/** | ||
Ignore changes to objects that become detached from the watched object. | ||
@default false | ||
*/ | ||
ignoreDetached?: boolean; | ||
@default false | ||
*/ | ||
readonly ignoreDetached?: boolean; | ||
/** | ||
Trigger callbacks for each change within specified method calls or all method calls. | ||
/** | ||
Trigger callbacks for each change within specified method calls or all method calls. | ||
@default false | ||
*/ | ||
details?: boolean | string[]; | ||
@default false | ||
*/ | ||
readonly details?: boolean | readonly string[]; | ||
/** | ||
The function receives the same arguments and context as the [onChange callback](#onchange). The function is called whenever a change is attempted. Returning true will allow the change to be made and the onChange callback to execute, returning anything else will prevent the change from being made and the onChange callback will not trigger. | ||
/** | ||
The function receives the same arguments and context as the [onChange callback](#onchange). The function is called whenever a change is attempted. Returning true will allow the change to be made and the onChange callback to execute, returning anything else will prevent the change from being made and the onChange callback will not trigger. | ||
@example | ||
``` | ||
const onChange = require('on-change'); | ||
@example | ||
``` | ||
import onChange from 'on-change'; | ||
const object = {a: 0}; | ||
let i = 0; | ||
const watchedObject = onChange(object, () => { | ||
console.log('Object changed:', ++i); | ||
}, {onValidate: () => false}); | ||
const object = {a: 0}; | ||
let index = 0; | ||
const watchedObject = onChange(object, () => { | ||
console.log('Object changed:', ++index); | ||
}, {onValidate: () => false}); | ||
watchedObject.a = true; | ||
// watchedObject.a still equals 0 | ||
``` | ||
*/ | ||
onValidate?: ( | ||
this: unknown, | ||
path: string, | ||
value: unknown, | ||
previousValue: unknown, | ||
applyData: ApplyData | ||
) => boolean; | ||
watchedObject.a = true; | ||
// watchedObject.a still equals 0 | ||
``` | ||
*/ | ||
onValidate?: ( | ||
this: unknown, | ||
path: string, | ||
value: unknown, | ||
previousValue: unknown, | ||
applyData: ApplyData | ||
) => boolean; | ||
} | ||
} | ||
export interface ApplyData { | ||
/** | ||
The name of the method that produced the change. | ||
*/ | ||
readonly name: string; | ||
interface ApplyData { | ||
/** | ||
The name of the method that produced the change. | ||
*/ | ||
name: string; | ||
/** | ||
The arguments provided to the method that produced the change. | ||
*/ | ||
args: any[]; | ||
/** | ||
The result returned from the method that produced the change. | ||
*/ | ||
result: any; | ||
} | ||
/** | ||
The arguments provided to the method that produced the change. | ||
*/ | ||
readonly args: unknown[]; | ||
/** | ||
The result returned from the method that produced the change. | ||
*/ | ||
readonly result: unknown; | ||
} | ||
@@ -157,3 +156,3 @@ | ||
``` | ||
const onChange = require('on-change'); | ||
import onChange from 'on-change'; | ||
@@ -171,5 +170,5 @@ const object = { | ||
let i = 0; | ||
let index = 0; | ||
const watchedObject = onChange(object, function (path, value, previousValue, applyData) { | ||
console.log('Object changed:', ++i); | ||
console.log('Object changed:', ++index); | ||
console.log('this:', this); | ||
@@ -248,3 +247,3 @@ console.log('path:', path); | ||
*/ | ||
<ObjectType extends {[key: string]: any}>( | ||
<ObjectType extends Record<string, any>>( | ||
object: ObjectType, | ||
@@ -256,18 +255,18 @@ onChange: ( | ||
previousValue: unknown, | ||
applyData: onChange.ApplyData | ||
applyData: ApplyData | ||
) => void, | ||
options?: onChange.Options & {pathAsArray?: false} | ||
options?: Options & {pathAsArray?: false} | ||
): ObjectType; | ||
// Overload that returns an Array as path when pathAsArray is true | ||
<ObjectType extends {[key: string]: any}>( | ||
// Overload that returns an Array as path when `pathAsArray` option is true. | ||
<ObjectType extends Record<string, any>>( | ||
object: ObjectType, | ||
onChange: ( | ||
this: ObjectType, | ||
path: Array<string|symbol>, | ||
path: Array<string | symbol>, | ||
value: unknown, | ||
previousValue: unknown, | ||
applyData: onChange.ApplyData | ||
applyData: ApplyData | ||
) => void, | ||
options: onChange.Options & {pathAsArray: true} | ||
options: Options & {pathAsArray: true} | ||
): ObjectType; | ||
@@ -279,3 +278,3 @@ | ||
*/ | ||
target<ObjectType extends {[key: string]: any}>(object: ObjectType): ObjectType; // eslint-disable-line @typescript-eslint/method-signature-style | ||
target<ObjectType extends Record<string, any>>(object: ObjectType): ObjectType; | ||
@@ -288,5 +287,5 @@ /** | ||
*/ | ||
unsubscribe<ObjectType extends {[key: string]: any}>(object: ObjectType): ObjectType; // eslint-disable-line @typescript-eslint/method-signature-style | ||
unsubscribe<ObjectType extends Record<string, any>>(object: ObjectType): ObjectType; | ||
}; | ||
export = onChange; | ||
export default onChange; |
121
index.js
@@ -1,13 +0,12 @@ | ||
'use strict'; | ||
/* eslint-disable unicorn/prefer-spread */ | ||
import {TARGET, UNSUBSCRIBE} from './lib/constants.js'; | ||
import {isBuiltinWithMutableMethods, isBuiltinWithoutMutableMethods} from './lib/is-builtin.js'; | ||
import path from './lib/path.js'; | ||
import isSymbol from './lib/is-symbol.js'; | ||
import isIterator from './lib/is-iterator.js'; | ||
import wrapIterator from './lib/wrap-iterator.js'; | ||
import ignoreProperty from './lib/ignore-property.js'; | ||
import Cache from './lib/cache.js'; | ||
import SmartClone from './lib/smart-clone/smart-clone.js'; | ||
const {TARGET, UNSUBSCRIBE} = require('./lib/constants'); | ||
const isBuiltin = require('./lib/is-builtin'); | ||
const path = require('./lib/path'); | ||
const isSymbol = require('./lib/is-symbol'); | ||
const isIterator = require('./lib/is-iterator'); | ||
const wrapIterator = require('./lib/wrap-iterator'); | ||
const ignoreProperty = require('./lib/ignore-property'); | ||
const Cache = require('./lib/cache'); | ||
const SmartClone = require('./lib/smart-clone/smart-clone.js'); | ||
const defaultOptions = { | ||
@@ -20,3 +19,3 @@ equals: Object.is, | ||
ignoreDetached: false, | ||
details: false | ||
details: false, | ||
}; | ||
@@ -27,4 +26,5 @@ | ||
...defaultOptions, | ||
...options | ||
...options, | ||
}; | ||
const proxyTarget = Symbol('ProxyTarget'); | ||
@@ -37,12 +37,10 @@ const {equals, isShallow, ignoreDetached, details} = options; | ||
// 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 validate = (target, property, value, previous, applyData) => !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)) | ||
!ignoreProperty(cache, options, property) | ||
&& !(ignoreDetached && cache.isDetached(target, object)) | ||
) { | ||
@@ -62,16 +60,14 @@ handleChange(cache.getPath(target), property, value, previous); | ||
const getProxyTarget = value => { | ||
return value ? | ||
(value[proxyTarget] || value) : | ||
value; | ||
}; | ||
const getProxyTarget = value => 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)) | ||
isBuiltinWithoutMutableMethods(value) | ||
|| property === 'constructor' | ||
|| (isShallow && !SmartClone.isHandledMethod(target, property)) | ||
|| ignoreProperty(cache, options, property) | ||
|| cache.isGetInvariant(target, property) | ||
|| (ignoreDetached && cache.isDetached(target, object)) | ||
) { | ||
@@ -96,5 +92,5 @@ return value; | ||
if ( | ||
property === UNSUBSCRIBE && | ||
!cache.isUnsubscribed && | ||
cache.getPath(target).length === 0 | ||
property === UNSUBSCRIBE | ||
&& !cache.isUnsubscribed | ||
&& cache.getPath(target).length === 0 | ||
) { | ||
@@ -106,5 +102,5 @@ cache.unsubscribe(); | ||
const value = isBuiltin.withMutableMethods(target) ? | ||
Reflect.get(target, property) : | ||
Reflect.get(target, property, receiver); | ||
const value = isBuiltinWithMutableMethods(target) | ||
? Reflect.get(target, property) | ||
: Reflect.get(target, property, receiver); | ||
@@ -127,4 +123,4 @@ return prepareValue(value, target, property); | ||
if ( | ||
isValid && | ||
cache.setProperty(reflectTarget, property, value, receiver, previous) | ||
isValid | ||
&& cache.setProperty(reflectTarget, property, value, receiver, previous) | ||
) { | ||
@@ -144,4 +140,4 @@ handleChangeOnTarget(target, property, target[property], previous); | ||
if ( | ||
validate(target, property, descriptor.value, previous) && | ||
cache.defineProperty(target, property, descriptor, previous) | ||
validate(target, property, descriptor.value, previous) | ||
&& cache.defineProperty(target, property, descriptor, previous) | ||
) { | ||
@@ -161,6 +157,7 @@ handleChangeOnTarget(target, property, descriptor.value, previous); | ||
const previous = Reflect.get(target, property); | ||
const isValid = validate(target, property, undefined, previous); | ||
if ( | ||
validate(target, property, undefined, previous) && | ||
cache.deleteProperty(target, property, previous) | ||
isValid | ||
&& cache.deleteProperty(target, property, previous) | ||
) { | ||
@@ -172,3 +169,3 @@ handleChangeOnTarget(target, property, undefined, previous); | ||
return false; | ||
return !isValid; | ||
}, | ||
@@ -184,5 +181,5 @@ | ||
if ( | ||
(details === false || | ||
(details !== true && !details.includes(target.name))) && | ||
SmartClone.isHandledType(thisProxyTarget) | ||
(details === false | ||
|| (details !== true && !details.includes(target.name))) | ||
&& SmartClone.isHandledType(thisProxyTarget) | ||
) { | ||
@@ -197,5 +194,5 @@ let applyPath = path.initial(cache.getPath(target)); | ||
smartClone.preferredThisArg(target, thisArg, thisProxyTarget), | ||
isHandledMethod ? | ||
argumentsList.map(argument => getProxyTarget(argument)) : | ||
argumentsList | ||
isHandledMethod | ||
? argumentsList.map(argument => getProxyTarget(argument)) | ||
: argumentsList, | ||
); | ||
@@ -218,10 +215,10 @@ | ||
args: argumentsList, | ||
result | ||
result, | ||
}; | ||
const changePath = smartClone.isCloning ? | ||
path.initial(applyPath) : | ||
applyPath; | ||
const property = smartClone.isCloning ? | ||
path.last(applyPath) : | ||
''; | ||
const changePath = smartClone.isCloning | ||
? path.initial(applyPath) | ||
: applyPath; | ||
const property = smartClone.isCloning | ||
? path.last(applyPath) | ||
: ''; | ||
@@ -236,4 +233,4 @@ if (validate(path.get(object, changePath), property, thisProxyTarget, previous, applyData)) { | ||
if ( | ||
(thisArg instanceof Map || thisArg instanceof Set) && | ||
isIterator(result) | ||
(thisArg instanceof Map || thisArg instanceof Set) | ||
&& isIterator(result) | ||
) { | ||
@@ -247,3 +244,3 @@ return wrapIterator(result, target, thisArg, applyPath, prepareValue); | ||
return Reflect.apply(target, thisArg, argumentsList); | ||
} | ||
}, | ||
}; | ||
@@ -255,3 +252,3 @@ | ||
if (hasOnValidate) { | ||
options.onValidate = options.onValidate.bind(proxy); | ||
options.onValidate = options.onValidate.bind(proxy); // eslint-disable-line unicorn/prefer-prototype-methods | ||
} | ||
@@ -265,2 +262,2 @@ | ||
module.exports = onChange; | ||
export default onChange; |
@@ -1,10 +0,8 @@ | ||
'use strict'; | ||
import path from './path.js'; | ||
const path = require('./path'); | ||
/** | ||
* @class Cache | ||
* @private | ||
*/ | ||
class Cache { | ||
@class Cache | ||
@private | ||
*/ | ||
export default class Cache { | ||
constructor(equals) { | ||
@@ -58,12 +56,15 @@ this._equals = equals; | ||
this._pathCache.set(target, path); | ||
const reflectTarget = target[proxyTarget]; | ||
const source = reflectTarget || target; | ||
let proxy = this._proxyCache.get(target); | ||
this._pathCache.set(source, path); | ||
let proxy = this._proxyCache.get(source); | ||
if (proxy === undefined) { | ||
proxy = target[proxyTarget] === undefined ? | ||
new Proxy(target, handler) : | ||
target; | ||
proxy = reflectTarget === undefined | ||
? new Proxy(target, handler) | ||
: target; | ||
this._proxyCache.set(target, proxy); | ||
this._proxyCache.set(source, proxy); | ||
} | ||
@@ -128,10 +129,10 @@ | ||
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; | ||
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; | ||
} | ||
@@ -142,5 +143,5 @@ | ||
return descriptor !== undefined && | ||
descriptor.configurable !== true && | ||
descriptor.writable !== true; | ||
return descriptor !== undefined | ||
&& descriptor.configurable !== true | ||
&& descriptor.writable !== true; | ||
} | ||
@@ -155,3 +156,1 @@ | ||
} | ||
module.exports = Cache; |
@@ -1,5 +0,3 @@ | ||
module.exports = { | ||
PATH_SEPARATOR: '.', | ||
TARGET: Symbol('target'), | ||
UNSUBSCRIBE: Symbol('unsubscribe') | ||
}; | ||
export const PATH_SEPARATOR = '.'; | ||
export const TARGET = Symbol('target'); | ||
export const UNSUBSCRIBE = Symbol('unsubscribe'); |
@@ -1,10 +0,8 @@ | ||
'use strict'; | ||
import isSymbol from './is-symbol.js'; | ||
const isSymbol = require('./is-symbol'); | ||
module.exports = (cache, options, property) => { | ||
return cache.isUnsubscribed || | ||
(options.ignoreSymbols && isSymbol(property)) || | ||
(options.ignoreUnderscores && property.charAt(0) === '_') || | ||
('ignoreKeys' in options && options.ignoreKeys.includes(property)); | ||
}; | ||
export default function ignoreProperty(cache, options, property) { | ||
return cache.isUnsubscribed | ||
|| (options.ignoreSymbols && isSymbol(property)) | ||
|| (options.ignoreUnderscores && property.charAt(0) === '_') | ||
|| ('ignoreKeys' in options && options.ignoreKeys.includes(property)); | ||
} |
@@ -1,3 +0,1 @@ | ||
'use strict'; | ||
module.exports = Array.isArray; | ||
export default Array.isArray; |
@@ -1,14 +0,12 @@ | ||
'use strict'; | ||
export function isBuiltinWithMutableMethods(value) { | ||
return value instanceof Date | ||
|| value instanceof Set | ||
|| value instanceof Map | ||
|| value instanceof WeakSet | ||
|| value instanceof WeakMap | ||
|| ArrayBuffer.isView(value); | ||
} | ||
const isBuiltin = { | ||
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 | ||
}; | ||
module.exports = isBuiltin; | ||
export function isBuiltinWithoutMutableMethods(value) { | ||
return (typeof value === 'object' ? value === null : typeof value !== 'function') || value instanceof RegExp; | ||
} |
@@ -1,3 +0,3 @@ | ||
'use strict'; | ||
module.exports = value => typeof value === 'object' && typeof value.next === 'function'; | ||
export default function isIterator(value) { | ||
return typeof value === 'object' && typeof value.next === 'function'; | ||
} |
@@ -1,3 +0,3 @@ | ||
'use strict'; | ||
module.exports = value => toString.call(value) === '[object Object]'; | ||
export default function isObject(value) { | ||
return toString.call(value) === '[object Object]'; | ||
} |
@@ -1,3 +0,3 @@ | ||
'use strict'; | ||
module.exports = value => typeof value === 'symbol'; | ||
export default function isSymbol(value) { | ||
return typeof value === 'symbol'; | ||
} |
@@ -1,8 +0,6 @@ | ||
'use strict'; | ||
import {PATH_SEPARATOR} from './constants.js'; | ||
import isArray from './is-array.js'; | ||
import isSymbol from './is-symbol.js'; | ||
const {PATH_SEPARATOR} = require('./constants'); | ||
const isArray = require('./is-array'); | ||
const isSymbol = require('./is-symbol'); | ||
module.exports = { | ||
const path = { | ||
after: (path, subPath) => { | ||
@@ -21,3 +19,3 @@ if (isArray(path)) { | ||
if (isArray(path)) { | ||
path = path.slice(); | ||
path = [...path]; | ||
@@ -81,3 +79,5 @@ if (key) { | ||
if (isArray(path)) { | ||
path.forEach(key => callback(key)); | ||
for (const key of path) { | ||
callback(key); | ||
} | ||
} else if (path !== '') { | ||
@@ -111,3 +111,5 @@ let position = 0; | ||
return object; | ||
} | ||
}, | ||
}; | ||
export default path; |
@@ -1,10 +0,8 @@ | ||
'use strict'; | ||
import {HANDLED_ARRAY_METHODS} from '../methods/array.js'; | ||
import CloneObject from './clone-object.js'; | ||
const CloneObject = require('./clone-object.js'); | ||
const {HANDLED_ARRAY_METHODS} = require('../methods/array.js'); | ||
module.exports = class CloneArray extends CloneObject { | ||
export default class CloneArray extends CloneObject { | ||
static isHandledMethod(name) { | ||
return HANDLED_ARRAY_METHODS.has(name); | ||
} | ||
}; | ||
} |
@@ -1,6 +0,4 @@ | ||
'use strict'; | ||
import CloneObject from './clone-object.js'; | ||
const CloneObject = require('./clone-object.js'); | ||
module.exports = class CloneDate extends CloneObject { | ||
export default class CloneDate extends CloneObject { | ||
undo(object) { | ||
@@ -13,2 +11,2 @@ object.setTime(this.clone.getTime()); | ||
} | ||
}; | ||
} |
@@ -1,7 +0,5 @@ | ||
'use strict'; | ||
import {HANDLED_MAP_METHODS} from '../methods/map.js'; | ||
import CloneObject from './clone-object.js'; | ||
const CloneObject = require('./clone-object.js'); | ||
const {HANDLED_MAP_METHODS} = require('../methods/map.js'); | ||
module.exports = class CloneMap extends CloneObject { | ||
export default class CloneMap extends CloneObject { | ||
static isHandledMethod(name) { | ||
@@ -22,2 +20,2 @@ return HANDLED_MAP_METHODS.has(name); | ||
} | ||
}; | ||
} |
@@ -1,12 +0,10 @@ | ||
'use strict'; | ||
import path from '../../path.js'; | ||
import isArray from '../../is-array.js'; | ||
import isObject from '../../is-object.js'; | ||
import {MUTABLE_ARRAY_METHODS} from '../methods/array.js'; | ||
import {MUTABLE_SET_METHODS} from '../methods/set.js'; | ||
import {MUTABLE_MAP_METHODS} from '../methods/map.js'; | ||
import {IMMUTABLE_OBJECT_METHODS} from '../methods/object.js'; | ||
const path = require('../../path.js'); | ||
const isArray = require('../../is-array.js'); | ||
const isObject = require('../../is-object.js'); | ||
const {MUTABLE_ARRAY_METHODS} = require('../methods/array.js'); | ||
const {MUTABLE_SET_METHODS} = require('../methods/set.js'); | ||
const {MUTABLE_MAP_METHODS} = require('../methods/map.js'); | ||
const {IMMUTABLE_OBJECT_METHODS} = require('../methods/object.js'); | ||
module.exports = class CloneObject { | ||
export default class CloneObject { | ||
constructor(value, path, argumentsList, hasOnValidate) { | ||
@@ -86,3 +84,3 @@ this._path = path; | ||
property, | ||
previous: value | ||
previous: value, | ||
}); | ||
@@ -110,6 +108,6 @@ } | ||
isChanged(value) { | ||
return this._onIsChanged === undefined ? | ||
this._isChanged : | ||
this._onIsChanged(this.clone, value); | ||
return this._onIsChanged === undefined | ||
? this._isChanged | ||
: this._onIsChanged(this.clone, value); | ||
} | ||
}; | ||
} |
@@ -1,7 +0,5 @@ | ||
'use strict'; | ||
import {HANDLED_SET_METHODS} from '../methods/set.js'; | ||
import CloneObject from './clone-object.js'; | ||
const CloneObject = require('./clone-object.js'); | ||
const {HANDLED_SET_METHODS} = require('../methods/set.js'); | ||
module.exports = class CloneSet extends CloneObject { | ||
export default class CloneSet extends CloneObject { | ||
static isHandledMethod(name) { | ||
@@ -12,12 +10,13 @@ return HANDLED_SET_METHODS.has(name); | ||
undo(object) { | ||
this.clone.forEach(value => { | ||
for (const value of this.clone) { | ||
object.add(value); | ||
}); | ||
object.forEach(value => { | ||
} | ||
for (const value of object) { | ||
if (!this.clone.has(value)) { | ||
object.delete(value); | ||
} | ||
}); | ||
} | ||
} | ||
}; | ||
} | ||
@@ -1,6 +0,4 @@ | ||
'use strict'; | ||
import CloneObject from './clone-object.js'; | ||
const CloneObject = require('./clone-object.js'); | ||
module.exports = class CloneWeakMap extends CloneObject { | ||
export default class CloneWeakMap extends CloneObject { | ||
constructor(value, path, argumentsList, hasOnValidate) { | ||
@@ -29,2 +27,2 @@ super(undefined, path, argumentsList, hasOnValidate); | ||
} | ||
}; | ||
} |
@@ -1,6 +0,4 @@ | ||
'use strict'; | ||
import CloneObject from './clone-object.js'; | ||
const CloneObject = require('./clone-object.js'); | ||
module.exports = class CloneWeakSet extends CloneObject { | ||
export default class CloneWeakSet extends CloneObject { | ||
constructor(value, path, argumentsList, hasOnValidate) { | ||
@@ -24,3 +22,3 @@ super(undefined, path, argumentsList, hasOnValidate); | ||
} | ||
}; | ||
} | ||
@@ -1,5 +0,3 @@ | ||
'use strict'; | ||
module.exports = (clone, value) => { | ||
export default function isDiffArrays(clone, value) { | ||
return clone.length !== value.length || clone.some((item, index) => value[index] !== item); | ||
}; | ||
} |
@@ -1,3 +0,3 @@ | ||
'use strict'; | ||
module.exports = () => true; | ||
export default function isDiffCertain() { | ||
return true; | ||
} |
@@ -1,4 +0,2 @@ | ||
'use strict'; | ||
module.exports = (clone, value) => { | ||
export default function isDiffMaps(clone, value) { | ||
if (clone.size !== value.size) { | ||
@@ -18,2 +16,2 @@ return true; | ||
return false; | ||
}; | ||
} |
@@ -1,4 +0,2 @@ | ||
'use strict'; | ||
module.exports = (clone, value) => { | ||
export default function isDiffSets(clone, value) { | ||
if (clone.size !== value.size) { | ||
@@ -15,2 +13,2 @@ return true; | ||
return false; | ||
}; | ||
} |
@@ -1,7 +0,5 @@ | ||
'use strict'; | ||
import isDiffCertain from '../diff/is-diff-certain.js'; | ||
import isDiffArrays from '../diff/is-diff-arrays.js'; | ||
import {IMMUTABLE_OBJECT_METHODS} from './object.js'; | ||
const isDiffCertain = require('../diff/is-diff-certain.js'); | ||
const isDiffArrays = require('../diff/is-diff-arrays.js'); | ||
const {IMMUTABLE_OBJECT_METHODS} = require('./object.js'); | ||
const IMMUTABLE_ARRAY_METHODS = new Set([ | ||
@@ -13,6 +11,6 @@ 'concat', | ||
'keys', | ||
'lastIndexOf' | ||
'lastIndexOf', | ||
]); | ||
const MUTABLE_ARRAY_METHODS = { | ||
export const MUTABLE_ARRAY_METHODS = { | ||
push: isDiffCertain, | ||
@@ -27,9 +25,9 @@ pop: isDiffCertain, | ||
flat: isDiffArrays, | ||
fill: isDiffArrays | ||
fill: isDiffArrays, | ||
}; | ||
const HANDLED_ARRAY_METHODS = new Set([...IMMUTABLE_OBJECT_METHODS] | ||
.concat([...IMMUTABLE_ARRAY_METHODS]) | ||
.concat(Object.keys(MUTABLE_ARRAY_METHODS))); | ||
module.exports = {MUTABLE_ARRAY_METHODS, HANDLED_ARRAY_METHODS}; | ||
export const HANDLED_ARRAY_METHODS = new Set([ | ||
...IMMUTABLE_OBJECT_METHODS, | ||
...IMMUTABLE_ARRAY_METHODS, | ||
...Object.keys(MUTABLE_ARRAY_METHODS), | ||
]); |
@@ -1,19 +0,17 @@ | ||
'use strict'; | ||
import isDiffMaps from '../diff/is-diff-maps.js'; | ||
import {IMMUTABLE_SET_METHODS, COLLECTION_ITERATOR_METHODS} from './set.js'; | ||
const {IMMUTABLE_SET_METHODS, COLLECTION_ITERATOR_METHODS} = require('./set.js'); | ||
const isDiffMaps = require('../diff/is-diff-maps.js'); | ||
const IMMUTABLE_MAP_METHODS = new Set([...IMMUTABLE_SET_METHODS, 'get']); | ||
const IMMUTABLE_MAP_METHODS = new Set([...IMMUTABLE_SET_METHODS].concat(['get'])); | ||
const MUTABLE_MAP_METHODS = { | ||
export const MUTABLE_MAP_METHODS = { | ||
set: isDiffMaps, | ||
clear: isDiffMaps, | ||
delete: isDiffMaps, | ||
forEach: isDiffMaps | ||
forEach: isDiffMaps, | ||
}; | ||
const HANDLED_MAP_METHODS = new Set([...IMMUTABLE_MAP_METHODS] | ||
.concat(Object.keys(MUTABLE_MAP_METHODS)) | ||
.concat(COLLECTION_ITERATOR_METHODS)); | ||
module.exports = {MUTABLE_MAP_METHODS, HANDLED_MAP_METHODS}; | ||
export const HANDLED_MAP_METHODS = new Set([ | ||
...IMMUTABLE_MAP_METHODS, | ||
...Object.keys(MUTABLE_MAP_METHODS), | ||
...COLLECTION_ITERATOR_METHODS, | ||
]); |
@@ -1,4 +0,2 @@ | ||
'use strict'; | ||
const IMMUTABLE_OBJECT_METHODS = new Set([ | ||
export const IMMUTABLE_OBJECT_METHODS = new Set([ | ||
'hasOwnProperty', | ||
@@ -9,5 +7,3 @@ 'isPrototypeOf', | ||
'toString', | ||
'valueOf' | ||
'valueOf', | ||
]); | ||
module.exports = {IMMUTABLE_OBJECT_METHODS}; |
@@ -1,32 +0,25 @@ | ||
'use strict'; | ||
import isDiffSets from '../diff/is-diff-sets.js'; | ||
const isDiffSets = require('../diff/is-diff-sets.js'); | ||
const COLLECTION_ITERATOR_METHODS = [ | ||
export const COLLECTION_ITERATOR_METHODS = [ | ||
'keys', | ||
'values', | ||
'entries' | ||
'entries', | ||
]; | ||
const IMMUTABLE_SET_METHODS = new Set([ | ||
export const IMMUTABLE_SET_METHODS = new Set([ | ||
'has', | ||
'toString' | ||
'toString', | ||
]); | ||
const MUTABLE_SET_METHODS = { | ||
export const MUTABLE_SET_METHODS = { | ||
add: isDiffSets, | ||
clear: isDiffSets, | ||
delete: isDiffSets, | ||
forEach: isDiffSets | ||
forEach: isDiffSets, | ||
}; | ||
const HANDLED_SET_METHODS = new Set([...IMMUTABLE_SET_METHODS] | ||
.concat(Object.keys(MUTABLE_SET_METHODS)) | ||
.concat(COLLECTION_ITERATOR_METHODS)); | ||
module.exports = { | ||
IMMUTABLE_SET_METHODS, | ||
MUTABLE_SET_METHODS, | ||
HANDLED_SET_METHODS, | ||
COLLECTION_ITERATOR_METHODS | ||
}; | ||
export const HANDLED_SET_METHODS = new Set([ | ||
...IMMUTABLE_SET_METHODS, | ||
...Object.keys(MUTABLE_SET_METHODS), | ||
...COLLECTION_ITERATOR_METHODS, | ||
]); |
@@ -1,15 +0,13 @@ | ||
'use strict'; | ||
import isArray from '../is-array.js'; | ||
import {isBuiltinWithMutableMethods} from '../is-builtin.js'; | ||
import isObject from '../is-object.js'; | ||
import CloneObject from './clone/clone-object.js'; | ||
import CloneArray from './clone/clone-array.js'; | ||
import CloneDate from './clone/clone-date.js'; | ||
import CloneSet from './clone/clone-set.js'; | ||
import CloneMap from './clone/clone-map.js'; | ||
import CloneWeakSet from './clone/clone-weakset.js'; | ||
import CloneWeakMap from './clone/clone-weakmap.js'; | ||
const isArray = require('../is-array.js'); | ||
const isBuiltin = require('../is-builtin.js'); | ||
const isObject = require('../is-object.js'); | ||
const CloneObject = require('./clone/clone-object.js'); | ||
const CloneArray = require('./clone/clone-array.js'); | ||
const CloneDate = require('./clone/clone-date.js'); | ||
const CloneSet = require('./clone/clone-set.js'); | ||
const CloneMap = require('./clone/clone-map.js'); | ||
const CloneWeakSet = require('./clone/clone-weakset.js'); | ||
const CloneWeakMap = require('./clone/clone-weakmap.js'); | ||
class SmartClone { | ||
export default class SmartClone { | ||
constructor(hasOnValidate) { | ||
@@ -21,5 +19,5 @@ this._stack = []; | ||
static isHandledType(value) { | ||
return isObject(value) || | ||
isArray(value) || | ||
isBuiltin.withMutableMethods(value); | ||
return isObject(value) | ||
|| isArray(value) | ||
|| isBuiltinWithMutableMethods(value); | ||
} | ||
@@ -44,7 +42,7 @@ | ||
return isBuiltin.withMutableMethods(target); | ||
return isBuiltinWithMutableMethods(target); | ||
} | ||
get isCloning() { | ||
return this._stack.length !== 0; | ||
return this._stack.length > 0; | ||
} | ||
@@ -100,3 +98,1 @@ | ||
} | ||
module.exports = SmartClone; |
@@ -1,7 +0,5 @@ | ||
'use strict'; | ||
import {TARGET} from './constants.js'; | ||
const {TARGET} = require('./constants'); | ||
// eslint-disable-next-line max-params | ||
module.exports = (iterator, target, thisArg, applyPath, prepareValue) => { | ||
export default function wrapIterator(iterator, target, thisArg, applyPath, prepareValue) { | ||
const originalNext = iterator.next; | ||
@@ -18,3 +16,3 @@ | ||
result.value[0], | ||
applyPath | ||
applyPath, | ||
); | ||
@@ -25,3 +23,3 @@ result.value[1] = prepareValue( | ||
result.value[0], | ||
applyPath | ||
applyPath, | ||
); | ||
@@ -43,3 +41,3 @@ } | ||
keyIterator.next().value, | ||
applyPath | ||
applyPath, | ||
); | ||
@@ -59,3 +57,3 @@ } | ||
result.value, | ||
applyPath | ||
applyPath, | ||
); | ||
@@ -69,2 +67,2 @@ } | ||
return iterator; | ||
}; | ||
} |
{ | ||
"name": "on-change", | ||
"version": "3.0.2", | ||
"version": "4.0.0", | ||
"description": "Watch an object or array for changes", | ||
@@ -13,8 +13,10 @@ "license": "MIT", | ||
}, | ||
"type": "module", | ||
"exports": "./index.js", | ||
"engines": { | ||
"node": ">=10" | ||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0" | ||
}, | ||
"scripts": { | ||
"test": "xo && ava && tsd", | ||
"bench": "karma start karma.bench.conf.js" | ||
"bench": "karma start karma.bench.conf.cjs" | ||
}, | ||
@@ -24,3 +26,3 @@ "files": [ | ||
"index.d.ts", | ||
"lib/" | ||
"lib" | ||
], | ||
@@ -44,9 +46,11 @@ "keywords": [ | ||
"devDependencies": { | ||
"ava": "^3.13.0", | ||
"display-value": "^1.8.1", | ||
"karma-webpack-bundle": "^0.5.3", | ||
"@typescript-eslint/parser": "^4.29.3", | ||
"ava": "^3.15.0", | ||
"display-value": "^1.8.5", | ||
"karma-webpack-bundle": "^1.2.0", | ||
"powerset": "0.0.1", | ||
"tsd": "^0.13.1", | ||
"xo": "^0.32.1" | ||
"tsd": "^0.17.0", | ||
"typescript": "^4.4.2", | ||
"xo": "^0.44.0" | ||
} | ||
} |
@@ -18,3 +18,3 @@ # on-change | ||
```js | ||
const onChange = require('on-change'); | ||
import onChange from 'on-change'; | ||
@@ -32,5 +32,5 @@ const object = { | ||
let i = 0; | ||
let index = 0; | ||
const watchedObject = onChange(object, function (path, value, previousValue, applyData) { | ||
console.log('Object changed:', ++i); | ||
console.log('Object changed:', ++index); | ||
console.log('this:', this); | ||
@@ -203,3 +203,3 @@ console.log('path:', path); | ||
<br/> | ||
<br> | ||
@@ -206,0 +206,0 @@ ### onChange.target(object) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Yes
38980
8
1086