.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / base / index.js
1 'use strict';
2
3 var util = require('util');
4 var define = require('define-property');
5 var CacheBase = require('cache-base');
6 var Emitter = require('component-emitter');
7 var isObject = require('isobject');
8 var merge = require('mixin-deep');
9 var pascal = require('pascalcase');
10 var cu = require('class-utils');
11
12 /**
13  * Optionally define a custom `cache` namespace to use.
14  */
15
16 function namespace(name) {
17   var Cache = name ? CacheBase.namespace(name) : CacheBase;
18   var fns = [];
19
20   /**
21    * Create an instance of `Base` with the given `config` and `options`.
22    *
23    * ```js
24    * // initialize with `config` and `options`
25    * var app = new Base({isApp: true}, {abc: true});
26    * app.set('foo', 'bar');
27    *
28    * // values defined with the given `config` object will be on the root of the instance
29    * console.log(app.baz); //=> undefined
30    * console.log(app.foo); //=> 'bar'
31    * // or use `.get`
32    * console.log(app.get('isApp')); //=> true
33    * console.log(app.get('foo')); //=> 'bar'
34    *
35    * // values defined with the given `options` object will be on `app.options
36    * console.log(app.options.abc); //=> true
37    * ```
38    *
39    * @param {Object} `config` If supplied, this object is passed to [cache-base][] to merge onto the the instance upon instantiation.
40    * @param {Object} `options` If supplied, this object is used to initialize the `base.options` object.
41    * @api public
42    */
43
44   function Base(config, options) {
45     if (!(this instanceof Base)) {
46       return new Base(config, options);
47     }
48     Cache.call(this, config);
49     this.is('base');
50     this.initBase(config, options);
51   }
52
53   /**
54    * Inherit cache-base
55    */
56
57   util.inherits(Base, Cache);
58
59   /**
60    * Add static emitter methods
61    */
62
63   Emitter(Base);
64
65   /**
66    * Initialize `Base` defaults with the given `config` object
67    */
68
69   Base.prototype.initBase = function(config, options) {
70     this.options = merge({}, this.options, options);
71     this.cache = this.cache || {};
72     this.define('registered', {});
73     if (name) this[name] = {};
74
75     // make `app._callbacks` non-enumerable
76     this.define('_callbacks', this._callbacks);
77     if (isObject(config)) {
78       this.visit('set', config);
79     }
80     Base.run(this, 'use', fns);
81   };
82
83   /**
84    * Set the given `name` on `app._name` and `app.is*` properties. Used for doing
85    * lookups in plugins.
86    *
87    * ```js
88    * app.is('foo');
89    * console.log(app._name);
90    * //=> 'foo'
91    * console.log(app.isFoo);
92    * //=> true
93    * app.is('bar');
94    * console.log(app.isFoo);
95    * //=> true
96    * console.log(app.isBar);
97    * //=> true
98    * console.log(app._name);
99    * //=> 'bar'
100    * ```
101    * @name .is
102    * @param {String} `name`
103    * @return {Boolean}
104    * @api public
105    */
106
107   Base.prototype.is = function(name) {
108     if (typeof name !== 'string') {
109       throw new TypeError('expected name to be a string');
110     }
111     this.define('is' + pascal(name), true);
112     this.define('_name', name);
113     this.define('_appname', name);
114     return this;
115   };
116
117   /**
118    * Returns true if a plugin has already been registered on an instance.
119    *
120    * Plugin implementors are encouraged to use this first thing in a plugin
121    * to prevent the plugin from being called more than once on the same
122    * instance.
123    *
124    * ```js
125    * var base = new Base();
126    * base.use(function(app) {
127    *   if (app.isRegistered('myPlugin')) return;
128    *   // do stuff to `app`
129    * });
130    *
131    * // to also record the plugin as being registered
132    * base.use(function(app) {
133    *   if (app.isRegistered('myPlugin', true)) return;
134    *   // do stuff to `app`
135    * });
136    * ```
137    * @name .isRegistered
138    * @emits `plugin` Emits the name of the plugin being registered. Useful for unit tests, to ensure plugins are only registered once.
139    * @param {String} `name` The plugin name.
140    * @param {Boolean} `register` If the plugin if not already registered, to record it as being registered pass `true` as the second argument.
141    * @return {Boolean} Returns true if a plugin is already registered.
142    * @api public
143    */
144
145   Base.prototype.isRegistered = function(name, register) {
146     if (this.registered.hasOwnProperty(name)) {
147       return true;
148     }
149     if (register !== false) {
150       this.registered[name] = true;
151       this.emit('plugin', name);
152     }
153     return false;
154   };
155
156   /**
157    * Define a plugin function to be called immediately upon init. Plugins are chainable
158    * and expose the following arguments to the plugin function:
159    *
160    * - `app`: the current instance of `Base`
161    * - `base`: the [first ancestor instance](#base) of `Base`
162    *
163    * ```js
164    * var app = new Base()
165    *   .use(foo)
166    *   .use(bar)
167    *   .use(baz)
168    * ```
169    * @name .use
170    * @param {Function} `fn` plugin function to call
171    * @return {Object} Returns the item instance for chaining.
172    * @api public
173    */
174
175   Base.prototype.use = function(fn) {
176     fn.call(this, this);
177     return this;
178   };
179
180   /**
181    * The `.define` method is used for adding non-enumerable property on the instance.
182    * Dot-notation is **not supported** with `define`.
183    *
184    * ```js
185    * // arbitrary `render` function using lodash `template`
186    * app.define('render', function(str, locals) {
187    *   return _.template(str)(locals);
188    * });
189    * ```
190    * @name .define
191    * @param {String} `key` The name of the property to define.
192    * @param {any} `value`
193    * @return {Object} Returns the instance for chaining.
194    * @api public
195    */
196
197   Base.prototype.define = function(key, val) {
198     if (isObject(key)) {
199       return this.visit('define', key);
200     }
201     define(this, key, val);
202     return this;
203   };
204
205   /**
206    * Mix property `key` onto the Base prototype. If base is inherited using
207    * `Base.extend` this method will be overridden by a new `mixin` method that will
208    * only add properties to the prototype of the inheriting application.
209    *
210    * ```js
211    * app.mixin('foo', function() {
212    *   // do stuff
213    * });
214    * ```
215    * @name .mixin
216    * @param {String} `key`
217    * @param {Object|Array} `val`
218    * @return {Object} Returns the `base` instance for chaining.
219    * @api public
220    */
221
222   Base.prototype.mixin = function(key, val) {
223     Base.prototype[key] = val;
224     return this;
225   };
226
227   /**
228    * Non-enumberable mixin array, used by the static [Base.mixin]() method.
229    */
230
231   Base.prototype.mixins = Base.prototype.mixins || [];
232
233   /**
234    * Getter/setter used when creating nested instances of `Base`, for storing a reference
235    * to the first ancestor instance. This works by setting an instance of `Base` on the `parent`
236    * property of a "child" instance. The `base` property defaults to the current instance if
237    * no `parent` property is defined.
238    *
239    * ```js
240    * // create an instance of `Base`, this is our first ("base") instance
241    * var first = new Base();
242    * first.foo = 'bar'; // arbitrary property, to make it easier to see what's happening later
243    *
244    * // create another instance
245    * var second = new Base();
246    * // create a reference to the first instance (`first`)
247    * second.parent = first;
248    *
249    * // create another instance
250    * var third = new Base();
251    * // create a reference to the previous instance (`second`)
252    * // repeat this pattern every time a "child" instance is created
253    * third.parent = second;
254    *
255    * // we can always access the first instance using the `base` property
256    * console.log(first.base.foo);
257    * //=> 'bar'
258    * console.log(second.base.foo);
259    * //=> 'bar'
260    * console.log(third.base.foo);
261    * //=> 'bar'
262    * // and now you know how to get to third base ;)
263    * ```
264    * @name .base
265    * @api public
266    */
267
268   Object.defineProperty(Base.prototype, 'base', {
269     configurable: true,
270     get: function() {
271       return this.parent ? this.parent.base : this;
272     }
273   });
274
275   /**
276    * Static method for adding global plugin functions that will
277    * be added to an instance when created.
278    *
279    * ```js
280    * Base.use(function(app) {
281    *   app.foo = 'bar';
282    * });
283    * var app = new Base();
284    * console.log(app.foo);
285    * //=> 'bar'
286    * ```
287    * @name #use
288    * @param {Function} `fn` Plugin function to use on each instance.
289    * @return {Object} Returns the `Base` constructor for chaining
290    * @api public
291    */
292
293   define(Base, 'use', function(fn) {
294     fns.push(fn);
295     return Base;
296   });
297
298   /**
299    * Run an array of functions by passing each function
300    * to a method on the given object specified by the given property.
301    *
302    * @param  {Object} `obj` Object containing method to use.
303    * @param  {String} `prop` Name of the method on the object to use.
304    * @param  {Array} `arr` Array of functions to pass to the method.
305    */
306
307   define(Base, 'run', function(obj, prop, arr) {
308     var len = arr.length, i = 0;
309     while (len--) {
310       obj[prop](arr[i++]);
311     }
312     return Base;
313   });
314
315   /**
316    * Static method for inheriting the prototype and static methods of the `Base` class.
317    * This method greatly simplifies the process of creating inheritance-based applications.
318    * See [static-extend][] for more details.
319    *
320    * ```js
321    * var extend = cu.extend(Parent);
322    * Parent.extend(Child);
323    *
324    * // optional methods
325    * Parent.extend(Child, {
326    *   foo: function() {},
327    *   bar: function() {}
328    * });
329    * ```
330    * @name #extend
331    * @param {Function} `Ctor` constructor to extend
332    * @param {Object} `methods` Optional prototype properties to mix in.
333    * @return {Object} Returns the `Base` constructor for chaining
334    * @api public
335    */
336
337   define(Base, 'extend', cu.extend(Base, function(Ctor, Parent) {
338     Ctor.prototype.mixins = Ctor.prototype.mixins || [];
339
340     define(Ctor, 'mixin', function(fn) {
341       var mixin = fn(Ctor.prototype, Ctor);
342       if (typeof mixin === 'function') {
343         Ctor.prototype.mixins.push(mixin);
344       }
345       return Ctor;
346     });
347
348     define(Ctor, 'mixins', function(Child) {
349       Base.run(Child, 'mixin', Ctor.prototype.mixins);
350       return Ctor;
351     });
352
353     Ctor.prototype.mixin = function(key, value) {
354       Ctor.prototype[key] = value;
355       return this;
356     };
357     return Base;
358   }));
359
360   /**
361    * Used for adding methods to the `Base` prototype, and/or to the prototype of child instances.
362    * When a mixin function returns a function, the returned function is pushed onto the `.mixins`
363    * array, making it available to be used on inheriting classes whenever `Base.mixins()` is
364    * called (e.g. `Base.mixins(Child)`).
365    *
366    * ```js
367    * Base.mixin(function(proto) {
368    *   proto.foo = function(msg) {
369    *     return 'foo ' + msg;
370    *   };
371    * });
372    * ```
373    * @name #mixin
374    * @param {Function} `fn` Function to call
375    * @return {Object} Returns the `Base` constructor for chaining
376    * @api public
377    */
378
379   define(Base, 'mixin', function(fn) {
380     var mixin = fn(Base.prototype, Base);
381     if (typeof mixin === 'function') {
382       Base.prototype.mixins.push(mixin);
383     }
384     return Base;
385   });
386
387   /**
388    * Static method for running global mixin functions against a child constructor.
389    * Mixins must be registered before calling this method.
390    *
391    * ```js
392    * Base.extend(Child);
393    * Base.mixins(Child);
394    * ```
395    * @name #mixins
396    * @param {Function} `Child` Constructor function of a child class
397    * @return {Object} Returns the `Base` constructor for chaining
398    * @api public
399    */
400
401   define(Base, 'mixins', function(Child) {
402     Base.run(Child, 'mixin', Base.prototype.mixins);
403     return Base;
404   });
405
406   /**
407    * Similar to `util.inherit`, but copies all static properties, prototype properties, and
408    * getters/setters from `Provider` to `Receiver`. See [class-utils][]{#inherit} for more details.
409    *
410    * ```js
411    * Base.inherit(Foo, Bar);
412    * ```
413    * @name #inherit
414    * @param {Function} `Receiver` Receiving (child) constructor
415    * @param {Function} `Provider` Providing (parent) constructor
416    * @return {Object} Returns the `Base` constructor for chaining
417    * @api public
418    */
419
420   define(Base, 'inherit', cu.inherit);
421   define(Base, 'bubble', cu.bubble);
422   return Base;
423 }
424
425 /**
426  * Expose `Base` with default settings
427  */
428
429 module.exports = namespace();
430
431 /**
432  * Allow users to define a namespace
433  */
434
435 module.exports.namespace = namespace;