snakeskin
Version:
Компилятор блочных шаблонов c поддержкой наследования.
254 lines (202 loc) • 6.35 kB
JavaScript
var ss = module.exports = exports = global['SNAKESKIN_DEBUG'] || require('./dist/snakeskin.min');
var path = require('path'),
fs = require('fs'),
cache = {};
function clone(obj) {
return JSON.parse(JSON.stringify(obj));
}
// Явный экспорт, чтобы работал автокомплит в IDE
/** @see {Snakeskin.VERSION} */
exports.VERSION = ss.VERSION;
/** @see {Snakeskin.Filters} */
exports.Filters = ss.Filters;
/** @see {Snakeskin.Vars} */
exports.Vars = ss.Vars;
/** @see {Snakeskin.importFilters} */
exports.importFilters = ss.importFilters;
/** @see {Snakeskin.compile} */
exports.compile = ss.compile;
/**
* Вернуть true, если заданный файл шаблонов соответствует скомпилированному
* по временной метке
*
* @param {string} source - путь к исходному файлу
* @param {string} result - путь к скомпилированному файлу
* @param {(string|boolean|null)=} [opt_key] - ключ параметров компиляции
* @param {?boolean=} [opt_includes=false] - если true, то в случае успешного результата
* вернётся массив подключаемых файлов
*
* @return {(boolean|!Array)}
*/
exports.check = function (source, result, opt_key, opt_includes) {
source = path.normalize(path.resolve(source));
result = path.normalize(path.resolve(result));
if (!fs.existsSync(source) || !fs.existsSync(result)) {
return false;
}
var code = fs.readFileSync(result).toString(),
label = /label <([\d]+)>/.exec(code);
if (opt_key === null || !label || fs.statSync(source).mtime.valueOf() != label[1]) {
return false;
}
if (opt_key) {
var key = /key <(.*?)>/.exec(code);
if (!key || key[1] != opt_key) {
return false;
}
}
var includes = /includes <(.*?)>/.exec(code);
if (!includes) {
return false;
}
if (includes[1]) {
includes = JSON.parse(includes[1]);
for (var i = 0; i < includes.length; i++) {
var el = includes[i];
if (fs.existsSync(el[0])) {
if (fs.statSync(el[0]).mtime.valueOf() != el[1]) {
return false;
}
} else {
return false;
}
}
if (opt_includes) {
return includes.map(function (el) {
return el[0];
});
}
}
return opt_includes ? [] : true;
};
/**
* Скомпилировать заданный файл и вернуть ссылку на полученный объект
* или false, если произошла ошибка при компиляции
*
* @param {string} src - путь к файлу шаблонов
*
* @param {Object=} [opt_params] - дополнительные параметры компиляции
* @see Snakeskin.compile
*
* @return {(!Object|boolean)}
*/
exports.compileFile = function (src, opt_params) {
src = path.normalize(path.resolve(src));
var p = opt_params || {};
var cacheEnabled = p.cache !== false;
var cacheKey = this.compile(null, p, null, {cacheKey: true}),
fromCache = cacheEnabled &&
cache[cacheKey] &&
cache[cacheKey][src];
if (fromCache) {
var tmp = fromCache;
if (p.words) {
if (!tmp.words) {
fromCache = false;
} else {
p.words = clone(tmp.words);
}
}
if (p.debug) {
if (!tmp.debug) {
fromCache = false;
} else {
p.debug = clone(tmp.debug);
}
}
if (fromCache) {
return tmp.tpls;
}
}
var source = fs.readFileSync(src).toString(),
resSrc = src + '.js';
var tpls,
res = true,
that = this;
var compile = function () {
res = that.compile(source, p, {file: src});
if (res !== false) {
fs.writeFileSync(resSrc, res);
}
};
if (cacheEnabled) {
if (!this.check(src, resSrc, cacheKey)) {
compile();
}
} else {
compile();
}
if (res !== false) {
delete require.cache[require.resolve(resSrc)];
tpls = require(resSrc);
if (cacheKey && (cacheEnabled || cache[cacheKey])) {
cache[cacheKey] = cache[cacheKey] || {};
cache[cacheKey][src] = {
tpls: tpls,
debug: p.debug,
words: p.words
};
}
if (tpls.init) {
tpls.init(this);
}
return tpls;
}
return false;
};
/**
* Вернуть ссылку на главный шаблон
*
* @param {!Object} tpls - таблица шаблонов
* @param {?string=} [opt_src] - путь к файлу шаблонов
* @param {?string=} [opt_tplName] - имя главного шаблона
* @return {Function}
*/
exports.returnMainTpl = function (tpls, opt_src, opt_tplName) {
var tpl;
if (opt_tplName) {
tpl = tpls[opt_tplName];
} else {
tpl = opt_src && tpls[path.basename(opt_src, path.extname(opt_src))] ||
tpls.main ||
tpls.index ||
tpls[Object.keys(tpls).sort()[0]];
}
return tpl || null;
};
/**
* Скомпилировать заданный файл и вернуть ссылку на главный шаблон (функцию)
*
* @param {string} src - путь к файлу шаблонов
*
* @param {Object=} [opt_params] - дополнительные параметры компиляции
* @see Snakeskin.compile
*
* @param {?string=} [opt_tplName] - имя главного шаблона
* @return {Function}
*/
exports.execFile = function (src, opt_params, opt_tplName) {
var tpls = this.compileFile(src, opt_params);
if (!tpls) {
return null;
}
return this.returnMainTpl(tpls, src, opt_tplName);
};
/**
* Скомпилировать заданный текст и вернуть ссылку на главный шаблон (функцию)
*
* @param {string} txt - исходный текст
*
* @param {Object=} [opt_params] - дополнительные параметры компиляции
* @see Snakeskin.compile
*
* @param {?string=} [opt_tplName] - имя главного шаблона
* @return {Function}
*/
exports.exec = function (txt, opt_params, opt_tplName) {
var tpls = {};
opt_params = opt_params || {};
opt_params.context = tpls;
this.compile(txt, opt_params);
return this.returnMainTpl(tpls, null, opt_tplName);
};