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
|
2019-10-06 20:04:33 +00:00
|
|
|
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
|
2019-10-06 20:04:33 +00:00
|
|
|
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
|
|
|
};
|
2019-10-06 20:04:33 +00:00
|
|
|
const shortHand = {
|
|
|
|
|
n: ["--namespace"],
|
|
|
|
|
o: ["--outputdir"],
|
|
|
|
|
vn: ["--variable"],
|
|
|
|
|
w: ["--wrapper"],
|
|
|
|
|
h: ["--help"],
|
|
|
|
|
v: ["--version"]
|
2016-04-16 11:06:03 +00:00
|
|
|
};
|
2019-10-06 20:04:33 +00:00
|
|
|
let templates;
|
2016-04-16 11:06:03 +00:00
|
|
|
|
|
|
|
|
// options
|
|
|
|
|
options = nopt(options, shortHand);
|
|
|
|
|
|
|
|
|
|
// escape special regexp characters
|
|
|
|
|
function esc(text) {
|
2019-10-06 20:04:33 +00:00
|
|
|
return text.replace(specialsRegExp, "\\$1");
|
2016-04-16 11:06:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// cyan function for rob
|
|
|
|
|
function cyan(text) {
|
2019-10-06 20:04:33 +00:00
|
|
|
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) {
|
2019-10-06 20:04:33 +00:00
|
|
|
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) {
|
2019-10-06 20:04:33 +00:00
|
|
|
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)) {
|
2019-10-06 20:04:33 +00:00
|
|
|
arg = arg.split("*");
|
2016-08-27 11:46:22 +00:00
|
|
|
files = files.concat(
|
2019-10-06 20:04:33 +00:00
|
|
|
fs
|
|
|
|
|
.readdirSync(arg[0] || ".")
|
2016-04-16 11:06:03 +00:00
|
|
|
.map(function(f) {
|
2019-10-06 20:04:33 +00:00
|
|
|
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) {
|
2019-10-06 20:04:33 +00:00
|
|
|
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(' +
|
2019-10-06 20:04:33 +00:00
|
|
|
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) {
|
2019-10-06 20:04:33 +00:00
|
|
|
nodeOutput = nodeOutput + "\n" + "module.exports = " + globalObj + ";";
|
2016-04-16 11:06:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nodeOutput;
|
|
|
|
|
default:
|
2019-10-06 20:04:33 +00:00
|
|
|
return (
|
|
|
|
|
(options.variable || "templates") +
|
|
|
|
|
'["' +
|
|
|
|
|
name +
|
|
|
|
|
'"] = new Hogan.Template(' +
|
|
|
|
|
hogan.compile(openedFile, { asString: 1 }) +
|
|
|
|
|
");"
|
|
|
|
|
);
|
2016-04-16 11:06:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function prepareOutput(content) {
|
2019-10-06 20:04:33 +00:00
|
|
|
const variableName = options.variable || "templates";
|
2016-04-16 11:06:03 +00:00
|
|
|
switch (options.wrapper) {
|
2019-10-06 20:04:33 +00:00
|
|
|
case "amd":
|
2016-04-16 11:06:03 +00:00
|
|
|
return content;
|
2019-10-06 20:04:33 +00:00
|
|
|
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) {
|
2019-10-06 20:04:33 +00:00
|
|
|
nodeExport = "module.exports = global." + variableName + ";\n";
|
2016-04-16 11:06:03 +00:00
|
|
|
}
|
|
|
|
|
|
2019-10-06 20:04:33 +00:00
|
|
|
return (
|
|
|
|
|
"(function() {\n" +
|
|
|
|
|
"if (!!!global." +
|
|
|
|
|
variableName +
|
|
|
|
|
") global." +
|
|
|
|
|
variableName +
|
|
|
|
|
" = {};\n" +
|
2016-04-25 14:45:47 +00:00
|
|
|
'var Hogan = require("hogan.js");' +
|
2019-10-06 20:04:33 +00:00
|
|
|
content +
|
|
|
|
|
"\n" +
|
2016-04-16 11:06:03 +00:00
|
|
|
nodeExport +
|
2019-10-06 20:04:33 +00:00
|
|
|
"})();"
|
|
|
|
|
);
|
2016-04-16 11:06:03 +00:00
|
|
|
default:
|
2019-10-06 20:04:33 +00:00
|
|
|
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) {
|
2019-10-06 20:04:33 +00:00
|
|
|
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) {
|
2019-10-06 20:04:33 +00:00
|
|
|
let openedFile = fs.readFileSync(file, "utf-8").trim();
|
|
|
|
|
let name;
|
2016-04-16 11:06:03 +00:00
|
|
|
if (!openedFile) return;
|
2019-10-06 20:04:33 +00:00
|
|
|
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;
|
2019-10-06 20:04:33 +00:00
|
|
|
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);
|
|
|
|
|
|
2019-10-06 20:04:33 +00:00
|
|
|
console.log(prepareOutput(templates.join("\n")));
|