UNPKG

3.62 kBJavaScriptView Raw
1'use strict';
2
3const path = require('path');
4const url = require('url');
5const fs = require('fs');
6const promisify = require('util.promisify');
7
8const TEMPLATE_ERROR = 0;
9const TEMPLATE_NOT_FOUND = 1;
10
11class TemplateError extends Error {
12 constructor(...args) {
13 super(...args);
14 this.code = TEMPLATE_ERROR;
15 this.presentable = 'template error';
16 const [{ code }] = args;
17
18 if (code === 'ENOENT') {
19 this.code = TEMPLATE_NOT_FOUND;
20 this.presentable = 'template not found';
21 }
22 }
23}
24
25/**
26 * Promisify the functions
27 */
28const readFilePromise = promisify(fs.readFile);
29const lstatPromise = promisify(fs.lstat);
30
31/**
32 * Read the file from File System
33 *
34 * @param {string} path
35 */
36const readFile = path =>
37 readFilePromise(path, 'utf-8').catch(err => {
38 throw new TemplateError(err);
39 });
40
41/**
42 * Returns the template path validating a exactly file or a directory
43 *
44 * @param {String} templatesPath - TemplatesPath config
45 * @param {String} pathname - Path name based on Request Object
46 *
47 * @return {Promise} Template Info object on success or TemplateError on fail
48 */
49const getTemplatePath = (templatesPath, pathname) =>
50 new Promise((resolve, reject) => {
51 lstatPromise(templatesPath).then(
52 data => {
53 let templateStat = {
54 isFile: data.isFile()
55 };
56
57 if (templateStat.isFile) {
58 templateStat.path = templatesPath;
59 } else {
60 templateStat.path = factoryFilePath(
61 templatesPath,
62 pathname
63 );
64 }
65
66 return resolve(templateStat);
67 },
68 err => {
69 return reject(new TemplateError(err));
70 }
71 );
72 });
73
74/**
75 * Returns pathname by request
76 *
77 * @param {Object} request - Request Object
78 *
79 * @return {String} pathname
80 */
81const getPathName = request => url.parse(request.url, true).pathname;
82
83/**
84 * Factory the complete file path
85 *
86 * @param {String} templatesPath - Templates dir path
87 * @param {String} filename - file name without extension
88 *
89 * @return {String} complete file path
90 */
91const factoryFilePath = (templatesPath, filename) =>
92 `${path.join(templatesPath, filename)}.html`;
93
94/**
95 * Fetches the template from File System
96 *
97 * @param {string} templatesPath - The path where the templates are stored
98 * @param {function=} baseTemplateFn - Function that returns the Base template name for a given page
99 */
100module.exports = (templatesPath, baseTemplateFn) => (
101 request,
102 parseTemplate
103) => {
104 const pathname = getPathName(request);
105
106 return getTemplatePath(templatesPath, pathname).then(templateStat => {
107 return readFile(templateStat.path).then(baseTemplate => {
108 if (templateStat.isFile || typeof baseTemplateFn !== 'function') {
109 return parseTemplate(baseTemplate);
110 }
111
112 const templateName = baseTemplateFn(pathname);
113 if (!templateName) {
114 return parseTemplate(baseTemplate);
115 }
116
117 const pageTemplate = baseTemplate;
118 const baseTemplatePath = factoryFilePath(
119 templatesPath,
120 templateName
121 );
122 return readFile(baseTemplatePath).then(baseTemplate =>
123 parseTemplate(baseTemplate, pageTemplate)
124 );
125 });
126 });
127};
128
129module.exports.TEMPLATE_ERROR = TEMPLATE_ERROR;
130module.exports.TEMPLATE_NOT_FOUND = TEMPLATE_NOT_FOUND;