Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
@skava/modules / ___dist / state-tree / state-tree-modeling.js
Size: Mime:
import { types } from 'xmobx/mobx-state-tree'
// import { Typed } from 'modules/modeler'
import { forOwn } from 'chain'
// import {
//   transformWhereObj,
//   curry,
//   overStaticMethods,
//   getStaticMethods,
//   prop,
//   overArgs,
//   before,
// } from 'modules/deps'
import {
  toEmpty,
  isNumberish,
  isMap,
  toKindOf,
  isPrimitive,
  isFrozen,
  isObj,
  isArray,
  isFunction,
  isNumber,
  isBoolean,
  isString,
  toBoolean,
  toString,
  toNumber,
  toArray,
  toObject,
} from 'exotic'
import 'modules/thisless/statetree'
import { selfless, thisless } from 'modules/thisless'
import UniqueDictionary from './UniqueDictionary'
import { bindToSelf } from './deps/bindToSelf'
import { toEmptyRecursive } from './deps/empty'
import {
  toMobArray,
  toMobArrayOfAny,
  toMobModel,
  toMobArrayModel,
  toMobString,
  toMobBoolean,
  toMobNumber,
  toMobFrozen,
  toMobDate,
  toMobSet,
  toMobIdentity,
  toMobLate,
  toMobMap,
  looseyType,
} from './state-tree-types'

// const spread = Typed.spread(Object, Array, Function, Number, String, Boolean)
// const {
//   isObj,
//   isArray,
//   isFunction,
//   isNumber,
//   isBoolean,
//   isString,
//   toBoolean,
//   toString,
//   toNumber,
//   toArray,
//   toObject,
// } = spread

const fromNativeToMobx = (x, name) => _toMobx(toEmpty(x), name)

const stringify = x => JSON.stringify(x, null, 2)

// debugging unique dictionary with all types we ever use in all places
const modelDictionary = new UniqueDictionary()

/**
 * @private
 * @param {*} x any type schema
 * @param {string} [modelName=undefined] name of this type as-a-model
 * @return {StateTreeModel}
 */
function _toMobx(x, modelName = undefined) {
  let typed = -100

  if (x && x.isType) {
return x
}

  if (modelName === undefined) {
    console.log('did not pass in a name', x)
    modelName =
      typeof x === 'object' ? Object.keys(x).join('_') : stringify(x)
  }

  /**
   * @param {*} tapped
   * @example
   *    addToDictionary(...)
   *    //=> 'UserModel [object]': {tapped: MobxType, value: OriginalValue}
   */
  const addToDictionary = tapped => {
    modelDictionary.add(modelName + ' [' + toKindOf(x) + ']', {
      // mob: _toMobx(toEmpty(x), modelName),
      tapped,
      value: x,
      // kind: x,
      // name: modelName,
    })
  }

  /**
   * @return {StateTree|undefined} used to use returns for dictionary
   */
  const tapWrap = () => {
    /**
     * @TODO @FIXME @james
     * @NOTE this currently will coerce BuiltInNativeFunctions -> mobx
     */
    if (isFunction(x)) {
      return fromNativeToMobx(x, modelName)
    }
    if (isNumber(x)) {
      return toMobNumber(x, modelName)
    }
    if (isString(x)) {
      return toMobString(x, modelName)
    }
    if (isBoolean(x)) {
      return toMobBoolean(x, modelName)
    }
    if (isObj(x)) {
      if (isFrozen(x)) {
        return toMobFrozen(x, modelName)
      }
      if (isMap(x)) {
        return toMobMap(x, modelName)
      }

      /**
       * @NOTE opinionated
       * assumes all values in array are the same
       * because this simplifies things
       */
      if (isArray(x)) {
        const ArrayItemModel = _toMobx(x[0], modelName + 'ArrayItem')
        typed = toMobArray(ArrayItemModel, modelName)
        return undefined
      } else {
        const model = {}
        forOwn(x, (value, key) => {
          model[key] = _toMobx(value, key)
        })

        typed = toMobModel(model, modelName)
        return undefined
      }
    } else {
      throw new Error('what else?' + stringify({ x, modelName }))
      return undefined
    }
  }

  const tapped = tapWrap()
  addToDictionary(tapped)

  if (tapped === undefined) {
    if (typed === -100) {
      const last = modelDictionary.last()
      const msg = 'invalid type [' + modelName + '] ' + stringify(last) + stringify(x)
      const error = new Error(msg)
      throw error
      return types.late(() => {
        console.log({ error, last })
        throw error
      })
    }
    return typed
  } else {
    return tapped
  }
}

/**
 * @param {Schema} x ExoticSchema to transform
 * @return {Array} MobxModel, EmptyState, SchemaDataTransformer
 *
 * @TODO
 * const Transformer = transformWhereObj(x)
 */
const toMobx = (x, name) => {
  const Mobx = _toMobx(x, name)
  const Empty = toEmptyRecursive(x)

  // @TODO should move this back with thisless
  const creates = Object.getPrototypeOf(Mobx).create

  // @TODO need to document exposed dictionary for debug
  // console.log(modelDictionary)
  return [Mobx, Empty, modelDictionary]
}

// @NOTE currently unused
// @Typed
// class StateTreeType {
//   // static coercers = [
//   //   // recursive
//   //   [Object, types.model],
//   //   // [Object.Property, types.model],
//   //   [Array, types.array],
//   //   // simple
//   //   [Function, types.frozen],
//   //   [Number, types.number],
//   //   [String, types.string],
//   //   [Boolean, types.boolean],
//   // ]
// }

/**
 * @TODO - want to use this to generate a model from fixture json
 */
const shapeToMobx = (SchemaShape, name = undefined) => {
  const nameFromKeys = name || Object.keys(SchemaShape).join('_')
  const [Model, Empty] = toMobx(SchemaShape, nameFromKeys)
  // console.log({ Model })
  return Model
}

const OptionalArray = x => types.maybe(types.array(types.maybe(x)))

export { OptionalArray, toMobx, toMobx as toStateTree, shapeToMobx }
// --- export default exports