diff --git a/package-lock.json b/package-lock.json index e7cf978..356f460 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gitblog.md", - "version": "1.1.5", + "version": "1.2.5", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1337,7 +1337,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, "requires": { "sprintf-js": "~1.0.2" } @@ -3190,6 +3189,14 @@ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, + "fa-diagrams": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fa-diagrams/-/fa-diagrams-1.0.3.tgz", + "integrity": "sha512-z9pFYYnc6s1sUs4lq+DY2m5ddLCKN3jdo5O6hv450WwjiQ7otk1RoGQsvpMcwSU1kMEzPJUI6AeTVvzyIElhwQ==", + "requires": { + "xml-js": "^1.6.11" + } + }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", @@ -6617,7 +6624,6 @@ "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -6626,8 +6632,7 @@ "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" } } }, @@ -9087,8 +9092,7 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "sshpk": { "version": "1.16.1", @@ -9777,6 +9781,14 @@ "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=" }, + "xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "requires": { + "sax": "^1.2.4" + } + }, "xml-name-validator": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", diff --git a/package.json b/package.json index b05cb18..5c5b8e2 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,8 @@ "crypto": "^1.0.1", "ejs": "^2.6.2", "express": "^4.17.1", + "fa-diagrams": "^1.0.3", + "js-yaml": "^3.13.1", "mathjax-node": "^2.1.1", "ncp": "^2.0.0", "node-prismjs": "^0.1.2", diff --git a/src/config.default.json b/src/config.default.json index 63e3f92..79fe3f3 100644 --- a/src/config.default.json +++ b/src/config.default.json @@ -10,7 +10,8 @@ "webhook": true, "prism": true, "mathjax": true, - "plantuml": true + "plantuml": true, + "fa-diagrams": true }, "home": { "title": "GitBlog.md", diff --git a/src/renderer.js b/src/renderer.js index 2fd6a91..266feb1 100644 --- a/src/renderer.js +++ b/src/renderer.js @@ -150,22 +150,64 @@ module.exports = (config) => { cb(data); }; + let faDiagrams; + let yaml; + if (config['modules']['fa-diagrams']) { + faDiagrams = require('fa-diagrams'); + yaml = require('js-yaml'); + } + + const renderFaDiagrams = (data, cb) => { + if (!config['modules']['fa-diagrams']) + return cb(data); + const parts = getParts(data); + const diagramsRegex = /@startfad\r?\n((?:(?!@endfad)[\s\S])*)\r?\n@endfad/m; + let match; + parts.forEach(part => { + while ((match = diagramsRegex.exec(part.text))) { + const code = match[1].trim(); + let output; + try { + const diagData = yaml.safeLoad(code); + const findLineBreaks = (data) => { + Object.keys(data).forEach(key => { + if (typeof data[key] === 'object') + findLineBreaks(data[key]); + else if (typeof data[key] === 'string') + data[key] = data[key].replace(/\\n/gm, '\n'); + }); + }; + findLineBreaks(diagData); + output = faDiagrams.compute(diagData); + } catch (err) { + output = `${err.toString()}`; + } + part.text = part.text.slice(0, match.index) + output + part.text.slice(match.index + match[0].length); + } + data = data.slice(0, part.index) + part.text + data.slice(part.end); + }); + cb(data); + }; + return { getParts: config['test'] ? getParts : undefined, renderShowDown: config['test'] ? renderShowDown : undefined, renderPrism: config['test'] ? renderPrism : undefined, renderPlantUML: config['test'] ? renderPlantUML : undefined, renderMathJax: config['test'] ? renderMathJax : undefined, + renderFaDiagrams: config['test'] ? renderFaDiagrams : undefined, render: (file, cb) => { fs.readFile(file, {encoding: 'UTF-8'}, (err, data) => { if (err) return cb(err); renderPlantUML(data, (data) => { - renderMathJax(data, (data) => { - renderPrism(data, (data) => { - renderShowDown(data, (html) => { - cb(null, html); + renderFaDiagrams(data, (data) => { + renderMathJax(data, (data) => { + renderPrism(data, (data) => { + renderShowDown(data, (html) => { + cb(null, html); + }); }); }); }); diff --git a/test/renderer.test.js b/test/renderer.test.js index 5d05f7b..b4324a4 100644 --- a/test/renderer.test.js +++ b/test/renderer.test.js @@ -11,7 +11,8 @@ const config = { 'modules': { 'prism': true, 'mathjax': true, - 'plantuml': true + 'plantuml': true, + 'fa-diagrams': true, }, 'showdown': { 'simplifiedAutoLink': true, @@ -32,6 +33,7 @@ beforeEach(() => { config['modules']['prism'] = true; config['modules']['mathjax'] = true; config['modules']['plantuml'] = true; + config['modules']['fa-diagrams'] = true; utils.deleteFolderSync(dataDir); fs.mkdirSync(dataDir); }); @@ -212,6 +214,34 @@ describe('Test MathJax', () => { }); }); +describe('Test fa-diagrams', () => { + test('no fa-diagrams', (done) => { + config['modules']['fa-diagrams'] = false; + renderer.renderFaDiagrams('@startfad\noptions:\n\trendering:\t\tcolor:red\n\n@endfad', (data) => { + expect(data).toBe('@startfad\noptions:\n\trendering:\t\tcolor:red\n\n@endfad'); + done(); + }); + }); + test('no fa-diagrams in code', (done) => { + renderer.renderFaDiagrams('code:\n```\n@startfad\noptions:\n\trendering:\t\tcolor:red\n\n@endfad\n```', (data) => { + expect(data).toBe('code:\n```\n@startfad\noptions:\n\trendering:\t\tcolor:red\n\n@endfad\n```'); + done(); + }); + }); + test('valid fa-diagrams', (done) => { + renderer.renderFaDiagrams('before\n@startfad\noptions:\n rendering:\n color: red\n@endfad\nafter', (data) => { + expect(data).toBe('before\n\nafter'); + done(); + }); + }); + test('invalid yaml', (done) => { + renderer.renderFaDiagrams('before\n@startfad\noptions:\n@endfad\nafter', (data) => { + expect(data).toBe('before\nTypeError: Cannot convert undefined or null to object\nafter'); + done(); + }); + }); +}); + describe('Test render', () => { test('invalid file', (done) => { renderer.render('invalid file', (err, html) => {