You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							197 lines
						
					
					
						
							4.6 KiB
						
					
					
				
			
		
		
	
	
							197 lines
						
					
					
						
							4.6 KiB
						
					
					
				'use strict' | 
						|
 | 
						|
class FiggyPudding { | 
						|
  constructor (specs, opts, providers) { | 
						|
    this.__specs = specs || {} | 
						|
    Object.keys(this.__specs).forEach(alias => { | 
						|
      if (typeof this.__specs[alias] === 'string') { | 
						|
        const key = this.__specs[alias] | 
						|
        const realSpec = this.__specs[key] | 
						|
        if (realSpec) { | 
						|
          const aliasArr = realSpec.aliases || [] | 
						|
          aliasArr.push(alias, key) | 
						|
          realSpec.aliases = [...(new Set(aliasArr))] | 
						|
          this.__specs[alias] = realSpec | 
						|
        } else { | 
						|
          throw new Error(`Alias refers to invalid key: ${key} -> ${alias}`) | 
						|
        } | 
						|
      } | 
						|
    }) | 
						|
    this.__opts = opts || {} | 
						|
    this.__providers = reverse((providers).filter( | 
						|
      x => x != null && typeof x === 'object' | 
						|
    )) | 
						|
    this.__isFiggyPudding = true | 
						|
  } | 
						|
  get (key) { | 
						|
    return pudGet(this, key, true) | 
						|
  } | 
						|
  get [Symbol.toStringTag] () { return 'FiggyPudding' } | 
						|
  forEach (fn, thisArg = this) { | 
						|
    for (let [key, value] of this.entries()) { | 
						|
      fn.call(thisArg, value, key, this) | 
						|
    } | 
						|
  } | 
						|
  toJSON () { | 
						|
    const obj = {} | 
						|
    this.forEach((val, key) => { | 
						|
      obj[key] = val | 
						|
    }) | 
						|
    return obj | 
						|
  } | 
						|
  * entries (_matcher) { | 
						|
    for (let key of Object.keys(this.__specs)) { | 
						|
      yield [key, this.get(key)] | 
						|
    } | 
						|
    const matcher = _matcher || this.__opts.other | 
						|
    if (matcher) { | 
						|
      const seen = new Set() | 
						|
      for (let p of this.__providers) { | 
						|
        const iter = p.entries ? p.entries(matcher) : entries(p) | 
						|
        for (let [key, val] of iter) { | 
						|
          if (matcher(key) && !seen.has(key)) { | 
						|
            seen.add(key) | 
						|
            yield [key, val] | 
						|
          } | 
						|
        } | 
						|
      } | 
						|
    } | 
						|
  } | 
						|
  * [Symbol.iterator] () { | 
						|
    for (let [key, value] of this.entries()) { | 
						|
      yield [key, value] | 
						|
    } | 
						|
  } | 
						|
  * keys () { | 
						|
    for (let [key] of this.entries()) { | 
						|
      yield key | 
						|
    } | 
						|
  } | 
						|
  * values () { | 
						|
    for (let [, value] of this.entries()) { | 
						|
      yield value | 
						|
    } | 
						|
  } | 
						|
  concat (...moreConfig) { | 
						|
    return new Proxy(new FiggyPudding( | 
						|
      this.__specs, | 
						|
      this.__opts, | 
						|
      reverse(this.__providers).concat(moreConfig) | 
						|
    ), proxyHandler) | 
						|
  } | 
						|
} | 
						|
try { | 
						|
  const util = require('util') | 
						|
  FiggyPudding.prototype[util.inspect.custom] = function (depth, opts) { | 
						|
    return ( | 
						|
      this[Symbol.toStringTag] + ' ' | 
						|
    ) + util.inspect(this.toJSON(), opts) | 
						|
  } | 
						|
} catch (e) {} | 
						|
 | 
						|
function BadKeyError (key) { | 
						|
  throw Object.assign(new Error( | 
						|
    `invalid config key requested: ${key}` | 
						|
  ), {code: 'EBADKEY'}) | 
						|
} | 
						|
 | 
						|
function pudGet (pud, key, validate) { | 
						|
  let spec = pud.__specs[key] | 
						|
  if (validate && !spec && (!pud.__opts.other || !pud.__opts.other(key))) { | 
						|
    BadKeyError(key) | 
						|
  } else { | 
						|
    if (!spec) { spec = {} } | 
						|
    let ret | 
						|
    for (let p of pud.__providers) { | 
						|
      ret = tryGet(key, p) | 
						|
      if (ret === undefined && spec.aliases && spec.aliases.length) { | 
						|
        for (let alias of spec.aliases) { | 
						|
          if (alias === key) { continue } | 
						|
          ret = tryGet(alias, p) | 
						|
          if (ret !== undefined) { | 
						|
            break | 
						|
          } | 
						|
        } | 
						|
      } | 
						|
      if (ret !== undefined) { | 
						|
        break | 
						|
      } | 
						|
    } | 
						|
    if (ret === undefined && spec.default !== undefined) { | 
						|
      if (typeof spec.default === 'function') { | 
						|
        return spec.default(pud) | 
						|
      } else { | 
						|
        return spec.default | 
						|
      } | 
						|
    } else { | 
						|
      return ret | 
						|
    } | 
						|
  } | 
						|
} | 
						|
 | 
						|
function tryGet (key, p) { | 
						|
  let ret | 
						|
  if (p.__isFiggyPudding) { | 
						|
    ret = pudGet(p, key, false) | 
						|
  } else if (typeof p.get === 'function') { | 
						|
    ret = p.get(key) | 
						|
  } else { | 
						|
    ret = p[key] | 
						|
  } | 
						|
  return ret | 
						|
} | 
						|
 | 
						|
const proxyHandler = { | 
						|
  has (obj, prop) { | 
						|
    return prop in obj.__specs && pudGet(obj, prop, false) !== undefined | 
						|
  }, | 
						|
  ownKeys (obj) { | 
						|
    return Object.keys(obj.__specs) | 
						|
  }, | 
						|
  get (obj, prop) { | 
						|
    if ( | 
						|
      typeof prop === 'symbol' || | 
						|
      prop.slice(0, 2) === '__' || | 
						|
      prop in FiggyPudding.prototype | 
						|
    ) { | 
						|
      return obj[prop] | 
						|
    } | 
						|
    return obj.get(prop) | 
						|
  }, | 
						|
  set (obj, prop, value) { | 
						|
    if ( | 
						|
      typeof prop === 'symbol' || | 
						|
      prop.slice(0, 2) === '__' | 
						|
    ) { | 
						|
      obj[prop] = value | 
						|
      return true | 
						|
    } else { | 
						|
      throw new Error('figgyPudding options cannot be modified. Use .concat() instead.') | 
						|
    } | 
						|
  }, | 
						|
  deleteProperty () { | 
						|
    throw new Error('figgyPudding options cannot be deleted. Use .concat() and shadow them instead.') | 
						|
  } | 
						|
} | 
						|
 | 
						|
module.exports = figgyPudding | 
						|
function figgyPudding (specs, opts) { | 
						|
  function factory (...providers) { | 
						|
    return new Proxy(new FiggyPudding( | 
						|
      specs, | 
						|
      opts, | 
						|
      providers | 
						|
    ), proxyHandler) | 
						|
  } | 
						|
  return factory | 
						|
} | 
						|
 | 
						|
function reverse (arr) { | 
						|
  const ret = [] | 
						|
  arr.forEach(x => ret.unshift(x)) | 
						|
  return ret | 
						|
} | 
						|
 | 
						|
function entries (obj) { | 
						|
  return Object.keys(obj).map(k => [k, obj[k]]) | 
						|
}
 | 
						|
 |