markugen
Version:
Markdown to HTML/PDF static site generation tool
100 lines (99 loc) • 3.51 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Preprocessor = void 0;
const fs_extra_1 = __importDefault(require("fs-extra"));
const node_path_1 = __importDefault(require("node:path"));
const node_os_1 = __importDefault(require("node:os"));
const colors_1 = __importDefault(require("colors"));
const markugen_1 = __importDefault(require("./markugen"));
class Preprocessor {
/**
* The regular expression used to find the templates
*/
regex = /\{\{([^{].*?[^\\])\}\}/gs;
/**
* The regular expression used to filter the js code
*/
filter = /(\\\}\})|(process\s*.\s*exit\s*\(.*?\))|(import\s*\(.*?\))/gs;
/**
* Instance of the generator
*/
generator;
/**
* Variables to define before template expansion
*/
vars;
/**
* Constructs a new preprocessor with the given variables
*/
constructor(generator) {
this.generator = generator;
this.vars = structuredClone(generator.options.vars);
this.vars['markugen'] = markugen_1.default.toObject(generator.options.timestamp ? new Date() : undefined);
}
/**
* Expands the given string by replacing template parameters
* @param input the string to expand
* @param file file being expanded if given one
* @returns input expanded and template vars replaced
*/
process(input, file) {
if (!input)
return input;
// copy the string so as to not modify the original
let out = '';
let match, lastIndex = 0;
while ((match = this.regex.exec(input)) !== null) {
const last = lastIndex;
lastIndex = this.regex.lastIndex;
// check for an escaped template expansion
if (match.index && input[match.index - 1] === '\\') {
out += input.slice(last, match.index - 1) + match[0];
continue;
}
out += input.slice(last, match.index);
// if the expression is empty
const code = match[1];
if (code.trim() === '')
continue;
const result = this.safeFunction(code, file);
if (result != undefined)
out += result.toString();
}
if (lastIndex < input.length)
out += input.slice(lastIndex);
return out;
}
/**
*
* @param code the code to execute
* @param file file being expanded if given one
* @returns whatever is returned from the code call
*/
safeFunction(code, file) {
const filtered = code.replace(this.filter, (match, p1) => {
if (p1)
return '}}';
return '';
});
const safe = `'use strict';\n${filtered}`;
const utils = {
fs: fs_extra_1.default,
path: node_path_1.default,
os: node_os_1.default,
};
try {
const func = Function('vars', 'utils', safe);
const result = func(this.vars, utils);
return result;
}
catch (e) {
this.generator.warning(`Preprocesser failed when expanding ${colors_1.default.yellow(`{{${filtered}}}`)} ` +
colors_1.default.red(`[${e.message}` + (file ? ` in ${file}]` : ']')));
}
}
}
exports.Preprocessor = Preprocessor;