mini-preproc
Version:
A simple, light, and fast text preprocessor implemented as a node transform stream.
132 lines • 4.46 kB
JavaScript
// copyright 2020, craigphicks, ISC license
'use strict';
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createPreprocStream = void 0;
const stream_1 = __importDefault(require("stream"));
class MiniPreprocError extends Error {
constructor(msg) {
super("MiniPreprocError: " + msg);
}
}
//const stream = require('stream');
class State {
constructor(defs, opts = { strip: false }) {
this.defs = { ...defs };
this.opts = { ...opts };
this.done = false;
this.ifActive = false;
this.ifTrue = false;
}
isDone() { return this.done; }
doLine(linein) {
let isCmd = false;
let isPrefix = false;
if (linein.substring(0, 4) !== "//--") {
// no change in state
}
else {
isPrefix = true;
if (linein.substring(4, 6) === "IF") {
if (this.ifActive)
throw new MiniPreprocError('unexpected IF');
this.ifActive = true;
let re = /\{\{\s*(\D\w+)\s*\}\}/.exec(linein.substring(6));
if (!re || re.length < 2)
throw new MiniPreprocError(`invalid format "${linein.substring(4)}"`);
this.ifTrue = Object.keys(this.defs).includes(re[1])
&& this.defs[re[1]];
isCmd = true;
}
else if (linein.substring(4, 8) === "ELSE") {
if (!this.ifActive)
throw new MiniPreprocError('unexpected ELSE');
this.ifTrue = !this.ifTrue;
isCmd = true;
}
else if (linein.substring(4, 9) === "ENDIF") {
if (!this.ifActive)
throw new MiniPreprocError('unexpected ENDIF');
this.ifActive = false;
isCmd = true;
}
else if (linein.substring(4, 8) === "STOP") {
if (this.ifActive)
throw new MiniPreprocError('ENDIF required before STOP');
isCmd = true;
this.done = true;
}
}
if (isCmd)
return (this.opts.strip ? null : linein);
if (!this.ifActive)
return linein;
if (!this.ifTrue) {
if (this.opts.strip)
return null;
return isPrefix ? linein : '//--' + linein;
}
return isPrefix ? linein.substring(4) : linein;
} // do line
}
class MiniPreprocTransform extends stream_1.default.Transform {
constructor(defs, opts) {
super();
this._state = new State(defs, opts);
this._leftover = '';
}
_transform(chunk, _enc, callback) {
try {
if (this._state.isDone()) {
if (this._leftover) {
this.push(this._leftover);
this._leftover = '';
}
this.push(chunk);
callback();
return;
}
let str = chunk.toString();
if (this._leftover)
str = this._leftover + str;
let lines = str.split('\n');
this._leftover = lines.splice(-1, 1)[0];
lines.forEach((line) => {
if (this._state.isDone()) {
this.push(line + '\n');
return; // from iter of forEach
}
let out = this._state.doLine(line);
if (out === null)
return; // from iter of forEach
if (!Array.isArray(out)) {
this.push(out + '\n');
return; // from iter of forEach
}
out.forEach((x) => {
this.push(x + '\n');
});
});
callback();
}
catch (e) {
callback(e);
//this.emit("error",e);
}
}
;
_flush(callback) {
if (this._leftover)
this.push(this._leftover);
this._leftover = '';
callback();
}
;
}
function createPreprocStream(defs, opts) {
return new MiniPreprocTransform(defs, opts);
}
exports.createPreprocStream = createPreprocStream;
//# sourceMappingURL=mini-preproc.js.map