Фух, почти закончил работу над новой версией, вышло дольше чем думал. На этой недели закончу, но уже предлагаю поиграться с бетой и
заодно потестить :
http://jsfiddle.net/NAPWB/6/.
С функциональной стороны сделано всё, что хотел, и даже больше, однако ещё нужно написать новые тесты, обновить доку и т.д.
Ну а теперь по порядку. Изначально данный апдейт планировался как эволюционное развитие ветки 2.x, однако в ходе разработки, стало ясно, что необходимы некоторые принципиальные изменения, которые повлекут за собой несовместимость с предыдущей версией, поэтому новая версия выйдет как 3.0.0.
Что изменилось по сравнению с 2.x:
1) Реализована блочная область видимости переменных вместо единой шаблонной, т.е.
{template foo()}
{if 1}
{var a = 1}
{a} /// 1
{/}
{a} /// error, a is not defined
{/}
Отмечу, что данное нововведение распространяется именно на переменные, т.е. константы работают также, как и раньше.
2) Переосмыслена и переделана работа с пробельными символами: теперь любой пробельный символ (будь то табуляция или переход строки) трактуются как пробел, однако смежные пробельные символы схлопываются в один, т.е.
{template foo()}
/// перевод строки даст пробел
<div
class="foo">
{/}
Также введена новая директива &, которая декларирует, что все пробельные символы после этой директивы до любого не пробельного символа будут вырезаться, т.е.:
{template foo()}
Привет{&} Мир! /// получится ПриветМир!
{/}
3) Директивы cut и save были убраны, а их функционал частично заменила новая директива placeholder. Эта директива имеет одинаковый синтаксис с директивой template, однако, в отличии от template, placeholder существует только на этапе трансляции, т.е.
{placeholder foo()}
foobar
{/}
foo(); // error
Директива может участвовать в цепи наследований также, как и template.
4) Добавлен новый возможный аргумент для директив forEach и forIn (forIn отличается от forEach тем, что всегда итерирует объект, как for (key in data), причём без проверки на hasOwnProperty). Теперь порядок аргументов для forEach такой:
Для массивов:
*) Ссылка на элемент массива;
*) Индекс массива;
*) Ссылка на итерируемый массив;
*) Является ли первым;
*) Является ли последним;
*) Длина массива.
Для объектов:
*) Ссылка на свойство;
*) Ключ свойства;
*) Ссылка на итерируемый объект;
*) Номер итерации;
*) Является ли первым;
*) Является ли последним;
*) Длина объекта.
Для forIn аргументы такие же, как и у forEach для объектов. Кстати, теперь директивы forEach и forIn разворачиваются в циклы на этапе трансляции, что позволило увеличить скорость скомпилированных шаблонов, а также возможность использования новых директив break и continue.
5) Для директивы data изменено сокращение, теперь это =, т.е.
{template foo()}
{= foo, bar}
{/}
Старое сокращение {{}} теперь используется новой директивой decl, которая вставляет текст, так как он был написан вместе со скобками директивы, т.е.:
{template foo()}
{{foo}} /// даст {{foo}}
{/}
Также, как и в data, в decl можно прокидывать переменные из шаблона, с помощью синтаксиса ${}. Новая директива decl создана для удобного использования библиотек, которые осуществляют data binding (вроде
http://www.ractivejs.org/).
6) Костыль для console был удалён, теперь нужно использовать директиву void
{template foo()}
{void console.log(1)}
/// или так
{?console.log(1)}
{/}
На этом ломающие изменения заканчиваются. Основные нововведения:
1) Добавлена директива super, которая осуществляет вставку тела родительского блока или прототипа:
{template base()}
<head>
{block scripts}
<script src="../1.js"></script>
{/}
</head/>
{/}
{template child() extends base}
{block scripts}
{super}
<script src="../2.js"></script>
{/}
{/}
2) Прототипы теперь поддерживают параметры и рекурсию, а также новую директиву return:
{template foo()}
{proto bar(i)}
{i}
{if i === 2}
{return}
{/}
{if i}
{apply bar(--i)}
{/}
{/}
{apply bar(4)} /// 4 3 2
{/}
3) Прототипы теперь можно выносить за пределы шаблона, перед декларацией
{proto foo->bar}
1
{/}
{template foo()}
{apply bar}
{/}
4) Добавлена поддержка jsDoc
/**
* Данный комментарий будет в скомпилированном JS
* @return {string}
*/
{template foo()}
1
{/}
5) Директива var теперь имеет сокращение : и поддерживает множественную декларацию
{template foo()}
{:a = 1}
{var b = 2, e = 3}
{/}
6) Новые директивы switch case (имеет сокращение >) default
{template foo()}
{switch 1}
{case 1} foo {/}
{> 2} foo2 {/}
{default} foo3 {/}
{/}
{/}
7) Новые директивы try catch finally
{template foo()}
{try}
{void dddd()}
{catch err}
{err}
{finally}
bar!!!
{/}
{/}
8) Новые директивы break и continue. Могут использоваться внутри forEach, forIn, for, while, do, repeat.
9) Для цикла repeat-until добавлен псевдоним do-while
10) Новая директива return. Может использоваться внутри прототипов или шаблона (в случае шаблона может принимать значение)
11) Новая директива attr для удобного задания атрибутов узлам в xml разметке:
{template foo()}
<div {attr 'class', 'foo'} {attr -'bind', 'bar'}></div> /// class="foo" data-bind="bar"
{/}
12) Частично переписано АПИ добавления директив, в релизе будет иметь документацию, пример:
Snakeskin.addDirective(
'if',
{
placement: 'template',
notEmpty: true
},
function (command) {
this.startDir();
if (this.isSimpleOutput()) {
this.save('if (' + this.prepareOutput(command, true) + ') {');
}
}
);
Snakeskin.addDirective(
'else',
{
placement: 'template'
},
function () {
if (this.structure.name !== 'if') {
throw this.error('Directive "' + this.name + '" can only be used with a "if"');
}
if (this.isSimpleOutput()) {
this.save('} else {');
}
}
);
13) Увеличена скорость работы транслятора и исправлено множество ошибок
14) Сильно увеличена скорость работы в "живом" режиме в браузере
15) Очень сильно доработана обработка ошибок
16) 100% code review и рефакторинг + теперь исходный код переписан на ECMAScript 6
Вроде всё