javiercejudo/modelico

View on GitHub
src/types/EnumMap.js

Summary

Maintainability
A
1 hr
Test Coverage
import {reviverOrAsIs, isFunction} from '../U'
import AbstractMap, {set, of, metadata} from './AbstractMap'

const stringifyReducer = (acc, pair) => {
  acc[pair[0].toJSON()] = pair[1]

  return acc
}

const parseMapper = (keyReviver, valueReviver, obj, path) => enumerator => {
  const key = keyReviver('', enumerator, path)
  const val = valueReviver('', obj[enumerator], path.concat(enumerator))

  return [key, val]
}

const reviverFactory = (keyMetadata, valueMetadata) => (k, v, path = []) => {
  if (k !== '') {
    return v
  }

  const keyReviver = reviverOrAsIs(
    isFunction(keyMetadata) ? keyMetadata(v, path) : keyMetadata
  )

  const valueReviver = reviverOrAsIs(
    isFunction(valueMetadata) ? valueMetadata(v, path) : valueMetadata
  )

  if (v === null) {
    return new EnumMap(null)
  }

  return new EnumMap(
    new Map(Object.keys(v).map(parseMapper(keyReviver, valueReviver, v, path)))
  )
}

let EMPTY_ENUM_MAP

class EnumMap extends AbstractMap {
  constructor(innerMap) {
    super(EnumMap, innerMap, EMPTY_ENUM_MAP)

    if (!EMPTY_ENUM_MAP && this.size === 0) {
      EMPTY_ENUM_MAP = this
    }

    Object.freeze(this)
  }

  get [Symbol.toStringTag]() {
    return 'ModelicoEnumMap'
  }

  set(enumerator, value) {
    return set(this, EnumMap, enumerator, value)
  }

  toJSON() {
    return [...this].reduce(stringifyReducer, {})
  }

  static fromMap(map) {
    return new EnumMap(map)
  }

  static fromArray(pairs) {
    return EnumMap.fromMap(new Map(pairs))
  }

  static of(...args) {
    return of(EnumMap, args)
  }

  static metadata(keyMetadata, valueMetadata) {
    return metadata(EnumMap)(reviverFactory)(keyMetadata)(valueMetadata)
  }

  static EMPTY() {
    return EMPTY_ENUM_MAP || EnumMap.of()
  }
}

EnumMap.displayName = 'EnumMap'

export default Object.freeze(EnumMap)