Перейти к содержимому

Форматтер

Phasis поставляет встроенный форматтер JavaScript на основе собственного парсера. Он заново выводит исходный код с правилами разметки, совместимыми с prettier, полностью на PHP: без Node.js, интерпретируемых пакетов форматтера и внешних процессов.

formatSource

PHP
public static function formatSource(
    string $source,
    string $sourceType = 'script',
    ?FormatOptions $options = null,
): string

Единая точка входа в Phasis\Formatter\Formatter. $sourceType выбирает язык: script или module для JavaScript, json или css. JavaScript разбирает код с указанной целью, заново привязывает комментарии и выводит его с заданной шириной строки.

PHP
use Phasis\Formatter\Formatter;
use Phasis\Formatter\FormatOptions;

$formatted = Formatter::formatSource(
    "const a={x:1,y:2};",
    'script',
    new FormatOptions(useTabs: true, singleQuote: true),
);
// "const a = { x: 1, y: 2 };\n"

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

FormatOptions

Параметры разметки соответствуют 3.x prettier и по умолчанию используют значения prettier:

Параметр По умолчанию Значение
printWidth 80 Целевая ширина строки, под которую подгоняется разметка.
tabWidth 2 Число пробелов на уровень отступа (и измеряемая ширина табуляции).
useTabs false Использовать табуляцию вместо пробелов для отступа.
semi true Точки с запятой после инструкций.
singleQuote false Предпочитать ' вместо ", если это требует меньше экранирования.
trailingComma 'all' 'all', 'es5' или 'none'.
bracketSpacing true Пробелы внутри фигурных скобок объекта: { a } или {a}.
arrowParens 'always' 'always' или 'avoid' для стрелочных функций с одним параметром.

CSS

formatSource($css, 'css') форматирует таблицы стилей по правилам разметки таблиц стилей prettier: в списках селекторов — по одному селектору на строку, по одному объявлению на строку, нормализованные пробелы вокруг комбинаторов и значений, простые списки значений, упакованные в строки, списки теней и градиентов с элементами через запятую по одному на строку, аргументы функций либо все вместе, либо с переносами, сохранение пустых строк и комментариев, а также нетронутые преамбулы неизвестных правил at-rule, например Tailwind из @apply. Составные селекторы, не помещающиеся в строку, переносятся после комбинаторов потомков, а слишком длинные аргументы псевдоклассов переносятся внутри скобок.

JSON

formatSource($json, 'json') повторно использует парсер JavaScript и форматтеры с правилами JSON от prettier: ключи остаются в кавычках, строки — в двойных кавычках независимо от singleQuote, завершающие запятые не появляются, а комментарии // внутри документа сохраняются.

Правила форматирования

Форматтер реализует модель документов prettier: группы разворачиваются, если помещаются в ширину строки, и переносятся в противном случае; аргументы вызова примыкают к следующему аргументу-функции или объекту; цепочки свойств переносятся перед каждой точкой, если не помещаются в строку; объекты, записанные в несколько строк, остаются многострочными; между инструкциями сохраняется не более одной пустой строки. На коде, отформатированном prettier с совпадающими параметрами, результат побайтно совпадает для реальных программ; соответствие проверяется набором тестов на фикстурах, созданных самим prettier.

Комментарии

Комментарии собираются при токенизации (Parser::setCollectComments(true), доступны в парсере для инструментов) и повторно привязываются к дереву как предшествующие, последующие или висячие. Комментарии в строке остаются на своих строках, комментарии в конце строки остаются рядом со своей инструкцией, пустые строки вокруг комментариев сохраняются, а блоки /** ... */ получают отступ с выравниванием желоба *.

Гарантии

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

  • Результат повторно разбирается в эквивалентную программу (без учета расположения).
  • Все комментарии из исходного кода сохраняются в результате.
  • Форматирование идемпотентно: повторное форматирование результата ничего не меняет.

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

Форматирование выполняется со скоростью парсера: реальные файлы форматируются за десятки миллисекунд, а написанный вручную JavaScript типичного проекта форматируется от начала до конца менее чем за секунду в одном процессе.