Форматувальник
Phasis постачає вбудований форматувальник JavaScript, побудований на власному парсері. Він виводить вихідний код із правилами розмітки, сумісними з prettier, повністю в PHP: без Node.js, інтерпретованих пакетів форматувальника та зовнішніх процесів.
formatSource
public static function formatSource(
string $source,
string $sourceType = 'script',
?FormatOptions $options = null,
): string
Універсальна точка входу Phasis\Formatter\Formatter для одного виклику. $sourceType задає мову: script або module для JavaScript, json чи css. JavaScript виконує розбір відповідно до заданої мети, повертає коментарі на місце та друкує результат із заданою шириною рядка.
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
Параметри розмітки відповідають prettier 3.x і за замовчуванням використовують стандартні значення 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-правил, як-от Tailwind @apply. Довгі складені селектори розбиваються на комбінаторах нащадків, а надто довгі аргументи псевдокласів переносяться всередині дужок.
JSON
formatSource($json, 'json') повторно використовує парсер і принтери JavaScript із правилами JSON від prettier: ключі залишаються в лапках, рядки завжди беруться в подвійні лапки незалежно від singleQuote, кінцевих ком немає, а коментарі // усередині документа зберігаються.
Правила розмітки
Принтер реалізує модель документа prettier: групи згортаються, якщо вміщуються у ширину друку, інакше переносяться; аргументи виклику прилягають до кінцевого аргументу-функції або об’єкта; ланцюжки властивостей розриваються перед кожною крапкою, якщо виходять за межі рядка; об’єкти, записані в кількох рядках, залишаються багаторядковими; між інструкціями зберігається не більш ніж один порожній рядок. Для коду, відформатованого prettier з відповідними параметрами, форматувальник створює байт-у-байт ідентичний результат на реальному коді; набір перевірок відповідності підтверджує це за допомогою зразків, згенерованих самим prettier.
Коментарі
Коментарі збираються під час токенізації (Parser::setCollectComments(true), доступні в парсері для інструментів) і повертаються до дерева як початкові, кінцеві або висячі вкладення. Коментарі рядка залишаються на своїх рядках, кінцеві коментарі в тому самому рядку залишаються при своїй інструкції, порожні рядки навколо коментарів зберігаються, а блоки /** ... */ отримують відступи, вирівняні за полем *.
Гарантії
Для кожного відформатованого результату виконуються три інваріанти, перевірені набором тестів:
- Результат повторно розбирається в еквівалентну програму (без урахування розташування).
- Усі коментарі з вхідного коду зберігаються у результаті.
- Форматування ідемпотентне: повторне форматування результату нічого не змінює.
Продуктивність
Форматування працює зі швидкістю парсера: файли з реального світу форматуються за десятки мілісекунд, а типовий написаний вручну JavaScript у звичайному проєкті повністю форматується за значно менше ніж секунду в одному процесі.