partpipe
Version:
Command line filter to apply unix filter to parts of input stream.
242 lines (232 loc) • 9.36 kB
JavaScript
// Generated by CoffeeScript 2.4.1
var D, E, T, checkSeparator, child_process, co, escapeRegExp, partpipe;
co = require('co');
child_process = require('child_process');
T = console.log;
E = console.error;
D = (opt, str) => {
if ((opt != null ? opt.debugConsole : void 0) != null) {
return opt.debugConsole("partpipe:" + str);
}
};
checkSeparator = (str) => {
return !str.match(/[():;]/);
};
//str.match /\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|/
escapeRegExp = function(str) {
return str.replace(/[\-\[\]\/\{\}\*\+\.\\\^\$]/g, "\\$&");
};
partpipe = function(input, opt = {}) {
var debugConsole, inputLines, marker, processIndent, runProcessWithInjection, tags, unknownTag;
({tags = {}, marker = null, debugConsole = null, processIndent = true, unknownTag = 'bypass'} = opt);
if (marker && !checkSeparator(marker)) {
throw `you can't use '():;' for separator: ${marker}`;
}
if (marker == null) {
marker = '(?:@PARTPIPE@)';
}
D(opt, "===starting partpipe process");
D(opt, `marker:${marker}`);
D(opt, `processIndent:${processIndent}`);
D(opt, `tags:${JSON.stringify(tags)}`);
D(opt, `unknownTag:${unknownTag}`);
inputLines = input.split("\n");
runProcessWithInjection = function(commandLine, buffer, opt) {
return new Promise(function(rv, rj) {
var isEcho, p;
switch (commandLine) {
case 'cat':
D(opt, "command line is cat, bypassing content");
return rv(buffer != null ? buffer : '');
case '':
D(opt, "command line is null, removing content");
return rv();
default:
isEcho = commandLine.match(/^echo (.*)$/);
if (isEcho) {
D(opt, `command line is echo, overwriting content with ${isEcho[1]}`);
return rv(isEcho[1]);
}
}
p = child_process.exec(commandLine, function(err, stdout, stderr) {
if (err) {
return rj(stderr);
} else {
return rv(stdout);
}
});
if (buffer !== null) {
p.stdin.write(buffer);
}
return p.stdin.end();
});
};
return co(function*() {
var actualMarkerE, actualMarkerS, beginningLineno, buffer, commandLine, commandOutput, emarkerE, emarkerS, i, indent, inlineRegexp, len, line, lineno, m, mi, numEmarkerUsed, output, ref, ref1, ref2, ref3, regex, regex2, state;
buffer = '';
commandLine = '';
state = 'bypass';
output = '';
lineno = 0;
beginningLineno = 0;
for (i = 0, len = inputLines.length; i < len; i++) {
line = inputLines[i];
lineno++;
D(opt, "block:input:" + line);
m = line.match(new RegExp(`^([ ]*)${escapeRegExp(marker)}([|=!]?)([^;]*)$`));
if (m && m[3] && state === 'buffering') {
throw `Missing block separator for line ${beginningLineno}`;
}
if (m != null ? m[3].match(new RegExp(escapeRegExp(marker))) : void 0) { //if inline, drop it
m = null;
}
D(opt, "block:match:" + JSON.stringify(m));
if (m && m[3] && m[2] === '') {
m[2] = '=';
}
if ((m != null ? m[2] : void 0) === '=' && !tags.hasOwnProperty(m != null ? m[3] : void 0)) {
switch (unknownTag) {
case 'remove':
D(opt, `Removing uknown tag '${m[3]}'`);
m[2] = 'x';
break;
case 'show':
D(opt, `Showing uknown tag '${m[3]}'`);
m[2] = '|';
m[3] = 'cat';
break;
case 'bypass':
m = 0;
state = 'bypass';
break;
default:
throw `Unknown tag '${m[3]}' found on line ${lineno}.check argument or input syntax or use option about unknown tag. `;
}
}
switch (false) {
case !(m && state === 'bypass' && ((ref = m[2]) === '|' || ref === '=' || ref === 'x' || ref === '!')):
D(opt, `block:found beginnning marker at line ${lineno}`);
state = 'buffering';
commandLine = m[3];
if (m[2] === '=') {
commandLine = tags[m[3]];
}
if (m[2] === 'x') {
commandLine = '';
}
indent = m[1];
buffer = m[2] !== '!' ? '' : null;
beginningLineno = lineno;
D(opt, `block:command line:${commandLine}`);
D(opt, `block:current indent:[${indent}]`);
break;
case !(m && state === 'buffering'):
D(opt, `block:found end marker at line ${lineno}`);
state = 'bypass';
D(opt, `block:command:${(commandLine === '' ? 'REMOVE' : commandLine)}`);
D(opt, `block:indent:${indent.length}`);
if (buffer !== null) {
D(opt, `\n###\n${buffer}###`);
}
commandOutput = (yield runProcessWithInjection(commandLine, buffer, opt));
if (!commandOutput) {
continue;
}
commandOutput = commandOutput.replace(/\n$/m, "");
D(opt, `block:command output:\n###\n${commandOutput}\n###`);
if (indent.length > 0 && processIndent) {
commandOutput = commandOutput.replace(/^/mg, indent);
}
output += `${commandOutput}\n`;
break;
case !(!m && state === 'buffering'):
if (indent.length > 0 && processIndent) {
line = line.replace(new RegExp(`^${indent}`), '');
}
if (buffer !== null) {
buffer += `${line}\n`;
}
break;
default:
actualMarkerS = "@PARTPIPE@";
actualMarkerE = "@PARTPIPE@";
numEmarkerUsed = 0;
while (true) {
emarkerS = `@${Math.floor(Math.random() * 10000000)}@`;
emarkerE = `@${Math.floor(Math.random() * 10000000)}@`;
if (!(line.match(emarkerS || line.match(emarkerE)))) {
break;
}
}
while (true) {
//regex="(#{escapeRegExp(marker)})([!|=]?)([^;]+?)(;.*?)?(#{escapeRegExp(marker)})"
regex = `(${escapeRegExp(marker)})(.+?)(${escapeRegExp(marker)})`;
inlineRegexp = new RegExp(regex);
D(opt, "inline:input:" + line);
mi = line.match(inlineRegexp);
if (mi) {
D(opt, "inline:macth:" + JSON.stringify(mi));
actualMarkerS = mi[1];
actualMarkerE = mi[3];
regex2 = "([!|=]?)([^;]+);?(.*?)$";
mi = mi[2].match(regex2);
D(opt, "inline:2nd macth:" + JSON.stringify(mi));
if ((mi != null ? mi[1] : void 0) === '') {
mi[1] = '=';
}
mi[3] = (ref1 = (ref2 = mi[3]) != null ? ref2.replace(/^/, '') : void 0) != null ? ref1 : '';
if ((mi != null ? mi[1] : void 0) === '=' && !tags.hasOwnProperty(mi[2])) {
D(opt, `found inline marker at line ${lineno}`);
D(opt, `match:${JSON.stringify(mi)}`);
switch (unknownTag) {
case 'remove':
D(opt, `Removing uknown tag '${mi[2]}'`);
line = line.replace(inlineRegexp, "");
break;
case 'show':
D(opt, `Showing uknown tag '${mi[2]}'`);
line = line.replace(inlineRegexp, `${mi[3]}`);
break;
case 'bypass':
D(opt, `replacing remaining of line with internal maker '${emarkerS}' '${emarkerE}'`);
line = line.replace(inlineRegexp, `${emarkerS}${mi[1]}${mi[2]};${(ref3 = mi[3]) != null ? ref3 : ''}${emarkerE}`);
numEmarkerUsed++;
break;
default:
throw `Unknown tag '${mi[2]}' found on line ${lineno}.check argument or input syntax or use option about unknown tag. `;
}
continue;
}
commandLine = mi[2];
if (mi[1] === '=') {
commandLine = tags[mi[2]];
}
buffer = mi[1] !== '!' ? mi[3] : null;
D(opt, `inline:command:${commandLine}`);
D(opt, `inline:buffer:${buffer}`);
commandOutput = (yield runProcessWithInjection(commandLine, buffer, opt));
commandOutput = commandOutput != null ? commandOutput : '';
D(opt, `inline:command output:${commandOutput != null ? typeof commandOutput.trim === "function" ? commandOutput.trim() : void 0 : void 0}`);
line = line.replace(inlineRegexp, commandOutput.replace(/\n$/, ''));
} else {
break;
}
}
if (numEmarkerUsed > 0) {
D(opt, `restoring internal markers to actual marker, '${emarkerS}','${emarkerE}'->'${actualMarkerS}','${actualMarkerE}'`);
D(opt, `before:${line}`);
line = line.replace(new RegExp(escapeRegExp(emarkerS), 'g'), actualMarkerS);
line = line.replace(new RegExp(escapeRegExp(emarkerE), 'g'), actualMarkerE);
D(opt, `after:${line}`);
}
output += `${line}\n`;
}
}
if (state === 'buffering') {
throw `Missing block separator for line ${beginningLineno}`;
}
D(opt, "===partpipe process finished");
return output;
});
};
module.exports = partpipe;