Source: lib/configuration.js

/*------------------------------------*\
	CONFIGURATION
\*------------------------------------*/
/* jslint node: true */

/**
 * Set required variables for application and CLI language messages.
 * @private
 * @function initRequiredVars
 * @memberOf NA#
 * @this NA
 */
exports.initRequiredVars = function () {
	var NA = this,
		path = NA.modules.path;

	/**
	 * Name of file which contains language error messages. The name of file is without extension.
	 * @private
	 * @alias cliLanguage
	 * @type {string}
	 * @memberOf NA#
	 * @default "default"
	 */
	NA.cliLanguage = "default";

	/**
	 * All internationalize labels from `NA#cliLanguage` file.
	 * @private
	 * @alias cliLabels
	 * @type {Object}
	 * @memberOf NA#
	 */
	NA.cliLabels = require("../languages/" + NA.cliLanguage + ".json");

	/**
	 * OS absolute path which contains NodeAtlas folders and files.
	 * @public
	 * @alias nodeatlasPath
	 * @type {string}
	 * @memberOf NA#
	 * @default « The path where `node-atlas` module is. »
	 */
	NA.nodeatlasPath = path.join(__dirname, "..");

	/**
	 * Contain all functions of controllers both common and specific.
	 * @namespace controllers[]
	 * @private
	 * @alias controllers
	 * @type {Array.<Object>}
	 * @memberOf NA#
	 * @example // Functions for common controller if common `controller` value is "common.json".
	 * NA.controllers["common.json"].setModules(...);
	 * NA.controllers["common.json"].setSessions(...);
	 * NA.controllers["common.json"].setSockets(...);
	 * NA.controllers["common.json"].setConfigurations(...);
	 * NA.controllers["common.json"].setRoutes(...);
	 * NA.controllers["common.json"].changeVariations(...);
	 * NA.controllers["common.json"].changeDom(...);
	 *
	 * // Functions for specific controller if a route `controller` value is "index.json".
	 * NA.controllers["index.json"].setSockets(...);
	 * NA.controllers["index.json"].changeVariations(...);
	 * NA.controllers["index.json"].changeDom(...);
	 */
	NA.controllers = [];
};

/**
 * Set command line options usable when NodeAtlas is executed as CLI.
 * @private
 * @function initCliConfiguration
 * @memberOf NA#
 * @this NA
 */
exports.initCliConfiguration = function () {
	var NA = this,
		commander = NA.modules.commander,
		commands = [
			"lang",
			"generate",
			"create",
			"httpSecure",
			"browse",
			"version",
			"cache",
			"path",
			"webconfig",
			"httpHostname",
			"httpPort",
		],
		i;

	/**
	 * Allows you to know the current version of NodeAtlas.
	 * @public
	 * @alias version
	 * @type {string}
	 * @memberOf NA#
	 */
	NA.version = require("../package.json").version;

	commander

		/* Version of NodeAtlas currently in use with `--version` option. */
		.version(NA.version)

		/* Automaticly run default browser with `--browse` options. If a param is setted, the param is added to the and of url. */
		.option(NA.cliLabels.commander.browse.command, NA.cliLabels.commander.browse.description, String)

		/* Target the directory in which website and NodeAtlas will be running. */
		.option(NA.cliLabels.commander.path.command, NA.cliLabels.commander.path.description, String)

		/* Change name of JSON file used as the webconfig file. */
		.option(NA.cliLabels.commander.webconfig.command, NA.cliLabels.commander.webconfig.description, String)

		/* Change the hostname that runs the NodeAtlas website. */
		.option(NA.cliLabels.commander.httpHostname.command, NA.cliLabels.commander.httpHostname.description, String)

		/* Change the port that runs the NodeAtlas website. */
		.option(NA.cliLabels.commander.httpPort.command, NA.cliLabels.commander.httpPort.description, String)

		/* Minify all files and re-create all HTML assets into generates folder. */
		.option(NA.cliLabels.commander.generate.command, NA.cliLabels.commander.generate.description)

		/* Avoid cache at all levels (Server, Template Engine...). */
		.option(NA.cliLabels.commander.cache.command, NA.cliLabels.commander.cache.description)

		/* Copy all data from `test/<project-name>` from NodeAtlas package to current directory. */
		.option(NA.cliLabels.commander.create.command, NA.cliLabels.commander.create.description)

		/* Start the server with HTTPs Protocol. */
		.option(NA.cliLabels.commander.httpSecure.command, NA.cliLabels.commander.httpSecure.description)

		/* Change language used by NodeAtlas. */
		.option(NA.cliLabels.commander.lang.command, NA.cliLabels.commander.lang.description)
		.parse(process.argv);

	/* `NA#configuration.xxx` setted from `--xxx`. */
	for (i = 0; i < commands.length; i++) {
		if (commander[commands[i]]) {
			NA.configuration[commands[i]] = commander[commands[i]];
		}
	}
};

/**
 * Set required variables for the webconfig depending of NPM modules.
 * @private
 * @function initRequiredNpmModulesVars
 * @memberOf NA#
 * @this NA
 */
exports.initRequiredNpmModulesVars = function () {
	var NA = this,
		path = NA.modules.path;

	if (typeof NA.configuration.path !== "string") {

		/**
		 * System files path to the NodeAtlas project directory (webconfig + website folder tree).
		 * @public
		 * @alias serverPath
		 * @type {string}
		 * @memberOf NA#
		 * @default « System files path from NodeAtlas is called ».
		 */
		NA.serverPath = path.join(process.cwd(), "/");
	} else {

		/* `NA#serverPath` setted from CLI command parameters or API configuration options. */
		NA.serverPath = path.join(NA.configuration.path, "/");
	}

	/**
	 * Name of the webconfig used for run the NodeAtlas project website.
	 * @public
	 * @alias webconfigName
	 * @type {string}
	 * @memberOf NA#
	 * @default "webconfig.json".
	 */
	NA.webconfigName = "webconfig.json";

	/* `webconfigName` manually setted value with `NA#config`. */
	if (NA.configuration.webconfig) {
		NA.webconfigName = NA.configuration.webconfig;
	}
};

/**
 * Decide to run a « Simple Web Server » or a « With Weconfig Server » depending to webconfig opening success.
 * If webconfig is correctly openned, the `NA#createWebconfig` and `callback` function will be run, else, just `NA#simpleWebServer` will be run.
 * @private
 * @function initWebsite
 * @memberOf NA#
 * @this NA
 * @param {NA~callback} next Called if webconfig is correctly openned.
 */
exports.initWebsite = function (next) {
	var NA = this;

	/* Webconfig based website... */
	NA.ifFileExist(NA.serverPath, NA.webconfigName, function (err) {
		if (err && err.code === 'ENOENT') {

			/* ... or static website. */
			return NA.simpleWebServer();
		}

		/* Construction of webconfig. */
		NA.createWebconfig();

		next();
	});
};

/**
 * Set modules and NPM modules used by NodeAtlas project.
 * @private
 * @function initServerModules
 * @memberOf NA#
 * @this NA
 */
exports.initServerModules = function () {
	var NA = this;

	/* Open `common` controller. */
	NA.openController(

		/**
		 * Name of file for `common` controller.
		 * @public
		 * @alias controller
		 * @type {string}
		 * @memberOf NA#webconfig
		 */
		NA.webconfig.controller);

	/**
	 * Folder which contain the `node-atlas` node modules.
	 * @public
	 * @alias nodeatlasModulesRelativePath
	 * @type {string}
	 * @memberOf NA#
	 * @default "node_modules/"
	 */
	NA.nodeatlasModulesRelativePath = "node_modules/";

	/**
	 * Folder which contain the current website node modules.
	 * @public
	 * @alias serverModulesRelativePath
	 * @type {string}
	 * @memberOf NA#
	 * @default "node_modules/"
	 */
	NA.serverModulesRelativePath = "node_modules/";

	/* Use the `NA.controllers[<controller>].setModules(...)` function if set... */
	if (typeof NA.controllers[NA.webconfig.controller] !== 'undefined' &&
		typeof NA.controllers[NA.webconfig.controller].setModules !== 'undefined') {

		/**
		 * Define this function for adding npm module into `NA.modules` of application. Only for `common` controller file.
		 * @function setModules
		 * @memberOf NA#controllers[]
		 */
		NA.controllers[NA.webconfig.controller].setModules.call(NA);
	}
};

/**
 * Set routes, statics and prefix routes.
 * @private
 * @function setWebconfigRoutes
 * @memberOf NA~
 */
function setWebconfigRoutes(NA) {
	var path = NA.modules.path,
		url = NA.modules.url;

	/**
	 * Adding subfolder to original url.
	 * @public
	 * @alias urlRelativeSubPath
	 * @type {string}
	 * @memberOf NA#webconfig
	 * @default ""
	 * @example
	 * // If `NA#webconfig.urlRelativeSubPath` is setted to "example"
	 * // Website will run by default to « http://localhost/example »
	 */
	if (NA.webconfig.urlRelativeSubPath) {
		NA.webconfig.urlRelativeSubPath = url.format(path.join("/", NA.webconfig.urlRelativeSubPath)).replace(/\/+$/g, "");
	} else {
		NA.webconfig.urlRelativeSubPath = "";
	}

	if (typeof NA.webconfig.routes === "string") {

		/**
		 * Contain all routes into an Object or an Array depending how the intial format setted.
		 * @public
		 * @alias routes
		 * @type {Object|Array}
		 * @memberOf NA#webconfig
		 * @default « The webconfig's object property `routes` »
		 */
		NA.webconfig.routes = NA.openConfiguration(NA.webconfig.routes);
	}

	if (typeof NA.webconfig.statics === "string") {

		/**
		 * Contain all statics files into an Object or an Array depending how the intial format setted.
		 * @public
		 * @alias statics
		 * @type {Object|Array}
		 * @memberOf NA#webconfig
		 * @default « The webconfig's object property `statics` »
		 */
		NA.webconfig.statics = NA.openConfiguration(NA.webconfig.statics);
	}
}

/**
 * Set bundles and optimizations.
 * @private
 * @function setWebconfigCompressions
 * @memberOf NA~
 */
function setWebconfigCompressions(NA) {

	if (typeof NA.webconfig.bundles === 'string') {

		/**
		 * Configuration for CSS minification/bundle and JS obfuscation/bundle.
		 * @public
		 * @alias bundles
		 * @type {Object}
		 * @memberOf NA#webconfig
		 * @property {Object} bundles             The bundles object.
		 * @property {Object} bundles.javascripts Each object name represent an output javascript file and each property of object represent an array of inputs files.
		 * @property {Object} bundles.stylesheets Each object name represent an output stylesheet file and each property of object represent an array of inputs files.
		 * @example {
		 *     "javascripts": {
		 *         "javascript/framework.min.js": [
		 *             "javascript/modernizr.js",
		 *             "javascript/jquery.js",
		 *             "javascript/prettify.js",
		 *             "javascript/prettify/run_prettify.js"
		 *         ],
		 *         "javascript/common.min.js": [
		 *             "javascript/components/extended-format-date.js",
		 *             "javascript/common.js"
		 *         ]
		 *     },
		 *     "stylesheets": {
		 *         "stylesheets/common.min.css": [
		 *             "stylesheets/common.css",
		 *             "stylesheets/common-min780.css",
		 *             "stylesheets/common-min1160.css"
		 *         ]
		 *     }
		 * }
		 */
		NA.webconfig.bundles = NA.openConfiguration(NA.webconfig.bundles);
	}
}

/**
 * Set pug, less and enbaleStylus.
 * @private
 * @function setWebconfigPreprocessors
 * @memberOf NA~
 */
function setWebconfigPreprocessors(NA) {

	/**
	 * Enable Pug preprocessor.
	 * @public
	 * @alias pug
	 * @type {boolean}
	 * @memberOf NA#webconfig
	 * @default false
	 */
	NA.webconfig.pug = NA.webconfig.pug || false;

	if (NA.webconfig.less === true) {

		/**
		 * Enable Less preprocessor.
		 * @namespace less
		 * @public
		 * @alias less
		 * @type {boolean|Object}
		 * @memberOf NA#webconfig
		 * @default false
		 * @property {boolean}        compress  Minify the Less file.
		 * @property {boolean}        sourceMap Create a sourceMap file for development.
		 * @property {Array.<string>} files     The file for compilation in an Array.
		 */
		NA.webconfig.less = {
			compress: false,
			sourceMap: true
		};
	} else if (typeof NA.webconfig.less === "object" && typeof NA.webconfig.less.files === "string") {

		/**
		 * Contain Less files required for compilation.
		 * @public
		 * @alias files
		 * @type {Array.<string>}
		 * @memberOf NA#webconfig.less
		 * @example {
		 *     "files": [
		 *         "stylesheets/common.less",
		 *         "stylesheets/component-1.less",
		 *         "stylesheets/component-2.less",
		 *         "stylesheets/component-3.less"
		 *     ]
		 * }
		 */
		NA.webconfig.less.files = NA.openConfiguration(NA.webconfig.less.files);
	}

	if (NA.webconfig.stylus === true) {

		/**
		 * Enable Stylus preprocessor.
		 * @namespace stylus
		 * @public
		 * @alias stylus
		 * @type {boolean|Object}
		 * @memberOf NA#webconfig
		 * @default false
		 * @property {boolean}        compress  Minify the Stylus file.
		 * @property {boolean}        sourceMap Create a sourceMap file for development.
		 * @property {Array.<string>} files The file for compilation in an Array.
		 */
		NA.webconfig.stylus = {
			compress: false,
			sourceMap: true
		};
	} else if (typeof NA.webconfig.stylus === 'object' && typeof NA.webconfig.stylus.files === 'string') {

		/**
		 * Contain Stylus files required for compilation.
		 * @public
		 * @alias files
		 * @type {Array.<string>}
		 * @memberOf NA#webconfig.stylus
		 * @example {
		 *     "files": [
		 *         "stylesheets/common.styl",
		 *         "stylesheets/component-1.styl",
		 *         "stylesheets/component-2.styl",
		 *         "stylesheets/component-3.styl"
		 *     ]
		 * }
		 */
		NA.webconfig.stylus.files = NA.openConfiguration(NA.webconfig.stylus.files);
	}
}

/**
 * Set NodeAtlas directory names.
 * @private
 * @function setWebconfigDirectories
 * @memberOf NA~
 */
function setWebconfigDirectories(NA) {

	if (typeof NA.webconfig.variationsRelativePath === "undefined") {

		/**
		 * Language and variable variation files folder depending of languages.
		 * @public
		 * @alias variationsRelativePath
		 * @type {string}
		 * @memberOf NA#webconfig
		 * @default "variations"
		 */
		NA.webconfig.variationsRelativePath = "variations";
	}

	if (typeof NA.webconfig.controllersRelativePath === "undefined") {

		/**
		 * Controller folder for Back-end part.
		 * @public
		 * @alias controllersRelativePath
		 * @type {string}
		 * @memberOf NA#webconfig
		 * @default "controllers"
		 */
		NA.webconfig.controllersRelativePath = "controllers";
	}

	if (typeof NA.webconfig.middlewaresRelativePath === "undefined") {

		/**
		 * Controller folder for Middlewares part.
		 * @public
		 * @alias middlewaresRelativePath
		 * @type {string}
		 * @memberOf NA#webconfig
		 * @default "middlewares"
		 */
		NA.webconfig.middlewaresRelativePath = "middlewares";
	}

	/* Path to view. */
	if (typeof NA.webconfig.viewsRelativePath === "undefined") {

		/**
		 * View folder for Template Engine files.
		 * @public
		 * @alias viewsRelativePath
		 * @type {string}
		 * @memberOf NA#webconfig
		 * @default "views"
		 */
		NA.webconfig.viewsRelativePath = "views";
	}

	if (typeof NA.webconfig.assetsRelativePath === "undefined") {

		/**
		 * Folder for public file like images, CSS, JS...
		 * @public
		 * @alias assetsRelativePath
		 * @type {string}
		 * @memberOf NA#webconfig
		 * @default "assets"
		 */
		NA.webconfig.assetsRelativePath = "assets";
	}

	if (typeof NA.webconfig.serverlessRelativePath === "undefined") {

		/**
		 * HTML assets generation Folder.
		 * @public
		 * @alias serverlessRelativePath
		 * @type {string}
		 * @memberOf NA#webconfig
		 * @default "serverless"
		 */
		NA.webconfig.serverlessRelativePath = "serverless";
	}
}

/**
 * Set HTTP Port and HTTP hostname.
 * @private
 * @function setWebconfigHost
 * @memberOf NA~
 */
function setWebconfigHost(NA) {
	var defaultPort = NA.webconfig.httpSecure ? 443 : 80;

	/**
	 * Server listening port.
	 * @public
	 * @alias httpPort
	 * @type {string}
	 * @memberOf NA#webconfig
	 * @default « The webconfig's property `httpPort` » || « The `process.env.PORT` if setted » || « 443/80 default port »
	 */
	NA.webconfig.httpPort = NA.configuration.httpPort || NA.webconfig.httpPort || process.env.PORT || defaultPort;

	/**
	 * Url access port (for reverse proxy).
	 * @public
	 * @alias urlPort
	 * @type {string}
	 * @memberOf NA#webconfig
	 * @default undefined
	 */
	NA.webconfig.urlPort = NA.webconfig.urlPort || NA.webconfig.httpPort;

	/**
	 * Server listening hostname by HTTP.
	 * @public
	 * @alias httpHostname
	 * @type {string}
	 * @memberOf NA#webconfig
	 * @default « The webconfig's property `httpHostname` » || « The `process.env.IP_ADDRESS` if setted » || "localhost";
	 */
	NA.webconfig.httpHostname = NA.configuration.httpHostname || NA.webconfig.httpHostname || process.env.IP_ADDRESS || "localhost";

	/**
	 * Url access hostname (for reverse proxy).
	 * @public
	 * @alias urlHostname
	 * @type {string}
	 * @memberOf NA#webconfig
	 * @default undefined
	 */
	NA.webconfig.urlHostname = NA.webconfig.urlHostname || NA.webconfig.httpHostname;
}

/**
 * Set default Cache and Secure.
 * @private
 * @function setWebconfigSecure
 * @memberOf NA~
 */
function setWebconfigSecure(NA) {

	/**
	 * Avoil all caching at all level (server, template engine...). Do not use in production.
	 * @public
	 * @alias cache
	 * @type {boolean}
	 * @memberOf NA#webconfig
	 * @default false
	 */
	NA.webconfig.cache = NA.configuration.cache || NA.webconfig.cache || (process.env.NODE_ENV === 'production');

	/**
	 * Define is site is running with HTTP(S) protocol.
	 * @public
	 * @alias httpSecure
	 * @type {boolean|string|Object}
	 * @memberOf NA#webconfig
	 * @default false
	 */
	NA.webconfig.httpSecure = NA.configuration.httpSecure || NA.webconfig.httpSecure || false;

	/**
	 * Define the path to the Private Key for HTTPs.
	 * @public
	 * @alias httpSecureKeyRelativePath
	 * @type {string}
	 * @memberOf NA#webconfig
	 */
	NA.webconfig.httpSecureKeyRelativePath = NA.webconfig.httpSecureKeyRelativePath || ((typeof NA.webconfig.httpSecure === "string") ? NA.webconfig.httpSecure + ".key" : null);

	/**
	 * Define the path to the Certificate for HTTPs.
	 * @public
	 * @alias httpSecureCertificateRelativePath
	 * @type {string}
	 * @memberOf NA#webconfig
	 */
	NA.webconfig.httpSecureCertificateRelativePath = NA.webconfig.httpSecureCertificateRelativePath || ((typeof NA.webconfig.httpSecure === "string") ? NA.webconfig.httpSecure + ".crt" : null);
}

/**
 * Set the mimeType, charset and headers.
 * @private
 * @function setWebconfigHeaders
 * @memberOf NA~
 */
function setWebconfigHeaders(NA) {

	/**
	 * Default Content-Type used for all pages.
	 * @public
	 * @alias mimeType
	 * @type {string}
	 * @memberOf NA#webconfig
	 * @default "text/html"
	 */
	NA.webconfig.mimeType = NA.webconfig.mimeType || "text/html";

	/**
	 * Default Charset used for all pages.
	 * @public
	 * @alias charset
	 * @type {string}
	 * @memberOf NA#webconfig
	 * @default "utf-8"
	 */
	NA.webconfig.charset = NA.webconfig.charset || "utf-8";

	/**
	 * Default Headers used for all pages.
	 * @public
	 * @alias headers
	 * @type {Object}
	 * @memberOf NA#webconfig
	 * @default {}
	 */
	NA.webconfig.headers = NA.webconfig.headers || {};
}

/**
 * Set all default webconfig's value into `NA#webconfig`.
 * @private
 * @function createWebconfig
 * @memberOf NA#
 */
exports.createWebconfig = function () {
	var NA = this,
		fs = NA.modules.fs,
		path = NA.modules.path,
		ejs = NA.modules.ejs;

	/**
	 * Content of Webconfig file enhenced by `NA#configuration` and CLI commands.
	 * @namespace webconfig
	 * @public
	 * @alias webconfig
	 * @type {Object}
	 * @memberOf NA#
	 */
	NA.webconfig = NA.openConfiguration(NA.webconfigName);

	/**
	 * Find the version of current NodeAtlas website.
	 * @public
	 * @alias version
	 * @type {string}
	 * @memberOf NA#webconfig
	 * @default "0.0.0"
	 */
	NA.webconfig.version = NA.webconfig.version || (fs.existsSync(path.join(NA.serverPath, "package.json")) ? (require(path.join(NA.serverPath, "package.json")).version || "0.0.0") : "0.0.0");

	/* Set all webconfig parameters. */
	setWebconfigRoutes(NA);
	setWebconfigCompressions(NA);
	setWebconfigPreprocessors(NA);
	setWebconfigDirectories(NA);
	setWebconfigHost(NA);
	setWebconfigSecure(NA);
	setWebconfigHeaders(NA);

	/**
	 * Set open and close bracket used by Teplate Engine.
	 * @public
	 * @alias templateEngineDelimiter
	 * @type {string}
	 * @memberOf NA#webconfig
	 * @default "?"
	 */
	ejs.delimiter = NA.webconfig.templateEngineDelimiter || (

		/**
		 * Set a custom template engine.
		 * @public
		 * @alias engine
		 * @type {string}
		 * @memberOf NA#webconfig
		 * @default undefined
		 */
		NA.webconfig.engine ? "%" : "?");

	/**
	 * Deliver the client-side window.NA.socket and window.NA.io object.
	 * @public
	 * @alias socketClientFile
	 * @type {string}
	 * @memberOf NA#webconfig
	 * @default "/node-atlas/socket.io.js"
	 */
	NA.webconfig.socketClientFile = (NA.webconfig.socketClientFile === false) ? false : (NA.webconfig.socketClientFile || "/node-atlas/socket.io.js");

	/**
	 * Website http(s) absolute url based from `NA#webconfig.httpSecure`, `NA#webconfig.urlHostname` and `NA#webconfig.urlPort`.
	 * This value does not contain `NA#webconfig.urlRelativeSubPath`.
	 * @public
	 * @alias urlRoot
	 * @type {string}
	 * @memberOf NA#webconfig
	 */
	NA.webconfig.urlRoot = 'http' + ((NA.webconfig.httpSecure) ? 's' : '') + '://' + NA.webconfig.urlHostname + ((NA.webconfig.urlPort !== ((NA.webconfig.httpSecure) ? 443 : 80)) ? ':' + NA.webconfig.urlPort : '');
};