override: (scope) => _createResolver([scope].concat(scopes), prefixes),
};
return new Proxy(cache, {
+ /**
+ * A trap for getting property values.
+ */
get(target, prop) {
return _cached(target, prop,
() => _resolveWithPrefixes(prop, prefixes, scopes));
},
- ownKeys(target) {
- return getKeysFromAllScopes(target);
- },
-
+ /**
+ * A trap for Object.getOwnPropertyDescriptor.
+ * Also used by Object.hasOwnProperty.
+ */
getOwnPropertyDescriptor(target, 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) {
scopes[0][prop] = value;
return delete target[prop];
override: (scope) => _attachContext(proxy.override(scope), context, subProxy)
};
return new Proxy(cache, {
+ /**
+ * A trap for getting property values.
+ */
get(target, prop, receiver) {
return _cached(target, prop,
() => _resolveWithContext(target, prop, receiver));
},
- ownKeys() {
- return Reflect.ownKeys(proxy);
+ /**
+ * A trap for Object.getOwnPropertyDescriptor.
+ * Also used by Object.hasOwnProperty.
+ */
+ getOwnPropertyDescriptor(target, prop) {
+ return Reflect.getOwnPropertyDescriptor(proxy, prop);
},
- getOwnPropertyDescriptor(target, prop) {
- return Reflect.getOwnPropertyDescriptor(proxy._scopes[0], 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() {
+ return Reflect.ownKeys(proxy);
},
+ /**
+ * A trap for setting property values.
+ */
set(target, prop, value) {
proxy[prop] = value;
return delete target[prop];
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() {
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() {
it('should default to true', function() {
const options = {