UNPKG

13.5 kBJavaScriptView Raw
1/*------------------------------------*\
2 GLOBAL FUNCTIONS
3\*------------------------------------*/
4/* jslint node: true */
5
6/**
7 * Read a JSON file and return a literal Object else kill process.
8 * @private
9 * @function openConfiguration
10 * @memberOf NA#
11 * @this NA
12 * @param {string} configName File name (on file path + name in relative). Base folder is the folder where is `webconfig.json`.
13 * @return {Object} Literal object of JSON file.
14 */
15exports.openConfiguration = function (configName) {
16 var NA = this,
17 path = NA.modules.path,
18 data = {},
19 pathfile = path.join(NA.serverPath, configName);
20
21 try {
22
23 /* If file is a correct JSON file, return a literal Object file's content. */
24 delete require.cache[pathfile];
25 return require(pathfile);
26 } catch (exception) {
27 if (exception.toString().indexOf("SyntaxError") !== -1) {
28
29 /* If the file is a JSON file, but contain a Syntax error. */
30 data.syntaxError = exception.toString();
31 data.fileName = configName;
32 NA.log(NA.cliLabels.webconfigSyntaxError.replace(/%([\-a-zA-Z0-9_]+)%/g, function (regex, matches) { return data[matches]; }));
33 } else {
34
35 /* Other errors. */
36 NA.log('openConfiguration exception', exception);
37 }
38
39 /* In case of error, kill current process. */
40 process.kill(process.pid);
41 }
42};
43
44/**
45 * Allow you to write from CLI.
46 * @private
47 * @function log
48 * @memberOf NA#
49 * @this NA
50 * @param {...string} str All sentence you want display in server-side console.
51 */
52exports.log = function () {
53 var logs = console.log,
54 args = arguments,
55 color = "\u001b[36m";
56
57 if (/[\u001b]/.test(arguments[0])) {
58 args = Array.prototype.slice.call(arguments, 1);
59 color = arguments[0];
60 }
61
62 for (var log in args) {
63 if (args.hasOwnProperty(log)) {
64 logs(color + args[log] + '\u001B[0m');
65 }
66 }
67};
68
69/**
70 * Open a controller file.
71 * @private
72 * @function loadController
73 * @memberOf NA#
74 * @this NA
75 * @param {string} controller The name of controller file we want to load.
76 */
77exports.openController = function (controller) {
78 var NA = this,
79 path = NA.modules.path,
80 commonControllerPath = path.join(
81 NA.serverPath,
82 NA.webconfig.controllersRelativePath,
83 (controller) ? controller : ''
84 );
85
86 /* If a controller is required. Loading of this controller... */
87 if (typeof controller !== 'undefined') {
88
89 /* Open controller and load it */
90 try {
91 NA.controllers[controller] = require(commonControllerPath);
92 /* In case of error. */
93 } catch (err) {
94 if (err && err.code === 'MODULE_NOT_FOUND') {
95 err.controller = commonControllerPath;
96 return NA.log(NA.cliLabels.notFound.controller.replace(/%([\-a-zA-Z0-9_]+)%/g, function (regex, matches) { return err[matches]; }));
97 } else if (err) {
98 return NA.log('openController exception', err);
99 }
100 }
101 }
102};
103
104/**
105 * Intercept DOM from common file.
106 * @private
107 * @function explainError
108 * @memberOf NA~
109 * @param {NA} NA NodeAtlas instance.
110 * @param {Object} err Error to explain.
111 * @param {string} variationName Name of JSON file.
112 * @param {string} languageCode Current language for this variation.
113 * @param {boolean|undefined} errorDisabled Force no error message.
114 */
115function explainError(NA, err, variationsPath, languageCode, errorDisabled) {
116 err.variationsPath = variationsPath;
117 if (err.code === 'ENOENT' && !errorDisabled && !languageCode) {
118 NA.log(NA.cliLabels.variationNotFound.replace(/%([\-a-zA-Z0-9_]+)%/g, function (regex, matches) { return err[matches]; }));
119 } else if (err.toString().indexOf('SyntaxError') !== -1) {
120 err.syntaxError = err.toString();
121 NA.log(NA.cliLabels.variationSyntaxError.replace(/%([\-a-zA-Z0-9_]+)%/g, function (regex, matches) { return err[matches]; }));
122 } else if (err.code !== 'ENOENT') {
123 NA.log(err);
124 }
125 return false;
126}
127
128/**
129 * Open a variation file.
130 * @private
131 * @function openVariation
132 * @memberOf NA#
133 * @this NA
134 * @param {string} variationName Name of JSON file.
135 * @param {string} languageCode Current language for this variation.
136 * @param {boolean|undefined} errorDisabled Force no error message.
137 * @returns {Object|boolean} Return all data from JSON or false if an error occured.
138 */
139exports.openVariation = function (variationName, languageCode, errorDisabled) {
140 var NA = this,
141 fs = NA.modules.fs,
142 path = NA.modules.path,
143 variationsPath;
144
145 /* Find the correct path for variations. */
146 variationsPath = path.join(
147 NA.serverPath,
148 NA.webconfig.variationsRelativePath,
149 (languageCode) ? languageCode : '',
150 (variationName) ? variationName : ''
151 );
152
153 /* Explain errors. */
154 if (typeof variationName !== 'undefined') {
155 try {
156 /* Return the variations variable into an object. */
157 return JSON.parse(fs.readFileSync(variationsPath, 'utf-8'));
158 } catch (err) {
159 /* Explain errors. */
160 explainError(NA, err, variationsPath, languageCode, errorDisabled);
161 }
162 } else {
163 return {};
164 }
165};
166
167/**
168 * Open a temlpate file.
169 * @private
170 * @function openView
171 * @memberOf NA#
172 * @this NA
173 * @param {Object} routeParameters Parameters set into `routes[<currentRoute>]`.
174 * @param {Object} viewsPath Path to template file.
175 * @param {openView~callback} callback Next steps after opening file.
176 */
177exports.openView = function (routeParameters, viewsPath, callback) {
178 var NA = this,
179 fs = NA.modules.fs;
180
181 fs.readFile(viewsPath, 'utf-8', function (err, data) {
182 if (NA.webconfig.view) {
183 data = data.replace("#{routeParameters.view}", routeParameters.view);
184 }
185 if (err) {
186 err.viewsPath = viewsPath;
187 if (typeof routeParameters.view === 'undefined') {
188 NA.log(NA.cliLabels.viewNotSet);
189 } else {
190 NA.log(NA.cliLabels.viewNotFound.replace(/%([\-a-zA-Z0-9_]+)%/g, function (regex, matches) { return err[matches]; }));
191 }
192 } else {
193
194 /**
195 * Next steps after opening file.
196 * @callback openView~callback
197 * @param {string} data All HTML data from template.
198 */
199 callback(data);
200 }
201 });
202};
203
204/**
205 * Clone Object A into B and the purpose is : change A not affect B.
206 * @public
207 * @function clone
208 * @memberOf NA#
209 * @param {Object} object The A object.
210 * @return {Object} Return the B object.
211 */
212exports.clone = function (object) {
213 var NA = this,
214 copy,
215 result;
216
217 /* Handle the 3 simple types, and null or undefined */
218 if (null === object || undefined === object || "object" !== typeof object) {
219 result = object;
220 }
221
222 /* Handle Date */
223 if (object instanceof Date) {
224 copy = new Date();
225 copy.setTime(object.getTime());
226 result = copy;
227 }
228
229 /* Handle Array */
230 if (object instanceof Array) {
231 result = object.slice(0);
232 }
233
234 /* Handle Object */
235 if (object instanceof Object) {
236 copy = {};
237 NA.forEach(object, function (attr) {
238 copy[attr] = NA.clone(object[attr]);
239 });
240 result = copy;
241 }
242
243 return result;
244};
245
246/**
247 * A safe iterator for object properties.
248 * @public
249 * @function forEach
250 * @memberOf NA#
251 * @param {Object|Array} object The Object or Array to iterate.
252 * @param {forEach~callback} callback Provide in first argument the current object, provide in second all objects.
253 */
254exports.forEach = function (object, callback) {
255 if (object instanceof Array) {
256 for (var i = 0; i < object.length; i++) {
257 callback(object[i], object);
258 }
259 } else {
260 for (var current in object) {
261 if (object.hasOwnProperty(current)) {
262
263 /**
264 * Run this for each object.
265 * @callback forEach~callback
266 */
267 callback(current, object);
268 }
269 }
270 }
271};
272
273/**
274 * Know if a file exist.
275 * @private
276 * @function ifFileExist
277 * @memberOf NA#
278 * @param {string} physicalPath Absolute OS path to a filename.
279 * @param {string} [fileName] Name of file if not set in end of `physicalPath`.
280 * @param {ifFileExist~callback} callback If file exist provide arguments `callback(null, true)` else `callback(err)`
281 * with `err` containing `path`, `physicalPath` and `filename` informations.
282 */
283exports.ifFileExist = function (physicalPath, fileName, callback) {
284 var NA = this,
285 fs = NA.modules.fs,
286 path = NA.modules.path,
287 pathToResolve = physicalPath;
288
289 if (typeof fileName === 'string') {
290 pathToResolve = path.join(physicalPath, fileName);
291 }
292
293 /* This function block the event loop (EL) */
294 fs.stat(pathToResolve, function (err) {
295 if (err && err.code === 'ENOENT') {
296 err.path = pathToResolve;
297 err.physicalPath = physicalPath;
298 err.fileName = fileName;
299
300 /**
301 * If file do not exist, bad next step...
302 * @callback ifFileExist~callback
303 */
304 callback(err, false);
305 } else {
306
307 /**
308 * If file exist, good next step !
309 */
310 callback(null, true);
311 }
312 });
313};
314
315/**
316 * Load into `{locals}.common` to object format the content of common variation file.
317 * @public
318 * @function common
319 * @memberOf NA#
320 * @param {string} languageCode Select a subdirectory for load variation (name is generaly the languageCode).
321 * @param {object} locals An object for attach common variation. If empty, a new empty object is created.
322 */
323exports.common = function (languageCode, locals) {
324 var NA = this,
325 extend = NA.modules.extend;
326
327 /* Create a global variation object if is not passed. */
328 locals = locals || {};
329
330 /* Load variation from languageCode directory or root directory (depend if languageCode is defined)... */
331 locals.common = NA.openVariation(NA.webconfig.variation, languageCode);
332
333 /* ...and complete empty value with value of file in root directory. */
334 if (languageCode) {
335 locals.common = extend(true, NA.openVariation(NA.webconfig.variation, undefined, true), locals.common);
336 }
337
338 return locals;
339};
340
341/**
342 * Load into `{locals}.specific` to object format the content of a specific variation file.
343 * @public
344 * @function specific
345 * @memberOf NA#
346 * @param {string} specific Select the specific variation associate to the current page.
347 * @param {string} languageCode Select a subdirectory for load variation (name is generaly the languageCode).
348 * @param {object} locals An object for attach specific variation. If empty, a new empty object is created.
349 */
350exports.specific = function (specific, languageCode, locals) {
351 var NA = this,
352 extend = NA.modules.extend;
353
354 /* Create a global variation object if is not passed. */
355 locals = locals || {};
356
357 /* Load variation from languageCode directory or root directory (depend if languageCode is defined)... */
358 locals.specific = NA.openVariation(specific, languageCode);
359
360 /* ...and complete empty value with value of file in root directory. */
361 if (languageCode) {
362 locals.specific = extend(true, NA.openVariation(specific, undefined, true), locals.specific);
363 }
364
365 return locals;
366};
367
368/**
369 * Load a HTML fragment and inject variation for an async result.
370 * @public
371 * @function view
372 * @memberOf NA#
373 * @param {string} viewFile Path of file used into viewsRelativePath directory.
374 * @param {object} locals Local variables used for transform view + locals into HTML.
375 */
376exports.view = function (viewFile, locals) {
377 var NA = this,
378 data,
379 ejs = NA.modules.ejs,
380 pug = NA.modules.pug,
381 fs = NA.modules.fs,
382 path = NA.modules.path,
383 engine = NA.webconfig.pug ? pug : ejs;
384
385 /* Set the file currently in use. */
386 locals.filename = path.join(NA.serverPath, NA.webconfig.viewsRelativePath, viewFile);
387
388 if (typeof locals.pug === "boolean") {
389 engine = locals.pug ? pug : ejs;
390 }
391
392 try {
393 /* Transform ejs/pug data and inject incduded file. */
394 data = engine.render(
395 fs.readFileSync(path.join(NA.serverPath, NA.webconfig.viewsRelativePath, viewFile), 'utf-8'),
396 locals
397 );
398 } catch (err) {
399 /* Make error more readable. */
400 data = err.toString()
401 .replace(/</g, "&lt;")
402 .replace(/[\n]/g, "<br>")
403 .replace(/\t/g, "<span style='display:inline-block;width:32px'></span>")
404 .replace(/ /g, "<span style='display:inline-block;width:32px'></span>")
405 .replace(/ /g, "<span style='display:inline-block;width:32px'></span>")
406 .replace(/ /g, "<span style='display:inline-block;width:32px'></span>")
407 .replace(/ >> /g, "<span style='display:inline-block;width:32px'>&gt;&gt;</span>")
408 .replace(/> ([0-9])+\|/g, "<span style='display:inline-block;margin-left:-13px'>> $1|</span>")
409 .replace(/^([a-zA-Z]+):/g, "$1:<br><br>");
410 }
411
412 return data;
413};
414
415/**
416 * Extend an object with next object passed in param.
417 * @public
418 * @function extend
419 * @memberOf NA#
420 * @param {...object} objects Each object to extend the first.
421 */
422exports.extend = function (objects) {
423 var NA = this;
424
425 function copyItem(source, prop) {
426 if (source[prop].constructor === Object) {
427 if (!objects[prop] || objects[prop].constructor === Object) {
428 objects[prop] = objects[prop] || {};
429 NA.extend(objects[prop], source[prop]);
430 } else {
431 objects[prop] = source[prop];
432 }
433 } else {
434 objects[prop] = source[prop];
435 }
436 }
437
438 Array.prototype.slice.call(arguments, 1).forEach(function(source) {
439 if (source) {
440 NA.forEach(source, function (prop) {
441 copyItem(source, prop);
442 });
443 }
444 });
445
446 return objects;
447};
\No newline at end of file