All files keyblade.js

100% Statements 20/20
100% Branches 14/14
100% Functions 3/3
100% Lines 20/20
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 881x   1x                                           33x         33x   33x   50x 50x 23x       27x 5x     22x 22x 21x 1x   20x       22x                       20x   20x     1x                               31x    
module.exports.keyblade = keyblade
 
const UndefinedKeyError = module.exports.UndefinedKeyError = require('./UndefinedKeyError')
 
/**
 * Protects the given object by wrapping it in a Proxy.
 *
 * @param  {object} obj
 * The object to wrap.
 *
 * @param  {(string) => string} opts.message
 * Optional function used to construct the error message.
 * Will get the key passed as the only argument.
 *
 * @param {string[]} ignore
 * Fields to ignore.
 *
 * @param {bool|Function(message: string, key: string)}
 * If specified, and is a function, is invoked before throwing.
 * If specified, and is truthy, `console.error` before throwing.
 *
 * @return {Proxy<object>}
 */
function keyblade (obj, opts) {
  opts = Object.assign({
    message: _defaultMessage,
    logBeforeThrow: true,
    ignore: []
  }, opts)
  opts.ignore = (opts.ignore && Array.isArray(opts.ignore)) ? opts.ignore : []
 
  return new Proxy(obj, {
    get (target, propKey, receiver) {
      const useGetter = Reflect.has(target, propKey, receiver) || _isReserved(propKey, opts.ignore)
      if (useGetter) {
        return Reflect.get(target, propKey, receiver)
      }
 
      // Leave symbols alone.
      if (typeof propKey === 'symbol') {
        return Reflect.get(target, propKey, receiver)
      }
 
      const message = opts.message(propKey)
      if (opts.logBeforeThrow) {
        if (typeof opts.logBeforeThrow === 'function') {
          opts.logBeforeThrow(message, propKey)
        } else {
          console.error(message)
        }
      }
 
      throw new UndefinedKeyError(message)
    }
  })
}
 
/**
 * Default message creator.
 *
 * @param  {string} key
 * @return {string}
 */
function _defaultMessage (key) {
  key = String(key)
 
  return `The key '${key}' does not exist on the object.`
}
 
const RESERVED_PROPS = [
  'toJSON',
  'toString',
  'inspect',
  '__esModule'
]
 
/**
 * Determines if the key name is a reserved key.
 *
 * @param  {string}  name
 * @param  {string[]}  additionalFieldsToIgnore
 * @return {Boolean}
 * @api private
 */
function _isReserved (name, additionalFieldsToIgnore) {
  return [].concat(RESERVED_PROPS, additionalFieldsToIgnore).includes(name)
}