Use pre-compiled templates in node

This commit is contained in:
Rodrigo Fernandes 2016-04-16 12:06:03 +01:00
parent 05a09ae2a7
commit b1f1ba6008
No known key found for this signature in database
GPG key ID: 08E3C5F38969078E
12 changed files with 263 additions and 30 deletions

3
.gitignore vendored
View file

@ -19,5 +19,8 @@ target/
node_modules/
npm-debug.log
# Istanbul
coverage/
# Bower
bower_components/

View file

@ -21,9 +21,7 @@
"disallowTrailingWhitespace": true,
"maximumLineLength": 130,
"requireCamelCaseOrUpperCaseIdentifiers": true,
"requireCapitalizedComments": true,
"requireCapitalizedConstructors": true,
"requireCurlyBraces": true,
"requireSpaceAfterKeywords": [
"if",
"else",

View file

@ -5,6 +5,5 @@ test:
- nvm install 5 && npm test
post:
- npm install
- istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec
- npm test
- cat ./coverage/lcov.info | ./node_modules/.bin/codacy-coverage
- rm -rf ./coverage

View file

@ -32,14 +32,15 @@
"url": "https://www.github.com/rtfpessoa/diff2html/issues"
},
"engines": {
"node": ">=0.10"
"node": ">=0.12"
},
"preferGlobal": true,
"scripts": {
"release": "bash release.sh",
"test": "mocha",
"release": "./scripts/release.sh",
"templates": "./scripts/hulk.js --wrapper node --variable 'browserTemplates' ./src/templates/*.mustache > ./src/templates/diff2html-templates.js",
"test": "istanbul cover _mocha --report lcovonly -- -u exports -R spec ./test/**/*",
"style": "jscs src test",
"codacy": "istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/.bin/codacy-coverage && rm -rf ./coverage"
"codacy": "istanbul cover _mocha --report lcovonly -- -u exports -R spec ./test/**/* && cat ./coverage/lcov.info | codacy-coverage"
},
"main": "./src/diff2html.js",
"browser": {
@ -56,7 +57,9 @@
"fast-html-parser": "^1.0.1",
"istanbul": "^0.4.2",
"jscs": "^2.11.0",
"mkdirp": "^0.5.1",
"mocha": "^2.4.5",
"nopt": "^3.0.6",
"uglifyjs": "^2.4.10"
},
"license": "MIT",

0
scripts/.ignore Normal file
View file

206
scripts/hulk.js Executable file
View file

@ -0,0 +1,206 @@
#!/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
var hogan = require('hogan.js');
var path = require('path');
var nopt = require('nopt');
var mkderp = require('mkdirp');
var fs = require('fs');
// locals
var specials = ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\'];
var specialsRegExp = new RegExp('(\\' + specials.join('|\\') + ')', 'g');
var options = {
'namespace': String,
'outputdir': path,
'variable': String,
'wrapper': String,
'version': true,
'help': true
};
var shortHand = {
'n': ['--namespace'],
'o': ['--outputdir'],
'vn': ['--variable'],
'w': ['--wrapper'],
'h': ['--help'],
'v': ['--version']
};
var templates;
// options
options = nopt(options, shortHand);
// escape special regexp characters
function esc(text) {
return text.replace(specialsRegExp, '\\$1');
}
// cyan function for rob
function cyan(text) {
return '\033[36m' + text + '\033[39m';
}
// check for dirs and correct ext (<3 for windows)
function extractFiles(args) {
var 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';
var files = [];
if (options.version) {
console.log(require('../package.json').version);
process.exit(0);
}
if (!args.length || options.help) {
console.log(usage);
process.exit(0);
}
args.forEach(function(arg) {
if (/\*/.test(arg)) {
arg = arg.split('*');
return files = files.concat(
fs.readdirSync(arg[0] || '.')
.map(function(f) {
var file = path.join(arg[0], f);
return new RegExp(esc(arg[1]) + '$').test(f) && fs.statSync(file).isFile() && file;
})
.filter(function(f) {
return f;
})
);
}
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) + '", ' : '') +
'[ "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}) + ');';
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 + ';';
}
return nodeOutput;
default:
return (options.variable || 'templates') +
'["' + name + '"] = new Hogan.Template(' +
hogan.compile(openedFile, {asString: 1}) +
');';
}
}
function prepareOutput(content) {
var variableName = options.variable || 'templates';
switch (options.wrapper) {
case "amd":
return content;
case "node":
var nodeExport = '';
// if we have aggregated templates the export will expose the template map
if (!options.outputdir) {
nodeExport = 'module.exports = global.' + variableName + ';\n';
}
return '(function() {\n' +
'if (!!!global.' + variableName + ') global.' + variableName + ' = {};\n' +
content + '\n' +
nodeExport +
'})();';
default:
return 'if (!!!' + variableName + ') var ' + variableName + ' = {};\n' + content;
}
}
// write the directory
if (options.outputdir) {
mkderp.sync(options.outputdir);
}
// Prepend namespace to template name
function namespace(name) {
return (options.namespace || '') + name;
}
// write a template foreach file that matches template extension
templates = extractFiles(options.argv.remain)
.map(function(file) {
var openedFile = fs.readFileSync(file, 'utf-8');
var name;
if (!openedFile) return;
name = namespace(path.basename(file).replace(/\..*$/, ''));
openedFile = removeByteOrderMark(openedFile.trim());
openedFile = wrap(file, name, openedFile);
if (!options.outputdir) return openedFile;
fs.writeFileSync(path.join(options.outputdir, name + '.js')
, prepareOutput(openedFile));
})
.filter(function(t) {
return t;
});
// output templates
if (!templates.length || options.outputdir) process.exit(0);
console.log(prepareOutput(templates.join('\n')));

View file

@ -14,6 +14,8 @@ INPUT_JS_FILE=${INPUT_DIR}/diff2html.js
INPUT_JS_UI_FILE=${INPUT_UI_DIR}/js/diff2html-ui.js
INPUT_CSS_FILE=${INPUT_UI_DIR}/css/diff2html.css
GENERATED_TEMPLATES_FILE=${INTPUT_TEMPLATES_DIR}/diff2html-templates.js
OUTPUT_DIR=dist
OUTPUT_JS_FILE=${OUTPUT_DIR}/diff2html.js
OUTPUT_MIN_JS_FILE=${OUTPUT_DIR}/diff2html.min.js
@ -30,16 +32,15 @@ echo "Cleaning previous versions ..."
rm -rf ${OUTPUT_DIR}
mkdir -p ${OUTPUT_DIR}
echo "Copying css file to ${OUTPUT_CSS_FILE}"
cp -f ${INPUT_CSS_FILE} ${OUTPUT_CSS_FILE}
echo "Minifying ${OUTPUT_CSS_FILE} to ${OUTPUT_MIN_CSS_FILE}"
cp -f ${INPUT_CSS_FILE} ${OUTPUT_CSS_FILE}
cleancss --advanced --compatibility=ie8 -o ${OUTPUT_MIN_CSS_FILE} ${OUTPUT_CSS_FILE}
echo "Pre-compile hogan.js templates in ${INTPUT_TEMPLATES_DIR}"
hulk --variable "browserTemplates" ${INTPUT_TEMPLATES_DIR}/*.mustache > ${OUTPUT_TEMPLATES_FILE}
echo "Pre-compile hogan.js templates"
npm run templates
echo "Minifying ${OUTPUT_TEMPLATES_FILE} to ${OUTPUT_MIN_TEMPLATES_FILE}"
browserify -e ${GENERATED_TEMPLATES_FILE} -o ${OUTPUT_TEMPLATES_FILE}
uglifyjs ${OUTPUT_TEMPLATES_FILE} -c -o ${OUTPUT_MIN_TEMPLATES_FILE}
echo "Generating js aggregation file in ${OUTPUT_JS_FILE}"

View file

@ -12,10 +12,17 @@
var hogan = require('hogan.js');
var hoganTemplates;
var templatesPath = path.resolve(__dirname, 'templates');
var templatesCache = {};
function HoganJsUtils() {
try {
hoganTemplates = require('./templates/diff2html-templates.js');
} catch (_ignore) {
hoganTemplates = {};
}
}
HoganJsUtils.prototype.render = function(namespace, view, params) {
@ -32,22 +39,29 @@
HoganJsUtils.prototype._getTemplate = function(templateKey) {
var template = this._readFromCache(templateKey);
if (!template && fs) {
var templatePath = path.join(templatesPath, templateKey);
var templateContent = fs.readFileSync(templatePath + '.mustache', 'utf8');
template = hogan.compile(templateContent);
this._addToCache(templateKey, template);
if (!template) {
template = this._loadTemplate(templateKey);
}
return template;
};
HoganJsUtils.prototype._addToCache = function(templateKey, template) {
templatesCache[templateKey] = template;
HoganJsUtils.prototype._loadTemplate = function(templateKey) {
var template;
if (fs.readFileSync) {
var templatePath = path.join(templatesPath, templateKey);
var templateContent = fs.readFileSync(templatePath + '.mustache', 'utf8');
template = hogan.compile(templateContent);
templatesCache[templateKey] = template;
}
return template;
};
HoganJsUtils.prototype._readFromCache = function(templateKey) {
return global.browserTemplates && global.browserTemplates[templateKey] || templatesCache[templateKey];
return global.browserTemplates && global.browserTemplates[templateKey] ||
hoganTemplates[templateKey] ||
templatesCache[templateKey];
};
HoganJsUtils.prototype._templateKey = function(namespace, view) {

View file

@ -39,8 +39,8 @@
var oldFilename = file.oldName;
var newFilename = file.newName;
if (oldFilename && newFilename && oldFilename !== newFilename
&& !isDevNullName(oldFilename) && !isDevNullName(newFilename)) {
if (oldFilename && newFilename && oldFilename !== newFilename &&
!isDevNullName(oldFilename) && !isDevNullName(newFilename)) {
return oldFilename + ' -> ' + newFilename;
} else if (newFilename && !isDevNullName(newFilename)) {
return newFilename;

View file

@ -0,0 +1,9 @@
(function() {
if (!!!global.browserTemplates) global.browserTemplates = {};
global.browserTemplates["line-by-line-column-line-number"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<tr>");t.b("\n" + i);t.b(" <td class=\"d2h-code-linenumber ");t.b(t.v(t.d("diffParser.LINE_TYPE.INFO",c,p,0)));t.b("\"></td>");t.b("\n" + i);t.b(" <td class=\"");t.b(t.v(t.d("diffParser.LINE_TYPE.INFO",c,p,0)));t.b("\">");t.b("\n" + i);t.b(" <div class=\"d2h-code-line ");t.b(t.v(t.d("diffParser.LINE_TYPE.INFO",c,p,0)));t.b("\">");t.b(t.t(t.f("blockHeader",c,p,0)));t.b("</div>");t.b("\n" + i);t.b(" </td>");t.b("\n" + i);t.b("</tr>");return t.fl(); },partials: {}, subs: { }});
global.browserTemplates["line-by-line-empty-diff"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<tr>");t.b("\n" + i);t.b(" <td class=\"");t.b(t.v(t.d("diffParser.LINE_TYPE.INFO",c,p,0)));t.b("\">");t.b("\n" + i);t.b(" <div class=\"d2h-code-line ");t.b(t.v(t.d("diffParser.LINE_TYPE.INFO",c,p,0)));t.b("\">");t.b("\n" + i);t.b(" File without changes");t.b("\n" + i);t.b(" </div>");t.b("\n" + i);t.b(" </td>");t.b("\n" + i);t.b("</tr>");return t.fl(); },partials: {}, subs: { }});
global.browserTemplates["line-by-line-file-diff"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<div id=\"");t.b(t.v(t.f("fileHtmlId",c,p,0)));t.b("\" class=\"d2h-file-wrapper\" data-lang=\"");t.b(t.v(t.d("file.language",c,p,0)));t.b("\">");t.b("\n" + i);t.b(" <div class=\"d2h-file-header\">");t.b("\n" + i);t.b(" <span class=\"d2h-file-stats\">");t.b("\n" + i);t.b(" <span class=\"d2h-lines-added\">");t.b("\n" + i);t.b(" <span>+");t.b(t.v(t.d("file.addedLines",c,p,0)));t.b("</span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b(" <span class=\"d2h-lines-deleted\">");t.b("\n" + i);t.b(" <span>-");t.b(t.v(t.d("file.deletedLines",c,p,0)));t.b("</span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b(" <span class=\"d2h-file-name-wrapper\">");t.b("\n" + i);t.b(" <span class=\"d2h-file-name\">&nbsp;");t.b(t.v(t.f("fileDiffName",c,p,0)));t.b("</span>");t.b("\n" + i);t.b(" </span>");t.b("\n" + i);t.b(" </div>");t.b("\n" + i);t.b(" <div class=\"d2h-file-diff\">");t.b("\n" + i);t.b(" <div class=\"d2h-code-wrapper\">");t.b("\n" + i);t.b(" <table class=\"d2h-diff-table\">");t.b("\n" + i);t.b(" <tbody class=\"d2h-diff-tbody\">");t.b("\n" + i);t.b(" ");t.b(t.t(t.f("diffs",c,p,0)));t.b("\n" + i);t.b(" </tbody>");t.b("\n" + i);t.b(" </table>");t.b("\n" + i);t.b(" </div>");t.b("\n" + i);t.b(" </div>");t.b("\n" + i);t.b("</div>");return t.fl(); },partials: {}, subs: { }});
global.browserTemplates["line-by-line-line"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<tr>");t.b("\n" + i);t.b(" <td class=\"d2h-code-linenumber ");t.b(t.v(t.f("type",c,p,0)));t.b("\">");t.b("\n" + i);t.b(" <div class=\"line-num1\">");t.b(t.v(t.f("oldNumber",c,p,0)));t.b("</div>");t.b("\n" + i);t.b(" <div class=\"line-num2\">");t.b(t.v(t.f("newNumber",c,p,0)));t.b("</div>");t.b("\n" + i);t.b(" </td>");t.b("\n" + i);t.b(" <td class=\"");t.b(t.v(t.f("type",c,p,0)));t.b("\">");t.b("\n" + i);t.b(" <div class=\"d2h-code-line ");t.b(t.v(t.f("type",c,p,0)));t.b("\">");t.b("\n" + i);if(t.s(t.f("prefix",c,p,1),c,p,0,253,329,"{{ }}")){t.rs(c,p,function(c,p,t){t.b(" <span class=\"d2h-code-line-prefix\">");t.b(t.t(t.f("prefix",c,p,0)));t.b("</span>");t.b("\n" + i);});c.pop();}if(t.s(t.f("content",c,p,1),c,p,0,361,435,"{{ }}")){t.rs(c,p,function(c,p,t){t.b(" <span class=\"d2h-code-line-ctn\">");t.b(t.t(t.f("content",c,p,0)));t.b("</span>");t.b("\n" + i);});c.pop();}t.b(" </div>");t.b("\n" + i);t.b(" </td>");t.b("\n" + i);t.b("</tr>");return t.fl(); },partials: {}, subs: { }});
global.browserTemplates["line-by-line-wrapper"] = new Hogan.Template({code: function (c,p,i) { var t=this;t.b(i=i||"");t.b("<div class=\"d2h-wrapper\">");t.b("\n" + i);t.b(" ");t.b(t.t(t.f("content",c,p,0)));t.b("\n" + i);t.b("</div>");return t.fl(); },partials: {}, subs: { }});
module.exports = global.browserTemplates;
})();

View file

@ -1,6 +1,6 @@
<tr>
<td class="d2h-code-linenumber {{diffParser.LINE_TYPE.INFO}}"></td>
<td class="{{diffParser.LINE_TYPE.INFO}}">
<div class="d2h-code-line {{diffParser.LINE_TYPE.INFO}}"> {{{blockHeader}}}</div>
<div class="d2h-code-line {{diffParser.LINE_TYPE.INFO}}">{{{blockHeader}}}</div>
</td>
</tr>

View file

@ -5,12 +5,12 @@
</td>
<td class="{{type}}">
<div class="d2h-code-line {{type}}">
{{#prefix}}
<span class="d2h-code-line-prefix">{{{prefix}}}</span>
{{/prefix}}
{{#content}}
<span class="d2h-code-line-ctn">{{{content}}}</span>
{{/content}}
{{#prefix}}
<span class="d2h-code-line-prefix">{{{prefix}}}</span>
{{/prefix}}
{{#content}}
<span class="d2h-code-line-ctn">{{{content}}}</span>
{{/content}}
</div>
</td>
</tr>