packages/remote-context/src/actions/RemoteSetObjectAction.js
- /**
- * Copyright 2017 Moshe Simantov
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- import { trimArgumentsList } from 'remote-instance';
- import RemoteSetAction from './RemoteSetAction';
- import PropertyDescriptorAction from './PropertyDescriptorAction';
- import { setCachedGetter } from '../helpers/descriptors';
-
- const ARRAY_PROTOTYPE_CODE = 1;
-
- function toPropertiesArray(session, obj, mapFn) {
- return Object.keys(obj).reduce((arr, property) => {
- arr.push(session.dispatch(property), mapFn(obj[property], property));
- return arr;
- }, []);
- }
-
- function isValidPropertiesArray(propsArr) {
- return Array.isArray(propsArr) && propsArr.length % 2 === 0;
- }
-
- function fromPropertiesArray(session, propsArr, forEachFn) {
- for (let i = 0; i < propsArr.length; i += 2) {
- const property = session.fetch(propsArr[i]);
- const value = session.fetch(propsArr[i + 1]);
-
- forEachFn(value, property);
- }
- }
-
- export default class RemoteSetObjectAction extends RemoteSetAction {
- static fromSnapshot(session, reference, snapshot) {
- const obj = snapshot.value;
- if (obj === null) return null;
-
- // Fetch order should be the same: first prototype then the descriptors
- const proto = session.dispatch(this.getPrototype(snapshot));
-
- const descriptors = toPropertiesArray(
- session,
- snapshot.ownPropertyDescriptors,
- desc => PropertyDescriptorAction.fromPropertyDescriptor(session, desc)
- );
-
- const isExtensible = Object.isExtensible(obj);
-
- const cachedGetters = toPropertiesArray(
- session,
- snapshot.cachedGetters,
- cachedValue => session.dispatch(cachedValue)
- );
-
- return new this(reference, descriptors, proto, isExtensible, cachedGetters);
- }
-
- static getPrototype(snapshot) {
- const proto = snapshot.prototype;
-
- if (proto === Object.prototype) {
- return null;
- }
-
- if (proto === Array.prototype) {
- return ARRAY_PROTOTYPE_CODE;
- }
-
- return proto;
- }
-
- constructor(
- reference,
- descriptors = [],
- proto = null,
- isExtensible = true,
- cachedGetters = []
- ) {
- if (!isValidPropertiesArray(descriptors)) {
- throw new TypeError(`Invalid descriptors: ${descriptors}`);
- }
-
- if (typeof proto !== 'object') {
- if (proto !== ARRAY_PROTOTYPE_CODE) {
- throw new TypeError('Object prototype may only be an Object or null');
- }
- }
-
- if (typeof isExtensible !== 'boolean') {
- throw new TypeError('Expect "isExtensible" to be boolean');
- }
-
- if (!isValidPropertiesArray(cachedGetters)) {
- throw new TypeError(`Invalid "cachedGetters" param: ${cachedGetters}`);
- }
-
- super(reference);
-
- this.descriptors = descriptors;
- this.proto = proto;
- this.isExtensible = isExtensible;
- this.cachedGetters = cachedGetters;
- }
-
- // eslint-disable-next-line class-methods-use-this
- createInstance() {
- if (this.proto === ARRAY_PROTOTYPE_CODE) {
- return [];
- }
-
- return {};
- }
-
- populateInstance(session, instance) {
- // Fetch order the same as dispatch order (ie. first prototype then descriptors)
- // @see {@link RemoteSetObjectAction.fromValue}
-
- const proto = session.fetch(this.proto);
- if (proto !== null && typeof proto === 'object') {
- Object.setPrototypeOf(instance, proto);
- }
-
- fromPropertiesArray(session, this.descriptors, (descriptor, property) => {
- Object.defineProperty(instance, property, descriptor);
- });
-
- fromPropertiesArray(session, this.cachedGetters, (value, property) => {
- setCachedGetter(instance, property, value);
- });
- }
-
- toArgumentsList() {
- const argumentsList = [
- this.reference,
- this.descriptors,
- this.proto,
- this.isExtensible,
- this.cachedGetters,
- ];
- const defaults = [undefined, [], null, true, []];
-
- return trimArgumentsList(argumentsList, defaults);
- }
- }
-
- RemoteSetAction.types.object = RemoteSetObjectAction;