bowheart/react-zedux

View on GitHub
src/utils/general.js

Summary

Maintainability
A
30 mins
Test Coverage
import { StoreApi } from '../api/StoreApi'


export function aliasProps(fieldsToPropsMap, store) {
  const props = {}

  for (let key in fieldsToPropsMap) {
    props[fieldsToPropsMap[key]] = store[key]
  }

  return props
}


export function assertApiIsValid(api) {
  if (isObservable(api.store)) return true

  const constructorName = api.constructor.name

  throw new TypeError(
    `React Zedux Error - new ${constructorName}() - `
    + 'instantiated api must have a visible "store" property '
    + 'whose value is an observable (e.g. a Zedux store).'
  )
}


export function assertIsPlainObject(thing, context) {
  if (isPlainObject(thing)) return true

  throw new TypeError(
    `React Zedux Error - ${context} - `
    + 'Expected a plain object.'
  )
}


/**
  Retrieve the displayName of a component

  Returns 'Unknown' if no displayName is found
*/
export const getDisplayName = Component =>
  Component.displayName
    || Component.name
    || 'Unknown'


export function getProvidedValue(Api) {
  if (!isStoreApi(Api)) return Api

  const api = new Api()

  assertApiIsValid(api)

  return api._bindControls(Api)
}


export function isObservable(thing) {
  return thing && typeof thing.subscribe === 'function'
}


/**
  Checks whether thing is a plain old object.

  The object may originate from another realm or have its prototype
  explicitly set to Object.prototype, but it may not have a null
  prototype or prototype chain more than 1 layer deep.
*/
export function isPlainObject(thing) {
  if (typeof thing !== 'object' || !thing) return false

  let prototype = Object.getPrototypeOf(thing)
  if (!prototype) return false // it was created with Object.create(null)

  // If the prototype chain is exactly 1 layer deep, it's a normal object
  return Object.getPrototypeOf(prototype) === null
}


export function isStoreApi(Thing) {
  return Thing && Thing.prototype instanceof StoreApi
}


export function mapProps(mapper, store) {
  const props = mapper(store)

  assertIsPlainObject(props, 'mapStoreToProps')

  return props
}


export function pluckProps(propsToPluck, store) {
  const props = {}

  for (let key of propsToPluck) props[key] = store[key]

  return props
}


export function resolveProps(mapper, store, method) {
  if (!mapper) return store

  if (typeof mapper === 'string') return { [mapper]: store }

  if (Array.isArray(mapper)) return pluckProps(mapper, store)

  if (typeof mapper === 'function') return mapProps(mapper, store)

  if (isPlainObject(mapper)) return aliasProps(mapper, store)

  throw new TypeError(
    `React Zedux Error - Context.${method}() - `
    + 'invalid mapStoreToProps parameter. mapStoreToProps may be a string, '
    + 'an array, a plain object, or a function that returns an object. '
    + `Received ${typeof mapper}.`
  )
}


export function wrapStore(store, state) {
  return Object.create(store, {
    state: { value: state, enumerable: true }
  })
}