From d3431797642ba191b0a8de4e3f440991cf2e5866 Mon Sep 17 00:00:00 2001 From: Klemek Date: Sat, 22 Jun 2019 10:17:04 +0200 Subject: [PATCH 1/8] Updated code coverage files --- package.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 75cba16..e48d98d 100644 --- a/package.json +++ b/package.json @@ -37,5 +37,13 @@ "bugs": { "url": "https://github.com/klemek/gitblog.md/issues" }, - "homepage": "https://github.com/klemek/gitblog.md#readme" + "homepage": "https://github.com/klemek/gitblog.md#readme", + "jest": { + "collectCoverageFrom": [ + "src/**/*.js", + "!/node_modules/", + "!src/server.js", + "!src/postinstall.js" + ] + } } From def326676cce1a351f3011163979b3a5a748b567 Mon Sep 17 00:00:00 2001 From: Klemek Date: Sat, 22 Jun 2019 11:00:02 +0200 Subject: [PATCH 2/8] More tests --- src/app.js | 5 +-- test/app.test.js | 78 ++++++++++++++++++++++++++-------------- test/file_walker.test.js | 2 +- test/renderer.test.js | 2 +- 4 files changed, 55 insertions(+), 32 deletions(-) diff --git a/src/app.js b/src/app.js index 08b72a0..7ee2dc1 100644 --- a/src/app.js +++ b/src/app.js @@ -154,10 +154,7 @@ module.exports = (config) => { app.post(config['webhook']['endpoint'], (req, res) => { if (config['modules']['webhook']) { if (config['webhook']['signature_header'] && config['webhook']['secret']) { - const payload = JSON.stringify(req.body); - if (!payload) { - return res.sendStatus(403); - } + const payload = JSON.stringify(req.body) || ''; const hmac = crypto.createHmac('sha1', config['webhook']['secret']); const digest = 'sha1=' + hmac.update(payload).digest('hex'); const checksum = req.headers[config['webhook']['signature_header']]; diff --git a/test/app.test.js b/test/app.test.js index bea34ec..da9f2c7 100644 --- a/test/app.test.js +++ b/test/app.test.js @@ -13,19 +13,24 @@ const config = require('../src/config')(); config['test'] = true; config['data_dir'] = dataDir; +config['webhook']['endpoint'] = '/webhooktest'; +config['rss']['endpoint'] = '/rsstest'; +config['rss']['length'] = 2; config['home']['index'] = testIndex; config['home']['error'] = testError; config['article']['template'] = testTemplate; -config['home']['hidden'].push('.test'); -config['rss']['endpoint'] = '/rsstest'; -config['rss']['length'] = 2; -config['webhook']['endpoint'] = '/webhooktest'; -config['access_log'] = path.join(dataDir, 'access.log'); -config['error_log'] = path.join(dataDir, 'error.log'); const app = require('../src/app')(config); beforeEach((done, fail) => { + config['data_dir'] = dataDir; + config['article']['index'] = 'index.md'; + config['home']['hidden'] = ['.ejs', '.test']; + config['access_log'] = ''; + config['error_log'] = ''; + config['modules']['rss'] = true; + config['modules']['webhook'] = true; + utils.deleteFolderSync(dataDir); fs.mkdirSync(dataDir); app.reload(done, fail); @@ -37,17 +42,22 @@ afterAll(() => { } }); +describe('Test reload', () => { + test('reload fail', (done, fail) => { + config['data_dir'] = ''; + app.reload(fail, done); + }); +}); + describe('Test request logging', () => { test('test no log', (done) => { - const tmp = config['access_log']; - config['access_log'] = ''; request(app).get('/rsstest').then(() => { - config['access_log'] = tmp; expect(fs.existsSync(path.join(dataDir, 'access.log'))).toBe(false); done(); }); }); test('test get 200', (done) => { + config['access_log'] = path.join(dataDir, 'access.log'); request(app).get('/rsstest').then(() => { fs.readFile(path.join(dataDir, 'access.log'), {encoding: 'UTF-8'}, (err, data) => { expect(err).toBeNull(); @@ -57,6 +67,7 @@ describe('Test request logging', () => { }); }); test('test post 400', (done) => { + config['access_log'] = path.join(dataDir, 'access.log'); request(app).post('/rsstest').then(() => { fs.readFile(path.join(dataDir, 'access.log'), {encoding: 'UTF-8'}, (err, data) => { expect(err).toBeNull(); @@ -66,6 +77,7 @@ describe('Test request logging', () => { }); }); test('test 2 requests', (done) => { + config['access_log'] = path.join(dataDir, 'access.log'); request(app).get('/rss').then(() => { request(app).post('/rsstest').then(() => { fs.readFile(path.join(dataDir, 'access.log'), {encoding: 'UTF-8'}, (err, data) => { @@ -81,22 +93,16 @@ describe('Test request logging', () => { describe('Test error logging', () => { test('test no log', (done) => { - const tmp = config['home']['hidden']; config['home']['hidden'] = null; - const tmp2 = config['errpr_log']; - config['error_log'] = ''; request(app).get('/somefile.txt').then(() => { - config['home']['hidden'] = tmp; - config['error_log'] = tmp2; expect(fs.existsSync(path.join(dataDir, 'error.log'))).toBe(false); done(); }); }); test('test null error ', (done) => { - const tmp = config['home']['hidden']; config['home']['hidden'] = null; + config['error_log'] = path.join(dataDir, 'error.log'); request(app).get('/somefile.txt').then(() => { - config['home']['hidden'] = tmp; fs.readFile(path.join(dataDir, 'error.log'), {encoding: 'UTF-8'}, (err, data) => { expect(err).toBeNull(); const start = data.split('\n').slice(0, 2).join('\n'); @@ -123,6 +129,13 @@ describe('Test root path', () => { done(); }); }); + test('500 render error', (done) => { + fs.writeFileSync(path.join(dataDir, testIndex), 'articles <%= null.length %>'); + request(app).get('/').then((response) => { + expect(response.statusCode).toBe(500); + done(); + }); + }); test('200 no articles', (done) => { fs.writeFileSync(path.join(dataDir, testIndex), 'articles <%= articles.length %>'); request(app).get('/').then((response) => { @@ -156,7 +169,6 @@ describe('Test RSS feed', () => { config['modules']['rss'] = false; request(app).get('/rsstest').then((response) => { expect(response.statusCode).toBe(404); - config['modules']['rss'] = true; done(); }); }); @@ -168,6 +180,16 @@ describe('Test RSS feed', () => { done(); }); }); + test('200 rss cache', (done) => { + request(app).get('/rsstest').then(() => { + request(app).get('/rsstest').then((response) => { + expect(response.statusCode).toBe(200); + expect(response.text.length).toBeGreaterThan(0); + expect(response.text.split('').length).toBe(1); + done(); + }); + }); + }); test('200 2 rss items', (done, fail) => { utils.createEmptyDirs([ path.join(dataDir, '2019', '05', '05'), @@ -213,7 +235,6 @@ describe('Test webhook', () => { config['modules']['webhook'] = false; request(app).post('/webhooktest').then((response) => { expect(response.statusCode).toBe(400); - config['modules']['webhook'] = true; done(); }); }); @@ -244,14 +265,6 @@ describe('Test webhook', () => { done(); }); }); - test('403 no payload', (done) => { - config['webhook']['signature_header'] = 'testheader'; - config['webhook']['secret'] = 'testvalue'; - request(app).post('/webhooktest').then((response) => { - expect(response.statusCode).toBe(403); - done(); - }); - }); test('403 wrong secret', (done) => { config['webhook']['signature_header'] = 'testheader'; config['webhook']['secret'] = 'testvalue'; @@ -282,6 +295,19 @@ describe('Test articles rendering', () => { }); }); + test('500 no index', (done, fail) => { + utils.createEmptyDirs([path.join(dataDir, '2019', '05', '05'),]); + fs.writeFileSync(path.join(dataDir, '2019', '05', '05', 'index.md'), '# Hello'); + fs.writeFileSync(path.join(dataDir, testTemplate), '<%- article.content %><%- `reload` %>'); + app.reload(() => { + config['article']['index'] = 'invalid.md'; + request(app).get('/2019/05/05/hello/').then((response) => { + expect(response.statusCode).toBe(500); + done(); + }); + }, fail); + }); + test('500 no template', (done, fail) => { utils.createEmptyDirs([path.join(dataDir, '2019', '05', '05'),]); fs.writeFileSync(path.join(dataDir, '2019', '05', '05', 'index.md'), '# Hello'); diff --git a/test/file_walker.test.js b/test/file_walker.test.js index bf30e49..55ff7ce 100644 --- a/test/file_walker.test.js +++ b/test/file_walker.test.js @@ -22,6 +22,7 @@ const config = { const fw = require('../src/file_walker')(config); beforeEach(() => { + config['data_dir'] = dataDir; utils.deleteFolderSync(dataDir); fs.mkdirSync(dataDir); }); @@ -193,7 +194,6 @@ describe('Test article fetching', () => { fw.fetchArticles((err, list) => { expect(err).not.toBeNull(); expect(list).not.toBeDefined(); - config['data_dir'] = dataDir; done(); }); }); diff --git a/test/renderer.test.js b/test/renderer.test.js index c2912eb..fff5723 100644 --- a/test/renderer.test.js +++ b/test/renderer.test.js @@ -19,6 +19,7 @@ const config = { const renderer = require('../src/renderer')(config); beforeEach(() => { + config['modules']['prism'] = true; utils.deleteFolderSync(dataDir); fs.mkdirSync(dataDir); }); @@ -61,7 +62,6 @@ test('no prism', (done) => { renderer.render(file, (err, html) => { expect(err).toBeNull(); expect(html).toBe('
print("hello")\n
\n
print("hello")\n
'); - config['modules']['prism'] = true; done(); }); }); From 9d3c1d08478c46b2a5c3fe074f178788192e16e9 Mon Sep 17 00:00:00 2001 From: Klemek Date: Sat, 22 Jun 2019 13:48:08 +0200 Subject: [PATCH 3/8] MathJax support --- .gitignore | 3 +- README.md | 7 ++ package-lock.json | 216 +++++++++++++--------------------------- package.json | 1 + src/config.default.json | 7 +- src/renderer.js | 106 ++++++++++++++++---- test/renderer.test.js | 172 ++++++++++++++++++++++---------- 7 files changed, 292 insertions(+), 220 deletions(-) diff --git a/.gitignore b/.gitignore index 54ecd89..9295227 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ /data /test_data /access.log -/error.log \ No newline at end of file +/error.log +/coverage \ No newline at end of file diff --git a/README.md b/README.md index f32b751..9b2e970 100644 --- a/README.md +++ b/README.md @@ -207,6 +207,8 @@ Any URL like `/year/month/day/anything/` will redirect to this article (and link activate the webhook endpoint and its features * `prism` (default: true) activate Prism code highlighting + * `mathjax` (default: true) + activate MathJax equations formatting * `home` * `index` (default: index.ejs) the name of the home page template on the data directory @@ -244,3 +246,8 @@ Any URL like `/year/month/day/anything/` will redirect to this article (and link the command used by the server on webhook trigger * `showdown` Options to be applied to Showdown renderer (see [showdown options](https://github.com/showdownjs/showdown#valid-options) for more info) +* `mathjax` + * `output_format`: (default: svg) + specify the output format between svg, html or MathMl (mml) + * `speak_text`: (default: true) + activate the alternate text in equations diff --git a/package-lock.json b/package-lock.json index 9fb4096..d56c5eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gitblog.md", - "version": "1.0.0", + "version": "1.0.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1257,8 +1257,7 @@ "abab": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", - "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==", - "dev": true + "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==" }, "accepts": { "version": "1.3.7", @@ -1272,14 +1271,12 @@ "acorn": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", - "dev": true + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==" }, "acorn-globals": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.2.tgz", "integrity": "sha512-BbzvZhVtZP+Bs1J1HcwrQe8ycfO0wStkSGxuul3He3GkHOIZ6eTqOkPuw9IP1X3+IkOo4wiJmwkobzXYz4wewQ==", - "dev": true, "requires": { "acorn": "^6.0.1", "acorn-walk": "^6.0.1" @@ -1288,22 +1285,19 @@ "acorn": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", - "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", - "dev": true + "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==" } } }, "acorn-walk": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", - "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==", - "dev": true + "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==" }, "ajv": { "version": "6.10.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", - "dev": true, "requires": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", @@ -1373,8 +1367,7 @@ "array-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", - "dev": true + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=" }, "array-flatten": { "version": "1.1.1", @@ -1392,7 +1385,6 @@ "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, "requires": { "safer-buffer": "~2.1.0" } @@ -1400,8 +1392,7 @@ "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, "assign-symbols": { "version": "1.0.0", @@ -1425,14 +1416,12 @@ "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", - "dev": true + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "atob": { "version": "2.1.2", @@ -1443,14 +1432,12 @@ "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", - "dev": true + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, "babel-cli": { "version": "6.26.0", @@ -2311,7 +2298,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, "requires": { "tweetnacl": "^0.14.3" } @@ -2353,8 +2339,7 @@ "browser-process-hrtime": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", - "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", - "dev": true + "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==" }, "browser-resolve": { "version": "1.11.3", @@ -2457,8 +2442,7 @@ "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, "chalk": { "version": "1.1.3", @@ -2604,7 +2588,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -2680,8 +2663,7 @@ "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "coveralls": { "version": "3.0.4", @@ -2723,14 +2705,12 @@ "cssom": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz", - "integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A==", - "dev": true + "integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A==" }, "cssstyle": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.2.2.tgz", "integrity": "sha512-43wY3kl1CVQSvL7wUY1qXkxVGkStjpkDmVjiIKX8R97uhajy8Bybay78uOtqvh7Q5GK75dNPfW0geWjE6qQQow==", - "dev": true, "requires": { "cssom": "0.3.x" } @@ -2739,7 +2719,6 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, "requires": { "assert-plus": "^1.0.0" } @@ -2748,7 +2727,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", - "dev": true, "requires": { "abab": "^2.0.0", "whatwg-mimetype": "^2.2.0", @@ -2759,7 +2737,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", - "dev": true, "requires": { "lodash.sortby": "^4.7.0", "tr46": "^1.0.1", @@ -2790,8 +2767,7 @@ "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" }, "define-properties": { "version": "1.1.3", @@ -2858,8 +2834,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "delegate": { "version": "3.2.0", @@ -2902,7 +2877,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", - "dev": true, "requires": { "webidl-conversions": "^4.0.2" } @@ -2911,7 +2885,6 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, "requires": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -2996,7 +2969,6 @@ "version": "1.11.1", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz", "integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==", - "dev": true, "requires": { "esprima": "^3.1.3", "estraverse": "^4.2.0", @@ -3009,7 +2981,6 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, "optional": true } } @@ -3017,20 +2988,17 @@ "esprima": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", - "dev": true + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" }, "estraverse": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", - "dev": true + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" }, "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, "etag": { "version": "1.8.1", @@ -3184,8 +3152,7 @@ "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "extend-shallow": { "version": "3.0.2", @@ -3221,26 +3188,22 @@ "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" }, "fast-safe-stringify": { "version": "2.0.6", @@ -3305,14 +3268,12 @@ "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, "form-data": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -3930,7 +3891,6 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, "requires": { "assert-plus": "^1.0.0" } @@ -4026,14 +3986,12 @@ "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "har-validator": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "dev": true, "requires": { "ajv": "^6.5.5", "har-schema": "^2.0.0" @@ -4157,7 +4115,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", - "dev": true, "requires": { "whatwg-encoding": "^1.0.1" } @@ -4178,7 +4135,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -4440,8 +4396,7 @@ "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, "is-windows": { "version": "1.0.2", @@ -4469,8 +4424,7 @@ "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "istanbul-lib-coverage": { "version": "2.0.5", @@ -6680,14 +6634,12 @@ "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, "jsdom": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", - "dev": true, "requires": { "abab": "^2.0.0", "acorn": "^5.5.3", @@ -6732,20 +6684,17 @@ "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, "json5": { "version": "0.5.1", @@ -6757,7 +6706,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -6797,8 +6745,7 @@ "left-pad": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", - "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", - "dev": true + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==" }, "leven": { "version": "2.1.0", @@ -6810,7 +6757,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, "requires": { "prelude-ls": "~1.1.2", "type-check": "~0.3.2" @@ -6840,14 +6786,12 @@ "lodash": { "version": "4.17.11", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", - "dev": true + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" }, "log-driver": { "version": "1.2.7", @@ -6931,6 +6875,21 @@ "dev": true, "optional": true }, + "mathjax": { + "version": "2.7.5", + "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-2.7.5.tgz", + "integrity": "sha512-OzsJNitEHAJB3y4IIlPCAvS0yoXwYjlo2Y4kmm9KQzyIBZt2d8yKRalby3uTRNN4fZQiGL2iMXjpdP1u2Rq2DQ==" + }, + "mathjax-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/mathjax-node/-/mathjax-node-2.1.1.tgz", + "integrity": "sha1-JcgPSU91QEGP/Pqcx1bf0hUCAb0=", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "jsdom": "^11.0.0", + "mathjax": "^2.7.2" + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -7237,14 +7196,12 @@ "nwsapi": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.4.tgz", - "integrity": "sha512-iGfd9Y6SFdTNldEy2L0GUhcarIutFmk+MPWIn9dmj8NMIup03G08uUF2KGbbmv/Ux4RT0VZJoP/sVbWA6d/VIw==", - "dev": true + "integrity": "sha512-iGfd9Y6SFdTNldEy2L0GUhcarIutFmk+MPWIn9dmj8NMIup03G08uUF2KGbbmv/Ux4RT0VZJoP/sVbWA6d/VIw==" }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, "object-assign": { "version": "4.1.1", @@ -7366,7 +7323,6 @@ "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, "requires": { "deep-is": "~0.1.3", "fast-levenshtein": "~2.0.4", @@ -7379,8 +7335,7 @@ "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" } } }, @@ -7496,8 +7451,7 @@ "parse5": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", - "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", - "dev": true + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==" }, "parseurl": { "version": "1.3.3", @@ -7549,8 +7503,7 @@ "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "pify": { "version": "3.0.0", @@ -7624,8 +7577,7 @@ "pn": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", - "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", - "dev": true + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==" }, "posix-character-classes": { "version": "0.1.1", @@ -7636,8 +7588,7 @@ "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" }, "preserve": { "version": "0.2.0", @@ -7722,8 +7673,7 @@ "psl": { "version": "1.1.32", "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.32.tgz", - "integrity": "sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g==", - "dev": true + "integrity": "sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g==" }, "pump": { "version": "3.0.0", @@ -7738,8 +7688,7 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "qs": { "version": "6.7.0", @@ -8308,7 +8257,6 @@ "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "dev": true, "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -8335,20 +8283,17 @@ "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "dev": true, "requires": { "psl": "^1.1.24", "punycode": "^1.4.1" @@ -8360,7 +8305,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", - "dev": true, "requires": { "lodash": "^4.17.11" } @@ -8369,7 +8313,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", - "dev": true, "requires": { "request-promise-core": "1.1.2", "stealthy-require": "^1.1.1", @@ -8829,8 +8772,7 @@ "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, "select": { "version": "1.1.2", @@ -9152,7 +9094,6 @@ "version": "1.16.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -9200,8 +9141,7 @@ "stealthy-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" }, "string-length": { "version": "2.0.0", @@ -9363,8 +9303,7 @@ "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, "test-exclude": { "version": "5.2.3", @@ -9461,7 +9400,6 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, "requires": { "psl": "^1.1.28", "punycode": "^2.1.1" @@ -9471,7 +9409,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "dev": true, "requires": { "punycode": "^2.1.0" } @@ -9486,7 +9423,6 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, "requires": { "safe-buffer": "^5.0.1" } @@ -9494,14 +9430,12 @@ "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, "requires": { "prelude-ls": "~1.1.2" } @@ -9625,7 +9559,6 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, "requires": { "punycode": "^2.1.0" } @@ -9672,8 +9605,7 @@ "uuid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", - "dev": true + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, "v8flags": { "version": "2.1.1", @@ -9703,7 +9635,6 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -9714,7 +9645,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", - "dev": true, "requires": { "browser-process-hrtime": "^0.1.2" } @@ -9731,14 +9661,12 @@ "webidl-conversions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" }, "whatwg-encoding": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, "requires": { "iconv-lite": "0.4.24" } @@ -9746,14 +9674,12 @@ "whatwg-mimetype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" }, "whatwg-url": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", - "dev": true, "requires": { "lodash.sortby": "^4.7.0", "tr46": "^1.0.1", @@ -9842,7 +9768,6 @@ "version": "5.2.2", "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", - "dev": true, "requires": { "async-limiter": "~1.0.0" } @@ -9855,8 +9780,7 @@ "xml-name-validator": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" }, "y18n": { "version": "3.2.1", diff --git a/package.json b/package.json index e48d98d..1a46d7b 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "crypto": "^1.0.1", "ejs": "^2.6.2", "express": "^4.17.1", + "mathjax-node": "^2.1.1", "ncp": "^2.0.0", "node-prismjs": "^0.1.2", "prismjs": "^1.16.0", diff --git a/src/config.default.json b/src/config.default.json index 5f39d6e..203e07c 100644 --- a/src/config.default.json +++ b/src/config.default.json @@ -7,7 +7,8 @@ "modules": { "rss": true, "webhook": true, - "prism": true + "prism": true, + "mathjax": true }, "home": { "index": "index.ejs", @@ -42,5 +43,9 @@ "tasklists": true, "openLinksInNewWindow": true, "emoji": true + }, + "mathjax": { + "output_format": "svg", + "speak_text": true } } \ No newline at end of file diff --git a/src/renderer.js b/src/renderer.js index 34f66b2..119a5ce 100644 --- a/src/renderer.js +++ b/src/renderer.js @@ -1,35 +1,99 @@ const fs = require('fs'); const showdown = require('showdown'); -const Prism = require('node-prismjs'); module.exports = (config) => { const converter = new showdown.Converter(config['showdown']); + + const renderShowDown = (data, cb) => { + const html = converter.makeHtml(data); + cb(html); + }; + + let Prism; + if (config['modules']['prism']) + Prism = require('node-prismjs'); + + const renderPrism = (data, cb) => { + if (!config['modules']['prism']) + return cb(data); + const codeRegex = /```([\w-]+)\r?\n((?:(?!```)[\s\S])*)\r?\n```/m; + let match; + while ((match = codeRegex.exec(data))) { + const lang = match[1].trim(); + const code = match[2].trim(); + try { + const block = Prism.highlight(code, Prism.languages[lang] || Prism.languages.autoit, lang); + data = data.slice(0, match.index) + `
` + block + '
' + data.slice(match.index + match[0].length); + } catch (err) { + console.error(err); + } + } + cb(data); + }; + + let mjAPI; + if (config['modules']['mathjax']) { + mjAPI = require('mathjax-node'); + mjAPI.config({ + MathJax: { + tex2jax: { + inlineMath: [['$', '$']], + displayMath: [['$$', '$$']] + } + } + }); + } + + const renderMathJax = (data, cb) => { + if (!config['modules']['mathjax']) + return cb(data); + + const doMJ = (match, format) => { + const eq = match[1].trim(); + const output = config['mathjax']['output_format']; + const mjConf = { + math: eq, + format: format, + speakText: config['mathjax']['speak_text'] + }; + mjConf[output] = true; + mjAPI.typeset(mjConf, (res) => { + data = data.slice(0, match.index) + res[output] + data.slice(match.index + match[0].length); + renderMathJax(data, (data2) => { + cb(data2); + }); + }); + }; + + const eqRegex = /\$\$((?:(?!\$\$)[\s\S])*)\$\$/m; + const inlineEqRegex = /\$([^$]*)\$/; + + let match; + if ((match = eqRegex.exec(data))) { + doMJ(match, 'TeX'); + } else if ((match = inlineEqRegex.exec(data))) { + doMJ(match, 'inline-TeX'); + } else { + cb(data); + } + }; + return { + renderShowDown: config['test'] ? renderShowDown : undefined, + renderPrism: config['test'] ? renderPrism : undefined, + renderMathJax: config['test'] ? renderMathJax : undefined, render: (file, cb) => { fs.readFile(file, {encoding: 'UTF-8'}, (err, data) => { if (err) return cb(err); - if (config['modules']['prism']) { - const codeRegex = /```([\w-]+)\r?\n((?:(?!```)[\s\S])*)\r?\n```/m; - let match; - while ((match = codeRegex.exec(data))) { - const lang = match[1].trim(); - const code = match[2].trim(); - try { - const block = Prism.highlight(code, Prism.languages[lang] || Prism.languages.autoit, lang); - data = data.slice(0, match.index) + `
` + block + '
' + data.slice(match.index + match[0].length); - } catch (err) { - console.error(err); - } - } - } - - - const html = converter.makeHtml(data); - - - cb(null, html); + renderPrism(data, (data2) => { + renderMathJax(data2, (data3) => { + renderShowDown(data3, (html) => { + cb(null, html); + }); + }); + }); }); } }; diff --git a/test/renderer.test.js b/test/renderer.test.js index fff5723..0d05864 100644 --- a/test/renderer.test.js +++ b/test/renderer.test.js @@ -7,12 +7,18 @@ const dataDir = 'test_data'; const file = path.join(dataDir, 'test.md'); const config = { + 'test': true, 'modules': { 'prism': true, + 'mathjax': true }, 'showdown': { 'simplifiedAutoLink': true, 'smartIndentationFix': true + }, + 'mathjax': { + 'output_format': 'html', + 'speak_text': false } }; @@ -20,6 +26,7 @@ const renderer = require('../src/renderer')(config); beforeEach(() => { config['modules']['prism'] = true; + config['modules']['mathjax'] = true; utils.deleteFolderSync(dataDir); fs.mkdirSync(dataDir); }); @@ -30,67 +37,130 @@ afterAll(() => { } }); -test('invalid file', (done) => { - renderer.render('invalid file', (err, html) => { - expect(err).not.toBeNull(); - expect(html).not.toBeDefined(); - done(); +describe('Test Showdown', () => { + test('normal', (done) => { + renderer.renderShowDown('# Hello', (html) => { + expect(html).toBe('

Hello

'); + done(); + }); + }); + test('custom rules', (done) => { + renderer.renderShowDown('www.google.com', (html) => { + expect(html).toBe('

www.google.com

'); + done(); + }); + }); + test('code format', (done) => { + renderer.renderShowDown('```python\nprint("hello")\n```\n\n```python\nprint("hello")\n```', (html) => { + expect(html).toBe('
print("hello")\n
\n
print("hello")\n
'); + done(); + }); }); }); -test('normal file', (done) => { - fs.writeFileSync(file, `# Hello`); - renderer.render(file, (err, html) => { - expect(err).toBeNull(); - expect(html).toBe('

Hello

'); - done(); +describe('Test Prism', () => { + test('no prism', (done) => { + config['modules']['prism'] = false; + renderer.renderPrism('```python\nprint("hello")\n```\n\n```python\nprint("hello")\n```', (data) => { + expect(data).toBe('```python\nprint("hello")\n```\n\n```python\nprint("hello")\n```'); + done(); + }); + }); + + test('prism correct', (done) => { + renderer.renderPrism('```python\nprint("hello")\n```', (data) => { + expect(data).not.toBe('
print("hello")\n
'); + expect(data.indexOf('
')).toBe(0);
+      done();
+    });
+  });
+
+  test('prism invalid lang', (done) => {
+    renderer.renderPrism('```pythdon\nprint("hello")\n```', (data) => {
+      expect(data).not.toBe('
print("hello")\n
'); + expect(data.indexOf('
')).toBe(0);
+      done();
+    });
+  });
+
+  test('prism mutliple code blocks', (done) => {
+    renderer.renderPrism('```python\n\n```\n```python\n\n```', (data) => {
+      expect(data).toBe('
\n
'); + done(); + }); }); }); -test('custom rules', (done) => { - fs.writeFileSync(file, `www.google.com`); - renderer.render(file, (err, html) => { - expect(err).toBeNull(); - expect(html).toBe('

www.google.com

'); - done(); +describe('Test MathJax', () => { + test('no mathjax', (done) => { + config['modules']['mathjax'] = false; + renderer.renderMathJax('$$\nhello\n$$\ntest$test$', (data) => { + expect(data).toBe('$$\nhello\n$$\ntest$test$'); + done(); + }); + }); + test('full eq', (done) => { + renderer.renderMathJax('$$\n\nA\n\n$$', (data) => { + expect(data).toBe('' + + '' + + '' + + 'A' + + ''); + done(); + }); + }); + test('inline eq', (done) => { + renderer.renderMathJax('start $a$ end', (data) => { + expect(data).toBe('start ' + + '' + + '' + + '' + + 'a' + + '' + + ' end'); + done(); + }); + }); + test('multiple eq', (done) => { + renderer.renderMathJax('$$\n\nA\n\n$$\nstart $a$ end\n$$\n\nA\n\n$$', (data) => { + expect(data).toBe('' + + '' + + '' + + '' + + 'A' + + '\n' + + 'start ' + + '' + + '' + + '' + + 'a' + + '' + + ' end\n' + + '' + + '' + + '' + + 'A' + + ''); + done(); + }); }); }); -test('no prism', (done) => { - config['modules']['prism'] = false; - fs.writeFileSync(file, '```python\nprint("hello")\n```\n\n```python\nprint("hello")\n```'); - renderer.render(file, (err, html) => { - expect(err).toBeNull(); - expect(html).toBe('
print("hello")\n
\n
print("hello")\n
'); - done(); +describe('Test render', () => { + test('invalid file', (done) => { + renderer.render('invalid file', (err, html) => { + expect(err).not.toBeNull(); + expect(html).not.toBeDefined(); + done(); + }); }); -}); -test('prism correct', (done) => { - fs.writeFileSync(file, '```python\nprint("hello")\n```'); - renderer.render(file, (err, html) => { - expect(err).toBeNull(); - expect(html).not.toBe('
print("hello")\n
'); - expect(html.indexOf('
')).toBe(0);
-    done();
-  });
-});
-
-test('prism invalid lang', (done) => {
-  fs.writeFileSync(file, '```pythdon\nprint("hello")\n```');
-  renderer.render(file, (err, html) => {
-    expect(err).toBeNull();
-    expect(html).not.toBe('
print("hello")\n
'); - expect(html.indexOf('
')).toBe(0);
-    done();
-  });
-});
-
-test('prism mutliple code blocks', (done) => {
-  fs.writeFileSync(file, '```python\n\n```\n\n```python\n\n```');
-  renderer.render(file, (err, html) => {
-    expect(err).toBeNull();
-    expect(html).toBe('
\n
'); - done(); + test('normal file', (done) => { + fs.writeFileSync(file, `# Hello`); + renderer.render(file, (err, html) => { + expect(err).toBeNull(); + expect(html).toBe('

Hello

'); + done(); + }); }); }); \ No newline at end of file From 6bdcd6872e47fbc64c48e7d8654b309a8b3b37fc Mon Sep 17 00:00:00 2001 From: Klemek Date: Sat, 22 Jun 2019 14:13:20 +0200 Subject: [PATCH 4/8] MathJax small fix --- src/renderer.js | 2 +- test/renderer.test.js | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/renderer.js b/src/renderer.js index 119a5ce..8944f9f 100644 --- a/src/renderer.js +++ b/src/renderer.js @@ -66,7 +66,7 @@ module.exports = (config) => { }; const eqRegex = /\$\$((?:(?!\$\$)[\s\S])*)\$\$/m; - const inlineEqRegex = /\$([^$]*)\$/; + const inlineEqRegex = /\$([^$\n]*)\$/; let match; if ((match = eqRegex.exec(data))) { diff --git a/test/renderer.test.js b/test/renderer.test.js index 0d05864..f9e8279 100644 --- a/test/renderer.test.js +++ b/test/renderer.test.js @@ -121,6 +121,12 @@ describe('Test MathJax', () => { done(); }); }); + test('fake inline eq', (done) => { + renderer.renderMathJax('i have $6\nyou have $5', (data) => { + expect(data).toBe('i have $6\nyou have $5'); + done(); + }); + }); test('multiple eq', (done) => { renderer.renderMathJax('$$\n\nA\n\n$$\nstart $a$ end\n$$\n\nA\n\n$$', (data) => { expect(data).toBe('' + From 333bbf6eb86740f72d9ee8b67d04d1cc4ff602b8 Mon Sep 17 00:00:00 2001 From: Klemek Date: Sat, 22 Jun 2019 14:25:41 +0200 Subject: [PATCH 5/8] updated article index.md --- sample_data/article/index.md | 62 ++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/sample_data/article/index.md b/sample_data/article/index.md index 971b3d2..370dc41 100644 --- a/sample_data/article/index.md +++ b/sample_data/article/index.md @@ -4,7 +4,24 @@ If you see this page, that means it's working ## Guide to Markdown formatting +* [Headers](#headers) +* [Emphasis](#emphasis) +* [Lists](#lists) +* [Links](#links) +* [Images](#images) +* [Code and Syntax Highlighting](#codeandsyntaxhighlighting) +* [Tables](#tables) +* [Blockquotes](#blockquotes) +* [Inline HTML](#inlinehtml) +* [Horizontal Rule](#horizontalrule) +* [Line Breaks](#linebreaks) +* [Check Boxes](#checkboxes) +* [Spoilers](#spoilers) +* [Math Equations](#mathequations) +* [Youtube Videos](#youtubevideos) + ### Headers +[Back to top](#top) # H1 ## H2 @@ -22,6 +39,7 @@ Alt-H2 ------ ### Emphasis +[Back to top](#top) Emphasis, aka italics, with *asterisks* or _underscores_. @@ -32,6 +50,7 @@ Combined emphasis with **asterisks and _underscores_**. Strikethrough uses two tildes. ~~Scratch this.~~ ### Lists +[Back to top](#top) 1. First ordered list item 2. Another item @@ -51,6 +70,7 @@ Strikethrough uses two tildes. ~~Scratch this.~~ + Or pluses ### Links +[Back to top](#top) [I'm an inline-style link](https://www.google.com) @@ -75,6 +95,7 @@ Some text to show that the reference links can follow later. [link text itself]: http://www.reddit.com ### Images +[Back to top](#top) Here's our logo (hover to see the title text): @@ -88,6 +109,7 @@ Reference-style: ### Code and Syntax Highlighting +[Back to top](#top) Inline `code` has `back-ticks around` it. @@ -108,6 +130,7 @@ But let's throw in a tag. ### Tables +[Back to top](#top) Colons can be used to align columns. @@ -127,6 +150,7 @@ Markdown | Less | Pretty 1 | 2 | 3 ### Blockquotes +[Back to top](#top) > Blockquotes are very handy in email to emulate reply text. > This line is part of the same quote. @@ -136,6 +160,7 @@ Quote break. > This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can *put* **Markdown** into a blockquote. ### Inline HTML +[Back to top](#top)
Definition list
@@ -146,6 +171,7 @@ Quote break.
### Horizontal Rule +[Back to top](#top) Three or more... @@ -162,6 +188,7 @@ ___ Underscores ### Line Breaks +[Back to top](#top) Here's a line for us to start with. @@ -169,3 +196,38 @@ This line is separated from the one above by two newlines, so it will be a *sepa This line is also a separate paragraph, but... This line is only separated by a single newline, so it's a separate line in the *same paragraph*. + +### Check Boxes +[Back to top](#top) + +* [x] Task completed +* [] Task to do + +### Spoilers +[Back to top](#top) + +
Title of the spoiler (click)

+Content of the spoiler + +On several lines +

+ +### Math Equations +[Back to top](#top) + +You can use LaTeX equations with MathJax for full equations and inline ones (based on the number of $) : + +$$ +\large{\beta=\sum_{i}^{\alpha }\frac{x^{i}}{\alpha}} +$$ + + +Where $\alpha$ is cool + + +### Youtube Videos +[Back to top](#top) + +Just use the "embedded" export on Youtube with dimensions of 535x300 for best results + + \ No newline at end of file From 0480536a2076fadc8ccb53d9d95e3d1979fad064 Mon Sep 17 00:00:00 2001 From: Klemek Date: Sat, 22 Jun 2019 14:29:54 +0200 Subject: [PATCH 6/8] Updated footer for more info --- package.json | 3 +-- sample_data/home/footer.ejs | 3 ++- src/app.js | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 1a46d7b..4b499d1 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,6 @@ { - "nodePort": 5000, "name": "gitblog.md", - "version": "1.0.2", + "version": "1.0.3", "description": "A static blog using Markdown pulled from your git repository.", "main": "src/server.js", "dependencies": { diff --git a/sample_data/home/footer.ejs b/sample_data/home/footer.ejs index 42edf34..1008e4e 100644 --- a/sample_data/home/footer.ejs +++ b/sample_data/home/footer.ejs @@ -1,5 +1,6 @@
- @<%= new Date().getFullYear() %> - Made with GitBlog.md + RSS feed - @<%= new Date().getFullYear() %> - Made with GitBlog.md (v<%= info.version %>)
\ No newline at end of file diff --git a/src/app.js b/src/app.js index 7ee2dc1..a59a44d 100644 --- a/src/app.js +++ b/src/app.js @@ -2,6 +2,7 @@ const express = require('express'); const app = express(); const fs = require('fs'); const path = require('path'); +const pjson = require('../package.json'); app.enable('trust proxy'); @@ -71,6 +72,9 @@ module.exports = (config) => { * @param code - code to send along the page */ const render = (res, vPath, data, code = 200) => { + data.info = { + version: pjson.version + }; res.render(vPath, data, (err, html) => { if (err) { res.sendStatus(500); From 0d173cfcef5f9caa6ef1c5fde859792fef3fd523 Mon Sep 17 00:00:00 2001 From: Klemek Date: Sat, 22 Jun 2019 14:37:52 +0200 Subject: [PATCH 7/8] [skip CI] updated README.md --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9b2e970..e6c82fc 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ A static blog using Markdown pulled from your git repository. * **[How it works](#how-it-works)** * **[Installation](#installation)** * **[Writing an article](#writing-an-article)** +* **[Modules](#modules)** * **[Configuration](#configuration)** ## How it works @@ -187,6 +188,18 @@ On that same folder, you can place resources like images and reference them in r Any URL like `/year/month/day/anything/` will redirect to this article (and link to correct resources) +## Modules +[back to top](#gitblog-md) + +* **RSS** + It allows your users to use the feed to be updated as soon as a new article is out +* **Webhook** + It update your blog from your online repo when it's updated +* **Prism** + It highlight code blocks to be more readable (more info [here](https://prismjs.com/), you will need the corresponding CSS file on your templates) +* **MathJax** + It allows you to add math equations to your articles by simply writing LaTeX between $$ for full size (and between $ for inline) (more info [here](https://www.mathjax.org/)) + ## Configuration [back to top](#gitblog-md) @@ -245,7 +258,7 @@ Any URL like `/year/month/day/anything/` will redirect to this article (and link * `pull_command`: (default: git pull) the command used by the server on webhook trigger * `showdown` - Options to be applied to Showdown renderer (see [showdown options](https://github.com/showdownjs/showdown#valid-options) for more info) + Options to be applied to Showdown renderer (see [showdown options](https://github.com/showdownjs/showdown/wiki/Showdown-Options) for more info) * `mathjax` * `output_format`: (default: svg) specify the output format between svg, html or MathMl (mml) From 35a7747d6d67213569504ef7d35b2c133aa9c99f Mon Sep 17 00:00:00 2001 From: Klemek Date: Sat, 22 Jun 2019 14:38:59 +0200 Subject: [PATCH 8/8] better warning when no config.json --- src/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.js b/src/config.js index a51b3c7..dca7338 100644 --- a/src/config.js +++ b/src/config.js @@ -25,7 +25,7 @@ module.exports = () => { let config = JSON.parse(configData); return merge(refConfig, config); } catch (error) { - console.error('Failed to load config.json : ' + error); + console.log('\x1b[33m⚠\x1b[0m %s', 'Failed to load config.json : ' + error); return refConfig; } }; \ No newline at end of file