This repository has been archived on 2018-10-12. You can view files and clone it, but cannot push or open issues or pull requests.
ProgBlog/app/Container.js

151 lines
3.3 KiB
JavaScript

'use strict';
const errors = require('errors');
const express = require('express');
const negotiate = require('express-negotiate');
const path = require('path');
const autoLoad = require('./config/container-autoload');
/**
* Determine the appropriate path to a module relative to the 'app' folder
*
* @private
* @param {string} modulePath - the raw path to the module
* @return {string} - the normalized path to the module
*/
function normalizeIncludePath(modulePath) {
const basePath = path.resolve(path.join(__dirname, '../'));
let includePath = modulePath;
// Allow referencing local modules without using a ./
// eg. util/route-loader instead of ./util/route-loader
if (
modulePath.includes('/') &&
! (modulePath.startsWith('./') || modulePath.includes(__dirname))
) {
includePath = path.join(__dirname, modulePath);
}
return includePath;
}
/**
* Container for keeping track of dependencies
*/
class Container {
constructor() {
const app = express();
let container = new Map();
// Save the base app object
container.set('app', app);
// Preload some configured modules
autoLoad.map((module) => {
let moduleMap = module;
// Normalize config into [key, value]
if (! Array.isArray(module)) {
moduleMap = [module, module];
}
// Actually require the module
moduleMap[1] = require(normalizeIncludePath(moduleMap[1]));
container.set.apply(container, moduleMap);
});
this._container = container;
}
/**
* Determine if an item exists in the container
*
* @param {string} name - name of the item
* @return {boolean} - whether the item exists in the container
*/
has(name) {
return this._container.has(name);
}
/**
* Return an existing object instance
*
* @param {string} name - name of the item
* @return {Object|undefined} - the item, or undefined if it doesn't exist
*/
get(name) {
if (this.has(name)) {
return this._container.get(name);
}
return this._require(name);
}
/**
* Get a base library instance
*
* @param {string} name - name of the base module
* @returns {*} - the base module
*/
getBase(name) {
return this.get(`base/${name}`);
}
/**
* Get a helper library instance
*
* @param {string} name - name of the helper module
* @return {*} - the helper instance
*/
getHelper(name) {
return this.get(`helpers/${name}`);
}
/**
* Get a model
* @param {string} name - the name of the model module
* @returns {*} - the model
*/
getModel(name) {
return this.get(`models/${name}`);
}
/**
* Set an object in the container
*
* @param {string} name - name to associate with object
* @param {Object} object - item to keep track of
* @return {Container} - the container instance
*/
set(name, object) {
this._container.set(name, object);
return this;
}
/**
* Does a native require, relative to the lib folder,
* and returns the value
*
* @private
* @param {string} modulePath - name of the module to require
* @return {*} - the value returned from require
*/
_require(modulePath) {
// If the value is already saved, just return it
if (this.has(modulePath)) {
return this.get(modulePath);
}
// Save the item for later
let item = require(normalizeIncludePath(modulePath));
this.set(modulePath, item);
return item;
}
}
module.exports = new Container();