akiha-circuit
Version:
Draws electric circuit diagram by ASCII art
221 lines (204 loc) • 6.65 kB
JavaScript
/**
* akiha-circuit
*
* Copyright (c) 2019 Yuichiro MORIGUCHI
*
* This software is released under the MIT License.
* http://opensource.org/licenses/mit-license.php
**/
var fs = require("fs"),
akiha = require("./akiha-facade.js"),
common = require("./akiha-common.js"),
svgLib = require("./svg-direct.js"),
preprocessors,
ptn = {};
function makeMkdir(imageDir) {
var madedir = false;
return function() {
var fstat;
if(madedir) {
return;
}
try {
fstat = fs.statSync(imageDir);
} catch(err) {
if(err.code === 'ENOENT') {
fs.mkdirSync(imageDir, 493); // 0o755
} else {
throw err;
}
}
if(fstat && !fstat.isDirectory()) {
throw new Error(imageDir + " is not a directory");
}
madedir = true;
}
}
function makeimg(imageDir, dataUri) {
var num = 1,
mkdir = makeMkdir(imageDir);
return function(input, opt, base) {
var foutput,
imgfn,
result;
foutput = akiha.createSvg(input, svgLib).toString();
if(dataUri) {
throw new Error("Data URI is not supported");
} else {
mkdir();
imgfn = base + "." + ("000" + (num++)).slice(-4);
result = imageDir + "/" + imgfn + ".svg";
fs.writeFileSync(result, foutput);
}
return result;
}
}
function preprocessimg(beginPatterns, endPatterns, imgOutput, useDataUri) {
var beginREs,
endREs;
function initPattern(opt) {
if(!beginREs) {
var i,
j;
beginREs = [];
endREs = [];
for(i = 0; i < beginPatterns.length; i++) {
beginREs[i] = [];
for(j = 0; j < beginPatterns[i].length; j++) {
beginREs[i][j] = common.replaceTemplateRegExp(beginPatterns[i][j], opt, 'i');
}
endREs[i] = new RegExp(endPatterns[i], 'i');
}
}
}
function matchPattern(line, lastmatch) {
var i,
match;
function execresult(num, lineno) {
var rematch,
result = {};
if(!!(rematch = beginREs[num][lineno].exec(line))) {
result.lineno = lineno + 1;
result.num = num;
result.match = rematch;
result.accept = result.lineno >= beginREs[num].length;
return result;
} else {
return false;
}
}
if(lastmatch) {
return execresult(lastmatch.num, lastmatch.lineno);
} else {
for(i = 0; i < beginREs.length; i++) {
if(!!(match = execresult(i, 0))) {
return match;
}
}
return false;
}
}
return function(fileinput, opt, base) {
var input,
lines,
line,
output = "",
i,
state = "INIT",
match = null,
dataUri = useDataUri && opt.direction.dataUri;
img = makeimg(opt.direction.imageDir, dataUri),
imgfn = {};
initPattern(opt.option);
lines = fileinput.split(/\r?\n/);
for(i = 0; i < lines.length; i++) {
line = lines[i];
switch(state) {
case "INIT":
if(!!(match = matchPattern(line, match)) && match.accept) {
state = "LINE";
input = "";
} else {
output += line + "\n";
}
break;
case "LINE":
if(endREs[match.num].test(line)) {
imgfn.img = img(input, opt.option, base);
if(typeof imgOutput === 'string') {
output += common.replaceTemplate(imgOutput, imgfn) + "\n";
} else {
output += imgOutput(imgfn, match.match);
}
state = "INIT";
match = null;
} else {
input += line + "\n";
}
break;
}
}
return output;
}
}
function preprocess(pptype, file, opt) {
var i,
match,
input,
output,
pp = preprocessors[pptype];
for(i = 0; i < pp.length; i++) {
match = pp[i].pattern.exec(file);
if(match) {
try {
input = fs.readFileSync(file, 'utf8');
output = pp[i].action(input, opt, match[1]);
fs.writeFileSync(match[1] + (match[2] ? match[2] : ""), output);
return 0;
} catch(err) {
console.error('File %s can not read', file);
throw err;
return 2;
}
}
}
console.error('Unrecognized file %s', file);
return 2;
}
ptn.val = '(?:[^\\/>\s]+|\'[^\']+\'|"[^"]+")';
ptn.valtmp = '(?:@className@|\'(?:[^\'\\s]+\\s+)*@className@(?:\\s+[^\'\\s]+)*\'|"(?:[^"\\s]+\\s+)*@className@(?:\\s+[^"\\s]+)*")';
ptn.classe = '[^\\/>\\s=]+=' + ptn.val;
ptn.classes = '(?:\\s*' + ptn.classe + ')*';
ptn.attr = ptn.classes + '\\s*class=' + ptn.valtmp + ptn.classes;
ptn.pre = '<(pre)(' + ptn.attr + ')\\s*>';
ptn.div = '<(div)(' + ptn.attr + ')\\s*>';
ptn.script = '<(script)\\s+type=(?:\'@scriptType@\'|"@scriptType@")>';
preprocessors = {
"default": [
{
pattern: /^(.*)\.akihac(\.md)$/,
action: preprocessimg([["^\\`\\`\\`akiha-circuit$"]], ["^\\`\\`\\`$"], '')
},
{
pattern: /^(.*)\.akihac(\.html?)$/,
action: preprocessimg(
[[ptn.script]],
['^\\s*<\\/script>'],
function(imgfn, match) {
var output = '';
switch(match[1].toLowerCase()) {
case 'script':
output += common.replaceTemplate('<img src="@img@">', imgfn) + "\n";
break;
}
return output;
},
true)
},
{
pattern: /^(.*)\.akihac(\.a(scii)?doc)$/,
action: preprocessimg([["^\\[akiha-circuit\\]$", "^-+$"]], ["^-+$"], 'image::@img@[svg]')
}
]
}
module.exports = preprocess;