UNPKG

5.23 kBJavaScriptView Raw
1'use strict';
2
3var path = require('path');
4var util = require('util');
5var async = require('async');
6var EventEmitter = require('events').EventEmitter;
7var Klect = require('klect');
8
9util.inherits(Bijous, EventEmitter);
10
11/**
12 * @callback Bijous~moduleCallback
13 * @desc The callback used when loading modules to tell {@linkcode Bijous} that the module has completed loading.
14 * @param {object=} error - If an error occurs the callback will receive an error object
15 * @param {*=} results - An object used to represent the module after loading
16 */
17
18/**
19 * @callback Bijous~module
20 * @desc A module to be loaded by {@linkcode Bijous}. This callback must be the sole export of the node module's
21 * entry-point.
22 * @param {Bijous} context - The {@linkcode Bijous} object that is loading the module
23 * @param {Bijous~moduleCallback} done - The callback that alerts {@linkcode Bijous} the async task is complete.
24 * @example
25 * // We may assume this resides in a file modules/module1/index.js
26 * exports = module.exports = function (context, done) {
27 * done(null, null);
28 * }
29 */
30
31/**
32 * An asynchronous module loader. Searches out {@linkcode Bijous~module|modules} and loads them asynchronously.
33 * @class
34 * @param {object=} options
35 * @param {string=} options.cwd - Override the current working directory
36 * @param {object=} options.bundles - Override the [klect]{@link https://github.com/awnist/klect} bundles description
37 * @property {string} cwd - The current working directory, used to find modules. Defaults to the directory the module's
38 * parent resides in
39 * @property {object} bundles - The [klect]{@link https://github.com/awnist/klect} bundles description, used to find
40 * modules. Defaults to {@linkcode Bijous#defaultBundles}
41 * @property {object} modules - An object containing keys that represent results returned by modules when the
42 * {@linkcode Bijous#load} method is called. The keys correspond with the module's filename, not including the
43 * extension. (e.g. modules/module1 would have a key module1 and modules/module2.js would have a key module2)
44 */
45function Bijous(options) {
46 options = options || {};
47 EventEmitter.call(this);
48
49 var mod = module.parent;
50
51 this.cwd = options.cwd || path.dirname(mod.filename);
52 this.bundles = options.bundles || Bijous.defaultBundles;
53 this.modules = {};
54}
55
56/**
57 * Retrieves all modules found for it's bundles or a supplied bundle name
58 * @param {string=} bundle - The name of the bundle that should be used when retrieving modules
59 * @returns {object[]} - An array of [klect]{@link https://github.com/awnist/klect} assets
60 */
61Bijous.prototype.list = function list(bundle) {
62 var klect = new Klect({ cwd: this.cwd });
63 var assets = klect.gather(this.bundles);
64
65 if (bundle) { return assets.bundles(bundle); }
66 else { return assets; }
67};
68
69/**
70 * @callback Bijous~loadCallback
71 * @desc Used as a callback override for the {@linkcode Bijous#load} method. If one is specified then error handling
72 * becomes it's responsibility. When one is not specified and an error occurs then the error will be thrown.
73 * @param {object=} error - If an error occurs the callback will receive an error object
74 * @param {*=} results - An array of any objects returned as representations of modules
75 */
76
77/**
78 * Requires all modules found for it's bundles or a supplied bundle name, and executes the async callback defined by the
79 * module
80 * @param {string=} bundle - The name of the bundle that should be used when loading modules
81 * @param {Bijous~loadCallback=} callback - A callback method to use when all modules are loaded
82 */
83Bijous.prototype.load = function load(bundle, callback) {
84 if ('function' === typeof bundle) {
85 callback = bundle;
86 bundle = null;
87 }
88
89 var modules = this.require(bundle);
90 var moduleKeys = Object.keys(modules);
91 var self = this;
92
93 var fns = moduleKeys.map(function (key) {
94 return function loadAsset(done) {
95 var cb = function (error, results) {
96 if (results) { self.modules[key] = results; }
97
98 self.emit('loaded', key, results);
99 done(error, results);
100 };
101
102 modules[key].call(null, self, cb);
103 };
104 });
105
106 async.series(fns, function (error, results) {
107 if (callback) { callback(error, results); }
108 else if (error) { throw error; }
109
110 self.emit('done', self);
111 });
112};
113
114/**
115 * Loads all modules found for it's bundles or a supplied bundle name
116 * @param {string=} bundle - The name of the bundle that should be used when requiring modules
117 * @returns {object} - An object containing keys corresponding with the module's filename, not including the extension.
118 * (e.g. modules/module1 would have a key module1 and modules/module2.js would have a key module2)
119 */
120Bijous.prototype.require = function req(bundle) {
121 var assets = this.list(bundle);
122 var self = this;
123 var modules = {};
124
125 assets.files().map(function (file) {
126 var extname = path.extname(file);
127 var basename = path.basename(file, extname);
128
129 modules[basename] = require(path.join(self.cwd, file));
130 });
131
132 return modules;
133};
134
135/**
136 * The default bundles definition, confirms to [klect]{@link https://github.com/awnist/klect} bundles
137 */
138Bijous.defaultBundles = 'modules/*';
139
140exports = module.exports = Bijous;
\No newline at end of file