UNPKG

js-lightning

Version:

Direct Javascript to Web interpreted server inspired by PHP

233 lines (192 loc) 6.32 kB
#!/usr/local/bin/node 'use strict'; const qt = require('qtools-functional-library'); //console.dir(qt.help()); const express = require('express'); const app = express(); const fs = require('fs'); const path = require('path'); const bodyParser = require('body-parser'); const marked = require('marked'); //START OF moduleFunction() ============================================================ const moduleFunction = function(args = {}) { const { userConfiguration } = args; const { siteDirectory, port, noServe, docRootPath, versionInfo } = userConfiguration; const moduleConfig = userConfiguration.getModuleConfig(__filename); const findDynamicPage = require('./lib/find-dynamic-page')({ userConfiguration }); // --------------------------------------------------------------------- // UTILITY FUNCTIONS const refreshRequire = (requestedModulePath, options = {}) => { const callingFilePath = new Error().stack .split(/\n/)[2] .trim() .match(/(\/.*?):.*/)[1]; const callingDirName = path.dirname(callingFilePath); const remappedModulePath = path.join(callingDirName, requestedModulePath); if (!options.noRefreshNormalRequire) { delete require.cache[require.resolve(remappedModulePath)]; } return require(remappedModulePath); }; const jslScope = { configuration: userConfiguration, expressjs: { app }, refreshRequire }; const jslInitPath = path.join(siteDirectory, 'jsl-init'); if (fs.existsSync(jslInitPath)) { try { require(jslInitPath)({ jslScope }); } catch (e) { console.dir({ ['e']: e }, { showHidden: false, depth: 4, colors: true }); console.error(`INITIALIZATION ERROR - EXITING`); process.exit(1); } } else if (fs.existsSync(`${jslInitPath}.js`)) { try { require(`${jslInitPath}.js`)({ jslScope }); } catch (e) { console.dir({ ['e']: e }, { showHidden: false, depth: 4, colors: true }); console.error(`INITIALIZATION ERROR - EXITING`); process.exit(1); } } if (userConfiguration.verbose) { console.dir( { ['userConfiguration']: userConfiguration }, { showHidden: false, depth: 6, colors: true } ); } Object.freeze(jslScope); // --------------------------------------------------------------------- // ASSSEMBLE EXPRESS APP app.use(function(req, res, next) { res.removeHeader('X-Powered-By'); res.setHeader( 'for-javascript-lovers', 'https://www.npmjs.com/package/js-lightning' ); next(); }); app.use(function(req, res, next) { if (userConfiguration.verbose) { console.log( `\n${req.method} request: ${req.host}${req.path}${ Object.keys(req.query).length ? '?' + Object.keys(req.query) .map( key => encodeURIComponent(key) + '=' + encodeURIComponent(req.query[key]) ) .join('&') : '' }` ); } if (req.path.match(/jsl-init/) || req.path.match(/\/lib\//) || req.path.match(/\/node_modules\//)) { qt.log(`rejecting request: ${req.path}`, { noSuffix: true }); res.status(404); res.send(`404 Not Found`); return; } findDynamicPage.get(req, (err, requestedModulePath) => { if (requestedModulePath) { const extension = path.extname(requestedModulePath); if (userConfiguration.verbose) { qt.log(`Processing dynamic file: ${requestedModulePath}, extension: ${extension}`, { noSuffix: true }); } if (extension === '.md') { // Process markdown file if (userConfiguration.verbose) { qt.log(`Processing markdown file: ${requestedModulePath}`, { noSuffix: true }); } try { const markdownContent = fs.readFileSync(requestedModulePath, 'utf8'); if (userConfiguration.verbose) { qt.log(`Read markdown content: ${markdownContent.substring(0, 100)}...`, { noSuffix: true }); } const htmlContent = marked.parse(markdownContent); if (userConfiguration.verbose) { qt.log(`Converted to HTML: ${htmlContent.substring(0, 100)}...`, { noSuffix: true }); } res.setHeader('Content-Type', 'text/html; charset=utf-8'); res.send(htmlContent); if (userConfiguration.verbose) { qt.log(`Markdown response sent successfully`, { noSuffix: true }); } } catch (e) { res.status(500); if ( moduleConfig.qtGetSurePath('revealErrorMessageToBrowser', false) ) { res.setHeader('reason', `bad markdown file ${escape(req.path)}`); res.send(`FATAL ERROR: ${escape(req.path)} ${e.toString()}`); } else { res.setHeader('reason', `bad markdown file`); res.send(`FATAL ERROR: internal server error`); } } } else { // Process JavaScript file delete require.cache[require.resolve(requestedModulePath)]; //kill cache jslScope.expressjs.next = next; jslScope.expressjs.app = app; jslScope.expressjs.req = req; jslScope.expressjs.res = res; try { require(requestedModulePath)(req, res, jslScope); } catch (e) { res.status(500); if ( moduleConfig.qtGetSurePath('revealErrorMessageToBrowser', false) ) { res.setHeader('reason', `bad module ${escape(req.path)}`); res.send(`FATAL ERROR: ${escape(req.path)} ${e.toString()}`); } else { res.setHeader('reason', `bad module`); res.send(`FATAL ERROR: internal server error`); } } } } else { next(); } }); return; //next() }); app.use(function(req, res, next) { qt.log(`trying static: ${docRootPath}/${req.path}`, { noSuffix: true }); next(); }); app.use(express.static(docRootPath)); if (noServe) { qt.log(`siteDirectory: ${siteDirectory}`, { noSuffix: true }); qt.log(`docRootPath: ${docRootPath}`, { noSuffix: true }); qt.log(`WARNING: noServe==true, exiting`, { noSuffix: true }); process.exit(); } app.listen(port, () => { qt.log(`siteDirectory: ${siteDirectory}`, { noSuffix: true }); qt.log(`docRootPath: ${docRootPath}`, { noSuffix: true }); qt.log( `Magic happens on port ${port} using ${versionInfo.name} Version ${ versionInfo.version }\n`, { noSuffix: true } ); }); }; //END OF moduleFunction() ============================================================ module.exports = args => new moduleFunction(args);