UNPKG

esf-puml

Version:

Renders puml-files from nested directories, a string or a single *.puml file

354 lines (271 loc) 8.54 kB
/** * Created by Denis Bondarenko <bond.den@gmail.com> on 29.07.2015. */ "use strict"; //todo: implement ESF coding standards Object.defineProperty(exports, "__esModule", { value: true }); var fs = require('fs-extra'), path = require('path'), stream = require('stream'), exec = require('child_process').exec, svgoMod = require('svgo'); class PumlRenderer { constructor() { var H = this; this.pumlJar = 'bin/plantuml.jar'; this.jarPth = path.resolve(__dirname + '/' + this.pumlJar); this.supportedFormats = { svg: '-tsvg', eps: '-teps', png: '' }; /** * private methods * @type {Object} */ this._ = { setFmt: function setFmt() { let fmt = arguments.length <= 0 || arguments[0] === undefined ? 'svg' : arguments[0]; let fmtOpt = H.supportedFormats.svg; if (H.supportedFormats.hasOwnProperty(fmt)) { fmtOpt = H.supportedFormats[fmt]; } return fmtOpt; }, customCwd: function customCwd(buf, cwd) { let s = buf.toString('utf8'); let rxs = '!include ((((\.\/)?(\.\.\/)+)|(\.\/(\.\.\/)*))((.+)[\r\n]))'; let m = s.match(new RegExp(rxs, 'ig')); if (m) { m.forEach((v, i, a) => { let before = v; let m1 = before.match(new RegExp(rxs, 'i')); if (m1 && m1.length && m1.length > 1) { let after = before.replace(before, '!include ' + path.resolve(cwd + '/' + m1[1].replace(/[\/\\]/gi, path.sep))); s = s.replace(before, after); } }); } return new Buffer(s, 'utf8'); }, createQryDir: function createQryDir(inpDir, outDir) { let fmt = arguments.length <= 2 || arguments[2] === undefined ? 'svg' : arguments[2]; return 'java -jar ' + H.jarPth + ' ' + '-charset "utf8" ' + H._.setFmt(fmt) + ' ' + '-o "' + outDir + '" "' + path.resolve(inpDir + '/**.puml') + '"'; }, createQryFile: function createQryFile(inp, out) { let fmt = arguments.length <= 2 || arguments[2] === undefined ? 'svg' : arguments[2]; return 'java -jar ' + H.jarPth + ' ' + '-charset "utf8" ' + H._.setFmt(fmt) + ' ' + '-o "' + out + '" "' + inp + '"'; }, createQryStr: function createQryStr(inpStr, outFile) { let fmt = arguments.length <= 2 || arguments[2] === undefined ? 'svg' : arguments[2]; return 'java -jar ' + H.jarPth + ' ' + '-charset "utf8" ' + H._.setFmt(fmt) + ' ' + '-pipe > "' + outFile + '"'; }, createQryStm: function createQryStm() { let fmt = arguments.length <= 0 || arguments[0] === undefined ? 'svg' : arguments[0]; return 'java -jar ' + H.jarPth + ' ' + '-charset "utf8" ' + H._.setFmt(fmt) + ' ' + '-pipe'; } }; } //todo: clean after render files by *.cmapx existence //todo: limit execution times /** * [renderDir description] * @param {string} inpDir input directory, that is to be recursively scanned * @param {string} outDir output directory to save rendered files * @return {Promise} returns a Promise, tha is resolved on process end. */ renderDir(inpDir, outDir) { var H = this; return new Promise((rs, rj) => { var t = setInterval(() => { process.stdout.write(' ->'); }, 1000); exec(H._.createQryDir(inpDir, outDir), { encoding: "utf8" }, (e, r) => { if (e) { clearInterval(t); rj(e); return e; } clearInterval(t); rs(true); }); }); } cleanSvgFile(fileOut) { //var H=this; return new Promise((rs, rj) => { fs.readFile(fileOut, 'utf8', (e1, r1) => { if (e1) { rj(e1); return e1; } let svgo = new svgoMod({ plugins: [{ cleanupIDs: false }] }); svgo.optimize(r1, r2 => { if (!r2) { let e2 = new Error('SVG Optimisation Error'); rj(e2); return e2; } let format = path.extname(fileOut); fileOut = path.resolve(fileOut.replace(format, 'opt' + format)); fs.writeFile(fileOut, r2.data, (e3, r3) => { if (e3) { rj(e3); return e3; } rs(fileOut); }); }); }); }); } /** * Renders a single puml to an image of one of supported by PlantUML formats * @param {string} fileIn path to input file * @param {string} dirOut output directory * @param {string} format='svg' format of rendered image, supported formats: SVG, PNG, EPS. Default: SVG. Optional * @return {Promise} returns a Promise */ renderFile(fileIn, dirOut) { let format = arguments.length <= 2 || arguments[2] === undefined ? 'svg' : arguments[2]; var H = this; return new Promise((rs, rj) => { exec(H._.createQryFile(fileIn, dirOut, format), { encoding: "utf8" }, (e, r) => { if (e) { rj(e); return e; } let fileOutBase = path.basename(fileIn, '.puml'); let fileOut = path.resolve(dirOut + '/' + fileOutBase + '.' + format); if (format === 'svg') { H.cleanSvgFile(fileOut).then(r => { rs(fileOut); }).catch(e => { rj(e); return e; }); } else { rs(fileOut); } }); }); } renderString(strIn, fileOut) { let format = arguments.length <= 2 || arguments[2] === undefined ? 'svg' : arguments[2]; var H = this; return new Promise((rs, rj) => { let qry = H._.createQryStr(strIn, fileOut, format); let pcs = exec(qry); pcs.stdin.write(strIn, e => { if (e) { rj(e); } pcs.stdin.end(); }); pcs.on('error', e => { rj(e); return e; }); pcs.stderr.on('data', data => { rj('stderr: ' + data); return 1; }); pcs.on('close', code => { if (code !== 0) { rj(new Error(qry + ' exited with code ' + code)); } else { rs(code); } }); }); } renderStringToString(strIn) { let format = arguments.length <= 1 || arguments[1] === undefined ? 'svg' : arguments[1]; var H = this; return new Promise((rs, rj) => { let out = ''; let qry = H._.createQryStm(format); let pcs = exec(qry); pcs.stdin.write(strIn, e => { if (e) { rj(e); } pcs.stdin.end(); }); pcs.on('error', e => { rj(e); return e; }); pcs.stderr.on('data', d => { rj('stderr: ' + d); return 1; }); pcs.on('close', code => { if (code !== 0) { rj(new Error(qry + ' exited with code ' + code)); } else { rs(code); } }); pcs.stdout.on('data', d => { out += d; }); pcs.stdout.on('end', () => { rs(out); }); }); } /** * Renders a stream of utf8-encoded puml code to selected format. Currently supported SVG * @param {string} format='svg' format of rendered image, supported formats: SVG. Default: SVG. Optional * @param {string} cwd. custom CWD. Deault: null. Optional * @return {stream.Duplex} returns a duplex stream, that can be piped in and out. */ stream() { let format = arguments.length <= 0 || arguments[0] === undefined ? 'svg' : arguments[0]; let cwd = arguments.length <= 1 || arguments[1] === undefined ? null : arguments[1]; var H = this; let pcs = exec(this._.createQryStm(format)); let stm = stream.Duplex({ read: function read(n) { //console.log('To read: '+n); }, write: function write(d, encoding, next) { if (cwd) { d = H._.customCwd(d, cwd); } pcs.stdin.write(d, null, () => { pcs.stdin.end(); }); } }); pcs.stdout.on('data', d => { stm.push(d); }); pcs.stdout.on('end', () => { stm.push(null); }); pcs.stderr.on('data', v => { stm.push(null); }); pcs.on('error', e => { stm.push(null); }); pcs.on('close', () => { stm.push(null); }); return stm; } } exports.PumlRenderer = PumlRenderer; //# sourceMappingURL=.maps/index.es7.js.map