[Pkg-javascript-commits] [node-base] 01/06: Import Upstream version 0.11.1
Sruthi Chandran
srud-guest at moszumanska.debian.org
Tue Nov 1 09:38:25 UTC 2016
This is an automated email from the git hooks/post-receive script.
srud-guest pushed a commit to branch master
in repository node-base.
commit ef1ca453cc8784ad8e0bb1f4a83a827f3bf8c336
Author: Sruthi <srud at disroot.org>
Date: Tue Nov 1 14:53:36 2016 +0530
Import Upstream version 0.11.1
---
.editorconfig | 22 ++
.eslintrc.json | 123 ++++++++
.gitattributes | 10 +
.gitignore | 15 +
.travis.yml | 12 +
.verb.md | 142 +++++++++
LICENSE | 21 ++
README.md | 475 ++++++++++++++++++++++++++++
docs/logo.png | Bin 0 -> 83366 bytes
docs/recipe.tasks.md | 47 +++
gulpfile.js | 30 ++
index.js | 429 +++++++++++++++++++++++++
package.json | 110 +++++++
test.js | 860 +++++++++++++++++++++++++++++++++++++++++++++++++++
utils.js | 25 ++
verbfile.js | 19 ++
16 files changed, 2340 insertions(+)
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..991900b
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,22 @@
+# http://editorconfig.org
+root = true
+
+[*]
+indent_style = space
+end_of_line = lf
+charset = utf-8
+indent_size = 2
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.md]
+trim_trailing_whitespace = false
+insert_final_newline = false
+
+[test/**]
+trim_trailing_whitespace = false
+insert_final_newline = false
+
+[templates/**]
+trim_trailing_whitespace = false
+insert_final_newline = false
diff --git a/.eslintrc.json b/.eslintrc.json
new file mode 100644
index 0000000..bb28232
--- /dev/null
+++ b/.eslintrc.json
@@ -0,0 +1,123 @@
+{
+ "ecmaFeatures": {
+ "modules": true,
+ "experimentalObjectRestSpread": true
+ },
+
+ "env": {
+ "browser": false,
+ "es6": true,
+ "node": true,
+ "mocha": true
+ },
+
+ "globals": {
+ "document": false,
+ "navigator": false,
+ "window": false
+ },
+
+ "rules": {
+ "accessor-pairs": 2,
+ "arrow-spacing": [2, { "before": true, "after": true }],
+ "block-spacing": [2, "always"],
+ "brace-style": [2, "1tbs", { "allowSingleLine": true }],
+ "comma-dangle": [2, "never"],
+ "comma-spacing": [2, { "before": false, "after": true }],
+ "comma-style": [2, "last"],
+ "constructor-super": 2,
+ "curly": [2, "multi-line"],
+ "dot-location": [2, "property"],
+ "eol-last": 2,
+ "eqeqeq": [2, "allow-null"],
+ "generator-star-spacing": [2, { "before": true, "after": true }],
+ "handle-callback-err": [2, "^(err|error)$" ],
+ "indent": [2, 2, { "SwitchCase": 1 }],
+ "keyword-spacing": [2, {"before": true, "after": true}],
+ "key-spacing": [2, { "beforeColon": false, "afterColon": true }],
+ "new-cap": [2, { "newIsCap": true, "capIsNew": false }],
+ "new-parens": 2,
+ "no-array-constructor": 2,
+ "no-caller": 2,
+ "no-class-assign": 2,
+ "no-cond-assign": 2,
+ "no-const-assign": 2,
+ "no-control-regex": 2,
+ "no-debugger": 2,
+ "no-delete-var": 2,
+ "no-dupe-args": 2,
+ "no-dupe-class-members": 2,
+ "no-dupe-keys": 2,
+ "no-duplicate-case": 2,
+ "no-empty-character-class": 2,
+ "no-labels": 2,
+ "no-eval": 2,
+ "no-ex-assign": 2,
+ "no-extend-native": 2,
+ "no-extra-bind": 2,
+ "no-extra-boolean-cast": 2,
+ "no-extra-parens": [2, "functions"],
+ "no-fallthrough": 2,
+ "no-floating-decimal": 2,
+ "no-func-assign": 2,
+ "no-implied-eval": 2,
+ "no-inner-declarations": [2, "functions"],
+ "no-invalid-regexp": 2,
+ "no-irregular-whitespace": 2,
+ "no-iterator": 2,
+ "no-label-var": 2,
+ "no-labels": 2,
+ "no-lone-blocks": 2,
+ "no-mixed-spaces-and-tabs": 2,
+ "no-multi-spaces": 2,
+ "no-multi-str": 2,
+ "no-multiple-empty-lines": [2, { "max": 1 }],
+ "no-native-reassign": 2,
+ "no-negated-in-lhs": 2,
+ "no-new": 2,
+ "no-new-func": 2,
+ "no-new-object": 2,
+ "no-new-require": 2,
+ "no-new-wrappers": 2,
+ "no-obj-calls": 2,
+ "no-octal": 2,
+ "no-octal-escape": 2,
+ "no-proto": 0,
+ "no-redeclare": 2,
+ "no-regex-spaces": 2,
+ "no-return-assign": 2,
+ "no-self-compare": 2,
+ "no-sequences": 2,
+ "no-shadow-restricted-names": 2,
+ "no-spaced-func": 2,
+ "no-sparse-arrays": 2,
+ "no-this-before-super": 2,
+ "no-throw-literal": 2,
+ "no-trailing-spaces": 0,
+ "no-undef": 2,
+ "no-undef-init": 2,
+ "no-unexpected-multiline": 2,
+ "no-unneeded-ternary": [2, { "defaultAssignment": false }],
+ "no-unreachable": 2,
+ "no-unused-vars": [2, { "vars": "all", "args": "none" }],
+ "no-useless-call": 0,
+ "no-with": 2,
+ "one-var": [0, { "initialized": "never" }],
+ "operator-linebreak": [0, "after", { "overrides": { "?": "before", ":": "before" } }],
+ "padded-blocks": [0, "never"],
+ "quotes": [2, "single", "avoid-escape"],
+ "radix": 2,
+ "semi": [2, "always"],
+ "semi-spacing": [2, { "before": false, "after": true }],
+ "space-before-blocks": [2, "always"],
+ "space-before-function-paren": [2, "never"],
+ "space-in-parens": [2, "never"],
+ "space-infix-ops": 2,
+ "space-unary-ops": [2, { "words": true, "nonwords": false }],
+ "spaced-comment": [0, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","] }],
+ "use-isnan": 2,
+ "valid-typeof": 2,
+ "wrap-iife": [2, "any"],
+ "yoda": [2, "never"]
+ }
+}
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..660957e
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,10 @@
+# Enforce Unix newlines
+* text eol=lf
+
+# binaries
+*.ai binary
+*.psd binary
+*.jpg binary
+*.gif binary
+*.png binary
+*.jpeg binary
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..80a228c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+*.DS_Store
+*.sublime-*
+_gh_pages
+bower_components
+node_modules
+npm-debug.log
+actual
+test/actual
+temp
+tmp
+TODO.md
+vendor
+.idea
+benchmark
+coverage
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..09768f0
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,12 @@
+sudo: false
+language: node_js
+node_js:
+ - "stable"
+ - "5"
+ - "4"
+ - "0.12"
+ - "0.10"
+matrix:
+ fast_finish: true
+ allow_failures:
+ - node_js: "0.10"
diff --git a/.verb.md b/.verb.md
new file mode 100644
index 0000000..f260034
--- /dev/null
+++ b/.verb.md
@@ -0,0 +1,142 @@
+{{#block "logo"}}
+<p align="center">
+ <a href="{%= homepage %}">
+ <img height="250" width="250" src="https://raw.githubusercontent.com/node-base/base/master/docs/logo.png">
+ </a>
+</p>
+{{/block}}
+
+{{#block "about"}}
+## What is Base?
+
+Base is a framework for rapidly creating high quality node.js applications, using plugins like building blocks.
+
+### Guiding principles
+
+The core team follows these principles to help guide API decisions:
+
+- **Compact API surface**: The smaller the API surface, the easier the library will be to learn and use.
+- **Easy to extend**: Implementors can use any npm package, and write plugins in pure JavaScript. If you're building complex apps, Base simplifies inheritance.
+- **Easy to test**: No special setup should be required to unit test `Base` or base plugins
+
+### Minimal API surface
+
+[The API](#api) was designed to provide only the minimum necessary functionality for creating a useful application, with or without [plugins](#plugins).
+
+**Base core**
+
+Base itself ships with only a handful of [useful methods](#api), such as:
+
+- `.set`: for setting values on the instance
+- `.get`: for getting values from the instance
+- `.has`: to check if a property exists on the instance
+- `.define`: for setting non-enumerable values on the instance
+- `.use`: for adding plugins
+
+**Be generic**
+
+When deciding on method to add or remove, we try to answer these questions:
+
+1. Will all or most Base applications need this method?
+1. Will this method encourage practices or enforce conventions that are beneficial to implementors?
+1. Can or should this be done in a plugin instead?
+
+### Composability
+
+**Plugin system**
+
+It couldn't be easier to extend Base with any features or custom functionality you can think of.
+
+Base plugins are just functions that take an instance of `Base`:
+
+```js
+var base = new Base();
+
+function plugin(base) {
+ // do plugin stuff, in pure JavaScript
+}
+// use the plugin
+base.use(plugin);
+```
+
+**Inheritance**
+
+Easily inherit Base using `.extend`:
+
+```js
+var Base = require('{%= name %}');
+
+function MyApp() {
+ Base.call(this);
+}
+Base.extend(MyApp);
+
+var app = new MyApp();
+app.set('a', 'b');
+app.get('a');
+//=> 'b';
+```
+
+**Inherit or instantiate with a namespace**
+
+By default, the `.get`, `.set` and `.has` methods set and get values from the root of the `base` instance. You can customize this using the `.namespace` method exposed on the exported function. For example:
+
+```js
+var Base = require('{%= name %}');
+// get and set values on the `base.cache` object
+var base = Base.namespace('cache');
+
+var app = base();
+app.set('foo', 'bar');
+console.log(app.cache.foo);
+//=> 'bar'
+```
+
+
+{{/block}}
+
+
+## API
+
+**Usage**
+
+```js
+var Base = require('base');
+var app = new Base();
+app.set('foo', 'bar');
+console.log(app.foo);
+//=> 'bar'
+```
+
+{%= apidocs("index.js") %}
+
+## In the wild
+
+The following node.js applications were built with `Base`:
+
+- [assemble][]
+- [verb][]
+- [generate][]
+- [scaffold][]
+- [boilerplate][]
+
+## Test coverage
+
+```
+{%= coverage('coverage/summary.txt') %}
+```
+
+## History
+
+**v0.11.0 - major breaking changes!**
+
+- Static `.use` and `.run` methods are now non-enumerable
+
+**v0.9.0 - major breaking changes!**
+
+- `.is` no longer takes a function, a string must be passed
+- all remaining `.debug` code has been removed
+- `app._namespace` was removed (related to `debug`)
+- `.plugin`, `.use`, and `.define` no longer emit events
+- `.assertPlugin` was removed
+- `.lazy` was removed
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..1e49edf
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015-2016, Jon Schlinkert.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7bd5310
--- /dev/null
+++ b/README.md
@@ -0,0 +1,475 @@
+# base [![NPM version](https://img.shields.io/npm/v/base.svg?style=flat)](https://www.npmjs.com/package/base) [![NPM downloads](https://img.shields.io/npm/dm/base.svg?style=flat)](https://npmjs.org/package/base) [![Build Status](https://img.shields.io/travis/node-base/base.svg?style=flat)](https://travis-ci.org/node-base/base)
+
+<p align="center">
+<a href="https://github.com/node-base/base">
+<img height="250" width="250" src="https://raw.githubusercontent.com/node-base/base/master/docs/logo.png">
+</a>
+</p>
+
+## What is Base?
+
+Base is a framework for rapidly creating high quality node.js applications, using plugins like building blocks.
+
+### Guiding principles
+
+The core team follows these principles to help guide API decisions:
+
+* **Compact API surface**: The smaller the API surface, the easier the library will be to learn and use.
+* **Easy to extend**: Implementors can use any npm package, and write plugins in pure JavaScript. If you're building complex apps, Base simplifies inheritance.
+* **Easy to test**: No special setup should be required to unit test `Base` or base plugins
+
+### Minimal API surface
+
+[The API](#api) was designed to provide only the minimum necessary functionality for creating a useful application, with or without [plugins](#plugins).
+
+**Base core**
+
+Base itself ships with only a handful of [useful methods](#api), such as:
+
+* `.set`: for setting values on the instance
+* `.get`: for getting values from the instance
+* `.has`: to check if a property exists on the instance
+* `.define`: for setting non-enumerable values on the instance
+* `.use`: for adding plugins
+
+**Be generic**
+
+When deciding on method to add or remove, we try to answer these questions:
+
+1. Will all or most Base applications need this method?
+2. Will this method encourage practices or enforce conventions that are beneficial to implementors?
+3. Can or should this be done in a plugin instead?
+
+### Composability
+
+**Plugin system**
+
+It couldn't be easier to extend Base with any features or custom functionality you can think of.
+
+Base plugins are just functions that take an instance of `Base`:
+
+```js
+var base = new Base();
+
+function plugin(base) {
+ // do plugin stuff, in pure JavaScript
+}
+// use the plugin
+base.use(plugin);
+```
+
+**Inheritance**
+
+Easily inherit Base using `.extend`:
+
+```js
+var Base = require('base');
+
+function MyApp() {
+ Base.call(this);
+}
+Base.extend(MyApp);
+
+var app = new MyApp();
+app.set('a', 'b');
+app.get('a');
+//=> 'b';
+```
+
+**Inherit or instantiate with a namespace**
+
+By default, the `.get`, `.set` and `.has` methods set and get values from the root of the `base` instance. You can customize this using the `.namespace` method exposed on the exported function. For example:
+
+```js
+var Base = require('base');
+// get and set values on the `base.cache` object
+var base = Base.namespace('cache');
+
+var app = base();
+app.set('foo', 'bar');
+console.log(app.cache.foo);
+//=> 'bar'
+```
+
+## Install
+
+Install with [npm](https://www.npmjs.com/):
+
+```sh
+$ npm install --save base
+```
+
+## API
+
+**Usage**
+
+```js
+var Base = require('base');
+var app = new Base();
+app.set('foo', 'bar');
+console.log(app.foo);
+//=> 'bar'
+```
+
+### [Base](index.js#L38)
+
+Create an instance of `Base` with the given `config` and `options`.
+
+**Params**
+
+* `config` **{Object}**: If supplied, this object is passed to [cache-base](https://github.com/jonschlinkert/cache-base) to merge onto the the instance upon instantiation.
+* `options` **{Object}**: If supplied, this object is used to initialize the `base.options` object.
+
+**Example**
+
+```js
+// initialize with `config` and `options`
+var app = new Base({isApp: true}, {abc: true});
+app.set('foo', 'bar');
+
+// values defined with the given `config` object will be on the root of the instance
+console.log(app.baz); //=> undefined
+console.log(app.foo); //=> 'bar'
+// or use `.get`
+console.log(app.get('isApp')); //=> true
+console.log(app.get('foo')); //=> 'bar'
+
+// values defined with the given `options` object will be on `app.options
+console.log(app.options.abc); //=> true
+```
+
+### [.is](index.js#L101)
+
+Set the given `name` on `app._name` and `app.is*` properties. Used for doing lookups in plugins.
+
+**Params**
+
+* `name` **{String}**
+* `returns` **{Boolean}**
+
+**Example**
+
+```js
+app.is('foo');
+console.log(app._name);
+//=> 'foo'
+console.log(app.isFoo);
+//=> true
+app.is('bar');
+console.log(app.isFoo);
+//=> true
+console.log(app.isBar);
+//=> true
+console.log(app._name);
+//=> 'bar'
+```
+
+### [.isRegistered](index.js#L139)
+
+Returns true if a plugin has already been registered on an instance.
+
+Plugin implementors are encouraged to use this first thing in a plugin
+to prevent the plugin from being called more than once on the same
+instance.
+
+**Params**
+
+* `name` **{String}**: The plugin name.
+* `register` **{Boolean}**: If the plugin if not already registered, to record it as being registered pass `true` as the second argument.
+* `returns` **{Boolean}**: Returns true if a plugin is already registered.
+
+**Events**
+
+* `emits`: `plugin` Emits the name of the plugin being registered. Useful for unit tests, to ensure plugins are only registered once.
+
+**Example**
+
+```js
+var base = new Base();
+base.use(function(app) {
+ if (app.isRegistered('myPlugin')) return;
+ // do stuff to `app`
+});
+
+// to also record the plugin as being registered
+base.use(function(app) {
+ if (app.isRegistered('myPlugin', true)) return;
+ // do stuff to `app`
+});
+```
+
+### [.use](index.js#L169)
+
+Define a plugin function to be called immediately upon init. Plugins are chainable and expose the following arguments to the plugin function:
+
+* `app`: the current instance of `Base`
+* `base`: the [first ancestor instance](#base) of `Base`
+
+**Params**
+
+* `fn` **{Function}**: plugin function to call
+* `returns` **{Object}**: Returns the item instance for chaining.
+
+**Example**
+
+```js
+var app = new Base()
+ .use(foo)
+ .use(bar)
+ .use(baz)
+```
+
+### [.define](index.js#L191)
+
+The `.define` method is used for adding non-enumerable property on the instance. Dot-notation is **not supported** with `define`.
+
+**Params**
+
+* `key` **{String}**: The name of the property to define.
+* `value` **{any}**
+* `returns` **{Object}**: Returns the instance for chaining.
+
+**Example**
+
+```js
+// arbitrary `render` function using lodash `template`
+app.define('render', function(str, locals) {
+ return _.template(str)(locals);
+});
+```
+
+### [.mixin](index.js#L216)
+
+Mix property `key` onto the Base prototype. If base is inherited using `Base.extend` this method will be overridden by a new `mixin` method that will only add properties to the prototype of the inheriting application.
+
+**Params**
+
+* `key` **{String}**
+* `val` **{Object|Array}**
+* `returns` **{Object}**: Returns the `base` instance for chaining.
+
+**Example**
+
+```js
+app.mixin('foo', function() {
+ // do stuff
+});
+```
+
+### [.base](index.js#L262)
+
+Getter/setter used when creating nested instances of `Base`, for storing a reference to the first ancestor instance. This works by setting an instance of `Base` on the `parent` property of a "child" instance. The `base` property defaults to the current instance if no `parent` property is defined.
+
+**Example**
+
+```js
+// create an instance of `Base`, this is our first ("base") instance
+var first = new Base();
+first.foo = 'bar'; // arbitrary property, to make it easier to see what's happening later
+
+// create another instance
+var second = new Base();
+// create a reference to the first instance (`first`)
+second.parent = first;
+
+// create another instance
+var third = new Base();
+// create a reference to the previous instance (`second`)
+// repeat this pattern every time a "child" instance is created
+third.parent = second;
+
+// we can always access the first instance using the `base` property
+console.log(first.base.foo);
+//=> 'bar'
+console.log(second.base.foo);
+//=> 'bar'
+console.log(third.base.foo);
+//=> 'bar'
+// and now you know how to get to third base ;)
+```
+
+### [#use](index.js#L287)
+
+Static method for adding global plugin functions that will be added to an instance when created.
+
+**Params**
+
+* `fn` **{Function}**: Plugin function to use on each instance.
+* `returns` **{Object}**: Returns the `Base` constructor for chaining
+
+**Example**
+
+```js
+Base.use(function(app) {
+ app.foo = 'bar';
+});
+var app = new Base();
+console.log(app.foo);
+//=> 'bar'
+```
+
+### [#extend](index.js#L331)
+
+Static method for inheriting the prototype and static methods of the `Base` class. This method greatly simplifies the process of creating inheritance-based applications. See [static-extend](https://github.com/jonschlinkert/static-extend) for more details.
+
+**Params**
+
+* `Ctor` **{Function}**: constructor to extend
+* `methods` **{Object}**: Optional prototype properties to mix in.
+* `returns` **{Object}**: Returns the `Base` constructor for chaining
+
+**Example**
+
+```js
+var extend = cu.extend(Parent);
+Parent.extend(Child);
+
+// optional methods
+Parent.extend(Child, {
+ foo: function() {},
+ bar: function() {}
+});
+```
+
+### [#mixin](index.js#L373)
+
+Used for adding methods to the `Base` prototype, and/or to the prototype of child instances. When a mixin function returns a function, the returned function is pushed onto the `.mixins` array, making it available to be used on inheriting classes whenever `Base.mixins()` is called (e.g. `Base.mixins(Child)`).
+
+**Params**
+
+* `fn` **{Function}**: Function to call
+* `returns` **{Object}**: Returns the `Base` constructor for chaining
+
+**Example**
+
+```js
+Base.mixin(function(proto) {
+ proto.foo = function(msg) {
+ return 'foo ' + msg;
+ };
+});
+```
+
+### [#mixins](index.js#L395)
+
+Static method for running global mixin functions against a child constructor. Mixins must be registered before calling this method.
+
+**Params**
+
+* `Child` **{Function}**: Constructor function of a child class
+* `returns` **{Object}**: Returns the `Base` constructor for chaining
+
+**Example**
+
+```js
+Base.extend(Child);
+Base.mixins(Child);
+```
+
+### [#inherit](index.js#L414)
+
+Similar to `util.inherit`, but copies all static properties, prototype properties, and getters/setters from `Provider` to `Receiver`. See [class-utils](https://github.com/jonschlinkert/class-utils#inherit) for more details.
+
+**Params**
+
+* `Receiver` **{Function}**: Receiving (child) constructor
+* `Provider` **{Function}**: Providing (parent) constructor
+* `returns` **{Object}**: Returns the `Base` constructor for chaining
+
+**Example**
+
+```js
+Base.inherit(Foo, Bar);
+```
+
+## In the wild
+
+The following node.js applications were built with `Base`:
+
+* [assemble](https://github.com/assemble/assemble)
+* [verb](https://github.com/verbose/verb)
+* [generate](https://github.com/generate/generate)
+* [scaffold](https://github.com/jonschlinkert/scaffold)
+* [boilerplate](https://github.com/jonschlinkert/boilerplate)
+
+## Test coverage
+
+```
+Statements : 98.95% ( 94/95 )
+Branches : 92.31% ( 24/26 )
+Functions : 100% ( 17/17 )
+Lines : 98.94% ( 93/94 )
+```
+
+## History
+
+**v0.11.0 - major breaking changes!**
+
+* Static `.use` and `.run` methods are now non-enumerable
+
+**v0.9.0 - major breaking changes!**
+
+* `.is` no longer takes a function, a string must be passed
+* all remaining `.debug` code has been removed
+* `app._namespace` was removed (related to `debug`)
+* `.plugin`, `.use`, and `.define` no longer emit events
+* `.assertPlugin` was removed
+* `.lazy` was removed
+
+## Related projects
+
+There are a number of different plugins available for extending base. Let us know if you create your own!
+
+* [base-cwd](https://www.npmjs.com/package/base-cwd): Base plugin that adds a getter/setter for the current working directory. | [homepage](https://github.com/node-base/base-cwd "Base plugin that adds a getter/setter for the current working directory.")
+* [base-data](https://www.npmjs.com/package/base-data): adds a `data` method to base-methods. | [homepage](https://github.com/node-base/base-data "adds a `data` method to base-methods.")
+* [base-fs](https://www.npmjs.com/package/base-fs): base-methods plugin that adds vinyl-fs methods to your 'base' application for working with the file… [more](https://github.com/node-base/base-fs) | [homepage](https://github.com/node-base/base-fs "base-methods plugin that adds vinyl-fs methods to your 'base' application for working with the file system, like src, dest, copy and symlink.")
+* [base-generators](https://www.npmjs.com/package/base-generators): Adds project-generator support to your `base` application. | [homepage](https://github.com/node-base/base-generators "Adds project-generator support to your `base` application.")
+* [base-option](https://www.npmjs.com/package/base-option): Adds a few options methods to base, like `option`, `enable` and `disable`. See the readme… [more](https://github.com/node-base/base-option) | [homepage](https://github.com/node-base/base-option "Adds a few options methods to base, like `option`, `enable` and `disable`. See the readme for the full API.")
+* [base-pipeline](https://www.npmjs.com/package/base-pipeline): base-methods plugin that adds pipeline and plugin methods for dynamically composing streaming plugin pipelines. | [homepage](https://github.com/node-base/base-pipeline "base-methods plugin that adds pipeline and plugin methods for dynamically composing streaming plugin pipelines.")
+* [base-pkg](https://www.npmjs.com/package/base-pkg): Plugin for adding a `pkg` method that exposes pkg-store to your base application. | [homepage](https://github.com/node-base/base-pkg "Plugin for adding a `pkg` method that exposes pkg-store to your base application.")
+* [base-plugins](https://www.npmjs.com/package/base-plugins): Upgrade's plugin support in base applications to allow plugins to be called any time after… [more](https://github.com/node-base/base-plugins) | [homepage](https://github.com/node-base/base-plugins "Upgrade's plugin support in base applications to allow plugins to be called any time after init.")
+* [base-questions](https://www.npmjs.com/package/base-questions): Plugin for base-methods that adds methods for prompting the user and storing the answers on… [more](https://github.com/node-base/base-questions) | [homepage](https://github.com/node-base/base-questions "Plugin for base-methods that adds methods for prompting the user and storing the answers on a project-by-project basis.")
+* [base-store](https://www.npmjs.com/package/base-store): Plugin for getting and persisting config values with your base-methods application. Adds a 'store' object… [more](https://github.com/node-base/base-store) | [homepage](https://github.com/node-base/base-store "Plugin for getting and persisting config values with your base-methods application. Adds a 'store' object that exposes all of the methods from the data-store library. Also now supports sub-stores!")
+* [base-task](https://www.npmjs.com/package/base-task): base plugin that provides a very thin wrapper around [https://github.com/doowb/composer](https://github.com/doowb/composer) for adding task methods to… [more](https://github.com/node-base/base-task) | [homepage](https://github.com/node-base/base-task "base plugin that provides a very thin wrapper around <https://github.com/doowb/composer> for adding task methods to your application.")
+
+## Contributing
+
+This document was generated by [verb-readme-generator](https://github.com/verbose/verb-readme-generator) (a [verb](https://github.com/verbose/verb) generator), please don't edit directly. Any changes to the readme must be made in [.verb.md](.verb.md). See [Building Docs](#building-docs).
+
+Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).
+
+Or visit the [verb-readme-generator](https://github.com/verbose/verb-readme-generator) project to submit bug reports or pull requests for the readme layout template.
+
+## Building docs
+
+_(This document was generated by [verb-readme-generator](https://github.com/verbose/verb-readme-generator) (a [verb](https://github.com/verbose/verb) generator), please don't edit the readme directly. Any changes to the readme must be made in [.verb.md](.verb.md).)_
+
+Generate readme and API documentation with [verb](https://github.com/verbose/verb):
+
+```sh
+$ npm install -g verb verb-readme-generator && verb
+```
+
+## Running tests
+
+Install dev dependencies:
+
+```sh
+$ npm install -d && npm test
+```
+
+## Author
+
+**Jon Schlinkert**
+
+* [github/jonschlinkert](https://github.com/jonschlinkert)
+* [twitter/jonschlinkert](http://twitter.com/jonschlinkert)
+
+## License
+
+Copyright © 2016, [Jon Schlinkert](https://github.com/jonschlinkert).
+Released under the [MIT license](https://github.com/node-base/base/blob/master/LICENSE).
+
+***
+
+_This file was generated by [verb](https://github.com/verbose/verb), v0.9.0, on June 23, 2016._
\ No newline at end of file
diff --git a/docs/logo.png b/docs/logo.png
new file mode 100755
index 0000000..f218612
Binary files /dev/null and b/docs/logo.png differ
diff --git a/docs/recipe.tasks.md b/docs/recipe.tasks.md
new file mode 100644
index 0000000..13b9bfb
--- /dev/null
+++ b/docs/recipe.tasks.md
@@ -0,0 +1,47 @@
+## Run gulp-like tasks
+
+Add the [base-task](https://github.com/node-base/base-task) plugin:
+
+```js
+var task = require('base-task');
+var Base = require('base');
+var app = new Base();
+
+// register the task plugin
+app.use(task());
+
+app.task('default', function(cb) {
+ // do task stuff
+ cb();
+});
+
+// run the `default` task
+app.build(function(err) {
+ if (err) throw err;
+});
+```
+
+**Display run times**
+
+To log out run times in the terminal, add the [base-runtimes](https://github.com/node-base/base-runtimes) plugin:
+
+```js
+var runtimes = require('base-runtimes');
+var task = require('base-task');
+var Base = require('base');
+var app = new Base();
+
+// register plugins
+app.use(runtimes());
+app.use(task());
+
+app.task('default', function(cb) {
+ // do task stuff
+ cb();
+});
+
+// run the `default` task
+app.build(function(err) {
+ if (err) throw err;
+});
+```
diff --git a/gulpfile.js b/gulpfile.js
new file mode 100644
index 0000000..aef2b75
--- /dev/null
+++ b/gulpfile.js
@@ -0,0 +1,30 @@
+'use strict';
+
+var gulp = require('gulp');
+var mocha = require('gulp-mocha');
+var istanbul = require('gulp-istanbul');
+var eslint = require('gulp-eslint');
+
+gulp.task('coverage', function() {
+ return gulp.src(['index.js', 'utils.js'])
+ .pipe(istanbul({includeUntested: true}))
+ .pipe(istanbul.hookRequire());
+});
+
+gulp.task('mocha', ['coverage'], function() {
+ return gulp.src('test.js')
+ .pipe(mocha())
+ .pipe(istanbul.writeReports())
+ .pipe(istanbul.writeReports({
+ reporters: [ 'text', 'text-summary' ],
+ reportOpts: {dir: 'coverage', file: 'summary.txt'}
+ }));
+});
+
+gulp.task('eslint', function() {
+ return gulp.src('*.js')
+ .pipe(eslint())
+ .pipe(eslint.format());
+});
+
+gulp.task('default', ['mocha', 'eslint']);
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..47fcd9a
--- /dev/null
+++ b/index.js
@@ -0,0 +1,429 @@
+'use strict';
+
+var util = require('util');
+var utils = require('./utils');
+
+/**
+ * Optionally define a custom `cache` namespace to use.
+ */
+
+function namespace(name) {
+ var Cache = name ? utils.Cache.namespace(name) : utils.Cache;
+ var fns = [];
+
+ /**
+ * Create an instance of `Base` with the given `config` and `options`.
+ *
+ * ```js
+ * // initialize with `config` and `options`
+ * var app = new Base({isApp: true}, {abc: true});
+ * app.set('foo', 'bar');
+ *
+ * // values defined with the given `config` object will be on the root of the instance
+ * console.log(app.baz); //=> undefined
+ * console.log(app.foo); //=> 'bar'
+ * // or use `.get`
+ * console.log(app.get('isApp')); //=> true
+ * console.log(app.get('foo')); //=> 'bar'
+ *
+ * // values defined with the given `options` object will be on `app.options
+ * console.log(app.options.abc); //=> true
+ * ```
+ *
+ * @param {Object} `config` If supplied, this object is passed to [cache-base][] to merge onto the the instance upon instantiation.
+ * @param {Object} `options` If supplied, this object is used to initialize the `base.options` object.
+ * @api public
+ */
+
+ function Base(config, options) {
+ if (!(this instanceof Base)) {
+ return new Base(config, options);
+ }
+ Cache.call(this, config);
+ this.is('base');
+ this.initBase(config, options);
+ }
+
+ /**
+ * Inherit cache-base
+ */
+
+ util.inherits(Base, Cache);
+
+ /**
+ * Add static emitter methods
+ */
+
+ utils.Emitter(Base);
+
+ /**
+ * Initialize `Base` defaults with the given `config` object
+ */
+
+ Base.prototype.initBase = function(config, options) {
+ this.options = utils.merge({}, this.options, options);
+ this.cache = this.cache || {};
+ this.define('registered', {});
+ if (name) this[name] = {};
+
+ // make `app._callbacks` non-enumerable
+ this.define('_callbacks', this._callbacks);
+ if (utils.isObject(config)) {
+ this.visit('set', config);
+ }
+ Base.run(this, 'use', fns);
+ };
+
+ /**
+ * Set the given `name` on `app._name` and `app.is*` properties. Used for doing
+ * lookups in plugins.
+ *
+ * ```js
+ * app.is('foo');
+ * console.log(app._name);
+ * //=> 'foo'
+ * console.log(app.isFoo);
+ * //=> true
+ * app.is('bar');
+ * console.log(app.isFoo);
+ * //=> true
+ * console.log(app.isBar);
+ * //=> true
+ * console.log(app._name);
+ * //=> 'bar'
+ * ```
+ * @name .is
+ * @param {String} `name`
+ * @return {Boolean}
+ * @api public
+ */
+
+ Base.prototype.is = function(name) {
+ if (typeof name !== 'string') {
+ throw new TypeError('expected name to be a string');
+ }
+ this.define('is' + utils.pascal(name), true);
+ this.define('_name', name);
+ this.define('_appname', name);
+ return this;
+ };
+
+ /**
+ * Returns true if a plugin has already been registered on an instance.
+ *
+ * Plugin implementors are encouraged to use this first thing in a plugin
+ * to prevent the plugin from being called more than once on the same
+ * instance.
+ *
+ * ```js
+ * var base = new Base();
+ * base.use(function(app) {
+ * if (app.isRegistered('myPlugin')) return;
+ * // do stuff to `app`
+ * });
+ *
+ * // to also record the plugin as being registered
+ * base.use(function(app) {
+ * if (app.isRegistered('myPlugin', true)) return;
+ * // do stuff to `app`
+ * });
+ * ```
+ * @name .isRegistered
+ * @emits `plugin` Emits the name of the plugin being registered. Useful for unit tests, to ensure plugins are only registered once.
+ * @param {String} `name` The plugin name.
+ * @param {Boolean} `register` If the plugin if not already registered, to record it as being registered pass `true` as the second argument.
+ * @return {Boolean} Returns true if a plugin is already registered.
+ * @api public
+ */
+
+ Base.prototype.isRegistered = function(name, register) {
+ if (this.registered.hasOwnProperty(name)) {
+ return true;
+ }
+ if (register !== false) {
+ this.registered[name] = true;
+ this.emit('plugin', name);
+ }
+ return false;
+ };
+
+ /**
+ * Define a plugin function to be called immediately upon init. Plugins are chainable
+ * and expose the following arguments to the plugin function:
+ *
+ * - `app`: the current instance of `Base`
+ * - `base`: the [first ancestor instance](#base) of `Base`
+ *
+ * ```js
+ * var app = new Base()
+ * .use(foo)
+ * .use(bar)
+ * .use(baz)
+ * ```
+ * @name .use
+ * @param {Function} `fn` plugin function to call
+ * @return {Object} Returns the item instance for chaining.
+ * @api public
+ */
+
+ Base.prototype.use = function(fn) {
+ fn.call(this, this);
+ return this;
+ };
+
+ /**
+ * The `.define` method is used for adding non-enumerable property on the instance.
+ * Dot-notation is **not supported** with `define`.
+ *
+ * ```js
+ * // arbitrary `render` function using lodash `template`
+ * app.define('render', function(str, locals) {
+ * return _.template(str)(locals);
+ * });
+ * ```
+ * @name .define
+ * @param {String} `key` The name of the property to define.
+ * @param {any} `value`
+ * @return {Object} Returns the instance for chaining.
+ * @api public
+ */
+
+ Base.prototype.define = function(key, val) {
+ if (utils.isObject(key)) {
+ return this.visit('define', key);
+ }
+ utils.define(this, key, val);
+ return this;
+ };
+
+ /**
+ * Mix property `key` onto the Base prototype. If base is inherited using
+ * `Base.extend` this method will be overridden by a new `mixin` method that will
+ * only add properties to the prototype of the inheriting application.
+ *
+ * ```js
+ * app.mixin('foo', function() {
+ * // do stuff
+ * });
+ * ```
+ * @name .mixin
+ * @param {String} `key`
+ * @param {Object|Array} `val`
+ * @return {Object} Returns the `base` instance for chaining.
+ * @api public
+ */
+
+ Base.prototype.mixin = function(key, val) {
+ Base.prototype[key] = val;
+ return this;
+ };
+
+ /**
+ * Non-enumberable mixin array, used by the static [Base.mixin]() method.
+ */
+
+ Base.prototype.mixins = Base.prototype.mixins || [];
+
+ /**
+ * Getter/setter used when creating nested instances of `Base`, for storing a reference
+ * to the first ancestor instance. This works by setting an instance of `Base` on the `parent`
+ * property of a "child" instance. The `base` property defaults to the current instance if
+ * no `parent` property is defined.
+ *
+ * ```js
+ * // create an instance of `Base`, this is our first ("base") instance
+ * var first = new Base();
+ * first.foo = 'bar'; // arbitrary property, to make it easier to see what's happening later
+ *
+ * // create another instance
+ * var second = new Base();
+ * // create a reference to the first instance (`first`)
+ * second.parent = first;
+ *
+ * // create another instance
+ * var third = new Base();
+ * // create a reference to the previous instance (`second`)
+ * // repeat this pattern every time a "child" instance is created
+ * third.parent = second;
+ *
+ * // we can always access the first instance using the `base` property
+ * console.log(first.base.foo);
+ * //=> 'bar'
+ * console.log(second.base.foo);
+ * //=> 'bar'
+ * console.log(third.base.foo);
+ * //=> 'bar'
+ * // and now you know how to get to third base ;)
+ * ```
+ * @name .base
+ * @api public
+ */
+
+ Object.defineProperty(Base.prototype, 'base', {
+ configurable: true,
+ get: function() {
+ return this.parent ? this.parent.base : this;
+ }
+ });
+
+ /**
+ * Static method for adding global plugin functions that will
+ * be added to an instance when created.
+ *
+ * ```js
+ * Base.use(function(app) {
+ * app.foo = 'bar';
+ * });
+ * var app = new Base();
+ * console.log(app.foo);
+ * //=> 'bar'
+ * ```
+ * @name #use
+ * @param {Function} `fn` Plugin function to use on each instance.
+ * @return {Object} Returns the `Base` constructor for chaining
+ * @api public
+ */
+
+ utils.define(Base, 'use', function(fn) {
+ fns.push(fn);
+ return Base;
+ });
+
+ /**
+ * Run an array of functions by passing each function
+ * to a method on the given object specified by the given property.
+ *
+ * @param {Object} `obj` Object containing method to use.
+ * @param {String} `prop` Name of the method on the object to use.
+ * @param {Array} `arr` Array of functions to pass to the method.
+ */
+
+ utils.define(Base, 'run', function(obj, prop, arr) {
+ var len = arr.length, i = 0;
+ while (len--) {
+ obj[prop](arr[i++]);
+ }
+ return Base;
+ });
+
+ /**
+ * Static method for inheriting the prototype and static methods of the `Base` class.
+ * This method greatly simplifies the process of creating inheritance-based applications.
+ * See [static-extend][] for more details.
+ *
+ * ```js
+ * var extend = cu.extend(Parent);
+ * Parent.extend(Child);
+ *
+ * // optional methods
+ * Parent.extend(Child, {
+ * foo: function() {},
+ * bar: function() {}
+ * });
+ * ```
+ * @name #extend
+ * @param {Function} `Ctor` constructor to extend
+ * @param {Object} `methods` Optional prototype properties to mix in.
+ * @return {Object} Returns the `Base` constructor for chaining
+ * @api public
+ */
+
+ utils.define(Base, 'extend', utils.cu.extend(Base, function(Ctor, Parent) {
+ Ctor.prototype.mixins = Ctor.prototype.mixins || [];
+
+ utils.define(Ctor, 'mixin', function(fn) {
+ var mixin = fn(Ctor.prototype, Ctor);
+ if (typeof mixin === 'function') {
+ Ctor.prototype.mixins.push(mixin);
+ }
+ return Ctor;
+ });
+
+ utils.define(Ctor, 'mixins', function(Child) {
+ Base.run(Child, 'mixin', Ctor.prototype.mixins);
+ return Ctor;
+ });
+
+ Ctor.prototype.mixin = function(key, value) {
+ Ctor.prototype[key] = value;
+ return this;
+ };
+ return Base;
+ }));
+
+ /**
+ * Used for adding methods to the `Base` prototype, and/or to the prototype of child instances.
+ * When a mixin function returns a function, the returned function is pushed onto the `.mixins`
+ * array, making it available to be used on inheriting classes whenever `Base.mixins()` is
+ * called (e.g. `Base.mixins(Child)`).
+ *
+ * ```js
+ * Base.mixin(function(proto) {
+ * proto.foo = function(msg) {
+ * return 'foo ' + msg;
+ * };
+ * });
+ * ```
+ * @name #mixin
+ * @param {Function} `fn` Function to call
+ * @return {Object} Returns the `Base` constructor for chaining
+ * @api public
+ */
+
+ utils.define(Base, 'mixin', function(fn) {
+ var mixin = fn(Base.prototype, Base);
+ if (typeof mixin === 'function') {
+ Base.prototype.mixins.push(mixin);
+ }
+ return Base;
+ });
+
+ /**
+ * Static method for running global mixin functions against a child constructor.
+ * Mixins must be registered before calling this method.
+ *
+ * ```js
+ * Base.extend(Child);
+ * Base.mixins(Child);
+ * ```
+ * @name #mixins
+ * @param {Function} `Child` Constructor function of a child class
+ * @return {Object} Returns the `Base` constructor for chaining
+ * @api public
+ */
+
+ utils.define(Base, 'mixins', function(Child) {
+ Base.run(Child, 'mixin', Base.prototype.mixins);
+ return Base;
+ });
+
+ /**
+ * Similar to `util.inherit`, but copies all static properties, prototype properties, and
+ * getters/setters from `Provider` to `Receiver`. See [class-utils][]{#inherit} for more details.
+ *
+ * ```js
+ * Base.inherit(Foo, Bar);
+ * ```
+ * @name #inherit
+ * @param {Function} `Receiver` Receiving (child) constructor
+ * @param {Function} `Provider` Providing (parent) constructor
+ * @return {Object} Returns the `Base` constructor for chaining
+ * @api public
+ */
+
+ utils.define(Base, 'inherit', utils.cu.inherit);
+ utils.define(Base, 'bubble', utils.cu.bubble);
+ return Base;
+}
+
+/**
+ * Expose `Base` with default settings
+ */
+
+module.exports = namespace();
+
+/**
+ * Allow users to define a namespace
+ */
+
+module.exports.namespace = namespace;
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..77f00c2
--- /dev/null
+++ b/package.json
@@ -0,0 +1,110 @@
+{
+ "name": "base",
+ "description": "base is the foundation for creating modular, unit testable and highly pluggable node.js applications, starting with a handful of common methods, like `set`, `get`, `del` and `use`.",
+ "version": "0.11.1",
+ "homepage": "https://github.com/node-base/base",
+ "author": "Jon Schlinkert (https://github.com/jonschlinkert)",
+ "contributors": [
+ "Brian Woodward (https://github.com/doowb)"
+ ],
+ "maintainers": [
+ "Brian Woodward (https://github.com/doowb)",
+ "Jon Schlinkert (https://github.com/jonschlinkert)"
+ ],
+ "repository": "node-base/base",
+ "bugs": {
+ "url": "https://github.com/node-base/base/issues"
+ },
+ "license": "MIT",
+ "files": [
+ "index.js",
+ "utils.js"
+ ],
+ "main": "index.js",
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "scripts": {
+ "test": "mocha"
+ },
+ "dependencies": {
+ "arr-union": "^3.1.0",
+ "cache-base": "^0.8.4",
+ "class-utils": "^0.3.4",
+ "component-emitter": "^1.2.1",
+ "define-property": "^0.2.5",
+ "isobject": "^2.1.0",
+ "lazy-cache": "^2.0.1",
+ "mixin-deep": "^1.1.3",
+ "pascalcase": "^0.1.1"
+ },
+ "devDependencies": {
+ "gulp": "^3.9.1",
+ "gulp-eslint": "^2.0.0",
+ "gulp-format-md": "^0.1.9",
+ "gulp-istanbul": "^0.10.4",
+ "gulp-mocha": "^2.2.0",
+ "helper-coverage": "^0.1.3",
+ "mocha": "^2.5.3",
+ "should": "^9.0.1",
+ "through2": "^2.0.1",
+ "verb-readme-generator": "^0.1.13"
+ },
+ "keywords": [
+ "boilerplate",
+ "cache",
+ "del",
+ "get",
+ "inherit",
+ "methods",
+ "set",
+ "starter",
+ "unset",
+ "visit"
+ ],
+ "verb": {
+ "run": true,
+ "toc": false,
+ "layout": "default",
+ "tasks": [
+ "readme"
+ ],
+ "plugins": [
+ "gulp-format-md"
+ ],
+ "helpers": [
+ "helper-coverage"
+ ],
+ "related": {
+ "description": "There are a number of different plugins available for extending base. Let us know if you create your own!",
+ "hightlight": "generate",
+ "list": [
+ "base-cwd",
+ "base-data",
+ "base-fs",
+ "base-generators",
+ "base-option",
+ "base-pipeline",
+ "base-pkg",
+ "base-plugins",
+ "base-questions",
+ "base-store",
+ "base-task"
+ ]
+ },
+ "reflinks": [
+ "assemble",
+ "boilerplate",
+ "cache-base",
+ "class-utils",
+ "generate",
+ "scaffold",
+ "verb",
+ "static-extend",
+ "verb-readme-generator"
+ ],
+ "lint": {
+ "reflinks": true
+ }
+ }
+}
diff --git a/test.js b/test.js
new file mode 100644
index 0000000..90a6404
--- /dev/null
+++ b/test.js
@@ -0,0 +1,860 @@
+'use strict';
+
+require('mocha');
+require('should');
+var assert = require('assert');
+var utils = require('./utils');
+var Base = require('./');
+var base;
+
+describe('constructor', function() {
+ it('should return an instance of Base:', function() {
+ base = new Base();
+ assert(base instanceof Base);
+ });
+
+ it('should return an instance of Base without new:', function() {
+ base = Base();
+ assert(base instanceof Base);
+ });
+
+ it('should "visit" over an object to extend the instance', function() {
+ base = new Base({foo: 'bar'});
+ assert.equal(base.foo, 'bar');
+ var app = new Base({options: {a: true, b: false}});
+ assert(app.options);
+ assert.equal(app.options.a, true);
+ assert.equal(app.options.b, false);
+ });
+
+ it('should map "visit" over an array to extend the instance', function() {
+ base = new Base([{foo: 'bar'}, {baz: 'qux'}]);
+ assert.equal(base.foo, 'bar');
+ assert.equal(base.baz, 'qux');
+ });
+
+ it('should set options passed as the second argument', function() {
+ base = new Base(null, {abc: 'xyz'});
+ assert.equal(base.options.abc, 'xyz');
+ });
+
+ it('should merge options throughout the inheritance chain', function() {
+ function Foo(options) {
+ Base.call(this, null, options);
+ this.options.x = 'y';
+ }
+ Base.extend(Foo);
+
+ function Bar(options) {
+ Foo.call(this, options);
+ }
+ Foo.extend(Bar);
+
+ var bar = new Bar({a: 'b'});
+
+ assert.equal(bar.options.a, 'b');
+ assert.equal(bar.options.x, 'y');
+ });
+
+ it('should add foo', function() {
+ base = new Base({
+ foo: 'bar'
+ });
+ assert.equal(base.foo, 'bar');
+ });
+
+ it('should set isBase on the instance', function() {
+ base = new Base();
+ assert.equal(base.isBase, true);
+ });
+});
+
+describe('static properties', function() {
+ beforeEach(function() {
+ base = new Base();
+ });
+
+ it('should expose `.use` method', function() {
+ assert.equal(typeof Base.use, 'function');
+ });
+
+ it('should expose `.extend` method', function() {
+ assert.equal(typeof Base.extend, 'function');
+ });
+
+ it('should extend the given Ctor with static methods:', function() {
+ function Ctor() {
+ Base.call(this);
+ }
+ Base.extend(Ctor);
+ assert.equal(typeof Ctor.extend, 'function');
+
+ function foo() {}
+ Ctor.extend(foo);
+ assert.equal(typeof foo.extend, 'function');
+ });
+
+ describe('.extend', function() {
+ it('should set the extend method on the given object:', function() {
+ function Ctor() {}
+ Base.extend(Ctor);
+ assert.equal(typeof Ctor.extend, 'function');
+ });
+ });
+
+ describe('.use', function() {
+ it('should set the use method on the given object:', function() {
+ function Ctor() {}
+ Base.extend(Ctor);
+ assert.equal(typeof Ctor.use, 'function');
+ });
+
+ it('should use a globally loaded plugin through the static use method:', function() {
+ function Ctor() {
+ Base.call(this);
+ }
+ Base.extend(Ctor);
+ Ctor.use(function(app) {
+ app.foo = 'bar';
+ });
+ var inst = new Ctor();
+ assert.equal(inst.foo, 'bar');
+ });
+
+ it('should use a globally loaded plugin through the static use method with namespace:', function() {
+ var Foo = Base.namespace('foo');
+ Foo.use(function(app) {
+ app.set('bar', 'baz');
+ });
+ var inst = new Foo();
+ assert.equal(inst.get('bar'), 'baz');
+ assert.equal(inst.foo.bar, 'baz');
+ });
+
+ it('should use different globally installed plugins when using different namespaces:', function() {
+ var Foo = Base.namespace('foo');
+ var Bar = Base.namespace('bar');
+
+ Foo.use(function(app) {
+ app.set('bar', 'baz');
+ });
+ Bar.use(function(app) {
+ app.set('beep', 'boop');
+ });
+
+ var foo = new Foo();
+ var bar = new Bar();
+
+ assert.equal(foo.get('bar'), 'baz');
+ assert.equal(foo.foo.bar, 'baz');
+ assert.equal(typeof foo.get('beep'), 'undefined');
+ assert.equal(typeof foo.foo.beep, 'undefined');
+
+ assert.equal(bar.get('beep'), 'boop');
+ assert.equal(bar.bar.beep, 'boop');
+ assert.equal(typeof bar.get('bar'), 'undefined');
+ assert.equal(typeof bar.bar.bar, 'undefined');
+ });
+ });
+
+ describe('.mixin', function() {
+ it('should set the mixin method on the given object:', function() {
+ function Ctor() {}
+ Base.extend(Ctor);
+ assert.equal(typeof Base.mixin, 'function');
+ assert.equal(typeof Ctor.mixin, 'function');
+ });
+
+ it('should use a globally loaded mixin through the static mixin method:', function() {
+ function Ctor() {
+ Base.call(this);
+ }
+ Base.extend(Ctor);
+ Base.mixin(function(proto) {
+ proto.foo = 'bar';
+ });
+
+ var inst = new Ctor();
+ Ctor.mixin(function(proto) {
+ proto.bar = 'baz';
+ });
+
+ assert.equal(Base.prototype.foo, 'bar');
+ assert.equal(Ctor.prototype.bar, 'baz');
+ assert.equal(inst.foo, 'bar');
+ assert.equal(inst.bar, 'baz');
+ });
+ });
+
+ describe('.mixins', function() {
+ it('should set the mixins method on the given object:', function() {
+ function Ctor() {}
+ Base.extend(Ctor);
+ assert.equal(typeof Ctor.mixins, 'function');
+ });
+
+ it('should use a globally loaded mixin through the static mixins method:', function() {
+
+ function Ctor() {
+ Base.call(this);
+ }
+ Base.extend(Ctor);
+ Base.mixin(function fn(proto) {
+ proto.bar = 'bar';
+ return fn;
+ });
+
+ function Child() {
+ Ctor.call(this);
+ }
+ Base.extend(Child);
+ Base.mixins(Child);
+ Ctor.mixins(Child);
+
+ var inst = new Child();
+ assert.equal(Child.prototype.bar, 'bar');
+ assert.equal(inst.bar, 'bar');
+ });
+ });
+});
+
+describe('extend prototype methods', function() {
+ beforeEach(function() {
+ var Ctor = require('./');
+ Base = Ctor.namespace();
+ });
+
+ it('should extend the prototype of the given Ctor:', function() {
+ function Ctor() {
+ Base.call(this);
+ }
+ Base.extend(Ctor);
+ assert.equal(typeof Ctor.extend, 'function');
+
+ var ctor = new Ctor();
+ assert.equal(typeof ctor.set, 'function');
+ assert.equal(typeof ctor.get, 'function');
+ });
+
+ it('should expose `prototype.set` method', function() {
+ assert.equal(typeof Base.prototype.set, 'function');
+ });
+
+ it('should expose `prototype.get` method', function() {
+ assert.equal(typeof Base.prototype.get, 'function');
+ });
+
+ it('should expose `prototype.del` method', function() {
+ assert.equal(typeof Base.prototype.del, 'function');
+ });
+
+ it('should expose `prototype.visit` method', function() {
+ assert.equal(typeof Base.prototype.visit, 'function');
+ });
+
+ it('should expose `prototype.define` method', function() {
+ assert.equal(typeof Base.prototype.define, 'function');
+ });
+
+ it('should expose `prototype.mixin` method', function() {
+ assert.equal(typeof Base.prototype.mixin, 'function');
+ });
+
+ it('should add prototype methods to the given Ctor:', function() {
+ function Ctor() {
+ Base.call(this);
+ }
+ Base.extend(Ctor);
+ assert.equal(typeof Ctor.prototype.set, 'function');
+ assert.equal(typeof Ctor.prototype.get, 'function');
+ assert.equal(typeof Ctor.prototype.del, 'function');
+ assert.equal(typeof Ctor.prototype.visit, 'function');
+ assert.equal(typeof Ctor.prototype.define, 'function');
+ assert.equal(typeof Ctor.prototype.mixin, 'function');
+
+ function foo() {}
+ Ctor.extend(foo);
+ assert.equal(typeof foo.prototype.set, 'function');
+ });
+});
+
+describe('instance properties', function() {
+ beforeEach(function() {
+ var Ctor = require('./');
+ Base = Ctor.namespace();
+ base = new Base();
+ });
+
+ it('should expose the options property:', function() {
+ assert(base.options);
+ assert.equal(typeof base.options, 'object');
+ });
+
+ it('should expose the cache property:', function() {
+ assert(base.cache);
+ assert.equal(typeof base.cache, 'object');
+ });
+});
+
+describe('prototype methods', function() {
+ beforeEach(function() {
+ var Ctor = require('./');
+ Base = Ctor.namespace();
+ base = new Base();
+ });
+
+ describe('.use', function() {
+ beforeEach(function() {
+ base = new Base();
+ });
+
+ it('should expose the use method:', function() {
+ assert(base.use);
+ assert.equal(typeof base.use, 'function');
+ });
+
+ it('should call the function passed to `use`:', function(cb) {
+ base.use(function(app) {
+ assert(app);
+ cb();
+ });
+ });
+
+ it('should expose the app instance:', function(cb) {
+ base.foo = 'bar';
+ base.use(function(app) {
+ assert.equal(app.foo, 'bar');
+ cb();
+ });
+ });
+
+ it('should expose the app instance as "this":', function(cb) {
+ base.foo = 'bar';
+ base.use(function(app) {
+ assert.equal(this.foo, 'bar');
+ cb();
+ });
+ });
+ });
+
+ describe('when `isRegistered` is used', function() {
+ it('should not call a plugin more than once on the same instance', function() {
+ base.i = 0;
+ function plugin(app) {
+ if (app.isRegistered('foo')) return;
+ base.i++;
+ }
+
+ base.use(plugin);
+ base.use(plugin);
+ base.use(plugin);
+ base.use(plugin);
+
+ assert.equal(base.i, 1);
+ });
+
+ it('should not register a plugin when `false` is passed as the 2nd arg', function() {
+ function plugin(app) {
+ if (app.isRegistered('foo', false)) return;
+ this.foo = 'bar';
+ }
+
+ base.use(plugin);
+ assert(!base.registered.hasOwnProperty('foo'));
+ assert.equal(base.foo, 'bar');
+ });
+
+ it('should not call a plugin more than once on the same instance', function() {
+ base.i = 0;
+ function plugin(app) {
+ if (app.isRegistered('foo')) return;
+ base.i++;
+ }
+
+ base.use(plugin);
+ base.use(plugin);
+ base.use(plugin);
+ base.use(plugin);
+
+ assert.equal(base.i, 1);
+ });
+ });
+
+ describe('.define', function() {
+ it('should define a key-value pair on the instance:', function() {
+ base.define('foo', 'bar');
+ assert.equal(base.foo, 'bar');
+ });
+
+ it('should define an own property', function() {
+ base.define('foo', 'bar');
+ assert(base.hasOwnProperty('foo'));
+ });
+
+ it('should define a non-emumerable property', function() {
+ base.define('foo', 'bar');
+ assert(Object.keys(base).indexOf('foo') === -1);
+ });
+
+ it('should multiple properties', function() {
+ base.define({
+ foo: 'bar',
+ baz: 'qux'
+ });
+
+ assert(base.hasOwnProperty('foo'));
+ assert(base.hasOwnProperty('baz'));
+ });
+ });
+
+ describe('.set', function() {
+ it('should set a key-value pair on the instance:', function() {
+ base.set('foo', 'bar');
+ assert.equal(base.foo, 'bar');
+ });
+
+ it('should set nested property:', function() {
+ base.set('a.b.c', 'd');
+ assert.equal(base.a.b.c, 'd');
+ });
+
+ it('should set a nested property with the key as an array:', function() {
+ base.set(['a', 'b', 'c'], 'd');
+ assert.equal(base.a.b.c, 'd');
+ });
+
+ it('should set an object on the instance:', function() {
+ base.set({a: 'b'});
+ assert.equal(base.a, 'b');
+ });
+ });
+
+ describe('.get', function() {
+ it('should get a property from the instance:', function() {
+ base.set({a: 'b'});
+ assert.equal(base.get('a'), 'b');
+ });
+
+ it('should get a nested property from the instance:', function() {
+ base.set({a: {b: {c: 'd'}}});
+ assert.equal(base.get('a.b.c'), 'd');
+ });
+
+ it('should get a property using an array:', function() {
+ base.set({a: {b: {c: 'd'}}});
+ assert.equal(base.get(['a', 'b', 'c']), 'd');
+ });
+
+ it('should get a property using a list of arguments', function() {
+ base.set({a: {b: {c: 'd'}}});
+ assert.equal(base.get('a', 'b', 'c'), 'd');
+ assert.equal(base.get(['a', 'b'], 'c'), 'd');
+ assert.equal(base.get('a', ['b', 'c']), 'd');
+ assert.equal(base.get('a', 'b.c'), 'd');
+ });
+ });
+
+ describe('.has', function() {
+ it('should work with namespaces:', function() {
+ var Ctor = require('./');
+ Base = Ctor.namespace('cache');
+ var foo = new Base();
+
+ foo.set({a: 'b'});
+ assert.equal(foo.has('a'), true);
+ });
+
+ it('should check for a property from the instance:', function() {
+ base.set({a: 'b'});
+ assert.equal(base.has('a'), true);
+ });
+
+ it('should check for a nested property from the instance:', function() {
+ base.set({a: {b: {c: 'd'}}});
+ assert.equal(base.has('a.b.c'), true);
+ });
+
+ it('should check for a property using an array:', function() {
+ base.set({a: {b: {c: 'd'}}});
+ assert.equal(base.has(['a', 'b', 'c']), true);
+ });
+
+ it('should check for a property using a list of arguments', function() {
+ base.set({a: {b: {c: 'd'}}});
+ assert.equal(base.has('a', 'b', 'c'), true);
+ assert.equal(base.has(['a', 'b'], 'c'), true);
+ assert.equal(base.has('a', ['b', 'c']), true);
+ assert.equal(base.has('a', 'b.c'), true);
+ });
+ });
+
+ describe('.visit', function() {
+ it('should visit an object with the given method:', function() {
+ base.visit('set', {a: 'b', c: 'd'});
+ assert.equal(base.get('a'), 'b');
+ assert.equal(base.get('c'), 'd');
+ });
+ it('should visit an array with the given method:', function() {
+ base.visit('set', [{a: 'b', c: 'd'}]);
+ assert.equal(base.get('a'), 'b');
+ assert.equal(base.get('c'), 'd');
+ });
+ });
+
+ describe('.del', function() {
+ it('should remove a property:', function() {
+ base.set({a: 'b'});
+ assert.equal(base.a, 'b');
+ base.del('a');
+ assert.equal(typeof base.a, 'undefined');
+ });
+
+ it('should remove an array of properties:', function() {
+ base.set({
+ a: 'a'
+ });
+ base.set({
+ b: 'b'
+ });
+ assert.equal(base.a, 'a');
+ assert.equal(base.b, 'b');
+ base.del(['a', 'b']);
+ assert.equal(typeof base.a, 'undefined');
+ assert.equal(typeof base.b, 'undefined');
+ });
+ });
+});
+
+describe('.mixin', function() {
+ beforeEach(function() {
+ var Ctor = require('./');
+ Base = Ctor.namespace();
+ base = new Base();
+ });
+
+ it('should add a property to the base prototype:', function() {
+ base.mixin('a', function() {});
+ assert.equal(typeof base.a, 'function');
+ assert.equal(typeof Base.prototype.a, 'function');
+ });
+
+ it('should add to the prototype of an inheriting app:', function() {
+ function Foo() {
+ Base.call(this);
+ }
+ Base.extend(Foo);
+ var foo = new Foo();
+ foo.mixin('a', function() {});
+ assert.equal(typeof Foo.prototype.a, 'function');
+ assert.equal(typeof foo.a, 'function');
+ });
+
+ it('should add to inheriting app prototype:', function() {
+ function Foo() {
+ Base.call(this);
+ }
+ Base.extend(Foo);
+
+ var base = new Base();
+ var foo = new Foo();
+
+ base.mixin('abc', function() {});
+ foo.mixin('xyz', function() {});
+
+ assert.equal(typeof Base.prototype.abc, 'function');
+ assert.equal(typeof Foo.prototype.abc, 'function');
+ assert.equal(typeof base.abc, 'function');
+ assert.equal(typeof foo.abc, 'function');
+
+ assert(typeof Base.prototype.xyz !== 'function');
+ assert.equal(typeof Foo.prototype.xyz, 'function');
+ assert.equal(typeof foo.xyz, 'function');
+ assert(typeof base.xyz !== 'function');
+ });
+
+ it('should chain calls to mixin:', function() {
+ function Foo() {
+ Base.call(this);
+ }
+ Base.extend(Foo);
+
+ var base = new Base();
+ var foo = new Foo();
+
+ base.mixin('abc', function() {})
+ .mixin('def', function() {});
+
+ foo.mixin('xyz', function() {})
+ .mixin('uvw', function() {});
+
+ assert.equal(typeof Base.prototype.abc, 'function');
+ assert.equal(typeof Base.prototype.def, 'function');
+ assert.equal(typeof Foo.prototype.abc, 'function');
+ assert.equal(typeof Foo.prototype.def, 'function');
+ assert.equal(typeof base.abc, 'function');
+ assert.equal(typeof base.def, 'function');
+ assert.equal(typeof foo.abc, 'function');
+ assert.equal(typeof foo.def, 'function');
+
+ assert(typeof Base.prototype.xyz !== 'function');
+ assert(typeof Base.prototype.uvw !== 'function');
+ assert.equal(typeof Foo.prototype.xyz, 'function');
+ assert.equal(typeof Foo.prototype.uvw, 'function');
+ assert.equal(typeof foo.xyz, 'function');
+ assert.equal(typeof foo.uvw, 'function');
+ assert(typeof base.xyz !== 'function');
+ assert(typeof base.uvw !== 'function');
+ });
+
+ it('should not add to Base.prototype from an inheriting app:', function() {
+ function Foo() {
+ Base.call(this);
+ }
+ Base.extend(Foo);
+
+ var foo = new Foo();
+ var base = new Base();
+
+ foo.mixin('a', function() {});
+
+ // yes
+ assert.equal(typeof Foo.prototype.a, 'function');
+ assert.equal(typeof foo.a, 'function');
+
+ // no
+ assert(typeof Base.prototype.a !== 'function');
+ assert(typeof base.a !== 'function');
+ });
+
+ it('should NOT mixin from one inheriting prototype to another:', function() {
+ function Foo() { Base.call(this); }
+ Base.extend(Foo);
+
+ function Bar() { Base.call(this); }
+ Base.extend(Bar);
+
+ var foo = new Foo();
+ var bar = new Bar();
+
+ foo.mixin('a', function() {});
+
+ // yes
+ assert.equal(typeof Foo.prototype.a, 'function');
+ assert.equal(typeof foo.a, 'function');
+
+ // no
+ assert(typeof Bar.prototype.a !== 'function');
+ assert(typeof bar.a !== 'function');
+ });
+
+ it('should mixin from Base.prototype to all others:', function() {
+ function Foo() { Base.call(this); }
+ Base.extend(Foo);
+
+ function Bar() { Base.call(this); }
+ Base.extend(Bar);
+
+ var base = new Base();
+ var foo = new Foo();
+ var bar = new Bar();
+
+ base.mixin('xyz', function() {});
+
+ assert.equal(typeof Base.prototype.xyz, 'function');
+ assert.equal(typeof Foo.prototype.xyz, 'function');
+ assert.equal(typeof Bar.prototype.xyz, 'function');
+
+ assert.equal(typeof base.xyz, 'function');
+ assert.equal(typeof foo.xyz, 'function');
+ assert.equal(typeof bar.xyz, 'function');
+ });
+});
+
+describe('namespaces', function() {
+ beforeEach(function() {
+ Base = require('./');
+ });
+
+ describe('constructor', function() {
+ it('should expose `namespace`', function() {
+ assert.equal(typeof Base.namespace, 'function');
+ });
+
+ it('should extend the given Ctor with static methods:', function() {
+ var Foo = Base.namespace('cache');
+
+ function Ctor() {
+ Foo.call(this);
+ }
+ Foo.extend(Ctor);
+ assert.equal(typeof Ctor.extend, 'function');
+
+ function foo() {}
+ Ctor.extend(foo);
+ assert.equal(typeof foo.extend, 'function');
+ });
+ });
+
+ describe('prototype methods', function() {
+ beforeEach(function() {
+ var Custom = Base.namespace('cache');
+ base = new Custom();
+ });
+
+ describe('set', function() {
+ it('should set a key-value pair on the instance:', function() {
+ base.set('foo', 'bar');
+ assert.equal(base.cache.foo, 'bar');
+ });
+
+ it('should set an object on the instance:', function() {
+ base.set({
+ a: 'b'
+ });
+ assert.equal(base.cache.a, 'b');
+ });
+ });
+
+ describe('get', function() {
+ it('should get a property from the instance:', function() {
+ base.set({
+ a: 'b'
+ });
+ assert.equal(base.get('a'), 'b');
+ });
+
+ it('should visit an object with the given method:', function() {
+ base.visit('set', {
+ a: 'b',
+ c: 'd'
+ });
+ assert.equal(base.get('a'), 'b');
+ assert.equal(base.get('c'), 'd');
+ });
+ it('should visit an array with the given method:', function() {
+ base.visit('set', [{
+ a: 'b',
+ c: 'd'
+ }]);
+ assert.equal(base.get('a'), 'b');
+ assert.equal(base.get('c'), 'd');
+ });
+ });
+
+ describe('del', function() {
+ it('should remove a property:', function() {
+ base.set({
+ a: 'b'
+ });
+ assert.equal(base.cache.a, 'b');
+ base.del('a');
+ assert.equal(typeof base.cache.a, 'undefined');
+ });
+
+ it('should remove an array of properties:', function() {
+ base.set({
+ a: 'a'
+ });
+ base.set({
+ b: 'b'
+ });
+ assert.equal(base.cache.a, 'a');
+ assert.equal(base.cache.b, 'b');
+ base.del(['a', 'b']);
+ assert.equal(typeof base.cache.a, 'undefined');
+ assert.equal(typeof base.cache.b, 'undefined');
+ });
+ });
+ });
+});
+
+describe('.base', function() {
+ beforeEach(function() {
+ base = new Base();
+ });
+
+ it('should set a `base` property on the instance', function() {
+ assert(base.base);
+ assert.equal(typeof base.base, 'object');
+ });
+
+ it('should use `parent` to set app.base', function() {
+ var foo = new Base();
+ foo.abc = 'xyz';
+
+ var bar = new Base();
+ bar.parent = foo;
+
+ var baz = new Base();
+ baz.parent = bar;
+
+ assert(baz.base);
+ assert.equal(baz.base.abc, 'xyz');
+ });
+});
+
+describe('.is', function() {
+ beforeEach(function() {
+ var Ctor = require('./');
+ Base = Ctor.namespace();
+ base = new Base();
+ });
+
+ it('should set a name prefixed with `is` on the instance:', function() {
+ base.is('Foo');
+ assert(base.isFoo);
+ assert.equal(base.isFoo, true);
+ });
+});
+
+describe('events', function() {
+ beforeEach(function() {
+ base = new Base();
+ });
+
+ it('should emit and listen for events:', function(cb) {
+ base.on('foo', function(val) {
+ assert.equal(val, 'bar');
+ cb();
+ });
+ base.emit('foo', 'bar');
+ });
+
+ it('should emit set', function(cb) {
+ base.on('set', function(key, val) {
+ assert.equal(key, 'foo');
+ assert.equal(val, 'bar');
+ cb();
+ });
+ base.set('foo', 'bar');
+ });
+
+ it('should emit get', function(cb) {
+ base.on('get', function(key, val) {
+ assert.equal(key, 'foo');
+ assert.equal(val, 'bar');
+ cb();
+ });
+ base.set('foo', 'bar');
+ base.get('foo');
+ });
+
+ it('should emit has', function(cb) {
+ base.on('has', function(key, has) {
+ assert.equal(key, 'foo');
+ assert.equal(has, true);
+ cb();
+ });
+ base.set('foo', 'bar');
+ base.has('foo');
+ });
+
+ it('should emit del', function(cb) {
+ base.on('del', function(key, val) {
+ assert.equal(key, 'foo');
+ cb();
+ });
+ base.set('foo', 'bar');
+ base.del('foo');
+ });
+});
diff --git a/utils.js b/utils.js
new file mode 100644
index 0000000..b4dd5cc
--- /dev/null
+++ b/utils.js
@@ -0,0 +1,25 @@
+'use strict';
+
+var utils = require('lazy-cache')(require);
+var fn = require;
+require = utils; // eslint-disable-line
+
+/**
+ * Lazily required module dependencies
+ */
+
+require('arr-union', 'union');
+require('cache-base', 'Cache');
+require('define-property', 'define');
+require('component-emitter', 'Emitter');
+require('class-utils', 'cu');
+require('isobject', 'isObject');
+require('mixin-deep', 'merge');
+require('pascalcase', 'pascal');
+require = fn; // eslint-disable-line
+
+/**
+ * Expose `utils` modules
+ */
+
+module.exports = utils;
diff --git a/verbfile.js b/verbfile.js
new file mode 100644
index 0000000..863263c
--- /dev/null
+++ b/verbfile.js
@@ -0,0 +1,19 @@
+'use strict';
+
+var through = require('through2');
+
+module.exports = function(verb) {
+ verb.use(require('verb-readme-generator'));
+ verb.task('default', ['readme'], function(cb) {
+ return verb.src('README.md')
+ .pipe(through.obj(function(file, enc, next) {
+ var str = file.contents.toString();
+ str = str.replace(/^(#+ \[)\.#/gm, '$1Base.');
+ file.contents = new Buffer(str);
+ next(null, file);
+ }))
+ .pipe(verb.dest('.'));
+ });
+};
+
+
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-base.git
More information about the Pkg-javascript-commits
mailing list