snakeskin
Version:
Компилятор блочных шаблонов c поддержкой наследования.
263 lines (208 loc) • 5.35 kB
JavaScript
(() => {
/**
* Преобразовать заданное значение в объект
*
* @expose
* @param {?} val - объект, строка для парсинга или URL
* @param {?string=} [opt_base] - базовый URL
* @param {?function(string)=} [opt_onFileExists] - функция обратного вызова,
* если исходный объект - путь к существующему файлу
*
* @return {!Object}
*/
Snakeskin.toObj = function (val, opt_base, opt_onFileExists) {
if (typeof val !== 'string') {
return val;
}
var res;
if (IS_NODE) {
let path = require('path'),
fs = require('fs'),
old = val;
try {
if (opt_base) {
val = path['resolve'](path['dirname'](opt_base), val);
}
val = path['normalize'](path['resolve'](val));
if (fs['existsSync'](val)) {
if (opt_onFileExists) {
opt_onFileExists(val);
}
let content = fs['readFileSync'](val).toString();
try {
res = JSON.parse(content);
} catch (ignore) {
try {
res = eval(`(${content})`);
} catch (ignore) {
delete require['cache'][require['resolve'](val)];
res = require(val);
}
}
return Object(res || {});
} else {
val = old;
}
} catch (ignore) {
val = old;
}
}
try {
res = JSON.parse(val);
} catch (ignore) {
try {
res = eval(`(${val})`);
} catch (ignore) {
res = {};
}
}
return Object(res || {});
};
/**
* Расширить объект a объектом b
* (глубокое расширение)
*
* @param {!Object} a
* @param {!Object} b
* @return {!Object}
*/
function extend(a, b) {
forIn(b, (el, key) => {
if (a[key] instanceof Object && el instanceof Object) {
extend(a[key], el);
} else {
a[key] = el;
}
});
return a;
}
/**
* Вернуть объект, расширенный с помощью заданных объектов
*
* @param {!Object} base - базовый расширяющий объект
* @param {Object=} [opt_adv] - дополнительный расширяющий объект
* @param {Object=} [opt_initial] - объект инициализации
* @return {!Object}
*/
function mix(base, opt_adv, opt_initial) {
var obj = opt_initial || {};
forIn(opt_adv, (el, key) => {
obj[key] = el;
});
return extend(obj, base);
}
function setSSFlag(command) {
this.startInlineDir();
var file = this.info['file'],
init = false;
var root = this.params[0],
last = this.params[this.params.length - 1],
params = last;
var cache,
parentCache,
tplName = this.tplName;
if (tplName) {
cache =
outputCache[tplName]['flag'] = outputCache[tplName]['flag'] || {};
if (this.parentTplName) {
parentCache = outputCache[this.parentTplName] && outputCache[this.parentTplName]['flag'];
}
}
if (last['@root'] || (file && last['@file'] !== file) || (tplName && last['@tplName'] !== tplName)) {
init = true;
params = {
'@file': file,
'@tplName': tplName
};
let inherit = (obj) => {
forIn(obj, (el, key) => {
if (key.charAt(0) !== '@' && key in root) {
params[key] =
this[key] = el;
if (cache) {
cache[key] = el;
}
}
});
};
inherit(last);
if (parentCache) {
inherit(parentCache);
}
this.params.push(params);
}
var flag,
value;
if (Array.isArray(command)) {
flag = command[0];
value = command[1];
} else {
let parts = command.split(' ');
flag = parts[0];
try {
value = this.returnEvalVal(parts.slice(1).join(' '));
} catch (err) {
return this.error(err.message);
}
}
var includeMap = {
'language': true,
'macros': true
};
if (flag === 'renderAs' && tplName) {
return this.error('flag "renderAs" can\'t be used in the template declaration');
}
if (flag in root) {
if (includeMap[flag]) {
value = mix(
Snakeskin.toObj(value, file, (src) => {
var root = this.module.root || this.module;
root.key.push([src, require('fs')['statSync'](src)['mtime'].valueOf()]);
this.files[src] = true;
}),
init ?
params[flag] : null,
init ?
null : params[flag]
);
if (flag === 'macros') {
try {
value = this.setMacros(value, null, init);
} catch (err) {
return this.error(err.message);
}
}
}
params[flag] =
this[flag] = value;
if (cache) {
cache[flag] = value;
}
} else if (flag.charAt(0) !== '@') {
return this.error(`unknown compiler flag "${flag}"`);
}
}
Snakeskin.addDirective(
'setSSFlag',
{
placement: 'global',
group: 'define',
notEmpty: true,
replacers: {
'@=': (cmd) => cmd.replace('@=', 'setSSFlag ')
}
},
setSSFlag
);
Snakeskin.addDirective(
'__setSSFlag__',
{
group: 'define',
notEmpty: true,
replacers: {
'@=': (cmd) => cmd.replace('@=', 'setSSFlag ')
}
},
setSSFlag
);
})();