Manual Reference Source Test

src/utilities/factories/HelperFactory.js

import Client from '../../Client';
import { flattenJsonApi, getJsonApiType, isJsonApiFormat } from '../JsonApiUtility';
import { stringToCamel } from '../FormatUtility';

/**
 * Factory to convert responses to classes (deserialization)
 */
class HelperFactory {
  /** @type {Object} - A hashmap from object names to classes */
  static get map() { return this._map; }

  /** @type {Object} - A hashmap from object names to classes */
  static set map(_map) { this._map = _map; }


  /**
   * Convert the json to the appropriate class (deserialize)
   *
   * @param  {Object} json      - The json from an api call (in JSON)
   * @param  {String} [type]    - The type to convert the object to (otherwise use json's data type)
   * @param  {Object} [meta]    - Any object to be passed through to assign meta to array if necessary
   * @return {Promise<Object>}  - Returns an object with the appropriate type
   */
  async get(json, type = undefined, meta = {}) {
    let obj;

    if (json && Array.isArray(json.data) && json.data.length === 0) {
      obj = [];
    } else if (type) {
      obj = await this.getClass(json, type);
    } else if (isJsonApiFormat(json)) {
      if (json.meta) {
        Object.keys(json.meta).forEach((key) => {
          json.meta[stringToCamel(key)] = json.meta[key];
          meta[stringToCamel(key)] = json.meta[key];
          delete json.meta[key];
        });

        json.data.meta = json.meta;
      }
      if (json.included) {
        Promise.all(json.included.map(d => this.getClass(d, type)));
      }
      if (Array.isArray(json.data)) {
        obj = await Promise.all(json.data.map(d => this.getClass(d, type)));
        Object.defineProperty(obj, 'meta', { enumerable: false, writable: true });
        obj.meta = json.meta;
      } else {
        obj = await this.getClass(json.data, type);
      }
    }
    obj = obj || json;
    return new Promise(resolve => resolve(obj));
  }

  /**
   * Converts an object to a class if it is mapped
   *
   * @param  {Object} json    - JSON to convert to a class
   * @param  {String} [type]  - The type to override the json.type
   * @return {Class}          - Returns a class
   */
  async getClass(json, type = undefined) {
    const flatJson = flattenJsonApi(json);
    const storage = Client.instance.storageUtility;
    const t = type || getJsonApiType(flatJson);
    let obj = {};
    if (storage.has(t, { id: flatJson.id })) {
      obj = new HelperFactory.map[t](flatJson);
      obj = await storage.get(t, { id: flatJson.id });
    } else if (HelperFactory.map[t]) {
      obj = new HelperFactory.map[t](flatJson);
      storage.set(t, obj, { id: obj.id });
    } else {
      obj = flatJson;
    }
    return obj;
  }
}

/** @type {HelperFactory} - An instance of HelperFactory */
const helperFactory = new HelperFactory();

export { HelperFactory, helperFactory };