• Directives
  • Creating templates

namespace

Директива декларирует пространство имён для файла в котором оно используется, т.е. все декларируемые в этом файле шаблоны будут частью заданного пространства имён.

Synopsis

Declaration Shorthand Directive type Interpolation
Only in the global scope, только одна декларация на файл Absent Inline, logic Not required

Description

Пространства имён Snakeskin служат для экспорта шаблонов из файла, поэтому перед тем как начать создавать сами шаблоны нужно предварительно объявить пространство имён, а уже после они будут экспортироваться по схеме exports.namespace.template. В рамках одного файла может быть только одно пространство имён.

For example:

- namespace demo

/// Шаблон экспортируется как exports.demo.index
- template index()
	Hello world!
{namespace demo}

/// Шаблон экспортируется как exports.demo.index
{template index()}
	Hello world!
{/template}

Пространство имён может состоять из множества частей (свойств объекта), причём Snakeskin проверяет существование заданного пути и создаёт только те части, которые отсутствуют.

- namespace demo.helloWorld

/// exports.demo.helloWorld.index
- template index()
	Hello world!

/// exports.demo.helloWorld.bar
- template bar()
	Hello people!
{namespace demo.helloWorld}

/// exports.demo.helloWorld.index
{template index()}
	Hello world!
{/template}

/// exports.demo.helloWorld.bar
{template bar()}
	Hello people!
{/template}

Т.к. пространство имён превращается в JS объект, то на декларируемое имя накладываются те же ограничения, что и на свойство объекта, однако можно использовать декларацию через квадратные скобки ([ ... ]), которая позволяет применять любые символы и сложные выражения, например:

- namespace ['@demo']['hello' + 'World']

/// exports['@demo']['helloWorld'].index
- template index()
	Hello world!
{namespace ['@demo']['hello' + 'World']}

/// exports['@demo']['helloWorld'].index
{template index()}
	Hello world!
{/template}

Если первая часть имени использует синтаксис без квадратных скобок, то будет создана глобальная (для Snakeskin) переменная с таким же именем:

/// var demo = exports.demo['helloWorld']
- namespace demo['hello' + 'World']

- template index()
	Hello world!
/// var demo = exports.demo['helloWorld']
{namespace ['@demo']['hello' + 'World']}

{template index()}
	Hello world!
{/template}

Пространство имён создаёт with биндинг, который можно использовать для удобного вызова шаблонов в рамках файла.

- namespace demo
- template parent()
	Hello world!

/// Тоже самое, что и extends exports.demo.parent
- template child() extends @parent
{namespace demo}
{template parent()}
	Hello world!
{/template}

/// Тоже самое, что и extends exports.demo.parent
{template child() extends @parent}
{/template}

Директива может использоваться только в глобальной области.

Плейсхолдеры имени

При декларации пространства имён можно использовать специальные плейсхолдеры, которые заменяются при трансляции на некоторое статическое значение в рамках своего контекста.

%dirName%

Плейсхолдер %dirName% заменяется на имя директории, в которой лежит исходный файл Snakeskin, например:

foo/index.ss

- namespace %dirName%.bar

/// exports.foo.bar.index
- template index()
	Hello world!
{namespace %dirName%.bar}

/// exports.foo.bar.index
{template index()}
	Hello world!
{/template}

Т.к. в названии директории могут встречаться “запрещённые” символы, то лучше использовать синтаксис с квадратными скобками:

- namespace [%dirName%].bar
- template index()
	Hello world!
{namespace [%dirName%].bar}
{template index()}
	Hello world!
{/template}

%fileName%

Плейсхолдер %fileName% заменяется на имя исходного файла-шаблона (без расширения), например:

foo/index.ss

- namespace %fileName%.bar

/// exports.index.bar.index
- template index()
	Hello world!
{namespace %fileName%.bar}

/// exports.index.bar.index
{template index()}
	Hello world!
{/template}

Т.к. в названии файла могут встречаться “запрещённые” символы, то лучше использовать синтаксис с квадратными скобками:

- namespace [%fileName%].bar
- template index()
	Hello world!
{namespace [%fileName%].bar}
{template index()}
	Hello world!
{/template}
  • Directives
  • Creating templates

template

This directive declares a template with specified name and input parameters.

Synopsis

Declaration Shorthand Directive type Interpolation
Only in the global scope, require pre-declaration of namespace Absent Block, logic, function Not required

Description

Snakeskin template is just a JavaScript function, that can be used inside regular code after being transpiled. Every template returns a string by default. You can adjust this behaviour by specifying a custom renderMode or explicit return of a value.

A template’s name matches name of function in JavaScript, so it should comply the same rules. template declaration should be preceeded by namespace declaration and should have a unique name. Besides, a template can be declared only within global scope. Nesting is not allowed - use blocks for this.

The directive is very similar to declaration of functions in JavaScript, for instance:

- namespace demo
- template index(name = 'world')
	Hello {name}!
{namespace demo}
{template index(name = 'world')}
	Hello {name}!
{/template}

You can find more advanced ways of parameters declaring here.

Nested namespaces

При декларации шаблона можно использовать пространства имён, подобно тому, как это делается в namespace, например:

foo/index.ss

- namespace demo
- template %fileName%.index(name = 'world')
	Hello {name}!
{namespace demo}
{template %fileName%.index(name = 'world')}
	Hello {name}!
{/template}

Механика здесь точно такая же, как и у namespace, поэтому рассматриваться отдельно не будет, однако, есть небольшой дополнительный нюанс: если последняя часть имени декларируется без квадратных скобок, то она будет установлена как свойство name полученной функции JavaScript, т.е.

- namespace demo
- template index(name = 'world')
	Hello {name}!
{namespace demo}
{template index(name = 'world')}
	Hello {name}!
{/template}

Превратится в:

exports.demo.index = function index(name) {
	name = name != null ? name : 'world';
	return 'Hello ' + name + '!';
};

Predefined variables

There are a couple of predefined constants and functions that can be used inside templates.

TPL_NAME - a string containing a full template’s name along with name of namespace as it was at the moment of declaration.

PARENT_TPL_NAME - a string containing a full name of a template’s parent along with its namespace as it was at the moment of declaration.

callee - link to a running template (i.e. function).

self - link to a callee.Blocks object, containing blocks (methods) of a running template.

$0 - link to current DOM node (only if renderMode equals 'dom').

$tagName - имя созданного через директиву тега (.getVar('$tagName'));

$attrKey - ключ атрибута тега созданного через директиву;

$attrs - объект атрибутов тега созданного через директиву (.getVar('$attrs'));

$class - значение липкой ссылки.

getTplResult - a function returning a template’s result. Accepts a boolean argument, pointing whether the result should be reseted after the function calling.

clearTplResult - a function that resets a template’s result.

Modificators

Snakeskin templates support declaration modificators.

Generator template

A template will be translated into a generator function (you should use a polyfill for older browsers).

- namespace demo
- template *hello()
	- yield
		Hello world!
{namespace demo}
{template *hello()}
	{yield}
		Hello world!
	{/}
{/template}

Async template

A template will be translated into an async function (you should use a polyfill for older browsers).

- namespace demo
- async template hello()
	- var data = await db.getData()
	Hello {data.name}!
{namespace demo}
{async template hello()}
	{var data = await db.getData() /}
	Hello {data.name}!
{/template}

Decorators

Every template can be attached by decorator functions (that can also be templates). Decorator accepts a link to original function and must return a function as its result.

- namespace demo
- import Typograf from 'typograf'

- template typograf(params)
	- return
		() => target
			- return
				() =>
					- return new Typograf(params).execute(target.apply(this, arguments))

- @typograf({locale: 'ru'})
- template index()
	Sport is well!
{namespace demo}
{import Typograf from 'typograf'}

{template typograf(params)}
	{return}
		{() => target}
			{return}
				{() =>}
					{return new Typograf(params).execute(target.apply(this, arguments)) /}
				{/}
			{/}
		{/}
	{/}
{/template}

{@typograf({locale: 'ru'})}
{template index()}
	Sport is well!
{/template}

Local translation options

When declaring a template you can attach specific translation rules by using @= operator.

- namespace demo
- template index() @= literalBounds ['<?php', '?>']
	{{ Hello }}
{namespace demo}
{template index() @= literalBounds ['<?php', '?>']}
	{{ Hello }}
{/template}

Template inheritance

Snakeskin templates are similar to classes in other programming languages, it means they have methods, properties and can inherit from others. Keyword extends is used to setup inheritance.

- namespace demo
- template index() extends anotherTemplate
	...
{namespace demo}
{template index() extends anotherTemplate
	...
{/template}

More about inheritance.

Explicit call of a template inside other template

Since Snakeskin templates are just functions, they can be called inside each other via the call directive.

- namespace demo

- template hello()
	Hello world!

- template index()
	/// Because "hello" and "index" are declared in the same
	/// namespace, we can use brief form of call
	/// (full form {+= demo.hello() /} is also avaliable though).
	+= @hello()
{namespace demo}

{template hello()}
	Hello world!
{/template}

{template index()}
	/// Because "hello" and "index" are declared in the same
	/// namespace, we can use brief form of call
	/// (full form {+= demo.hello() /} is also avaliable though).
	{+= @hello() /}
{/template}
  • Directives
  • Creating templates

interface

Директива декларирует шаблон-интерфейс c заданным именем и входными параметрами.

Synopsis

Declaration Shorthand Directive type Interpolation
Only in the global scope, require pre-declaration of namespace Absent Block, logic, function Not required

Description

Шаблон-интерфейс отличается от простого шаблона тем, что после трансляции в JS будет получена пустая функция с входными параметрами, например:

- namespace demo
- interface index(name = 'world')
	Hello {name}!
{namespace demo}
{interface index(name = 'world')}
	Hello {name}!
{/interface}

Превратится в:

exports.demo.index = function index(name) {};

В остальном механика таких шаблонов полностью идентичная template.

  • Directives
  • Creating templates

placeholder

Директива декларирует шаблон-плейсхолдер c заданным именем и входными параметрами.

Synopsis

Declaration Shorthand Directive type Interpolation
Only in the global scope, require pre-declaration of namespace Absent Block, logic, function Not required

Description

Шаблон-плейсхолдер отличается от простого шаблона тем, что он существует только на этапе трансляции и не будет включён в конечный JS, например:

- namespace demo
- placeholder index(name = 'world')
	Hello {name}!
{namespace demo}
{placeholder index(name = 'world')}
	Hello {name}!
{/placeholder}

Превратится в:

В остальном механика таких шаблонов полностью идентичная template.

  • Directives
  • Creating templates

block

Директива декларирует статичный блок or подшаблон c заданным именем и входными параметрами.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits Absent Block, logic, function Not required

Description

Директива block несёт двойную функциональность: с одной стороны она позволяет создавать статичные блоки, а с другой - вызываемые. Блоки являются фундаментальной ячейкой Snakeskin, т.к. играют ключевую роль при наследовании, но если статичный блок - это просто выделение фрагмента текста, чтобы в дальнейшем иметь возможность его переопределить в дочернем шаблоне, то вызываемый блок - это по сути вложенная функция-шаблон, т.е. после декларации его можно неоднократно вызывать и передавать различные параметры.

Разница в декларации статичного блока от динамического заключается в наличии скобок для параметров, например:

- namespace demo
- template index()
	/// Статичный блок
	- block hello
		Hello world!

	/// Вызываемый блок
	- block helloWithName(name)
		Hello {name}!
{namespace demo}
{template index()}
	/// Статичный блок
	{block hello}
		Hello world!
	{/}

	/// Вызываемый блок
	{block helloWithName(name)}
		Hello {name}!
	{/}
{/template}

Параметров у блока может быть неограниченное количество, а т.к. директива block является функциональной, то она реализует стандартный механизм декларации параметров. По умолчанию вызываемые блоки возвращают строки, однако это поведение можно поменять задав специальный renderMode or явно вернув значение через директиву return.

Название блока соответствует названию функции в JavaScript, поэтому оно подчиняется тем же правилам, причём статичные блоки и вызываемые лежат в одном пространстве имён. В рамках шаблона не может быть 2-х блоков с одинаковым названием.

Блок как метод шаблона

Вызываемые блоки - это методы шаблона, т.е. они наследуются в дочерних шаблонах, могут переопределяться и т.д., а сама механика наследования практически идентична со статичными блоками и шаблонами, и описана в отдельной главе.

При создании вызываемого блока он ставиться как свойство .Blocks.названиеБлока исходного шаблона, и, как правило, вызывается с помощью директивы call и указателя self, например:

- namespace demo
- template index()
	- block hello(name)
		Hello {name}!

	+= self.hello('kobezzza')
{namespace demo}
{template index()}
	{block hello(name)}
		Hello {name}!
	{/}

	{+= self.hello('kobezzza') /}
{/template}

Примечание: this внутри блока ссылается на this шаблона.

Стандартные переменные блока

Каждый вызываемый блок определяет ряд функций, которые можно использовать в нём:

getTplResult - функция, которая возвращает результат работы блока, также может принимать один логический входной параметр, при задании которого после вызова функции результат работы блока будет обнуляться;

clearTplResult - функция, которая обнуляет результат работы блока.

Внешние блоки

Любые блоки могут декларироваться как внутри шаблона or другого блока, так и в глобальной области, но при такой декларации есть ряд дополнительных правил: блок должен декларироваться до шаблона, методом которого он является; блок должен явно указывать к какому шаблону он принадлежит (для этого используется оператор ->), например:

- namespace demo

- block index->hello(name)
	Hello {name}!

- template index()
	+= self.hello('kobezzza')
{namespace demo}

{block index->hello(name)}
	Hello {name}!
{/block}

{template index()}
	{+= self.hello('kobezzza') /}
{/template}

Такие блоки могут даже находиться в разных файлах и подключаться через include, но должны обязательно подключаться до декларации шаблона.

Самовызываемые блоки

Вызываемый блок можно вызвать немедленно после декларации: для этого используется специальный оператор =>, например:

- namespace demo

- template index()
	- block hello(name) => 'kobezzza'
		Hello {name}!
{namespace demo}

{template index()}
	{block hello(name) => 'kobezzza'}
		Hello {name}!
	{/}
{/template}

Такой же синтаксис можно использовать и для внешних блоков:

- namespace demo

- block index->hello(name) => 'kobezzza'
	Hello {name}!

- template index()
{namespace demo}

{block index->hello(name) => 'kobezzza'}
	Hello {name}!
{/block}

{template index()}
{/template}

Ссылка & для удобного рекурсивного вызова блока

При использовании call для вызова блока можно использовать специальный указать &, который ссылается на блок внутри которого он используется - это удобно для организации рекурсий, например:

- namespace demo

- template index()
	- block iterate(i)
		{i}

		- if i
			+= &(--i)

	+= self.iterate(5)
{namespace demo}

{template index()}
	{block iterate(i)}
		{i}

		{if i}
			{+= &(--i) /}
		{/}
	{/}

	{+= self.iterate(5) /}
{/template}
  • Directives
  • Creating templates

set

The directive sets the value to the specified option.

Synopsis

Declaration Shorthand Directive type Interpolation
Only in the global scope @= Inline, logic Not required

Supported options

  • Directives
  • Creating templates

end

Директива декларирует завершение блочной директивы.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits / Inline, logic Not required

Description

Директива используется для завершения блочной директивы в классическом синтаксисе Snakeskinjade-like) она ставиться автоматически). У директивы есть 4-ре формы использования:

/// Полная форма
{if 1 > 2}
	...
{end if}

/// Сокращённая форма
{if 1 > 2}
	...
{end}

/// Альтернативная полная форма
{if 1 > 2}
	...
{/if}

/// Альтернативная сокращённая форма
{if 1 > 2}
	...
{/}

Какую форму использовать решает сам разработчик, но следует отметить, что при использовании форм с указанием имени закрываемой директивы Snakeskin будет проверять правильность, т.е.:

{if 1 > 2}
	...
{/else} /// Ошибка
  • Directives
  • Execution / output

output

Директива выполняет заданное выражение и выводит результат в шаблон (на выводимое выражение по умолчанию накладываются фильтры html и undef).

Synopsis

Declaration Shorthand Directive type Interpolation
Only within templates or external blocks Not required Inline, text Not required

Description

Директива output используется когда нам нужно вывести в текст шаблона значение переменной or выражения.

Директива не требует специального ключевого слова (хотя допускается), поэтому достаточно просто взять выводимое выражение в фигурные скобки, например:

- namespace demo
- template calc(a, b)
	a + b = {a + b}
{namespace demo}
{template calc(a, b)}
	a + b = {a + b}
{/template}

Однако нужно следить, чтобы первое слово выводимого выражения не было равно имени другой директивы Snakeskin, иначе возникнет ошибка:

- namespace demo
- template index(link)
	{link} /// Ошибка
{namespace demo}
{template index(link)}
	{link} /// Ошибка
{/template}

Для того чтобы пример выше отработал корректно достаточно просто взять наше выражение в круглые скобки:

- namespace demo
- template index(link)
	{(link)}
{namespace demo}
{template index(link)}
	{(link)}
{/template}

Внутри output можно использовать вызовы функций, тернарные операторы и т.д.

- namespace demo
- template calc(a, b)
	{a > 1 ? --a * b : Math.random() * b}
{namespace demo}
{template calc(a, b)}
	{a > 1 ? --a * b : Math.random() * b}
{/template}

На всё выводимое выражение по умолчанию накладывается специальный фильтр html, который экранирует html сущности, а также фильтр undef на каждый отдельный чанк выражения, который преобразует значение undefined в ''. Чтобы отменить это поведение нужно использовать фильтры !html и !undef or задать глобальное через параметр трансляции filters.

- namespace demo
- template index(val1, val2)
	{(val1|!undef) + (val2|!undef) |!html}
{namespace demo}
{template index(val1, val2)}
	{(val1|!undef) + (val2|!undef) |!html}
{/template}

Директива может использоваться только внутри шаблонов or внешних блоков.

  • Directives
  • Execution / output

call

Директива выполняет заданное выражение и выводит результат в шаблон (на выводимое выражение по умолчанию накладываются фильтр undef).

Synopsis

Declaration Shorthand Directive type Interpolation
Only within templates or external blocks += Block, text Not required

Description

Директива call похожа на output, т.е. она тоже вставляет результат выражения в шаблон, однако, она не накладывает по умолчанию на выводимые данные фильтр html, т.е. выводимое выражение не экранируется и это является аналогом использования фильтра !html.

Директива начинается с ключевого слова call (или символов +=), которое должно сопровождаться ссылкой на выводимое значение или выражение (заключать выражение в скобки не обязательно), например:

- namespace demo
- template index()
	+= 1 + 2
{namespace demo}
{template index()}
	{+= 1 + 2 /}
{/template}

Для удобства использования call в классическом синтаксисе существует короткая форма закрытия директивы, например:

/// Обычное закрытие
{+= 1 + 2}{/}

/// Короткая форма закрытия
{+= 1 + 2 /}

Главным кейзом использования call является вызов блоков и других шаблонов внутри шаблона, поэтому выводимые данные не экранируются, т.к. они уже и так экранированы, например:

- namespace demo

- template helper()
	< .foo
		Hello world!

- template index()
	/// <div class="foo">Hello world!</div>
	+= @helper()

	/// &lt;div class=&quot;foo&quot;&gt;Hello world!&lt;/div&gt;
	{@helper()}
{namespace demo}

{template helper()}
	{< .foo}
		Hello world!
	{/}
{/template}

{template index()}
	/// <div class="foo">Hello world!</div>
	{+= @helper() /}

	/// &lt;div class=&quot;foo&quot;&gt;Hello world!&lt;/div&gt;
	{@helper()}
{/template}

Директива может использоваться только внутри шаблонов or внешних блоков.

Расширенная декларация

Директива поддерживает специальную расширенную форму для передачи параметров-шаблонов в вызываемую функцию, например:

- namespace demo

- template helper(text)
	< .output
		{text}

- template index()
	/// <div class="output"><div class="foo">Hello world!</div></div>
	+= @helper()
		< .hello
			Hello world!
{namespace demo}

{template helper(text)}
	{< .output}
		{text}
	{/}
{/template}

{template index()}
	/// <div class="output"><div class="foo">Hello world!</div></div>
	{+= @helper()}
		{< .hello}
			Hello world!
		{/}
	{/}
{/template}

Внутри такой декларации можно использовать любые допустимые директивы, например, if, forEach и т.д. Если необходимо передать несколько параметров, то нужно использовать директиву putIn:

- namespace demo

- template helper(text1, text2)
	< .output1
		{text1}

	< .output2
		{text2}

- template index()
	+= @helper()
		*
			< .hello
				Hello world!
		*
			< .goodbye
				Goodbye cruel world!
{namespace demo}

{template helper(text1, text2)}
	{< .output1}
		{text1}
	{/}

	{< .output2}
		{text2}
	{/}
{/template}

{template index()
	{+= @helper()}
		{*}
			{< .hello}
				Hello world!
			{/}
		{/}
		{*}
			{< .goodbye}
				Goodbye cruel world!
			{/}
		{/}
	{/}
{/template}

Первый вызов putIn можно опустить:

- namespace demo

- template helper(text1, text2)
	< .output1
		{text1}

	< .output2
		{text2}

- template index()
	+= @helper()
			< .hello
				Hello world!
		*
			< .goodbye
				Goodbye cruel world!
{namespace demo}

{template helper(text1, text2)}
	{< .output1}
		{text1}
	{/}

	{< .output2}
		{text2}
	{/}
{/template}

{template index()
	{+= @helper()}
		{< .hello}
			Hello world!
		{/}
		{*}
			{< .goodbye}
				Goodbye cruel world!
			{/}
		{/}
	{/}
{/template}

Допускается совмещать передачу параметров в обычной и расширенной форме.

- namespace demo

- template helper(a, b, text1, text2)
	{a + b}

	< .output1
		{text1}

	< .output2
		{text2}

- template index()
	+= @helper(1, 2)
			< .hello
				Hello world!
		*
			< .goodbye
				Goodbye cruel world!
{namespace demo}

{template helper(a, b, text1, text2)}
	{a + b}

	{< .output1}
		{text1}
	{/}

	{< .output2}
		{text2}
	{/}
{/template}

{template index()
	{+= @helper(1, 2)}
		{< .hello}
			Hello world!
		{/}
		{*}
			{< .goodbye}
				Goodbye cruel world!
			{/}
		{/}
	{/}
{/template}

Examples

Передача функции-параметра с помощью func

- namespace demo

- template helper(fn)
	+= fn(1, 2)

- template index()
	+= @helper()
		() => a, b
			{a + b}
{namespace demo}

{template helper(fn)}
	{+= fn(1, 2) /}
{/template}

{template index()
	{+= @helper()}
		{() => a, b}
			{a + b}
		{/}
	{/}
{/template}

Передача объекта-параметра с помощью target

- namespace demo

- template helper(@params)
	{@data}

- template index()
	+= @helper()
		- target {}
			* data
				< .hello
					Hello world!
{namespace demo}

{template helper(@params)}
	{@data}
{/template}

{template index()
	{+= @helper()}
		{target {}}
			{* data}
				{< .hello}
					Hello world!
				{/}
			{/}
		{/}
	{/}
{/template}
  • Directives
  • Execution / output

void

The directive executes the specified expression, but no outputs the result to a template.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits ? Inline, logic Not required

Description

Директива void используется когда нам нужно выполнить некоторую логику, но чтобы она никак не отобразилась в шаблоне, например, сделать инкремент переменной or вывести текст в консоль разработчика.

Директива начинается с ключевого слова void (или символа ?), которое должно сопровождаться выражением (заключать выражение в скобки не обязательно). Самая простая форма выглядит так:

- void console.log('hello')
{void console.log('hello')}

The directive can be used anywhere.

Examples

- namespace demo
? console.log('hello world')
- template index()
	: a = 0
	- void a++
	{a} /// 1
{namespace demo}
{? console.log('hello world')}
{template index()}
	{: a = 0}
	{void a++}
	{a} /// 1
{/template}
  • Directives
  • Execution / output

return

Директива return является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в JavaScript.

Synopsis

Declaration Shorthand Directive type Interpolation
Только внутри функциональных директив Absent Block, logic Not required

Description

Большинство функциональных директив Snakeskin возвращают свой результат автоматически, но иногда бывает нужно вернуть определённый ответ в зависимости от условия, or если возвращаемое значение отлично от стандартного ответа Snakeskin.

Директива начинается с ключевого слова return, которое может сопровождаться ссылкой на возвращаемое значение или выражение, например:

- namespace demo
- template index()
	- return 1 + 2
{namespace demo}
{template index()}
	{return 1 + 2 /}
{/template}

Для удобства использования return в классическом синтаксисе существует короткая форма закрытия директивы, например:

/// Обычное закрытие
{return 1 + 2}{/}

/// Короткая форма закрытия
{return 1 + 2 /}

Директива может использоваться только внутри функциональных директив.

Расширенная декларация

Директива может включать возвращаемое значение в своё тело - это удобно, когда возвращаемое значение является подшаблоном, например:

- namespace demo
- template index()
	/// Шаблон вернёт ссылку на функцию,
	/// которая складывает два числа
	- return
		() => a, b
			- return a + b
{namespace demo}
{template index()}
	/// Шаблон вернёт ссылку на функцию,
	/// которая складывает два числа
	{return}
		{() => a, b}
			{return a + b /}
		{/}
	{/}
{/template}

Внутри такой декларации можно использовать любые допустимые директивы, например, if, forEach и т.д.

  • Directives
  • Global context

eval

Директива создаёт блок, который выполнится на этапе трансляции, но не войдёт в конечный JS.

Synopsis

Declaration Shorthand Directive type Interpolation
Only in the global scope Absent Block, logic Not required

Description

Т.к. любой код, размещённый вне тела шаблона будет выполняться как на этапе трансляции, так и войдёт в конечный JS код, то директива eval позволяет создать блок, содержимое которого будет исключаться из результирующего кода, но по прежнему будет выполняться на этапе трансляции.

- eval
	? console.log('Hello world!')
{eval}
	{? console.log('Hello world!')}
{/}

Директива может использоваться только в глобальной области.

  • Directives
  • Global context

head

Директива создаёт блок, который не выполнится на этапе трансляции, но войдёт в конечный JS.

Synopsis

Declaration Shorthand Directive type Interpolation
Only in the global scope Absent Block, logic Not required

Description

Т.к. любой код, размещённый вне тела шаблона будет выполняться как на этапе трансляции, так и войдёт в конечный JS код, то директива head позволяет создать блок, содержимое которого по прежнему не будет исключаться из результирующего кода, но не будет выполняться на этапе трансляции, а также переменные, которые были объявлены на корневом уровне директивы, будут считаться глобальными.

- namespace demo

- head
	/// Данный forEach не выполнится на этапе трансляции,
	/// но войдёт в конечный JS
	- forEach [1, 2, 3] => el
		? console.log(el)

	/// Данная переменная глобальная,
	/// хоть и объявлена внутри блочной директивы
	: foo = 'bar'

- template index()
	? console.log(foo) /// 'bar'
{namespace demo}

{head}
	/// Данный forEach не выполнится на этапе трансляции,
	/// но войдёт в конечный JS
	{forEach [1, 2, 3] => el}
		{? console.log(el)}
	{/}

	/// Данная переменная глобальная,
	/// хоть и объявлена внутри блочной директивы
	{var a = 1 /}
{/}

{template index()}
	{? console.log(foo)} /// 'bar'
{/template}

Директива может использоваться только в глобальной области.

  • Directives
  • Scope

with

Директива задаёт область видимости для поиска свойств объекта.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits Absent Block, logic Not required

Description

Директива позволяет задать “виртуальную” область видимости для объекта, чтобы затем обращаться к его свойствам с помощью специального модификатора контекста @, например:

- var base = {child: {name: 'Moscow'}}

- with base.child
	? console.log(@name) /// Moscow
{var base = {child: {name: 'Moscow'}}}

{with base.child}
	{? console.log(@name)} /// Kobezzza
{/}

С помощью @ можно как получать, так и устанавливать свойства объекту.

- var base = {child: {name: 'Moscow'}}

- with base.child
	? @name = 'Washington'
	? @type = 'city'

? console.log(base.child.name) /// Washington
? console.log(base.child.type) /// city
{var base = {child: {name: 'Moscow'}}}

{with base.child}
	{? console.log(@name)} /// Kobezzza
	{? @name = 'Washington'}
{/}

{console.log(base.child.name)} /// Washington

Любые входные параметры функциональных директив Snakeskin (template, forEach и т.д.) поддерживают короткую запись декларации with.

- namespace demo
- template index(@params)
	{@name} /// params.name
{namespace demo}
{template index(@params)}
	{@name} /// params.name
{/template}

Такая запись эквивалентна:

- namespace demo
- template index(params)
	- with params
		{@name}
{namespace demo}
{template index(params)}
	{with params}
		{@name}
	{/}
{/template}

Можно вкладывать with-блоки друг в друга, например:

- namespace demo
- template index()
	- with params
		{@name} /// params.name
		- with @data
			{@type} /// params.data.type
{namespace demo}
{template index(params)}
	{with params}
		{@name} /// params.name
		{with params}
			{@type} /// params.data.type
		{/}
	{/}
{/template}

The directive can be used anywhere.

  • Directives
  • Vars

var

Директива создаёт переменную/ые с указанным именем и значением.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits : Block, logic Not required

Description

Vars в Snakeskin имеют блочную область видимости и по своей семантике напоминают let из JS ES2015.

Директива var позволяет декларировать сразу несколько переменных через запятую (аналогично как это делается в JS).

Директива начинается с ключевого слова var (или символа :), которое должно сопровождаться списком имён создаваемых переменных (через запятую). Для присвоения значений созданной переменной необходимо поставить символ = после имени.

Самая простая форма выглядит так:

- var a = 1
{var a = 1 /}

Для удобства использования var в классическом синтаксисе существует короткая форма закрытия директивы, например:

/// Обычное закрытие
{var a = 1}{/}

/// Короткая форма закрытия
{var b = 2 /}

В отличии от JS переменные в Snakeskin декларируются только после места декларации.

: a = 2
- if true
	? console.log(a) /// 2
	: a = 1
	? console.log(a) /// 1
{: a = 2 /}
{if true}
	{? console.log(a)} /// 2
	{: a = 1 /}
	{? console.log(a)} /// 1
{/}

Допускается в рамках одного блока создавать переменные с одинаковым именем.

: a = 2
? console.log(a) /// 2
: a = 1
? console.log(a) /// 1
{: a = 2 /}
{? console.log(a)} /// 2
{: a = 1 /}
{? console.log(a)} /// 1

The directive can be used anywhere.

putIn декларация

С помощью ключевого слова putIn можно присвоить переменной подшаблон Snakeskin, однако при такой декларации допускается создавать только одну переменную за раз, например:

- namespace demo
- template index(value)
	: putIn tpl
		- if value !== 404
			< .hello
				Hello world!

		- else
			< .error
				404
{namespace demo}
{template index(value)}
	{: putIn tpl}
		{if value !== 404}
			{< .hello}
				Hello world!

		{else}
			{< .error}
				404
			{/}
		{/}
	{/}
{/template}

Внутри такой декларации можно использовать любые допустимые директивы, например, if, forEach и т.д.

Examples

- namespace demo
- template index(value)
	- if true
		: a = 1
		{a}

	{a} /// Error, a is not defined

	: b = 1, c = 2
	- if true
		{b} /// 1
		{c} /// 2

	{b} /// 1
{namespace demo}
{template index(value)}
	{if true}
		{: a = 1 /}
		{a}
	{/}

	{a} /// Error, a is not defined

	{: b = 1, c = 2 /}
	{if true}
		{b} /// 1
		{c} /// 2
	{/}

	{b} /// 1
{/template}
  • Directives
  • Vars

const

Директива создаёт константу с указанным именем и значением.

Synopsis

Declaration Shorthand Directive type Interpolation
Only within templates or external blocks Not required Inline, text / логическая Not required

Description

Константы Snakeskin не имеют ничего общего с константами из JS ES2015 и служат для других целей. Константы глобальны в рамках своего шаблона, поэтому не может быть 2-х констант с одинаковым именем. Значение константы может меняться по ходу выполнения шаблона.

При декларации константы не требуется специального ключевого слова (хотя допускается), например:

- namespace demo
- template index()
	- val = 'hello'
	{val}
{namespace demo}
{template calc(a, b)}
	{val = 'hello'}
	{val}
{/template}

С логической точки зрения константы Snakeskin - это свойства класса (шаблона), т.е. они доступны в любом месте шаблона и их можно переопределять в дочернем шаблоне. Константа может быть свойством объекта (включая свойство другой константы), например:

- namespace demo
- template index()
	- val = {}
	- val.name = 'Kobezzza'
{namespace demo}
{template calc(a, b)}
	{val = {}}
	{val.name = 'Kobezzza'}
{/template}

После декларации константы станет невозможным в рамках шаблона объявление переменной с таким же именем.

- namespace demo
- template index()
	- val = {}
	- var val = 1 /// Ошибка
{namespace demo}
{template calc(a, b)}
	{val = {}}
	{var val = 1 /} /// Ошибка
{/template}

Константы могут создаваться только внутри шаблонов or внешних блоков.

Распад константы

Если любая функциональная директива содержит параметр с именем равным константе, то он “замещает” константу в рамках своей блочной области видимости, например:

- namespace demo
- template index()
	- val = {}
	- forEach [1, 2] => val
		{val} /// 1, 2
{namespace demo}
{template calc(a, b)}
	{val = {}}
	{forEach [1, 2] => val}
		{val} /// 1, 2
	{/}
{/template}

Вызываемые константы

Если в конце декларации константы поставить символ ?, то её значение сразу же выведется в шаблон.

- namespace demo
- template index()
	< title
		- title = 'Главная страница' ?
{namespace demo}
{template calc(a, b)}
	{< title}
		{title = 'Главная страница' ?}
	{/}
{/template}
  • Directives
  • Vars

global

Директива создаёт супер-глобальную переменную с указанным именем и значением.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits Not required Inline, text / логическая Not required

Description

Супер-глобальная переменная Snakeskin - это свойство объекта Snakeskin.Vars, т.е. такая переменная доступна как из JavaScript, так и во всех файлах шаблонов. Устанавливать такие переменные можно из JS (причём можно до трансляции) или из шаблонов. Основной use-case супер-глобальных переменных - это прокидывание конфига, т.е. некоторый аналог переменных среды в операционной системе.

Задание из JS

Чтобы задать значение супер-глобальной переменной перед непосредственной трансляцией можно использовать параметр vars, а также в любой момент времени допускается вносить изменения напрямую в объект Snakeskin.Vars, например:

Snakeskin.Vars.server = 'localhost';
Snakeskin.Vars.port = '1989';

Задание и чтение из SS

Для задания супер-глобальной переменной из SS можно использовать несколько способов:

  1. Использование директивы global, например:
- global server = 'localhost'
- global port = '1989'
{global server = 'localhost'}
{global port = '1989'}

Вне тела шаблонов можно опустить ключевое слово global:

- server = 'localhost'
- port = '1989'
{server = 'localhost'}
{port = '1989'}

При задании имение допускается использовать скобочную нотацию:

- ['server'] = 'localhost'
- ['port'] = '1989'
{['server'] = 'localhost'}
{['port'] = '1989'}
  1. Использование литеральной формы через модификатор @@, например:
- @@server = 'localhost'
- @@port = '1989'
{@@server = 'localhost'}
{@@port = '1989'}

Такой вариант можно использовать как вне шаблонов, так и внутри их. Литеральная форма также поддерживает скобочную нотацию:

- @@['server'] = 'localhost'
- @@['port'] = '1989'
{@@['server'] = 'localhost'}
{@@['port'] = '1989'}

Чтение

Для чтения супер-глобальных переменных используется модификатор @@, например:

- @@server = 'localhost'
? console.log(@@server)
{@@server = 'localhost'}
{? console.log(@@server)}

Вызываемые переменные

Если в конце декларации супер-глобальной переменной поставить символ ?, то её значение сразу же выведется в шаблон.

- namespace demo
- template index()
	< title
		- @@title = 'Главная страница' ?
{namespace demo}
{template calc(a, b)}
	{< title}
		{@@title = 'Главная страница' ?}
	{/}
{/template}
  • Directives
  • Logic directives

if

Директива if является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в JavaScript.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits Absent Block, logic Not required

Description

Директива позволяет вашему шаблону в зависимости от условий выполнить некоторую логику или сгенерировать фрагмент шаблона, основываясь на значении переменной or выражения.

Директива начинается с ключевого слова if, которое должно сопровождаться выражением (заключать выражение в скобки не обязательно).

Самая простая форма выглядит так:

- if true
	Hello world!
{if true}
	Hello world!
{/if}

The directive can be used anywhere. Вместе с основной директивой можно использовать дополнительные:

  1. else - аналог else в JS;
  2. else if - аналог else if в JS;
  3. else unless - аналог else if (!(...)) в JS.

Examples

- namespace demo
- template index(value)
	< .result
		- if val > 3
			< .success
				Значение больше чем 3.

		- else if val < 3
			< .fail
				Значение меньше чем 3.

		- else
			< .error
				Значение рано 3.
{namespace demo}
{template index(value)}
	{< .result}
		{if val > 3}
			{< .success}
				Значение больше чем 3.
			{/}

		{else if val < 3}
			{< .fail}
				Значение меньше чем 3.
			{/}

		{else}
			{< .error}
				Значение рано 3.
			{/}
		{/}
	{/}
{/template}
  • Directives
  • Logic directives

unless

Директива unless является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в CoffeeScript.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits Absent Block, logic Not required

Description

Директива является инвертной формой if, т.е. если if блок выполнится только в том случае когда условное выражение будет приведено к true, то unless выполнится в случае false.

Директива позволяет вашему шаблону в зависимости от условий выполнить некоторую логику или сгенерировать фрагмент шаблона, основываясь на значении переменной or выражения.

Директива начинается с ключевого слова unless, которое должно сопровождаться выражением (заключать выражение в скобки не обязательно).

Самая простая форма выглядит так:

- unless false
	Hello world!
{unless false}
	Hello world!
{/}

The directive can be used anywhere. Вместе с основной директивой можно использовать дополнительные:

  1. else - аналог else в JS;
  2. else if - аналог else if в JS;
  3. else unless - аналог else if (!(...)) в JS.

Examples

- namespace demo
- template index(value)
	< .result
		- unless val >= 3
			< .success
				Значение меньше чем 3.

		- else unless val <= 3
			< .fail
				Значение больше чем 3.

		- else
			< .error
				Значение рано 3.
{namespace demo}
{template index(value)}
	{< .result}
		{unless val >= 3}
			{< .success}
				Значение меньше чем 3.

		{else unless val <= 3}
			{< .fail}
				Значение больше чем 3.

		{else}
			{< .error}
				Значение рано 3.
		{/}
	{/}
{/template}
  • Directives
  • Logic directives

switch

Директива switch является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в JavaScript (break ставится автоматически после каждого блока case).

Synopsis

Declaration Shorthand Directive type Interpolation
No limits > (для case) Block, logic Not required

Description

Подобно if or unless директива позволяет вашему шаблону в зависимости от условий выполнить некоторую логику или сгенерировать фрагмент шаблона, основываясь на значении переменной or выражения, но предоставляет более удобный синтаксис когда нужно сравнить выражение сразу с несколькими вариантами.

Директива начинается с ключевого слова switch, которое должно сопровождаться выражением (заключать выражение в скобки не обязательно), а внутри директивы должны использоваться вспомогательные директивы case и/или default. The directive can be used anywhere.

Директива case начинается с ключевого слова case (или символа >), а после должно следовать выражение выражение для сравнения со switch. В отличии от реализации case в JS - оператор break ставиться автоматически после каждого блока.

Декларация default полностью идентичная аналогичной в JS.

Examples

- namespace demo
- template index(value)
	< .result
		- switch value
			- case 1
				< .value-1
					value == 1

			- case 2
				< .value-2
					value == 2

			> 3
				< .value-3
					value == 3

			- default
				Условие, которое выполнится по умолчанию.
{namespace demo}
{template index(value)}
	{< .result}
		{switch value}
			{case 1}
				{< .value-1}
					value == 1
				{/}
			{/}

			{case 2}
				{< .value-2}
					value == 2
				{/}
			{/}

			{> 3}
				{< .value-3}
					value == 3
				{/}
			{/}

			{default}
				Условие, которое выполнится по умолчанию.
			{/}
		{/}
	{/}
{/template}
  • Directives
  • Циклы

for

Директива for является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в JavaScript.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits Absent Block, logic Not required

Description

Директива создаёт цикл, т.е. блок цикла будет выполняется до тех пор, пока управляющее логическое выражение не станет ложным or пока цикл не будет сброшен вручную. Директива проводит инициализацию перед первым шагом цикла. Затем выполняется проверка условия цикла, и в конце каждой итерации происходит изменение управляющей переменной.

for инициализация; логическое выражение (условие); шаг (итерация)
	команда

Самая простая форма выглядит так:

- for var i = 0; i < 3; i++
	Итерация - {i}
{for var i = 0; i < 3; i++}
	Итерация - {i}
{/for}

The directive can be used anywhere. Для управления циклом внутри блока можно использовать директивы:

  1. break - полностью прерывает выполнение цикла;
  2. continue - прерывает текущую итерацию и переходит к следующей.

Examples

Простой перебор массива

- namespace demo
- template index()
	- var arr = [1, 2, 3]

	/// Т.к. переменные Snakeskin имеют блочную область видимости,
	/// то i будет доступен только внутри for
	- for var i = 0; i < arr.length; i++
		{arr[i]}
{namespace demo}
{template index()}
	{var arr = [1, 2, 3] /}

	/// Т.к. переменные Snakeskin имеют блочную область видимости,
	/// то i будет доступен только внутри for
	{for var i = 0; i < arr.length; i++}
		{arr[i]}
	{/}
{/template}

Простой перебор объекта

- namespace demo
- template index()
	- var obj = {a: 1, b: 2}

	/// Т.к. переменные Snakeskin имеют блочную область видимости,
	/// то key будет доступен только внутри for
	- for var key in obj
		{key}
{namespace demo}
{template index()}
	{var obj = {a: 1, b: 2} /}

	/// Т.к. переменные Snakeskin имеют блочную область видимости,
	/// то key будет доступен только внутри for
	{for var key in obj}
		{key}
	{/}
{/template}

Сброс итераций

- namespace demo
- template index()
	- var obj = {a: 1, b: 2}
	- for var key in obj
		- if !obj.hasOwnProperty(key)
			- continue

		{key}
		- break
{namespace demo}
{template index()}
	{var obj = {a: 1, b: 2} /}
	{for var key in obj}
		{if !obj.hasOwnProperty(key)}
			{continue}
		{/}

		{key}
		{break}
	{/}
{/template}
  • Directives
  • Циклы

while

Директива while является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в JavaScript.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits Absent Block, logic Not required

Description

Директива создаёт цикл, т.е. блок цикла будет выполняется до тех пор, пока управляющее логическое выражение не станет ложным or пока цикл не будет сброшен вручную.

Директива начинается с ключевого слова while, которое должно сопровождаться выражением (заключать выражение в скобки не обязательно).

Самая простая форма выглядит так:

- var i = 3
- while i--
	{i}
{var i = 3 /}
{while i--}
	{i}
{/while}

The directive can be used anywhere. Для управления циклом внутри блока можно использовать директивы:

  1. break - полностью прерывает выполнение цикла;
  2. continue - прерывает текущую итерацию и переходит к следующей.

Examples

Перебор массива

- namespace demo
- template index()
	- var arr = [1, 2, 3]
	- while arr.length
		{arr[0]}
		? arr.shift()
{namespace demo}
{template index()}
	{var arr = [1, 2, 3] /}
	{while arr.length}
		{arr[0]}
		{? arr.shift()}
	{/}
{/template}

Сброс итераций

- namespace demo
- template index()
	- var i = 3
	- while i--
		{i}
		- break
{namespace demo}
{template index()}
	{var i = 3 /}
	{while i--}
		{i}
		{break}
	{/}
{/template}
  • Directives
  • Циклы

do

Директива do является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в JavaScript.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits Absent Block, logic Not required

Description

Директива создаёт цикл, т.е. блок цикла будет выполняется до тех пор, пока управляющее логическое выражение не станет ложным or пока цикл не будет сброшен вручную. Отличие do от while состоит в том, что цикл do-while выполняется по крайней мере один раз, даже если условие изначально ложно.

Директива начинается с ключевого слова do, а выражение для проверки идёт после вложенного блока цикла вместе с директивой while (заключать выражение в скобки не обязательно).

Самая простая форма выглядит так:

- var i = 3
- do
	{i}
- while i--
{var i = 3 /}
{do}
	{i}
{while i--}

The directive can be used anywhere. Для управления циклом внутри блока можно использовать директивы:

  1. break - полностью прерывает выполнение цикла;
  2. continue - прерывает текущую итерацию и переходит к следующей.

Examples

Перебор массива

- namespace demo
- template index()
	- var arr = [1, 2, 3]
	- do
		{arr[0]}
		? arr.shift()
	- while arr.length
{namespace demo}
{template index()}
	{var arr = [1, 2, 3] /}
	{do}
		{arr[0]}
		{? arr.shift()}
	{while arr.length}
{/template}

Бесконечный цикл

- namespace demo
- template index()
	- var i = 0
	- do
		{i}
		? i++
{namespace demo}
{template index()}
	{var i = 0 /}
	{do}
		{i}
		{? i++}
	{/}
{/template}

Сброс итераций

- namespace demo
- template index()
	- var i = 3
	- do
		{i}
		- break
	- while i--
{namespace demo}
{template index()}
	{var i = 3 /}
	{do}
		{i}
		{break}
	{while i--}
{/template}
  • Directives
  • Iterators

forEach

Директива итерирует заданный объект (с учётом hasOwnProperty) or массив.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits Absent Block, logic, function Not required

Description

Директива итерирует заданное значение с помощью функции Snakeskin.forEach и может работать как с объектами, так и с массивами.

Общая форма директивы следующая:

forEach ссылка на объект or сам объект => параметры функции через запятую
	команда

For example:

- forEach [1, 2, 3] => el
	{el}
{forEach [1, 2, 3] => el}
	{el}
{/forEach}

Директива может использоваться как внутри шаблонов or других директив, так и в глобальной области, а т.к. forEach является функциональной директивой, то он реализует стандартный механизм декларации параметров.

Для управления обходом внутри итератора можно использовать директивы:

  1. break - полностью прерывает выполнение итератора;
  2. continue - прерывает текущую итерацию и переходит к следующей.

Параметры для массива

  1. Значение элемента;
  2. Номер итерации;
  3. Ссылка на итерируемый массив;
  4. Объект:
    • isFirst - является ли элемент первым;
    • isLast - является ли элемент последним;
    • length - длина массива.

Параметры для таблицы

  1. Значение элемента;
  2. Ключ;
  3. Ссылка на итерируемый объект;
  4. Объект:
    • i - номер итерации;
    • isFirst - является ли элемент первым;
    • isLast - является ли элемент последним;
    • length - длина массива.

forEach и return

Несмотря на то что forEach использует функцию при обходе объекта, поведение директивы приближено к поведению цикла, т.е. внутри можно использовать директивы break, continue и return, принцип работы которых не будет отличаться, например:

- namespace demo

/// Шаблон вернёт 1
- template index()
	- forEach [1, 2, 3] => el
		- return el
	Hello world
{namespace demo

/// Шаблон вернёт 1
{template index()}
	{forEach [1, 2, 3] => el}
		{return el /}
	Hello world

Examples

Простой перебор массива

- namespace demo
- template index()
	- var arr = [1, 2, 3]
	- forEach arr => el
		{el}
{namespace demo}
{template index()}
	{var arr = [1, 2, 3] /}
	{forEach arr => el}
		{el}
	{/}
{/template}

Перебор массива с заданием with в списке входных параметров

- namespace demo
- template index()
	- var arr = [{name: 'Koba'}, {name: 'Over'}]
	- forEach arr => @el
		{@name}
{namespace demo}
{template index()}
	{var arr = [{name: 'Koba'}, {name: 'Over'}] /}
	{forEach arr => @el}
		{@name}
	{/}
{/template}

Простой перебор объекта

- namespace demo
- template index()
	- var obj = {a: 1, b: 2}
	- forEach obj => el, key
		{el} {key}
{namespace demo}
{template index()}
	{var obj = {a: 1, b: 2} /}
	{forEach obj => el, key}
		{el} {key}
	{/}
{/template}

Сброс итераций

- namespace demo
- template index()
	- forEach [1, 2, 3] => el
		{el}
		- break
{namespace demo}
{template index()}
	{forEach [1, 2, 3] => el}
		{el}
		{break}
	{/}
{/template}
  • Directives
  • Iterators

forIn

Директива итерирует заданный объект (без учёта hasOwnProperty).

Synopsis

Declaration Shorthand Directive type Interpolation
No limits Absent Block, logic, function Not required

Description

Директива итерирует заданный объект с помощью функции Snakeskin.forIn.

Общая форма директивы следующая:

forIn ссылка на объект or сам объект => параметры функции через запятую
	команда

For example:

- forIn {a: 1, b: 2} => el
	{el}
{forIn {a: 1, b: 2} => el}
	{el}
{/forIn}

Директива может использоваться как внутри шаблонов or других директив, так и в глобальной области, а т.к. forIn является функциональной директивой, то он реализует стандартный механизм декларации параметров.

Для управления обходом внутри итератора можно использовать директивы:

  1. break - полностью прерывает выполнение итератора;
  2. continue - прерывает текущую итерацию и переходит к следующей.

Параметры функции итератора

  1. Значение элемента;
  2. Ключ;
  3. Ссылка на итерируемый объект;
  4. Объект:
    • i - номер итерации;
    • isFirst - является ли элемент первым;
    • isLast - является ли элемент последним;
    • length - длина массива.

forIn и return

Несмотря на то что forIn использует функцию при обходе объекта, поведение директивы приближено к поведению цикла, т.е. внутри можно использовать директивы break, continue и return, принцип работы которых не будет отличаться, например:

- namespace demo

/// Шаблон вернёт 1
- template index()
	- forIn {a: 1, b: 2} => el
		- return el
	Hello world
{namespace demo

/// Шаблон вернёт 1
{template index()}
	{forIn {a: 1, b: 2} => el}
		{return el /}
	Hello world

Examples

Простой перебор

- namespace demo
- template index()
	- var obj = {a: 1, b: 2}
	- forIn obj => el, key
		{el} {key}
{namespace demo}
{template index()}
	{var obj = {a: 1, b: 2} /}
	{forIn obj => el, key}
		{el} {key}
	{/}
{/template}

Перебор с заданием with в списке входных параметров

- namespace demo
- template index()
	- var obj = {a: {name: 'Koba'}, b: {name: 'Over'}}
	- forIn obj => @el
		{@name}
{namespace demo}
{template index()}
	{var obj = {a: {name: 'Koba'}, b: {name: 'Over'}} /}
	{forEach obj => @el}
		{@name}
	{/}
{/template}

Сброс итераций

- namespace demo
- template index()
	- forEach {a: 1, b: 2, c: 3} => el
		{el}
		- break
{namespace demo}
{template index()}
	{forEach {a: 1, b: 2, c: 3} => el}
		{el}
		{break}
	{/}
{/template}
  • Directives
  • Working with exceptions

try

Директива try является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в JavaScript.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits Absent Block, logic Not required

Description

Директива позволяет вашему шаблону отлавливать и обрабатывать исключения, которые могут возникать по ходу выполнения программы на Snakeskin.

Самая простая форма выглядит так:

- try
	? 1 2
{try}
	{1 2}
{/try}

The directive can be used anywhere. Вместе с основной директивой можно использовать дополнительные:

  1. catch - аналог catch в JS (функциональная директива);
  2. finally - аналог finally в JS.

Examples

- namespace demo
- template index(value)
	< .result
		- try
			? value = JSON.parse(value)

		- catch err
			? console.error(err)

		- finally
			Hello world!
{namespace demo}
{template index(value)}
	{< .result}
		{try}
			{? value = JSON.parse(value)}

		{catch err}
			{? console.error(err)}

		{finally}
			Hello world!
		{/}
	{/}
{/template}
  • Directives
  • Working with exceptions

throw

Директива throw является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в JavaScript.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits Absent Inline, logic Not required

Description

Директива генерирует заданное исключение и начинается с ключевого слова throw, которое должно сопровождаться выражением. Самая простая форма выглядит так:

- throw new Error('Ошибка')
{throw new Error('Ошибка')}

The directive can be used anywhere.

Examples

- namespace demo
- template index(value)
	< .result
		- if value > 1
			- throw new Error('Invalid value')
{namespace demo}
{template index(value)}
	{< .result}
		{if value > 1}
			{throw new Error('Invalid value')}
		{/}
	{/}
{/template}
  • Directives
  • Working with whitespace

ignoreWhitespaces

The directive declares that all subsequent whitespace characters until first non-whitespace should be ignored.

Synopsis

Declaration Shorthand Directive type Interpolation
Only within templates or external blocks & Inline, logic Not required

Examples

- namespace demo
- template index(value, area)
	Hello{&}             World Bar
{namespace demo}
{template index(value, area)}
	Hello{&}             World Bar
{/template}

Output:

HelloWorld Bar
  • Directives
  • Working with whitespace

ignoreAllWhitespaces

The directive declares that all nested whitespace characters should be ignored.

Synopsis

Declaration Shorthand Directive type Interpolation
Only within templates or external blocks &+ Block, logic Not required

Examples

- namespace demo
- template index(value, area)
	&+
		Hello             World Bar
{namespace demo}
{template index(value, area)}
	{&+}
		Hello             World Bar
	{/}
{/template}

Output:

HelloWorldBar
  • Directives
  • Working with whitespace

unIgnoreAllWhitespaces

The directive declares that all nested whitespace characters should not be ignored (usually used in conjunction with ignoreAllWhitespaces).

Synopsis

Declaration Shorthand Directive type Interpolation
Only within templates or external blocks &- Block, logic Not required

Examples

- namespace demo
- template index(value, area)
	&+
		Hello             World Bar
		&-
			Hello             World Bar
{namespace demo}
{template index(value, area)}
	{&+}
		Hello             World Bar
		{&-}
			Hello             World Bar
		{/}
	{/}
{/template}

Output:

HelloWorldBarHello World Bar
  • Directives
  • Working with whitespace

sp

The directive puts in a template the space character (only relevant for Jade-Like).

Synopsis

Declaration Shorthand Directive type Interpolation
Only within templates or external blocks \ Inline, text Not required

Examples

- namespace demo
- template index(value, area)
	< .foo
	\
	< .bar

Output:

<div class="foo"></div> <div class="bar"></div>
  • Directives
  • Working with HTML/XML

doctype

Директива вставляет в шаблон код декларации заданного doctype, а также определяет правила форматирования для тегов и атрибутов.

Synopsis

Declaration Shorthand Directive type Interpolation
Only within templates or external blocks Absent Inline, text Не поддерживается

Description

Директива предназначена для указания типа текущего документа - DTD (document type definition, описание типа документа). Это необходимо, чтобы клиент/парсер понимал, как следует интерпретировать текущую страницу, а также указывает Snakeskin какие правила он должен применять при генерации кода тегов и атрибутов.

Директива может использоваться только внутри шаблонов or внешних блоков.

Таблица обозначений

html

<!DOCTYPE html>

xml

<?xml version="1.0" encoding="utf-8" ?>

transitional

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

strict

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

frameset

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">

1.1

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

basic

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">

mobile

<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">

mathml 1.0

<!DOCTYPE math SYSTEM "http://www.w3.org/Math/DTD/mathml1/mathml.dtd">

mathml 2.0

<!DOCTYPE math PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">

svg 1.0

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">

svg 1.1 full

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

svg 1.1 basic

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Basic//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-basic.dtd">

svg 1.1 tiny

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">

Examples

Использование значения по умолчанию (html5)

- namespace demo
- template index(value)
	- doctype
{namespace demo}
{template index(value)}
	{doctype}
{/template}

Явное указание типа

- namespace demo
- template index(value)
	- doctype xml
{namespace demo}
{template index(value)}
	{doctype xml}
{/template}
  • Directives
  • Working with HTML/XML

attr

Директива вставляет в шаблон код декларации HTML/XML атрибута по заданным параметрам.

Synopsis

Declaration Shorthand Directive type Interpolation
Only within templates or external blocks Absent Inline, text Supported

Description

Директива attr обычно используется для задания атрибутов вместе с директивой tag. Общая форма директивы следующая:

attr название атрибута = значение атрибута

For example:

- attr foo = bar
{attr foo = bar}

Обратите внимание, что крайние пробелы у символа = важны, иначе он трактуется как простой текст. Директива может использоваться только внутри шаблонов or внешних блоков.

Множественное задание атрибутов

Если необходимо задать несколько атрибутов, то нужно использовать специальный разделитель |, например:

- attr foo = bar | baz = bla
{attr foo = bar | baz = bla}

Обратите внимание, что крайние пробелы у символа | важны, иначе он трактуется как простой текст.

- attr foo = bar|baz=bla
{attr foo = bar|baz=bla}

Атрибуты с пустым значением

Если нужно задать атрибут с пустым значением, то достаточно просто ничего не писать после знака присвоения, например:

- attr alt =
{attr alt =}

Отрендерится как:

alt=""

Инлайновые атрибуты

Для задания “инлайновых” HTML атрибутов, например, <input disabled> нужно просто опустить знак присвоения.

- attr disabled
{attr disabled}

Задание data- атрибутов

Для декларации data- атрибутов поддерживается короткий синтаксис:

- attr -title = bla | -desc-field = bar
{attr -title = bla | -desc-field = bar}

Однако можно писать и полную форму:

- attr data-title = bla
{attr data-title = bla}

Группы атрибутов

В Snakeskin есть универсальный синтаксис для создания групп атрибутов с автоматическим добавлением указанного префикса, общая форма следующая:

attr опциональный префикс(( название атрибута = значение атрибута ))

For example:

- attr ng-(( repeat = el in data | bind = bla ))
{attr ng-(( repeat = el in data | bind = bla ))}

Отрендерится как:

ng-repeat="el in data" ng-bind="bla"

Обратите внимание, что крайние пробелы у символов (( и )) важны, иначе они трактуется как простой текст. Также следует отметить, что при комбинировании групп атрибутов с другими группами не нужно ставить специальный разделитель, например:

- attr ng-(( repeat = foo of bla )) (( baz = bar )) hello = world | foo = bar
{attr ng-(( repeat = foo of bla )) (( baz = bar )) hello = world | foo = bar}

Интерполяция

Для передачи значений Snakeskin внутрь директивы используется стандартный механизм интерполяции, например:

- var name = 'foo'
- attr ${name} = ${1 + 2}
{var name = 'foo' /}
{attr ${name} = ${1 + 2}}

Допускается смешивать интерполяцию с обычной декларацией:

- var name = 'foo'
- attr ${name}-bar = ${1 + 2} hello
{var name = 'foo' /}
{attr ${name}-bar = ${1 + 2} hello}

Интерполяция объекта

Snakeskin позволяет используя механизм интерполяции задать атрибуты с помощью объекта, где ключом является название атрибута or группы.

- var attrs = {foo: 'bar', 'ng-': {repeat: 'el in data'}}
- attr ${attrs}
{var attrs = {foo: 'bar', 'ng-': {repeat: 'el in data'}} /}
{attr ${attrs}}

Чтобы сделать атрибут “инлайновым” нужно использовать специальную константу TRUE:

- var attrs = {disabled: TRUE}
- attr ${attrs}
{var attrs = {disabled: TRUE} /}
{attr ${attrs}}

Отрендерится как:

disabled

А чтобы исключить, то нужно использовать константу FALSE:

- var attrs = {disabled: FALSE}
- attr ${attrs}
{var attrs = {disabled: FALSE} /}
{attr ${attrs}}

Значение ключа автоматически переводится из camelCase в dash-style, например:

- attr ${{fooBarBla: 'baz'}}
{attr ${{fooBarBla: 'baz'}}}

Отрендерится как:

foo-bar-bla="baz"

Char escaping

Для экранирования спецсимволов директивы используется символ \, например:

- attr foo = bar \= bla
{attr foo = bar \= bla}
  • Directives
  • Working with HTML/XML

tag

Директива вставляет в шаблон код декларации HTML/XML тега по заданным параметрам.

Synopsis

Declaration Shorthand Directive type Interpolation
Only within templates or external blocks < Block, text Supported

Description

Директива tag является универсальным инструментом для генерации XML подобных структур. Общая форма директивы следующая:

tag название директивы

For example:

- tag span
< span
{tag span}{/tag}
{< span}{/}

При использовании tag в классическом синтаксисе существует короткая форма закрытия директивы, например:

/// Обычное закрытие
{tag input type = text}{/}

/// Короткая форма закрытия
{tag input type = text /}

Директива может использоваться только внутри шаблонов or внешних блоков.

Создание элемента с заданием классов и ИД

Для удобного задания классов и ИД-а в tag используется синтаксис селекторов CSS, например:

< span#baz.foo.bar
/// Если не указать имя создаваемого тега,
/// то будет использоваться div
< .bla
{< span#baz.foo.bar}{/}
/// Если не указать имя создаваемого тега,
/// то будет использоваться div
{< .bla}{/}

Задание произвольных атрибутов

Директива tag поддерживает задание атрибутов с помощью attr, например:

< input value = foo | disabled
{< input value = foo | disabled /}

Отрендерится как:

<input value="foo" disabled>

Ссылки на родительский класс

В Snakeskin существует специальный механизм получения значения родительского класса в дочернем теге, который называется “липкая ссылка”. Принцип работы следующий: если при декларации тега задать имя класса, которое начинается с символа &, то он будет заменён на ближайший родительский класс, который декларировался без этого символа, например:

< .foo
	< .&__bar
	< .&__bla
{< .foo}
	{< .&__bar}{/}
	{< .&__bla}{/}
{/}

Отрендерится как:

<div class="foo">
	<div class="foo__bar"></div>
	<div class="foo__bla"></div>
</div>

Ссылка на родительский класс в произвольном атрибуте

Альтернативным способом получения липкой ссылки является вызов внутренней переменной шаблона $class, например:

< .foo value = ${$class}
{< .foo value = ${$class}}{/}

Отрендерится как:

<div class="foo" value="foo"></div>

Локальные ссылки

Если поместить декларацию класса в специальную конструкцию [...], то классы заданные внутри такого блока не будут запоминаться как липкая ссылка, а также плейсхолдер & будет ссылаться на ближайший по иерархии вложенности класс слева.

< .b-button[.g-helper]
	< button.&__elem[.&_focused_true]
{< .b-button[.g-helper]}
	{< button.&__elem[.&_focused_true]}{/}
{/}

Отрендерится как:

<div class="b-button g-helper">
	<button class="b-button__elem b-button__elem_focused_true"></button>
</div>

Тег-плейсходер

Специальный тег ? существует только на этапе трансляции и не включается в конечный код, например:

< ?.b-button
	< button.&__elem
{< ?.b-button}
	{< button.&__elem}{/}
{/}

Отрендерится как:

<button class="b-button__elem"></button>

Интерполяция

Для передачи значений Snakeskin внутрь директивы используется стандартный механизм интерполяции, например:

- var name = 'span'
< ${name}
{var name = 'foo' /}
{< ${name}}{/}

Допускается смешивать интерполяцию с обычной декларацией:

- var name = 'foo'
< .${name}-bla.bar
{var name = 'foo' /}
{< .${name}-bla.bar}{/}

Для интерполяции в атрибутах используется механизмы attr.

Интерполяция и тег-плейсхолдер

< ${'?'}.b-button
	< button.&__elem
{< ${'?'}.b-button}
	{< button.&__elem}{/}
{/}

Отрендерится как:

<button class="b-button__elem"></button>

“Инлайновые” теги

В HTML ряд тегов не требуют закрывающей части (</tag>), например, input or meta, причём если в XHTML такие теги закрываются явно, например:

<input type="text" />

То в HTML это можно опустить:

<input type="text">

Snakeskin знает про такие теги, а способ их закрытия зависит от выбранного doctype. Правила декларации заданы в объекте Snakeskin.inlineTags, структура следующая:

Snakeskin.inlineTags = {
	// Название используемого doctype
	'html': {
		// Тег br ставится инлайновым
		'br': true,

		// Тег input ставится инлайновым,
		// причём если вставить содержимое в такой тег, например,
		//
		// < input
		//   Hello world!
		//
		// то оно поставится как значение атрибута value
		'input': 'value'
	}
}

Если для заданного doctype нет своей схемы тегов, то используется html.

Локальная декларация инлайновых тегов

С помощью модификатора !inline любой тег можно сделать принудительно инлайновым, например:

< textarea!inline
{< textarea!inline /}

Отрендерится как:

<textarea>

Также можно задать локальную схему тегов, которая будет распространяться на все вложенные теги:

- var val = {textarea: true}
< div!inline=val
	< textarea
{var val = {textarea: true} /}
{< div!inline=val}
	{< textarea /}
{/}

Отрендерится как:

<div><textarea></div>

Полиморфизм тегов

При разработке шаблонов часто бывает такая ситуация, когда имя создаваемого тега зависит от различных параметров, и для решения такой задачи удобно использовать интерполяцию, например:

- namespace demo
- template index(value, area)
	< ${area ? 'textarea' : 'input'}.input
		{value}
{namespace demo}
{template index(value, area)}
	{< ${area ? 'textarea' : 'input'}.input}
		{value}
	{/}
{/template}

Snakeskin поймёт такую конструкцию и в случае textarea создаст код вида:

<textarea class="input">значение</textarea>

А в случае input:

<input class="input" value="значение">

Char escaping

Для экранирования спецсимволов директивы используется символ \, например:

< .bla foo = bar \= bla
{< .bla foo = bar \= bla}{/}
  • Directives
  • Working with HTML/XML

script

Директива вставляет в шаблон код декларации тега <script> с заданными параметрами.

Synopsis

Declaration Shorthand Directive type Interpolation
Only within templates or external blocks Absent Block, text Supported

Description

Директива предназначена для более удобного задания тегов <script> и может использоваться только внутри шаблонов или внешних блоков.

При использовании script в классическом синтаксисе существует короткая форма закрытия директивы, например:

/// Обычное закрытие
{script js src = foo.js}{/}

/// Короткая форма закрытия
{script js src = foo.js /}

Таблица обозначений

js

text/javascript

dart

application/dart

coffee

application/coffeescript

ts

application/typescript

cljs

application/clojurescript

ls

application/livescript

json

application/json

html

text/html

ss

text/x-snakeskin-template

Examples

Использование значения по умолчанию (js)

- namespace demo
- template index()
	# script
		var a = {};
{namespace demo}
{template index()}
	#{script}
		var a = {};
	#{/}
{/template}

Явное указание типа

- namespace demo
- template index()
	# script ts
		var a = {};
{namespace demo}
{template index()}
	#{script ts}
		var a = {};
	#{/}
{/template}

Указание собственного типа

- namespace demo
- template index()
	# script application/myscript
		var a = {};
{namespace demo}
{template index()}
	#{script application/myscript}
		var a = {};
	#{/}
{/template}

Задание произвольных атрибутов

(используется синтаксис attr)

- namespace demo
- template index()
	# script js class = foo
		var a = {};
{namespace demo}
{template index()}
	#{script js class = foo}
		var a = {};
	#{/}
{/template}
  • Directives
  • Working with HTML/XML

style

Директива вставляет в шаблон код декларации тега <style> с заданными параметрами.

Synopsis

Declaration Shorthand Directive type Interpolation
Only within templates or external blocks Absent Block, text Supported

Description

Директива предназначена для более удобного задания тегов <style> и может использоваться только внутри шаблонов или внешних блоков.

Таблица обозначений

css

text/css

Examples

Использование значения по умолчанию (css)

- namespace demo
- template index()
	# style
		.foo {
			color: red;
		}
{namespace demo}
{template index()}
	#{style}
		.foo {
			color: red;
		}
	#{/}
{/template}

Явное указание типа

- namespace demo
- template index()
	# style css
		.foo {
			color: red;
		}
{namespace demo}
{template index()}
	#{style css}
		.foo {
			color: red;
		}
	#{/}
{/template}

Указание собственного типа

- namespace demo
- template index()
	# style text/stylus
		.foo
			color red
{namespace demo}
{template index()}
	#{style text/stylus}
		.foo
			color red
	#{/}
{/template}

Задание произвольных атрибутов

(используется синтаксис attr)

- namespace demo
- template index()
	# style css class = foo
		.foo {
			color: red;
		}
{namespace demo}
{template index()}
	#{style css class = foo}
		.foo {
			color: red;
		}
	#{/}
{/template}
  • Directives
  • Working with HTML/XML

link

Директива вставляет в шаблон код декларации тега <link> с заданными параметрами.

Synopsis

Declaration Shorthand Directive type Interpolation
Only within templates or external blocks Absent Block, text Supported

Description

Директива предназначена для более удобного задания тегов <link> и может использоваться только внутри шаблонов или внешних блоков.

При использовании link в классическом синтаксисе существует короткая форма закрытия директивы, например:

/// Обычное закрытие
{link css href = foo.css}{/}

/// Короткая форма закрытия
{link css href = foo.css /}

Таблица обозначений

css

type="text/css" rel="stylesheet"

acss

type="text/css" rel="alternate stylesheet"

icon

type="image/x-icon" rel="icon"

Examples

Использование значения по умолчанию css

- namespace demo
- template index()
	- link
		http://bar.com/foo.css
{namespace demo}
{template index()}
	{link}http://bar.com/foo.css{/}
{/template}

Явное указание типа

- namespace demo
- template index()
	- link acss
		http://bar.com/foo.css
{namespace demo}
{template index()}
	{link acss}http://bar.com/foo.css{/}
{/template}

Указание собственного типа

- namespace demo
- template index()
	- link (( type = text/stylus | rel = stylesheet ))
		http://bar.com/foo.styl
{namespace demo}
{template index()}
	{link (( type = text/stylus | rel = stylesheet ))}http://bar.com/foo.styl{/}
{/template}

Задание произвольных атрибутов

(используется синтаксис attr)

- namespace demo
- template index()
	- link css rel = alternate stylesheet
		http://bar.com/foo.css
{namespace demo}
{template index()}
	{link css rel = alternate stylesheet}http://bar.com/foo.css{/}
{/template}
  • Directives
  • Working with HTML/XML

comment

Директива вставляет в шаблон код декларации XML комментария с заданными параметрами.

Synopsis

Declaration Shorthand Directive type Interpolation
Only within templates or external blocks <! Block, text Supported

Description

Директива предназначена для более удобного задания тегов XML комментариев и может использоваться только внутри шаблонов или внешних блоков.

Examples

Простое использование

- namespace demo
- template index()
	<!
		Hello world!
{namespace demo}
{template index()}
	{<!}Hello world!{/}
{/template}

Задание условного комментария

- namespace demo
- template index()
	<! IE 7
		Hello world!
{namespace demo}
{template index()}
	{<! IE 7}Hello world!{/}
{/template}

Отрендерится как:

<!--[if IE 7]>Hello world!<![endif]-->

Интерполяция

- namespace demo
- template index()
	- var ie = 7
	<! IE ${ie}
		Hello world!
{namespace demo}
{template index()}
	{var ie = 7 /}
	{<! IE ${ie}}Hello world!{/}
{/template}
  • Directives
  • Char escaping

cdata

Директива задаёт блок текста, который вырезается до трансляции, а затем вставляется без изменений в результирующую функцию (пробельные символы также остаются неизменны).

Synopsis

Declaration Shorthand Directive type Interpolation
Only within templates or external blocks Absent Block, text Не поддерживается

Description

Директива используется для экранирования больших фрагментов текста, которые должны вставляться “как есть”. Декларация директивы возможно только с помощью расширенного синтаксиса. Закрывающий end может быть либо #{end cdata}, либо #{/cdata}. Директива может использоваться только внутри шаблонов or внешних блоков.

Examples

- namespace demo
- template index()
	#{cdata}
		- if true
			Hello world!
	#{/cdata}
{namespace demo}
{template index()}
	#{cdata}
		{if true}
			Hello world!
		{/}
	#{/cdata}
{/template}
  • Directives
  • Char escaping

literal

Директива задаёт блок текста, который вставляется без изменений в результирующую функцию, а также будет врапиться специальными текстовыми символами согласно параметру literalBounds.

Synopsis

Declaration Shorthand Directive type Interpolation
Only within templates or external blocks Not required Inline, text Supported

Description

Директива используется для интеграции шаблонов Snakeskin с другими шаблонами. Директива может использоваться только внутри шаблонов or внешних блоков.

Examples

Простое использование

- namespace demo
- template index()
	{{ Hello }}
{namespace demo}
{template index()
	{{ Hello }}
{/template}

Отрендерится как:

{{ Hello }}

Интерполяция

Для передачи значений Snakeskin внутрь директивы используется стандартный механизм интерполяции.

- namespace demo
- template index()
	{{ Hello${1 + 2} }}
{namespace demo}
{template index()
	{{ Hello${1 + 2} }}
{/template}

Отрендерится как:

{{ Hello3 }}

Задание literalBounds

- namespace demo
- template index() @= literalBounds ['<?php', '?>']
	{{ Hello }}
{namespace demo}
{template index() @= literalBounds ['<?php', '?>']}
	{{ Hello }}
{/template}

Отрендерится как:

<?php Hello ?>
  • Directives
  • Modules

include

Директива включает содержимое заданного файла-шаблона в текущий.

Synopsis

Declaration Shorthand Directive type Interpolation
Вне шаблонов or внешних блоков Absent Inline, logic Not required

Description

Любой Snakeskin файл может включать в себя другие SS файлы, т.е. Snakeskin позволяет разбить код на логические части и создавать подключаемые библиотеки (подобно std.ss) и т.д. Чтобы подключить другой файл используется специальная директива include, которая начинается с одноименного ключевого слова и должна сопровождаться выражением, где задаётся путь к подключаемому файлу, например:

math.ss

- namespace math
- template calc(a, b)
	{a + b}
{namespace math}
{template calc(a, b)}
	{a + b}
{/template}

app.ss

- namespace app
- include './math'

- template index()
	/// При вызове шаблона из другого файла
	/// нужно обязательно указывать пространство имён
	+= math.calc(1, 2)
{namespace app}
{include './math'}

{template index()}
	/// При вызове шаблона из другого файла
	/// нужно обязательно указывать пространство имён
	{+= math.calc(1, 2) /}
{/template}

Snakeskin контролирует чтобы каждый подключаемый файл включался только один раз, т.е. гарантируется отсутствие дубликатов в конечном коде.

- namespace app
- include './math'

/// Этот include игнорируется
- include './math'

- template index()
	+= math.calc(1, 2)
{namespace app}
{include './math'}

/// Этот include игнорируется
{include './math'}

{template index()}
	{+= math.calc(1, 2) /}
{/template}

В любом Snakeskin файле каждый объявленный шаблон является публичным (экспортируемым), а все глобальные переменные будут инкапсулированы в рамках своего файла, т.е. нет явного способа получить значение такой переменной из другого файла, однако такая возможность есть при наследовании шаблонов.

base.ss

- namespace base
- var foo = 'bar'
{namespace math}
{var foo = 'bar' /}

app.ss

- namespace app
- include './base'

- template index()
	? console.log(foo) /// Error: foo is not defined
{namespace app}
{include './base'}

{template index()}
	{? console.log(foo)} /// Error: foo is not defined
{/template}

При указании пути можно использовать сложные выражения: вызовы функций, тернарные операторы и т.д.

- namespace app
- include './' + (@@base ? 'base' : 'default')

- template index()
	...
{namespace app}
{include './' + (@@base ? 'base' : 'default')}

{template index()}
	...
{/template}

Обратите внимание, что при подключении файла нужно обязательно указывать символы ./ or ../ для конкретизации поиска, т.к. если этого не сделать, то файл будет искаться в папке node_modules (как это делает require в node.js), а вот расширение файла можно не указывать - по умолчанию используется .ss. Директива может использоваться только вне шаблонов or внешних блоков.

Подключение файлов по маске

При указании пути к файлу можно использовать glob-шаблоны, например, чтобы подключить сразу множество файлов.

- namespace app
- include './modules/**/*'

- template index()
	...
{namespace app}
{include './modules/**/*'}

{template index()}
	...
{/template}

Динамическое подключение

Директиву include можно вызывать динамически, т.е. оборачивать её директивами типа if, forEach и т.д.

- namespace app

- eval
	- var fs = require('fs')
	- var path = require('path')

	/// В момент трансляции каждый файл имеет свои переменные
	/// __dirname и __filename
	- var url = path.join(__dirname, 'test')

	- forEach fs.readdirSync(url) => file
		- if path.extname(file) === '.ss'
			- include path.join(url, file)

- template index()
	...
{namespace app}

{eval}
	{var fs = require('fs') /}
	{var path = require('path') /}

	/// В момент трансляции каждый файл имеет свои переменные
	/// __dirname и __filename
	{var url = path.join(__dirname, 'test') /}

	{forEach fs.readdirSync(url) => file}
		{if path.extname(file) === '.ss'}
			{include path.join(url, file)}
		{/}
	{/}
{/eval}

{template index()}
	...
{/template}

Подключение папки

Если в пути к подключаемому файлу явно указать, что это папка (нужно добавить символ / в конце пути), то подключаться файл будет по правилу: (название папки|main|index).ss, например:

- namespace app

/// './base/base.ss' ИЛИ
/// './base/main.ss' ИЛИ
/// './base/index.ss'
- include './base/'

- template index()
	...
{namespace app}

/// './base/base.ss' ИЛИ
/// './base/main.ss' ИЛИ
/// './base/index.ss'
{include './base/'}

{template index()}
	...
{/template}

Обработка параметров трансляции при подключении

Если файл Snakeskin определяет параметры трансляции на глобальном уровне, то они также рекурсивно накладываются на все подключаемые файлы (если они не переопределяются явно в подключаемых файлах), например:

base.ss

- namespace base
@= tolerateWhitespaces true

- template index()
	...
{namespace math}
{@= tolerateWhitespaces true}

{template index()}
	...
{/template}

app.ss

- namespace app
@= tolerateWhitespaces false
@= renderMode 'dom'

- include './base'
- template index()
	...
{namespace app}
{@= tolerateWhitespaces false}
{@= renderMode 'dom'}

{include './base'}
{template index()}
	...
{/template}

Здесь файл base.ss наследует параметр renderMode = 'dom', но tolerateWhitespaces он переопределяет явно.

Подключение с заданием renderAs

Snakeskin позволяет явно задать параметр renderAs при подключении файла с помощью ключевого слова as, например:

- namespace app
- include './base' as placeholder
- template index()
	...
{namespace app}
{include './base' as placeholder}
{template index()}
	...
{/template}

Таким образом мы исключили подключаемые шаблоны из финального файла JS.

Доступ к глобальным переменным шаблона другого файла при наследовании

При наследовании дочерний шаблон автоматически получает доступ к замыканию родительского шаблона, например:

base.ss

- namespace base
- var hello = 'world'

- template index()
	Hello {hello}!
{namespace base}
{var hello = 'world' /}

{template index()}
	Hello {hello}!
{/template}

app.ss

- namespace app
- include './base'

- template index() extends base.index
	- block info
		hello = '{hello}'
{namespace app}
{include './base'}

{template index() extends base.index}
	{block info}
		hello = '{hello}'
	{/}
{/template}

Шаблон app.index отрендерится как:

Hello world!
hello = 'world'

Если в файле дочернего шаблона существует одноимённая глобальная переменная, то она будет переопределять родительскую:

app.ss

- namespace app
- include './base'

/// var может быть до include - это никак не влияет
- var hello = 'people'

- template index() extends base.index
	- block info
		hello = '{hello}'
{namespace app}
{include './base'}

/// var может быть до include - это никак не влияет
{var hello = 'people' /}

{template index() extends base.index}
	{block info}
		hello = '{hello}'
	{/}
{/template}

Шаблон app.index отрендерится как:

Hello people!
hello = 'people'
  • Directives
  • Modules

import

Директива импортирует в заданный файл ссылки из указанного JavaScript модуля и по своей семантике близка к реализации в JavaScript.

Synopsis

Declaration Shorthand Directive type Interpolation
Only in the global scope or on the global level of head Absent Inline, logic Not required

Description

Директива используется для импортирования JavaScript модулей в шаблон Snakeskin, а тип используемого импортирования зависит от параметра трансляции module (по умолчанию используется UMD). Синтаксис директивы идентичен аналогичной конструкции в JS ES2015. Директива может использоваться только в глобальной области or на глобальном уровне директивы head.

Examples

- namespace demo

- import path from 'path'
- import * as os from 'os'
- import { readdirSync } from 'fs'

- template index()
	...
{namespace demo}

{import path from 'path'}
{import * as os from 'os'}
{import { readdirSync } from 'fs'}

{template index()}
	...
{/template}
  • Directives
  • Creating literals

func

Директива декларирует анонимную функцию.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits () or () => Block, logic, function Not required

Description

Директива func декларирует анонимную функцию-литерал и обычно используется в связи с другими директивами, которые требуют аргумент-функцию, например, series or parallel.

Директива начинается с ключевого слова func (или символов () or () =>), которое может сопровождаться списком аргументов функции через запятую, например:

- namespace demo
- template index()
	() => db
		? db.ping()
{namespace demo}
{template index()}
	{() => db}
		{? db.ping()}
	{/}
{/template}

Параметров у такой функции может быть неограниченное количество, а т.к. директива func является функциональной, то она реализует стандартный механизм декларации параметров. По умолчанию такие функции возвращают строки, однако это поведение можно поменять задав специальный renderMode or явно вернув значение через директиву return. The directive can be used anywhere.

Стандартные переменные функции

Каждая директива func (за исключением тех, что используется совместно с асинхронными директивами) определяет ряд функций, которые можно использовать в ней:

getTplResult - функция, которая возвращает результат работы директивы, также может принимать один логический входной параметр, при задании которого после вызова функции результат работы директивы будет обнуляться;

clearTplResult - функция, которая обнуляет результат работы директивы.

func и var

Чтобы создать переменную с функциональным значением необходимо использовать конструкцию var putIn:

- namespace demo
- template index()
	/// Мы создали функцию,
	/// а затем присвоили её переменной calc
	- var putIn calc
		() => a, b
			- return a + b
{namespace demo}
{template index()}
	/// Мы создали функцию,
	/// а затем присвоили её переменной calc
	{var putIn calc}
		{() => a, b}
			{return a + b /}
		{/}
	{/}
{/template}

func и call, target, putIn

Функцию можно передавать как аргумент при вызове другой функции с помощью директивы call:

- namespace demo
- template index()
	+= [1, 2, 3].map()
		() => el
			el = {el}
{namespace demo}
{template index()}
	{+= [1, 2, 3].map()}
		{() => el}
			el = {el}
		{/}
	{/}
{/template}

Также функцию можно ставить как свойство объекта or массива через target, например:

- namespace demo
- template index()
	- target {} as map
		* calc
			() => a, b
				- return a + b
{namespace demo}
{template index()}
	{target {} as map}
		{* calc}
			{() => a, b}
				{return a + b /}
			{/}
		{/}
	{/}
{/template}

И можно установить/изменить значение свойства объекта or переменной на функцию с помощью putIn:

- namespace demo
- template index()
	- target {} as map
	- putIn map.calc
		() => a, b
			- return a + b
{namespace demo}
{template index()}
	{target {} as map /}
	{putIn map.calc}
		{() => a, b}
			{return a + b /}
		{/}
	{/}
{/template}
  • Directives
  • Creating literals

target

Директива возвращает ссылку на заданный объект и позволяет задавать ему свойства со значениями в виде подшаблонов Snakeskin.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits Absent Block, logic Not required

Description

Директива target несёт двойную функциональность: с одной стороны она возвращает ссылку на указанный объект, а с другой может задавать ему свойства-подшаблоны Snakeskin - т.е. представляет из себя литеральную форму для создания массивов и объектов со значениями в виде шаблонов, например:

- namespace demo
- template index(val)
	- target {}
		* prop1
			< .hello
				Hello world!

		* prop 2
			- if val > 1
				Success!
{namespace demo}
{template index()}
	{target {}}
		{* prop1}
			{< .hello}
				Hello world!
			{/}
		{/}

		{* prop 2}
			{if val > 1}
				Success!
			{/}
		{/}
	{/}
{/template}

Внутри такой декларации можно использовать любые допустимые директивы, например, if, forEach и т.д. Свойства объекту ставятся с помощью директивы putIn. Чтобы получить явную ссылку на созданный объект, то его нужно присвоить переменной: самый простой способ - это использовать оператор as, например:

- namespace demo
- template index(val)
	- target {} as myObj
		* prop1
			< .hello
				Hello world!

		* prop 2
			- if val > 1
				Success!

	? console.log(myObj)
{namespace demo}
{template index()}
	{target {} as myObj}
		{* prop1}
			{< .hello}
				Hello world!
			{/}
		{/}

		{* prop 2}
			{if val > 1}
				Success!
			{/}
		{/}
	{/}

	{? console.log(myObj)}
{/template}

А также можно использовать директиву var в режиме putIn:

- namespace demo
- template index(val)
	- var putIn myObj
		- target {}
			* prop1
				< .hello
					Hello world!

			* prop 2
				- if val > 1
					Success!

	? console.log(myObj)
{namespace demo}
{template index()}
	{var putIn myObj}
		{target {}}
			{* prop1}
				{< .hello}
					Hello world!
				{/}
			{/}

			{* prop 2}
				{if val > 1}
					Success!
				{/}
			{/}
		{/}
	{/}

	{? console.log(myObj)}
{/template}

Общая форма директивы следующая:

target ссылка на объект or сам объект [as опциональный идентификатор]
	[* опциональные свойства]

При использовании target в классическом синтаксисе существует короткая форма закрытия директивы, например:

/// Обычное закрытие
{target {a: 1, b: 2}}{/}

/// Короткая форма закрытия
{target {a: 1, b: 2} /}

Можно использовать директиву для уже созданных объектов, например:

- namespace demo
- template index(val)
	- var myObj = {}
	- target myObj
		* prop1
			< .hello
				Hello world!

		* prop 2
			- if val > 1
				Success!

	? console.log(myObj)
{namespace demo}
{template index()}
	{var myObj = {} /}
	{target myObj}
		{* prop1}
			{< .hello}
				Hello world!
			{/}
		{/}

		{* prop 2}
			{if val > 1}
				Success!
			{/}
		{/}
	{/}

	{? console.log(myObj)}
{/template}

The directive can be used anywhere.

Значение ключа putIn для объекта

Значение переданное в директиву putIn при задании свойства объекта трактуется как простая строка, а для прокидывания значений Snakeskin внутрь директивы используется стандартный механизм интерполяции, например:

- namespace demo
- template index(val)
	- target {} as myObj
		* some prop name ${1 + 2}
			< .hello
				Hello world!

	? console.log(myObj['some prop name 3'])
{namespace demo}
{template index()}
	{target {} as myObj}
		{* some prop name ${1 + 2}}
			{< .hello}
				Hello world!
			{/}
		{/}
	{/}

	{? console.log(myObj['some prop name 3'])}
{/template}

target для массивов

Создание и редактирование массивов через target почти не отличается от объектов - просто не нужно указывать название ключа и первый вызов putIn можно опустить, например:

- namespace demo
- template index(val)
	- target [] as myArray
			< .hello
				Hello world!
		*
			< .hello
				Hello people!

	? console.log(myArray)
{namespace demo}
{template index()}
	{target [] as myArray}
		{*}
			{< .hello}
				Hello world!
			{/}
		{/}
		{*}
			{< .hello}
				Hello people!
			{/}
		{/}
	{/}

	{? console.log(myArray)}
{/template}

Вложенный target

Директива может ставить как свойство объекта другой target, который может устанавливать любое значение.

- namespace demo
- template index(val)
	- target [] as myArray
			- target {a: 1, b: 2}
		*
			- target 1 + 2

	? console.log(myArray)
{namespace demo}
{template index()}
	{target [] as myArray}
		{*}
			{target {a: 1, b: 2} /}
		{/}
		{*}
			{target 1 + 2 /}
		{/}
	{/}

	{? console.log(myArray)}
{/template}

target и call, putIn, func

Директиву можно передавать как аргумент при вызове функции с помощью директивы call:

- namespace demo
- template index()
	+= someFunction()
		- target []
			Hello world!
{namespace demo}
{template index()}
	{+= someFunction()}
		{target []}
			Hello world!
		{/}
	{/}
{/template}

Также target можно ставить как свойство объекта or массива через putIn, например:

- namespace demo
- template index()
	- var myObj = {}
	- putIn myObj.foo
		- target []
			Hello world!
{namespace demo}
{template index()}
	{var myObj = {} /}
	{putIn myObj.foo}
		{target []}
			Hello world!
		{/}
	{/}
{/template}

И можно установить функцию как значение свойства объекта or элемент массива:

- namespace demo
- template index()
	- target []
		() => a, b
			- return a + b
{namespace demo}
{template index()}
	{target []}
		{() => a, b}
			{return a + b /}
		{/}
	{/}
{/template}
  • Directives
  • Creating literals

putIn

Директива задает значение переменной or свойству объекта в виде подшаблона Snakeskin.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits * Block, logic Not required

Description

Директива putIn несёт двойную функциональность: с одной стороны она позволяет присвоить подшаблон Snakeskin переменной or свойству объекта, а с другой - является частью директивы call и target. Совместное использование putIn подробно рассмотрено в других главах, поэтому здесь описываться не будет.

Для изменения переменной or свойства объекта через putIn используется общая форма:

putIn ссылка
	Шаблон

For example:

- namespace demo
- template index(val)
	- var myObj = {}

	- putIn myObj.foo
		< .hello
			Hello world!

	- putIn myObj.calc
		() => a, b
			- return a + b

	- putIn myObj.arr
		- target []
			Hello people!

	? console.log(myObj)
{namespace demo}
{template index()}
	{var myObj = {} /}

	{putIn myObj.foo}
		{< .hello}
			Hello world!
		{/}
	{/}

	{putIn myObj.calc}
		{() => a, b}
			{return a + b}
		{/}
	{/}

	{putIn myObj.arr}
		{target []}
			Hello people!
		{/}
	{/}

	{? console.log(myObj)}
{/template}

Внутри такой декларации можно использовать любые допустимые директивы, например, if, forEach и т.д. The directive can be used anywhere.

  • Directives
  • Asynchronous directives

series

Директива является фасадом для Async.series.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits Absent Block, logic Not required

Description

Директива является обёрткой над функцией series библиотеки Async и позволяет создавать удобные цепочки асинхронных вызовов. Вместе с директивой series должна использоваться директива func. Перед использованием директивы необходимо подключить через import саму библиотеку Async, например:

- namespace demo

- import async from 'async'
- import fs from 'fs'

- template index()
	- series
		() => cb
			fs.readFile('foo.txt', cb)

		() => cb
			fs.readFile('bar.txt', cb)
{namespace demo}

{import async from 'async'}
{import fs from 'fs'}

{template index()}
	{series}
		{() => cb}
			fs.readFile('foo.txt', cb)
		{/}

		{() => cb}
			fs.readFile('bar.txt', cb)
		{/}
	{/}
{/template}

The directive can be used anywhere. Вместе с основной директивой можно использовать дополнительные:

  1. final - второй параметр Async.series (функциональная директива).

Для управления переходами внутри блока можно использовать директивы:

  1. break - прерывает выполнение операции и переходит в final (если он задан), может принимать параметр;
  2. continue - прерывает выполнение текущей функции и переходит к следующей (если она есть) или к final (если он задан), может принимать параметр.

Examples

Задание final

- namespace demo

- import async from 'async'
- import fs from 'fs'

- template index()
	- series
		() => cb
			fs.readFile('foo.txt', cb)

		() => cb
			fs.readFile('bar.txt', cb)

	- final err, files
		? console.log(err, files)
{namespace demo}

{import async from 'async'}
{import fs from 'fs'}

{template index()}
	{series}
		{() => cb}
			fs.readFile('foo.txt', cb)
		{/}

		{() => cb}
			fs.readFile('bar.txt', cb)
		{/}

	{final err, res}
		{? console.log(err, files)}
	{/}
{/template}

Сброс операции

- namespace demo

- import async from 'async'
- import fs from 'fs'

- template index(brk)
	- series
		() => cb
			- if brk
				- break new Error('Skipped')

			? cb()

		() => cb
			fs.readFile('foo.txt', cb)

	- final err, res
		...
{namespace demo}

{import async from 'async'}
{import fs from 'fs'}

{template index(brk)}
	{series}
		{() => cb}
			{if brk}
				{break new Error('Skipped')}
			{/}

			{? cb()}
		{/}

		{() => cb}
			fs.readFile('foo.txt', cb)
		{/}

	{final err, res}
		...
	{/}
{/template}
  • Directives
  • Asynchronous directives

parallel

Директива является фасадом для Async.parallel.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits Absent Block, logic Not required

Description

Директива является обёрткой над функцией parallel библиотеки Async и позволяет создавать удобные цепочки асинхронных вызовов. Вместе с директивой parallel должна использоваться директива func. Перед использованием директивы необходимо подключить через import саму библиотеку Async, например:

- namespace demo

- import async from 'async'
- import fs from 'fs'

- template index()
	- parallel
		() => cb
			fs.readFile('foo.txt', cb)

		() => cb
			fs.readFile('bar.txt', cb)
{namespace demo}

{import async from 'async'}
{import fs from 'fs'}

{template index()}
	{parallel}
		{() => cb}
			fs.readFile('foo.txt', cb)
		{/}

		{() => cb}
			fs.readFile('bar.txt', cb)
		{/}
	{/}
{/template}

The directive can be used anywhere. Вместе с основной директивой можно использовать дополнительные:

  1. final - второй параметр Async.parallel (функциональная директива).

Для управления переходами внутри блока можно использовать директивы:

  1. break - прерывает выполнение операции и переходит в final (если он задан), может принимать параметр;
  2. continue - прерывает выполнение текущей функции и переходит к следующей (если она есть) или к final (если он задан), может принимать параметр.

Examples

Задание parallel

- namespace demo

- import async from 'async'
- import fs from 'fs'

- template index()
	- parallel
		() => cb
			fs.readFile('foo.txt', cb)

		() => cb
			fs.readFile('bar.txt', cb)

	- final err, files
		? console.log(err, files)
{namespace demo}

{import async from 'async'}
{import fs from 'fs'}

{template index()}
	{parallel}
		{() => cb}
			fs.readFile('foo.txt', cb)
		{/}

		{() => cb}
			fs.readFile('bar.txt', cb)
		{/}

	{final err, res}
		{? console.log(err, files)}
	{/}
{/template}

Сброс операции

- namespace demo

- import async from 'async'
- import fs from 'fs'

- template index(brk)
	- parallel
		() => cb
			- if brk
				- break new Error('Skipped')

			? cb()

		() => cb
			fs.readFile('foo.txt', cb)

	- final err, res
		...
{namespace demo}

{import async from 'async'}
{import fs from 'fs'}

{template index(brk)}
	{parallel}
		{() => cb}
			{if brk}
				{break new Error('Skipped')}
			{/}

			{? cb()}
		{/}

		{() => cb}
			fs.readFile('foo.txt', cb)
		{/}

	{final err, res}
		...
	{/}
{/template}
  • Directives
  • Asynchronous directives

waterfall

Директива является фасадом для Async.waterfall.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits Absent Block, logic Not required

Description

Директива является обёрткой над функцией waterfall библиотеки Async и позволяет создавать удобные цепочки асинхронных вызовов. Вместе с директивой waterfall должна использоваться директива func. Перед использованием директивы необходимо подключить через import саму библиотеку Async, например:

- namespace demo

- import async from 'async'
- import fs from 'fs'

- template index()
	- waterfall
		() => cb
			fs.readFile('foo.txt', cb)

		() => file1, cb
			fs.readFile('bar.txt', cb)
{namespace demo}

{import async from 'async'}
{import fs from 'fs'}

{template index()}
	{waterfall}
		{() => cb}
			fs.readFile('foo.txt', cb)
		{/}

		{() => file1, cb}
			fs.readFile('bar.txt', cb)
		{/}
	{/}
{/template}

The directive can be used anywhere. Вместе с основной директивой можно использовать дополнительные:

  1. final - второй параметр Async.waterfall (функциональная директива).

Для управления переходами внутри блока можно использовать директивы:

  1. break - прерывает выполнение операции и переходит в final (если он задан), может принимать параметр;
  2. continue - прерывает выполнение текущей функции и переходит к следующей (если она есть) или к final (если он задан), может принимать параметр.

Examples

Задание final

- namespace demo

- import async from 'async'
- import fs from 'fs'

- template index()
	- waterfall
		() => cb
			fs.readFile('foo.txt', cb)

	- final err, files
		? console.log(err, files)
{namespace demo}

{import async from 'async'}
{import fs from 'fs'}

{template index()}
	{waterfall}
		{() => cb}
			fs.readFile('foo.txt', cb)
		{/}

	{final err, res}
		{? console.log(err, files)}
	{/}
{/template}

Сброс операции

- namespace demo

- import async from 'async'
- import fs from 'fs'

- template index(brk)
	- waterfall
		() => cb
			- if brk
				- break new Error('Skipped')

			? cb()

		() => cb
			fs.readFile('foo.txt', cb)

	- final err, res
		...
{namespace demo}

{import async from 'async'}
{import fs from 'fs'}

{template index(brk)}
	{waterfall}
		{() => cb}
			{if brk}
				{break new Error('Skipped')}
			{/}

			{? cb()}
		{/}

		{() => cb}
			fs.readFile('foo.txt', cb)
		{/}

	{final err, res}
		...
	{/}
{/template}
  • Directives
  • Asynchronous directives

yield

Директива yield является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в JavaScript.

Synopsis

Declaration Shorthand Directive type Interpolation
Только внутри шаблона-генератора Absent Block, logic Not required

Description

Директива используется вместе с шаблонами-генераторами для организации “прерывания”, однако, Snakeskin не создаёт полифил, а генерирует “чистый” JavaScript код, поэтому для поддержки старых браузеров используйте Regenerator or Babel.

Директива начинается с ключевого слова yield, которое может сопровождаться ссылкой на возвращаемое значение или выражение, например:

- namespace demo
- template *index()
	- yield 1 + 2
{namespace demo}
{template index()}
	{yield *1 + 2 /}
{/template}

Для удобства использования yield в классическом синтаксисе существует короткая форма закрытия директивы, например:

/// Обычное закрытие
{yield 1 + 2}{/}

/// Короткая форма закрытия
{yield 1 + 2 /}

Директива может использоваться только внутри шаблона-генератора.

Расширенная декларация

Директива может включать возвращаемое значение в своё тело - это удобно, когда возвращаемое значение является подшаблоном, например:

- namespace demo
- template *index()
	/// Шаблон вернёт ссылку на функцию,
	/// которая складывает два числа
	- yield
		() => a, b
			- return a + b
{namespace demo}
{template *index()}
	/// Шаблон вернёт ссылку на функцию,
	/// которая складывает два числа
	{yield}
		{() => a, b}
			{return a + b /}
		{/}
	{/}
{/template}

Внутри такой декларации можно использовать любые допустимые директивы, например, if, forEach и т.д.

  • Directives
  • Asynchronous directives

await

Директива await является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в JavaScript.

Synopsis

Declaration Shorthand Directive type Interpolation
Только внутри шаблона-генератора Absent Block, logic Not required

Description

Директива используется вместе с async-шаблонами для организации “прерывания”, однако, Snakeskin не создаёт полифил, а генерирует “чистый” JavaScript код, поэтому для поддержки старых браузеров используйте Babel.

Директива начинается с ключевого слова await, которое может сопровождаться ссылкой на ожидаемое значение or выражение, например:

- namespace demo
- async template index(db)
	- await db.getData()
{namespace demo}
{async template index(db)}
	{await db.getData() /}
{/template}

Для удобства использования await в классическом синтаксисе существует короткая форма закрытия директивы, например:

/// Обычное закрытие
{await db.getData()}{/}

/// Короткая форма закрытия
{await db.getData() /}

Директива может использоваться только внутри async-шаблона.

Расширенная декларация

Директива может включать выражение в своё тело - это удобно, когда ожидаемое значение является подшаблоном, например:

- namespace demo
- async template index(db)
	- await
		- block getData() =>
			- return db.getData()
{namespace demo}
{async template index()}
	{await}
		{block getData() =>}
			{return db.getData() /}
		{/}
	{/}
{/template}

Внутри такой декларации можно использовать любые допустимые директивы, например, if, forEach и т.д.

  • Directives
  • Inheritance

super

Директива вставляет в шаблон тело родительского блока.

Synopsis

Declaration Shorthand Directive type Interpolation
Only within templates or external blocks Absent Inline, logic Not required

Description

Директива работает по схеме: всплывает по дереву шаблона до тех пор, пока не найдётся блок, который имеет родителя, и вставляет родительское тело в указанное место, а если такого родителя нет, то просто ничего не делает. Директива может использоваться только внутри шаблонов or внешних блоков.

Examples

- namespace demo

- template base()
	- block base
		Какой хороший день!

- template child() extends @base
	- block base
		- super
		Трудиться мне не лень!
{namespace demo}

{template base()}
	{block base}
		Какой хороший день!
	{/}
{/template}

{template child() extends @base}
	{block base}
		{super}
		Трудиться мне не лень!
	{/}
{/template}
  • Directives
  • Other

op

Директива создаёт логический блок Snakeskin без “побочного эффекта”.

Synopsis

Declaration Shorthand Directive type Interpolation
No limits Absent Block, logic Not required

Description

Директива используется для перехода в расширенный синтаксис без “побочных эффектов” других директив, т.е. сама директива ничего не делает. Директива может использоваться как внутри шаблонов or других директив, так и в глобальной области.

Examples

- namespace demo
- template index()
	# op
		{name: 'world'}
{namespace demo}
{template index()}
	#{op}
		{name: 'world'}
	#{/}
{/template}
  • Directives
  • Other

break

Директивы прерывает выполнение другой директивы, с которой она находится в связи.

Synopsis

Declaration Shorthand Directive type Interpolation
Только внутри специальных директив Absent Inline, logic Not required

Description

Поведение директивы break зависит от контекста, например, если использовать её внутри циклов or итераторов, то она будет немедленно прерывать итерации, а если использовать совместно с асинхронными директивами, то break будет осуществлять немедленный переход к результирующей функции.

Директива может использоваться только внутри директив:

Examples

Сброс for

- namespace demo
- template index()
	- var obj = {a: 1, b: 2}
	- for var key in obj
		{key}
		- break
{namespace demo}
{template index()}
	{var obj = {a: 1, b: 2} /}
	{for var key in obj}
		{key}
		{break}
	{/}
{/template}

Сброс series

- namespace demo

- import async from 'async'
- import fs from 'fs'

- template index(brk)
	- series
		() => cb
			- if brk
				/// Управление перейдёт в final c ошибкой
				- break new Error('Skipped')

			? cb()

		() => cb
			fs.readFile('foo.txt', cb)

	- final err, res
		...
{namespace demo}

{import async from 'async'}
{import fs from 'fs'}

{template index(brk)}
	{series}
		{() => cb}
			{if brk}
				/// Управление перейдёт в final c ошибкой
				{break new Error('Skipped')}
			{/}

			{? cb()}
		{/}

		{() => cb}
			fs.readFile('foo.txt', cb)
		{/}

	{final err, res}
		...
	{/}
{/template}
  • Directives
  • Other

continue

Директивы пропускает такт выполнения другой директивы, с которой она находится в связи.

Synopsis

Declaration Shorthand Directive type Interpolation
Только внутри специальных директив Absent Inline, logic Not required

Description

Поведение директивы continue зависит от контекста, например, если использовать её внутри циклов or итераторов, то она будет немедленно прерывать текущую итерацию и переходить к следующей, а если использовать совместно с асинхронными директивами, то continue будет осуществлять немедленный переход к следующей функции в цепи.

Директива может использоваться только внутри директив:

Examples

Использование с for

- namespace demo
- template index()
	- var obj = {a: 1, b: 2}
	- for var key in obj
		- if !obj.hasOwnProperty(key)
			- continue

		{key}
{namespace demo}
{template index()}
	{var obj = {a: 1, b: 2} /}
	{for var key in obj}
		{if !obj.hasOwnProperty(key)}
			{continue}
		{/}
		{key}
	{/}
{/template}

Использование с waterfall

- namespace demo

- import async from 'async'
- import fs from 'fs'

- template index(brk)
	- waterfall
		() => cb
			- if brk
				- continue 'foo.txt'

			...
			? cb('bar.txt')

		() => path, cb
			fs.readFile(path, cb)

	- final err, res
		...
{namespace demo}

{import async from 'async'}
{import fs from 'fs'}

{template index(brk)}
	{waterfall}
		{() => cb}
			{if brk}
				{continue 'foo.txt'}
			{/}

			...
			{? cb()}
		{/}

		{() => path, cb}
			fs.readFile(path, cb)
		{/}

	{final err, res}
		...
	{/}
{/template}
  • JS API
  • Общее

compile

Метод компилирует заданный текст шаблона or содержимое DOM узла.

Интерфейс

Snakeskin.compile(src, opt_params, opt_info) {
	return string || false || null;
}

Аргументы

  1. (!Element|string) src - ссылка на DOM узел, где декларированы шаблоны or исходный текст шаблонов;
  2. Object= opt_params - дополнительные параметры запуска;
  3. Object= opt_info - дополнительная информация для отладчика.

opt_params

opt_info

Параметры

cache

/**
 * @type {?boolean=}
 * @default true
 */

Если параметр равен false, то наличие шаблона в кеше не будет проверятся, а сам шаблон не будет кешироваться.

vars

/**
 * @type {Object=}
 */

Параметр задаёт суперглобальные переменные Snakeskin.

Snakeskin.compile('<шаблон>', {
	vars: {
		foo: 'bar'
	}
});

context

/**
 * @type {Object=}
 */

Параметр задаёт объект для экспорта свойств при компиляции в стиле CommonJS.

- namespace demo
- template index()
	Hello world!
{namespace demo}
{template index()
	Hello world!
{/template}
var tpls = {};

Snakeskin.compile('<шаблон>', {
	context: tpls
});

tpls.demo.foo() // Hello world

babel

/**
 * @type {Object=}
 */

Параметр задаёт объект настроек для Babel для обработки после основной трансляции.

onError

/**
 * @type {?function(!Error)=}
 */

Параметр задаёт функцию обратного вызова для обработки ошибок.

throws

/**
 * @type {?boolean=}
 * @default false
 */

Если параметр равен true, то в случае ошибки и отсутствия обработчика ошибок - будет возбуждено исключение.

По умолчанию просто выводится сообщение в stderr и прерывается операция.

debug

/**
 * @type {Object=}
 */

Объект, который будет содержать в себе некоторую отладочную информацию.

var info = {};
Snakeskin.compile('<шаблон>', {debug: info});
info.code // Исходный текст полученного JS файла

resolveModuleSource

/**
 * @type {(?function(string, string): string)=}
 */

Функция для резолвинга путей в import: первым параметром принимает строку запроса, а вторым полный путь к файлу, в котором вызывается директива. Функция должна возвращать строку, которая будет новым путём к подключаемому файлу.

pack

/**
 * @type {?boolean=}
 * @default false
 */

Если параметр равен true, то модель импорта/экспорта модулей будет оптимизирована для использования вместе с WebPack.

module

/**
 * @type {?string=}
 * @default 'umd'
 */

Тип импорта/экспорта модулей, доступны варианты:

  • umd;
  • global (сохранение напрямую в глобальный объект);
  • cjs;
  • amd;
  • native.

moduleId

/**
 * @type {?string=}
 * @default 'tpls'
 */

ИД модуля для umd/amd декларации: первый параметр функции define.

moduleName

/**
 * @type {?string=}
 */

Название модуля для umd/global декларации: если задан, то в глобальном объекте (window и т.д.) будет создано свойство с указанным именем, куда будут сохраняться полученные шаблоны, иначе, всё будет сохранено напрямую в глобальный объект.

useStrict

/**
 * @type {?boolean=}
 * @default true
 */

Если параметр равен false, то шаблоны компилируются без 'use strict';.

prettyPrint

/**
 * @type {?boolean=}
 * @default false
 */

Если параметр равен true, то полученный JS после трансляции будет отформатирован.

literalBounds

/**
 * @type {Array<string>=}
 * @default ['{{', '}}']
 */

Параметр задаёт “врапперы” для директивы literal, например:

- namespace demo
- template index() @= literalBounds ['<?php', '?>']
	{{ Hello }}
{namespace demo}
{template index() @= literalBounds ['<?php', '?>']}
	{{ Hello }}
{/template}

Отрендерится как:

<?php Hello ?>

attrLiteralBounds

/**
 * @type {Array<string>=}
 */

Параметр задаёт “врапперы” для директивы literal при декларации значения атрибута, например:

- namespace demo
- template index() @= attrLiteralBounds ['{', '}']
	< .foo title = {{ val }}
{namespace demo}
{template index() @= attrLiteralBounds ['{', '}']}
	{< .foo title = {{ val }} /}
{/template}

Отрендерится как:

<div class="foo" title={ val }></div>

tagFilter

/**
 * @type {?string=}
 */

Параметр задаёт название фильтра для обработки тега при создании через tag.

tagNameFilter

/**
 * @type {?string=}
 */

Параметр задаёт название фильтра для обработки имени тега при создании через tag.

attrKeyFilter

/**
 * @type {?string=}
 */

Параметр задаёт название фильтра для обработки ключа атрибута тега при создании через tag.

attrValueFilter

/**
 * @type {?string=}
 */

Параметр задаёт название фильтра для обработки значения атрибута тега при создании через tag.

bemFilter

/**
 * @type {?string=}
 */

Параметр задаёт название фильтра для обработки липких ссылок.

filters

/**
 * @type {Object<Array<string>>=}
 * @default {global: ['html', 'undef'], local: ['undef']}
 */

Объект фильтров по умолчанию для директивы output: фильтры бывают 2-х видов - глобальные (применяются ко всему полученному выражению, ключ global) и локальные (применяются к каждой части выражения по отдельности, ключ local).

localization

/**
 * @type {?boolean=}
 * @default true
 */

Если параметр равен false, то строки локализации будут отключены, т.е. сохраняются “как есть”.

i18nFn

/**
 * @type {?string=}
 * @default 'i18n'
 */

Название используемой глобальной функции локализации: данная функция будет оборачивать строки локализации.

- namespace demo
- template index()
	`Hello world!`
{namespace demo}
{template index()}
	`Hello world!`
{/template}

Строка `Hello world!` скомпилируется как

i18n("hello world!")

i18nFnOptions

/**
 * @type {?string=}
 */

Передаваемые параметры для глобальной функции локализации в строковом виде, например, '{lang: "en"}, true'.

language

/**
 * @type {Object=}
 */

Если задан данный параметр, то строки локализации будут заменятся на этапе трансляции.

- namespace demo
- template index()
	`Hello world!`
{namespace demo}
{template index()}
	`Hello world!`
{/template}
Snakeskin.compile('<шаблон>', {
	'Hello world!': 'Привет мир!'
});

words

/**
 * @type {Object=}
 */

Если задан данный параметр, то найденные в шаблонах строки локализации будут добавляться в него в виде свойств.

- namespace demo
- template index()
	`Hello world!`
{namespace demo}
{template index()}
	`Hello world!`
{/template}
var words = {};

Snakeskin.compile('<шаблон>', {
	words: words
});

// {'Hello world!': 'Hello world!'}
console.log(words);

ignore

/**
 * @type {RegExp=}
 */

Параметр задаёт пробельные символы, которые будут игнорироваться в шаблонах.

tolerateWhitespaces

/**
 * @type {?boolean=}
 * @default false
 */

Если параметр равен true, то все пробельные символы в шаблоне обрабатываются “как есть”.

eol

/**
 * @type {?string=}
 * @default '\n'
 */

Параметр задаёт символ перевода строки, который будет использоваться в сгенерированном файле, можно использовать \n, \r or \r\n.

doctype

/**
 * @type {?string=}
 * @default 'html'
 */

Параметр задаёт тип документа: это влияет на код, который генерируют некоторые директивы, например, tag. Доступные варианты.

renderAs

/**
 * @type {?string=}
 */

Параметр задаёт тип шаблонов для рендеринга, доступны варианты:

  • interface - все директивы template рендерятся как interface;
  • placeholder - все директивы template и interface рендерятся placeholder.

renderMode

/**
 * @type {?string=}
 * @default 'stringConcat'
 */

Параметр задаёт режим рендеринга шаблонов, доступны варианты:

  • stringConcat - шаблон генерируется в виде строки, для конкатенаций используется оператор +;
  • stringBuffer - шаблон генерируется в виде строки, для конкатенаций используется оператор StringBuffer;
  • dom - шаблон генерируется в виде DocumentFragment с помощью DOM API.

file

/**
 * @type {?string=}
 */

Параметр задаёт адрес компилируемого файла.

  • JS API
  • Общее

importFilters

Метод импортирует заданный объект в пространство имён фильтров Snakeskin.

Интерфейс

Snakeskin.importFilters(filters, opt_namespace) { return undefined; }

Аргументы

  1. !Object filters - импортируемый объект;
  2. ?string= opt_params - пространство имён для сохранения, например, foo.bar.
  • JS API
  • Общее

setFilterParams

Метод задаёт заданному фильтру дополнительные параметры.

Интерфейс

Snakeskin.setFilterParams(filter, params) { return Function; }

Аргументы

  1. (string|!Function) filter - название фильтра or функция-фильтр;
  2. !Object params - параметры фильтра.
  • JS API
  • node.js

check

Метод вернёт true, если заданный файл шаблонов соответствует скомпилированному по временной метке.

Интерфейс

Snakeskin.check(source, result) { return boolean; }

Аргументы

  1. string source - путь к исходному файлу;
  2. string result - путь к скомпилированному файлу.
  • JS API
  • node.js

compileFile

Метод скомпилирует заданный файл и вернёт ссылку на объект полученных шаблонов.

Интерфейс

Snakeskin.compileFile(src, opt_params) { return !Object || false; }

Аргументы

  1. string src — путь к файлу шаблонов;
  2. Object= opt_paramsдополнительные параметры запуска.
  • JS API
  • node.js

exec

Метод скомпилирует заданный текст и вернёт ссылку на главный шаблон.

Главный шаблон определяется по правилу: название файла без расширения or main or index or Object.keys().sort()[0].

Интерфейс

Snakeskin.exec(txt, opt_params, opt_tplName) { return Function; }

Аргументы

  1. string txt - исходный текст;
  2. Object= opt_params - дополнительные параметры запуска;
  3. ?string= opt_tplName - имя главного шаблона.
  • JS API
  • node.js

execFile

Метод скомпилирует заданный файл и вернёт ссылку на главный шаблон.

Главный шаблон определяется по правилу: название файла без расширения or main or index or Object.keys().sort()[0].

Интерфейс

Snakeskin.execFile(src, opt_params, opt_tplName) { return Function; }

Аргументы

  1. string src - путь к файлу шаблонов;
  2. Object= opt_params - дополнительные параметры запуска;
  3. ?string= opt_tplName - имя главного шаблона.