/*! * minibase * * Copyright (c) Charlike Mike Reagent <@tunnckoCore> (http://i.am.charlike.online) * Released under the MIT license. */ 'use strict' var util = require('util') var utils = require('./utils') /** * > Creates an instance of `MiniBase` with optional `options` * object - if given, otherwise the `minibase.options` * defaults to empty object. _**Never throws - emit events!™**_ * * **Example** * * ```js * const MiniBase = require('minibase').MiniBase * * // main export is instance * const app = require('minibase') * * app.once('error', (err) => { * console.log('error:', err) * }) * * app.use((self) => { * // this === self === app * console.log(self.use) // => 'function' * console.log(self.define) // => 'function' * self.define('foo', 'bar') * }) * * app.use(() => { * throw new Error('qux') * }) * ``` * * @param {Object} `[options]` optional, written to `this.options` * @api public */ function MiniBase (options) { if (!(this instanceof MiniBase)) { return new MiniBase(options) } utils.EventEmitter.call(this) this.initMiniBase(options) } /** * > Inherits from `EventEmitter3` lib, using * Node's built-in `inherits` method from * the core `util` module. * * @api private */ util.inherits(MiniBase, utils.EventEmitter) /** * > Adds a few non-enumerable ("hidden") methods * to our prototype of `MiniBase` class. Using * the `delegate-propeties` library. * * @api private */ utils.delegate(MiniBase.prototype, { /** * > Does defaulting stuff on init. * * @name .initMiniBase * @param {Object} `options` * @return {Object} Returns instance for chaining * @api private */ initMiniBase: function initMiniBase (options) { this.options = utils.extend({}, this.options, options) // hide them this.define('_events', this._events) this.define('_eventsCount', this._eventsCount) this.define('_anonymousPluginsCount', 1) return this }, /** * > Copy properties from `provider` to `this` instance * of `MiniBase`, using [delegate-properties][] lib. * * **Example** * * ```js * const minibase = require('minibase') * * minibase.use((app) => { * // `app` is `minibase` * * app.delegate({ * foo: 'bar', * qux: (name) => { * console.log(`hello ${name}`) * } * }) * }) * * // or directly use `.delegate`, * // not through plugin * minibase.delegate({ cats: 'dogs' }) * * console.log(minibase.cats) // => 'dogs' * console.log(minibase.foo) // => 'bar' * console.log(minibase.qux('kitty!')) // => 'hello kitty!' * ``` * * @name .delegate * @param {Object} `` object providing properties * @return {Object} Returns instance for chaining * @api public */ delegate: function delegateProperties (provider) { utils.delegate(this, provider) return this }, /** * > Used for adding non-enumerable property `key` with `value` * on the instance, using [define-property][] lib. * * **Example** * * ```js * const minibase = require('minibase') * * minibase.use(function (app) { * // `app` and `this` are instance of `MiniBase`, * // and so `minibase` * * this.define('set', function set (key, value) { * this.cache = this.cache || {} * this.cache[key] = value * return this * }) * app.define('get', function get (key) { * return this.cache[key] * }) * }) * * minibase * .set('foo', 'bar') * .set('qux', 123) * .set('baz', { a: 'b' }) * * // or directly use `.define`, * // not through plugin * minibase.define('hi', 'kitty') * console.log(minibase.hi) // => 'kitty' * * console.log(minibase.get('foo')) // => 'bar' * console.log(minibase.get('qux')) // => 123 * console.log(minibase.get('baz')) // => { a: 'b' } * * // or access the cache directly * console.log(minimist.cache.baz) // => { a: 'b' } * console.log(minimist.cache.qux) // => 123 * ``` * * @name .define * @param {String} `key` name of the property to be defined or modified * @param {any} `value` descriptor for the property being defined or modified * @return {Object} Returns instance for chaining * @api public */ define: function defineProperty (key, value) { utils.define(this, key, value) return this }, /** * > Define a synchronous plugin `fn` function to be * called immediately upon init. _**Never throws - emit events!™**_ * * **Example** * * ```js * const MiniBase = require('minibase').MiniBase * const app = MiniBase({ silent: true, foo: 'bar' }) * * app * .once('error', (err) => console.error(err.stack || err)) * .use((app) => { * console.log(app.options) // => { silent: true, foo: 'bar' } * return 555 * }) * .use(function () { * console.log(this.options) // => { silent: true, foo: 'bar' } * // intentionally * foo bar * }) * ``` * * @name .use * @emits `error` when plugin `fn` throws an error * @param {Function} `fn` plugin passed with `ctx` which is the instance * @return {Object} Returns instance for chaining * @api public */ use: function use (fn) { utils.tryCatchCallback.call(this, fn, { passCallback: false, args: [this] }, function (err, res) { if (err) { var anon = 'anonymous ' + (this._anonymousPluginsCount + 1) err.fn = fn err.fnName = utils.getFnName(fn) || anon this.emit('error', err) return } }.bind(this)) return this } }) utils.delegate(MiniBase, { /** * > Static method to delegate properties from `provider` to `receiver` * and make them non-enumerable. * * See [delegate-properties][] for more details, it is exact mirror. * * **Example** * * ```js * const MiniBase = require('minibase').MiniBase * * const obj = { foo: 'bar' } * * MiniBase.delegate(obj, { * qux: 123 * }) * * console.log(obj.foo) // => 'bar' * console.log(obj.qux) // => 123 * ``` * * @name #delegate * @param {Object} `receiver` object receiving properties * @param {Object} `provider` object providing properties * @api public */ delegate: utils.delegate, /** * > Static method to define a non-enumerable property on an object. * * See [define-property][] for more details, it is exact mirror. * * **Example** * * ```js * const MiniBase = require('minibase').MiniBase * * const obj = {} * MiniBase.define(obj, 'foo', 123) * MiniBase.define(obj, 'bar', () => console.log('qux')) * * console.log(obj.foo) // => 123 * console.log(obj.bar()) // => 'qux' * ``` * * @name #define * @param {Object} `obj` The object on which to define the property * @param {Object} `prop` The name of the property to be defined or modified * @param {any} `descriptor` The descriptor for the property being defined or modified * @api public */ define: utils.define, /** * > Static method for inheriting the prototype and static * methods of the `MiniBase` class. This method greatly simplifies * the process of creating inheritance-based applications. * * See [static-extend][] for more details. * * **Example** * * ```js * const MiniBase = require('minibase').MiniBase * * function MyApp (options) { * MiniBase.call(this, options) * } * * MiniBase.extend(MyApp) * * console.log(MyApp.extend) // => function * console.log(MyApp.define) // => function * console.log(MyApp.delegate) // => function * * const app = new MyApp() * * console.log(app.use) // => function * console.log(app.define) // => function * console.log(app.delegate) // => function * ``` * * @name #extend * @param {Function} `Ctor` constructor to extend * @param {Object} `methods` optional prototype properties to mix in * @api public */ extend: utils.staticExtend(MiniBase, function (Child) { utils.delegate(Child, { delegate: utils.delegate, define: utils.define }) }) }) /** * Expose `MiniBase` instance with default `options`. * * **Example** * * ```js * const minibase = require('minibase') * * console.log(minibase) * console.log(minibase.use) * console.log(minibase.define) * console.log(minibase.options) * console.log(minibase.delegate) * ``` * * @type {Object} * @api private */ module.exports = new MiniBase() /** * Expose `MiniBase` constructor. In some cases * you want to create a few new instances. Useful when you * don't want default error handler to be called * on error. In this case pass `silent: true` to * the `MiniBase` constructor. * * **Example** * * ```js * const MiniBase = require('minibase').MiniBase * const minibase = new MiniBase({ silent: true }) * * // or without `new` keyword * // const app = MiniBase() * ``` * * @type {Function} * @api private */ module.exports.MiniBase = MiniBase