mirror of
https://github.com/chartjs/Chart.js.git
synced 2024-10-06 12:19:08 +02:00
Add support for common object methods to Proxies (#8452)
This commit is contained in:
parent
ba99c4185c
commit
5411be10a0
@ -15,19 +15,46 @@ export function _createResolver(scopes, prefixes = ['']) {
|
|||||||
override: (scope) => _createResolver([scope].concat(scopes), prefixes),
|
override: (scope) => _createResolver([scope].concat(scopes), prefixes),
|
||||||
};
|
};
|
||||||
return new Proxy(cache, {
|
return new Proxy(cache, {
|
||||||
|
/**
|
||||||
|
* A trap for getting property values.
|
||||||
|
*/
|
||||||
get(target, prop) {
|
get(target, prop) {
|
||||||
return _cached(target, prop,
|
return _cached(target, prop,
|
||||||
() => _resolveWithPrefixes(prop, prefixes, scopes));
|
() => _resolveWithPrefixes(prop, prefixes, scopes));
|
||||||
},
|
},
|
||||||
|
|
||||||
ownKeys(target) {
|
/**
|
||||||
return getKeysFromAllScopes(target);
|
* A trap for Object.getOwnPropertyDescriptor.
|
||||||
},
|
* Also used by Object.hasOwnProperty.
|
||||||
|
*/
|
||||||
getOwnPropertyDescriptor(target, prop) {
|
getOwnPropertyDescriptor(target, prop) {
|
||||||
return Reflect.getOwnPropertyDescriptor(target._scopes[0], prop);
|
return Reflect.getOwnPropertyDescriptor(target._scopes[0], prop);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trap for Object.getPrototypeOf.
|
||||||
|
*/
|
||||||
|
getPrototypeOf() {
|
||||||
|
return Reflect.getPrototypeOf(scopes[0]);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trap for the in operator.
|
||||||
|
*/
|
||||||
|
has(target, prop) {
|
||||||
|
return getKeysFromAllScopes(target).includes(prop);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols.
|
||||||
|
*/
|
||||||
|
ownKeys(target) {
|
||||||
|
return getKeysFromAllScopes(target);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trap for setting property values.
|
||||||
|
*/
|
||||||
set(target, prop, value) {
|
set(target, prop, value) {
|
||||||
scopes[0][prop] = value;
|
scopes[0][prop] = value;
|
||||||
return delete target[prop];
|
return delete target[prop];
|
||||||
@ -54,19 +81,46 @@ export function _attachContext(proxy, context, subProxy) {
|
|||||||
override: (scope) => _attachContext(proxy.override(scope), context, subProxy)
|
override: (scope) => _attachContext(proxy.override(scope), context, subProxy)
|
||||||
};
|
};
|
||||||
return new Proxy(cache, {
|
return new Proxy(cache, {
|
||||||
|
/**
|
||||||
|
* A trap for getting property values.
|
||||||
|
*/
|
||||||
get(target, prop, receiver) {
|
get(target, prop, receiver) {
|
||||||
return _cached(target, prop,
|
return _cached(target, prop,
|
||||||
() => _resolveWithContext(target, prop, receiver));
|
() => _resolveWithContext(target, prop, receiver));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trap for Object.getOwnPropertyDescriptor.
|
||||||
|
* Also used by Object.hasOwnProperty.
|
||||||
|
*/
|
||||||
|
getOwnPropertyDescriptor(target, prop) {
|
||||||
|
return Reflect.getOwnPropertyDescriptor(proxy, prop);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trap for Object.getPrototypeOf.
|
||||||
|
*/
|
||||||
|
getPrototypeOf() {
|
||||||
|
return Reflect.getPrototypeOf(proxy);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trap for the in operator.
|
||||||
|
*/
|
||||||
|
has(target, prop) {
|
||||||
|
return Reflect.has(proxy, prop);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols.
|
||||||
|
*/
|
||||||
ownKeys() {
|
ownKeys() {
|
||||||
return Reflect.ownKeys(proxy);
|
return Reflect.ownKeys(proxy);
|
||||||
},
|
},
|
||||||
|
|
||||||
getOwnPropertyDescriptor(target, prop) {
|
/**
|
||||||
return Reflect.getOwnPropertyDescriptor(proxy._scopes[0], prop);
|
* A trap for setting property values.
|
||||||
},
|
*/
|
||||||
|
|
||||||
set(target, prop, value) {
|
set(target, prop, value) {
|
||||||
proxy[prop] = value;
|
proxy[prop] = value;
|
||||||
return delete target[prop];
|
return delete target[prop];
|
||||||
|
@ -88,6 +88,41 @@ describe('Chart.helpers.config', function() {
|
|||||||
option3: 'defaults3'
|
option3: 'defaults3'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should support common object methods', function() {
|
||||||
|
const defaults = {
|
||||||
|
option1: 'defaults'
|
||||||
|
};
|
||||||
|
class Options {
|
||||||
|
constructor() {
|
||||||
|
this.option2 = 'options';
|
||||||
|
}
|
||||||
|
get getter() {
|
||||||
|
return 'options getter';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const options = new Options();
|
||||||
|
|
||||||
|
const resolver = _createResolver([options, defaults]);
|
||||||
|
|
||||||
|
expect(Object.prototype.hasOwnProperty.call(resolver, 'option2')).toBeTrue();
|
||||||
|
|
||||||
|
expect(Object.prototype.hasOwnProperty.call(resolver, 'option1')).toBeFalse();
|
||||||
|
expect(Object.prototype.hasOwnProperty.call(resolver, 'getter')).toBeFalse();
|
||||||
|
expect(Object.prototype.hasOwnProperty.call(resolver, 'nonexistent')).toBeFalse();
|
||||||
|
|
||||||
|
expect(Object.keys(resolver)).toEqual(['option2']);
|
||||||
|
expect(Object.getOwnPropertyNames(resolver)).toEqual(['option2', 'option1']);
|
||||||
|
|
||||||
|
expect('option2' in resolver).toBeTrue();
|
||||||
|
expect('option1' in resolver).toBeTrue();
|
||||||
|
expect('getter' in resolver).toBeFalse();
|
||||||
|
expect('nonexistent' in resolver).toBeFalse();
|
||||||
|
|
||||||
|
expect(resolver instanceof Options).toBeTrue();
|
||||||
|
|
||||||
|
expect(resolver.getter).toEqual('options getter');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('_attachContext', function() {
|
describe('_attachContext', function() {
|
||||||
@ -249,6 +284,41 @@ describe('Chart.helpers.config', function() {
|
|||||||
expect(opts.fn).toEqual(1);
|
expect(opts.fn).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should support common object methods', function() {
|
||||||
|
const defaults = {
|
||||||
|
option1: 'defaults'
|
||||||
|
};
|
||||||
|
class Options {
|
||||||
|
constructor() {
|
||||||
|
this.option2 = () => 'options';
|
||||||
|
}
|
||||||
|
get getter() {
|
||||||
|
return 'options getter';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const options = new Options();
|
||||||
|
const resolver = _createResolver([options, defaults]);
|
||||||
|
const opts = _attachContext(resolver, {index: 1});
|
||||||
|
|
||||||
|
expect(Object.prototype.hasOwnProperty.call(opts, 'option2')).toBeTrue();
|
||||||
|
|
||||||
|
expect(Object.prototype.hasOwnProperty.call(opts, 'option1')).toBeFalse();
|
||||||
|
expect(Object.prototype.hasOwnProperty.call(opts, 'getter')).toBeFalse();
|
||||||
|
expect(Object.prototype.hasOwnProperty.call(opts, 'nonexistent')).toBeFalse();
|
||||||
|
|
||||||
|
expect(Object.keys(opts)).toEqual(['option2']);
|
||||||
|
expect(Object.getOwnPropertyNames(opts)).toEqual(['option2', 'option1']);
|
||||||
|
|
||||||
|
expect('option2' in opts).toBeTrue();
|
||||||
|
expect('option1' in opts).toBeTrue();
|
||||||
|
expect('getter' in opts).toBeFalse();
|
||||||
|
expect('nonexistent' in opts).toBeFalse();
|
||||||
|
|
||||||
|
expect(opts instanceof Options).toBeTrue();
|
||||||
|
|
||||||
|
expect(opts.getter).toEqual('options getter');
|
||||||
|
});
|
||||||
|
|
||||||
describe('_indexable and _scriptable', function() {
|
describe('_indexable and _scriptable', function() {
|
||||||
it('should default to true', function() {
|
it('should default to true', function() {
|
||||||
const options = {
|
const options = {
|
||||||
|
Loading…
Reference in New Issue
Block a user