sniper
Version:
Renders snippets on demand
144 lines (130 loc) • 4.31 kB
JavaScript
var fs = require('fs');
var path = require('path');
var join = path.join;
var swig = require('swig');
var Minilog = require('minilog');
var log = Minilog("sniper");
var helper = require("biojs-util-snippets").helper;
module.exports = function(opts) {
this.opts = opts;
var self = this;
var rootURL = opts.rootURL;
// adds an optional slash to relative paths
this.makeAbsolute = function(path) {
var firstChar = path.charAt(0);
// check whether it is http or https
if (path.indexOf(":") >= 0) {
return path;
}
// defined path
if (firstChar === "/") {
return rootURL + path.slice(1);
} else if (firstChar === ".") {
return path.slice(1);
}
return rootURL + path;
};
// removes the extension and filters duplicates
this.getSnippets = function() {
var snips = fs.readdirSync(self.opts.snippetFolder);
var snipsFiltered = [];
snips.forEach(function(entry) {
var file = entry.split(".")[0];
if (snipsFiltered.indexOf(file) < 0) {
snipsFiltered.push(file);
}
});
return snipsFiltered;
};
// merges non-duplicate entries of an array (remote)
// into a array (origin)
this.mergeStuff = function(origin, remote) {
if (remote !== undefined && origin !== undefined) {
remote.forEach(function(entry) {
// no duplicates
if (origin.indexOf(entry) < 0) {
origin.push(entry);
}
});
}
};
// parses and add a special config for each snippet
this.addJSON = function(name, parsedD) {
var parsedConfig = JSON.parse(fs.readFileSync(name, 'utf8'));
this.mergeStuff(parsedD.js, parsedConfig.js);
this.mergeStuff(parsedD.css, parsedConfig.css);
};
// displays the script tags
this.renderHead = function(snipTemplate, parsedD) {
var template = swig.compileFile(snipTemplate);
var css = {};
if (parsedD.css) {
css = parsedD.css.map(self.makeAbsolute);
}
var js = parsedD.js.map(self.makeAbsolute);
var head = template({
css: css,
scripts: js,
});
return head;
};
// warn the user that script and link tags are bad
function checkHTML(content) {
var tags = ["script", "body", "link", "html"];
var errors = [];
tags.forEach(function(tag) {
if (content.indexOf("<" + tag) >= 0) {
errors.push("Please do not include <" + tag + "> tags in your html - use the .js file. Pleast list your dependencies in the package.json");
}
});
var head = "<div style='background-color: rgba(240,0,0,0.7); margin-bottom: 10px;'><b>Warning</b>: ";
var foot = "</div>";
var errorMSG = errors.map(function(err) {
log.warn(err);
return head + err + foot;
});
return errorMSG.join("");
}
// builds the snippet html
// - reads the js & html (same name)
// - searches for a extra config file (same name.json)
this.buildSnippet = function(name, parsedD) {
var jsFile = join(self.opts.snippetFolder, name + ".js");
var extraFile = join(self.opts.snippetFolder, name + ".json");
var buffer = "";
if (fs.existsSync(extraFile)) {
log.info("found extra config: " + extraFile);
this.addJSON(extraFile, parsedD);
}
if (fs.existsSync(jsFile)) {
var htmlFile = join(self.opts.snippetFolder, name + ".html");
var htmlExists = fs.existsSync(htmlFile);
var divName;
if (htmlExists) {
var htmlContent = fs.readFileSync(htmlFile, "utf8");
buffer += checkHTML(htmlContent);
buffer += htmlContent;
} else {
// insert auto div
divName = Math.random().toString(36).substring(7);
buffer += "<div id='" + divName + "'></div>";
}
buffer += ("<script>");
var jsContent = fs.readFileSync(jsFile, 'utf8');
if (!htmlExists) {
buffer += "(function(){\n";
var mainVar = helper.findMainVar(jsContent);
log.debug("selected main var: " + mainVar);
buffer += "var " + mainVar + " = document.getElementById('" + divName + "');\n";
}
buffer += jsContent;
if (!htmlExists) {
buffer += "})();";
}
buffer += "</script>";
} else {
buffer += "Please make sure you add .html and .js for " + name;
}
return buffer;
};
};