Pull to refresh

Ещё один препроцессор для JavaScript

Reading time 4 min
Views 12K
Интересна ли вам возможность писать в JavaScript вот такие штуки?

$ ('.btn-toogle').onclick (lambda $ (this).toggleClass ('active'));

var chars = Array.prototype.forEach.call ('0123456789abcdef', lambda arg.charCodeAt (0));

function fn (arg1 = 100, arg2 = 'test'){ ... }

var html = h`
    <div>
        <a href="...">link</a>
    </div>`;

for (var key, value in object) 
    console.log (key + ' = ' + value);


Тогда, возможно, вас заинтересует эта статья.

Не буду расписывать всякую скукоту вроде истории или того, зачем я сделал эту штуку. Лучше попробую вкратце рассказать, как она работает и что она может делать.

Препроцессор написан на Node.JS, причём для парсинга JavaScript'а используется генератор парсеров PEG.js. Кстати, одной из сильных сторон препроцессора (ну, лично для меня) является то, что обычный JavaScript-код отлично парсится. Ну, если, конечно же, в коде не встречаются ключевые слова вроде lambda, module, import или export.

Конечно, парсер на JavaScript не отличается производительностью, но, к счастью, кеширование вполне это компенсирует.

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

1. Сокращённая запись функций.


var way0   = lambda arg.charCodeAt (0),
    way1   = lambda (arg) arg.charCodeAt (0),
    way2   = lambda { return arg.charCodeAt (0) },
    way3   = lambda (arg){ arg.charCodeAt (0) },
    result = function (arg){ return arg.charCodeAt (0) };

Все четыре способа записи дают одинаковый результат. Аргумент «arg» добавляется тем функциям, у которых отсутствуют обычные аргументы. Если всё тело функции состоит из одной операции (statement; если честно, не знаю, как корректно сказать по-русски), функция вернёт результат этой операции.

Вот ещё пара примеров:
var // Вернёт сумму четырёх аргументов
	example0 = lambda (a, b, c, d) a + b + c + d,   

	// Некий аналог forEach
    example1 = lambda (a, fn) 
    	for (var i = 0; i < a.length; i ++)
    		fn (a [i]),	

    // Вернёт объект с полями a и b.							
    example2 = lambda { 
    	a: arg * 2, 
    	b: arg
    };


2. Аргументы функций по умолчанию.


Ничего особенно, заголовок уже говорит сам за себя.
function fn (arg1 = 100, arg2 = 'test'){ ... }

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

3. Многострочные строки (прошу прощения за столь некрасивое выражение).


Для начала, это просто способ записи строк с использованием символа «`» как кавычек. Можно наконец-то перестать расставлять «\» в концах строк (хотя, признаюсь, никто обычно не пишет так, чтобы были нужны многострочные строки). Но это ещё не всё. В записимости от символа перед открывающей кавычкой препроцессор может как-то по-особенному обработать текст внутри. Напишите «h» и препроцессор сожмёт строку как html-код, «c» — как css-код, «s» — удалит идущие подряд пробелы, «l» — сконвертирует LESS внутри строки в CSS (ну и сожмёт тоже), а «lp» — мой любимый :) — не только сконвертирует LESS в CSS, но и оставит возможность в дальнейшем определять свойства через JavaScript. Довольно удобно.

4. Модули.


Если коротко, это в каком-то смысле аналог классов из той же Java. Но ни в коем случае не обычных классов. В JavaScript же уже есть прототипы, верно?

Модули заменяют собой то, что в других языках обычно называется статическими классами (надеюсь, такой термин вообще существует).

Пример простого модуля:

module Example {
    function init (){
        // ...
    }
}

Функция «init» будет вызвана при запуске скрипта (ну, об этом попозже).

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

module First {
    export function test (){
        console.log ('Эта строчка будет выведена третьей.');
    }

    function init (){
        console.log ('Эта — первой.');
    }
}

module Second {
    import First;

    function init (){
        console.log ('Ну а эта — второй, так как вначале будут проинициализированы все модули, включённые в этот.');
        First.test ();
    }
}


Если поставить перед именем импортируемого класса «@», импортируемый класс может быть проинициализирован и позже импортирующего. Помогает, если каждому из двух классов вдруг понадобится импортировать другой, хотя, конечно же, архитектурно такая структура выглядит отталкивающе.

Ну а ещё есть доступные лишь на чтение экспортируемые переменные:
module First {
    import @Second;

    export function test (){
        console.log ('Тут сейчас будет написано «1024»: ' + Second.value);
    }
}

module Second {
    import First;

    export var value = 1024;

    function init (){
        First.test ();
    }
}


Кстати, модули необязательно использовать именно другими модулями. Хотя и желательно. :)

5. Параметры препроцессора.


Чтобы настроить сборку кода, можно использовать хитрые комментарии в начале файла:
// ==Jsx==
// @target     web:onload
// @build-to   build/
// @define     __VERSION__ 1.00
// @import     utils/string.format
// @include     jquery.min.js
// ==/Jsx==

(Примерно в таком же стиле записываются комментарии для UserScript'ов.)

  • target — указывает, где будет выполняться скрипт. От этого аргумента зависит код, инициализирующий модули. Допустимые значения: «web» (будет использоваться переменная window), «web:onload» (модули начнут инициализироваться после завершения загрузки страницы), «node» (для Node.JS, будет использоваться GLOBAL), «local».
  • build-to — указывает, куда сохранить результат. По умолчанию скрипт сохраняет его в ту же папку, заменив расширение «jsx» на «js» (или добавив расширение «js», если у оригинального файла расширение отличается от «jsx».
  • define — заменит в результирующем файле все вхождения первого аргумента на второй. Иногда пригождается.
  • import — включит файл с расширением «jsxi» (которое писать в параметре не нужно), предварительно распарсив. Если файл не будет найден в папке рядом, поиск продолжится в папке с подключаемыми файлами препроцессора. (Ну, там довольно хитрый алгоритм; пожалуй, не стоит тут расписывать такие мелочи.)
  • include — включит файл в результат, никак не анализируя и не парся.


Это не все параметры, а так же не все фичи, но, по-моему, статья и так получилась чересчур великовата для краткого описания.

Скачать текущую версию можно отсюда. Заранее прошу прощения за все возможные ошибки и благодарю за уделённое внимание. :)
Tags:
Hubs:
+6
Comments 14
Comments Comments 14

Articles