lib/autoroute.js

1.
var _path = require("path");
2.

			
3.
/**
4.
 * This is the autoroute class. It is used to easily route views, assets and your favicon. If you 
5.
 * don't know what these are you can take look at each of the functions.
6.
 * @class autoroute
7.
 */
8.
class autoroute {
9.
	constructor(cerus) {
10.
		this.name = "cerus-autoroute";
11.
		this.version = "0.1.0";
12.
		this._folders = new folders();
13.
		this._cerus = cerus;
14.
	}
15.

			
16.
	/**
17.
	 * This function will return the folders class for this module. With it you can change the 
18.
	 * folders the views and assets should be stored in.
19.
	 * @summary Returns the folders class.
20.
	 * @return {Class} The autoroute.folders class.
21.
	 * @function folders
22.
	 */
23.
	folders() {
24.
		return folders;
25.
	}
26.

			
27.
	/**
28.
	 * With the favicon function you can easily route the favicon of your site. The favicon is the 
29.
	 * image a browser will request to use as icon for the site. There is no folder where the icon 
30.
	 * is meant to be stored, so the path that is used will start from the root if the path isn't 
31.
	 * absolute. If it is absolute it'll directly be used. Before usage the path is fixed by 
32.
	 * replacing all \\\\ with / to add support for all platforms.
33.
	 * @example
34.
	 * // with as project root "C:/project/"
35.
	 * cerus.autoroute().favicon("favicon.png");
36.
	 * // -> will load and route "C:/project/favicon.png" to the "/favicon.ico" url
37.
	 * @emits file When the specified file has been loaded. With the file as first parameter.
38.
	 * @emits request When the favicon is requested. With the request as first parameter and 
39.
	 * response as second.
40.
	 * @emits error When there was an error while loading the file. With the error as first 
41.
	 * parameter.
42.
	 * @summary Loads and routes the favicon.
43.
	 * @param {String} path The path to the icon.
44.
	 * @param {Object} (options={}) The object of options.
45.
	 * @param {String} (options.url="/favicon.ico") The url to route the favicon to.
46.
	 * @param {String} (options.type) The MIME type of the favicon. By default this is automatically selected.
47.
	 * @return {Promise} This function will return a promise.
48.
	 * @function favicon
49.
	 */
50.
	favicon(path, {url = "/favicon.ico", type} = {}) {
51.
		// Fix the url by replacing \\ with / to support all platforms
52.
		const fixed_path = _path
53.
			.resolve(this._cerus.root(), path)
54.
			.replace(/\\/g, "/");
55.

			
56.
		return this._cerus.promise(event => {
57.
			this._cerus.file(fixed_path).read()
58.
			.then((data, file) => {
59.
				event("file", file);
60.

			
61.
				this._cerus.router().get(url)
62.
				.then((req, res) => {
63.
					event("request", req, res);
64.
	
65.
					if(type !== undefined) res.type(type);
66.
	
67.
					res.file(file);
68.
				})
69.
			})
70.
			.catch(err => {
71.
				event("error", err);
72.
			});
73.
		});
74.
	}
75.

			
76.
	/**
77.
	 * This function is used to easily route a view. Views are often .html files, but can be 
78.
	 * generalized as a markup file. If you want to learn more about views you can read the 
79.
	 * tutorial about it. By default views are stored in the views folder, but you can change this 
80.
	 * with the .folders().views() function or by using an absolute path. When your path isn't 
81.
	 * absolute it is prefixed by the root and the views folder. If it is absolute the specified 
82.
	 * path won't be prefixed. All paths do however get fixed, all \\ are changed to a / to support
83.
	 * all platforms. The files also get suffixed by default. The suffix can be removed or changed 
84.
	 * with the ext parameter. The view will be routed to the specified url.
85.
	 * @example
86.
	 * // with as project env "C:\\project\\example.js"
87.
	 * cerus.autoroute().view("/home", "example");
88.
	 * // -> will load and route "C:/project/views/example.html" to "/home"
89.
	 * @emits file When the specified view has been loaded. With the file as first parameter.
90.
	 * @emits request When the view is requested. With the request as first parameter and 
91.
	 * response as second.
92.
	 * @emits error When there was an error while loading the file. With the error as first 
93.
	 * parameter.
94.
	 * @emits finish When it is finished loading and routing the file. This event has no 
95.
	 * parameters.
96.
	 * @summary Loads and routes a view.
97.
	 * @param {String} url The url the view will be routed to.
98.
	 * @param {String} filename The filename or path of the view.
99.
	 * @param {Object} (options={}) The object of options.
100.
	 * @param {String} (options.extension=".html") The extension of the view.
101.
	 * @param {String} (options.type) The MIME type of the favicon. By default this is automatically selected.
102.
	 * @return {Promise} This function will return a promise.
103.
	 * @function view
104.
	 */
105.
	view(url, filename, {extension = ".html", type} = {}) {
106.
		const _filename = _path.extname(filename) === "" && extension ? filename + extension : filename;
107.
		const path = _path
108.
			.resolve(`${this._cerus.root()}${this._folders._views}/`, _filename)
109.
			.replace(/\\/g, "/");
110.

			
111.
		return this._cerus.promise(event => {
112.
			this._cerus.file(path).async().read()
113.
			.then((data, file) => {
114.
				event("file", file);
115.

			
116.
				this._cerus.router().get(url)
117.
				.then((req, res) => {
118.
					event("request", req, res);
119.

			
120.
					if(typeof type === "string") {
121.
						res.type(type);
122.
					}
123.

			
124.
					res.file(file);
125.
				});
126.

			
127.
				event("finish");
128.
			})
129.
			.catch(err => event("error", err));
130.
		});
131.
	}
132.

			
133.
	/**
134.
	 * With this function you can route assets. Assets are folders containing a certain type of 
135.
	 * "assets", e.g. stylesheets, scripts, images, etc. If you want to learn more about how to use
136.
	 * assets take a look at the assets tutorial. By default all the assets are stored in the 
137.
	 * assets folder. You can change this folder with .folder().assets(). You can also use an 
138.
	 * absolute path. When using an absolute path the default prefix, the root and assets folder,
139.
	 * won't be used. This path is also fixed (\\\\ is changed to /) before being used to support 
140.
	 * all the platforms. The assets will be routed to /{FOLDER}/{FILE}, for example: "styles.css" 
141.
	 * from folder "css" will routed to "/css/styles.css". You can also override the type that will
142.
	 * be send with the request by using the type parameter.
143.
	 * @example
144.
	 * // with as project env "C:\\project\\example.js" and folder "C:\\project\\assets\\css\\" containing two files:
145.
	 * // "example1.css" and "example2.css"
146.
	 * cerus.autoroute().assets("css");
147.
	 * // -> will load and route "example1.css" to "/css/example1.css" and "example2.css" to "/css/example2.css"
148.
	 * @emits file When one of the assets has been loaded. With the file as first parameter.
149.
	 * @emits request When an asset is requested. With the request as first parameter and response 
150.
	 * as second.
151.
	 * @emits error When there was an error while loading the file. With the error as first 
152.
	 * parameter.
153.
	 * @emits finish When it is finished loading and routing all the assets. This event has no 
154.
	 * parameters.
155.
	 * @summary Loads and routes an assets folder.
156.
	 * @param {String} folder The assets folder that will be routed.
157.
	 * @param {Object} (options={}) The object of options.
158.
	 * @param {Boolean} (options.absolute) If the inserted path is absolute.
159.
	 * @param {Boolean} (options.url) The prefix of the url the assets are routed to. By default this is the folder parameter.
160.
	 * @param {String} (options.type) The MIME type of the favicon. By default this is automatically selected.
161.
	 * @return {Promise} This function will return a promise.
162.
	 * @function assets
163.
	 */
164.
	assets(folder, {type, url} = {}) {
165.
		// Fix the filename by replacing \\ with / to support all platforms
166.
		const path = _path
167.
			.resolve(`${this._cerus.root()}${this._folders._assets}/`, `${folder}/`)
168.
			.replace(/\\/g, "/");
169.

			
170.
		return this._cerus.promise(event => {
171.
			this._cerus.folder(path).files()
172.
			.on("file", (file, last) => {
173.
				file.async().read()
174.
				.then((data, file) => {
175.
					event("file", file);
176.

			
177.
					if(last) {
178.
						event("finish");
179.
					}
180.
					
181.
					this._cerus.router().get(`/${url || folder}/${file.base()}`)
182.
					.then((req, res) => {
183.
						event("request", req, res);
184.
						
185.
						res.type(type || file.type());
186.
	
187.
						if(res.type().startsWith("image")) {
188.
							res.send(data, "binary");
189.
						}
190.
						else {
191.
							res.file(file);
192.
						}
193.
					});
194.
				});
195.
			})
196.
			.catch(err => event("error", err));
197.
		})
198.
	}
199.
}
200.

			
201.
module.exports = function() {
202.
	const plugin = {};
203.
	let _autoroute;
204.

			
205.
	plugin.name = "cerus-autoroute";
206.
	plugin.version = "0.2.0";
207.
	plugin.dependencies = [
208.
		"cerus",
209.
		"cerus-router",
210.
		"cerus-fs"
211.
	];
212.

			
213.
	plugin._init = function(cerus) {
214.
		_autoroute = new autoroute(cerus);
215.
	};
216.

			
217.
	plugin.autoroute = function() {
218.
		return _autoroute;
219.
	};
220.

			
221.
	plugin.favicon = function(path) {
222.
		return _autoroute.favicon(path);
223.
	};
224.

			
225.
	plugin.view = function(url, filename, ext) {
226.
		return _autoroute.view(url, filename, ext);
227.
	};
228.

			
229.
	plugin.assets = function(folder, type) {
230.
		return _autoroute.assets(folder, type);
231.
	};
232.

			
233.
	return plugin;
234.
};
235.

			
236.
/**
237.
 * This class contains the folder settings for the autoroute module. With this class you can change
238.
 * the folders where the views and assets are stored in.
239.
 * @class autoroute.folders
240.
 */
241.
class folders {
242.
	constructor() {
243.
		this._views = "views";
244.
		this._assets = "assets";
245.
	}
246.

			
247.
	/**
248.
	 * This is the getter and setter for the views folder. This is the folder where the views 
249.
	 * should be put in. By default this path is "views". See {@link autoroute.view} to learn what 
250.
	 * a view is. This path is also fixed (\\\\ is changed to /) before being used to support all 
251.
	 * the platforms.
252.
	 * @summary The getter/setter for the views folder.
253.
	 * @param {String} (path) The new path for the views folder.
254.
	 * @return {String} The path for the views folder.
255.
	 * @function views
256.
	 */
257.
	views(path) {
258.
		if(typeof path !== "string") return this._views;
259.

			
260.
		return this._views = path.replace(/\\/g,"/");
261.
	}
262.

			
263.
	/**
264.
	 * This is the getter and setter for the assets folder. This is the folder where the assets 
265.
	 * classes should be put in. By default this path is "assets". See {@link autoroute.assets} for
266.
	 * what a assets is. This path is also fixed (\\\\ is changed to /) before being used to 
267.
	 * support all the platforms.
268.
	 * @summary The getter/setter for the assets folder.
269.
	 * @param {String} (path) The new path for the assets folder.
270.
	 * @return {String} The path for the assets folder.
271.
	 * @function assets
272.
	 */
273.
	assets(path) {
274.
		if(typeof path !== "string") return this._assets;
275.

			
276.
		return this._assets = path.replace(/\\/g,"/");
277.
	}
278.
}