diff2html/scripts/hulk.js

213 lines
5.9 KiB
JavaScript
Raw Normal View History

2016-04-16 11:06:03 +00:00
#!/usr/bin/env node
/*
* Copyright 2011 Twitter, Inc.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// dependencies
const path = require("path");
const fs = require("fs");
const hogan = require("hogan.js");
const nopt = require("nopt");
const mkderp = require("mkdirp");
2016-04-16 11:06:03 +00:00
// locals
const specials = ["/", ".", "*", "+", "?", "|", "(", ")", "[", "]", "{", "}", "\\"];
const specialsRegExp = new RegExp("(\\" + specials.join("|\\") + ")", "g");
let options = {
namespace: String,
outputdir: path,
variable: String,
wrapper: String,
version: true,
help: true
2016-04-16 11:06:03 +00:00
};
const shortHand = {
n: ["--namespace"],
o: ["--outputdir"],
vn: ["--variable"],
w: ["--wrapper"],
h: ["--help"],
v: ["--version"]
2016-04-16 11:06:03 +00:00
};
let templates;
2016-04-16 11:06:03 +00:00
// options
options = nopt(options, shortHand);
// escape special regexp characters
function esc(text) {
return text.replace(specialsRegExp, "\\$1");
2016-04-16 11:06:03 +00:00
}
// cyan function for rob
function cyan(text) {
return "\x1B[36m" + text + "\x1B[39m";
2016-04-16 11:06:03 +00:00
}
// check for dirs and correct ext (<3 for windows)
function extractFiles(args) {
const usage =
"\n" +
cyan("USAGE:") +
" hulk [--wrapper wrapper] [--outputdir outputdir] " +
"[--namespace namespace] [--variable variable] FILES\n\n" +
cyan("OPTIONS:") +
" [-w, --wrapper] :: wraps the template (i.e. amd)\n" +
" [-o, --outputdir] :: outputs the templates as individual files to a directory\n\n" +
" [-n, --namespace] :: prepend string to template names\n\n" +
" [-vn, --variable] :: variable name for non-amd wrapper\n\n" +
cyan("EXAMPLE:") +
" hulk --wrapper amd ./templates/*.mustache\n\n" +
cyan("NOTE:") +
' hulk supports the "*" wildcard and allows you to target specific extensions too\n';
let files = [];
2016-04-16 11:06:03 +00:00
if (options.version) {
console.log(require("../package.json").version);
2016-04-16 11:06:03 +00:00
process.exit(0);
}
if (!args.length || options.help) {
console.log(usage);
process.exit(0);
}
args.forEach(function(arg) {
if (/\*/.test(arg)) {
arg = arg.split("*");
2016-08-27 11:46:22 +00:00
files = files.concat(
fs
.readdirSync(arg[0] || ".")
2016-04-16 11:06:03 +00:00
.map(function(f) {
const file = path.join(arg[0], f);
return new RegExp(esc(arg[1]) + "$").test(f) && fs.statSync(file).isFile() && file;
2016-04-16 11:06:03 +00:00
})
.filter(function(f) {
return f;
})
);
2016-08-27 11:46:22 +00:00
return files;
2016-04-16 11:06:03 +00:00
}
if (fs.statSync(arg).isFile()) files.push(arg);
});
return files;
}
// remove utf-8 byte order mark, http://en.wikipedia.org/wiki/Byte_order_mark
function removeByteOrderMark(text) {
if (text.charCodeAt(0) === 0xfeff) {
return text.substring(1);
}
return text;
}
// wrap templates
function wrap(file, name, openedFile) {
switch (options.wrapper) {
case "amd":
return (
"define(" +
(!options.outputdir ? '"' + path.join(path.dirname(file), name) + '", ' : "") +
2016-04-16 11:06:03 +00:00
'[ "hogan.js" ], function(Hogan){ return new Hogan.Template(' +
hogan.compile(openedFile, { asString: 1 }) +
");});"
);
case "node":
var globalObj = "global." + (options.variable || "templates") + '["' + name + '"]';
var globalStmt = globalObj + " = new Hogan.Template(" + hogan.compile(openedFile, { asString: 1 }) + ");";
2016-04-16 11:06:03 +00:00
var nodeOutput = globalStmt;
// if we have a template per file the export will expose the template directly
if (options.outputdir) {
nodeOutput = nodeOutput + "\n" + "module.exports = " + globalObj + ";";
2016-04-16 11:06:03 +00:00
}
return nodeOutput;
default:
return (
(options.variable || "templates") +
'["' +
name +
'"] = new Hogan.Template(' +
hogan.compile(openedFile, { asString: 1 }) +
");"
);
2016-04-16 11:06:03 +00:00
}
}
function prepareOutput(content) {
const variableName = options.variable || "templates";
2016-04-16 11:06:03 +00:00
switch (options.wrapper) {
case "amd":
2016-04-16 11:06:03 +00:00
return content;
case "node":
var nodeExport = "";
2016-04-16 11:06:03 +00:00
// if we have aggregated templates the export will expose the template map
if (!options.outputdir) {
nodeExport = "module.exports = global." + variableName + ";\n";
2016-04-16 11:06:03 +00:00
}
return (
"(function() {\n" +
"if (!!!global." +
variableName +
") global." +
variableName +
" = {};\n" +
2016-04-25 14:45:47 +00:00
'var Hogan = require("hogan.js");' +
content +
"\n" +
2016-04-16 11:06:03 +00:00
nodeExport +
"})();"
);
2016-04-16 11:06:03 +00:00
default:
return "if (!!!" + variableName + ") var " + variableName + " = {};\n" + content;
2016-04-16 11:06:03 +00:00
}
}
// write the directory
if (options.outputdir) {
mkderp.sync(options.outputdir);
}
// Prepend namespace to template name
function namespace(name) {
return (options.namespace || "") + name;
2016-04-16 11:06:03 +00:00
}
// write a template foreach file that matches template extension
templates = extractFiles(options.argv.remain)
.map(function(file) {
let openedFile = fs.readFileSync(file, "utf-8").trim();
let name;
2016-04-16 11:06:03 +00:00
if (!openedFile) return;
name = namespace(path.basename(file).replace(/\..*$/, ""));
2016-10-09 15:41:54 +00:00
openedFile = removeByteOrderMark(openedFile);
2016-04-16 11:06:03 +00:00
openedFile = wrap(file, name, openedFile);
if (!options.outputdir) return openedFile;
fs.writeFileSync(path.join(options.outputdir, name + ".js"), prepareOutput(openedFile));
2016-04-16 11:06:03 +00:00
})
.filter(function(t) {
return t;
});
// output templates
if (!templates.length || options.outputdir) process.exit(0);
console.log(prepareOutput(templates.join("\n")));