
# Formátovač

Phasis poskytuje nativní formátovač JavaScript postavený na vlastním parseru. Zdrojový kód znovu vypisuje s rozvržením kompatibilním se sémantikou Prettieru, celý v PHP: bez Node.js, interpretovaných balíčků formátovače a externích procesů.

## formatSource

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

Jedno volání na `Phasis\Formatter\Formatter` stačí. Jazyk vybírá `$sourceType`: `script` nebo `module` pro JavaScript, `json` či `css`. JavaScript parsuje podle zadaného cíle, znovu připojí komentáře a vypíše kód podle nastavené šířky řádku.

```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"
```

Neplatný zdrojový kód vyvolá stejnou chybu `Phasis\Exceptions\SyntaxError` jako parser, včetně řádku, sloupce a posunu.

## FormatOptions

Možnosti rozvržení odpovídají 3.x Prettieru a ve výchozím nastavení používají jeho výchozí hodnoty:

| Možnost        | Výchozí hodnota | Význam                                                          |
| --------------- | ---------- | -------------------------------------------------------------- |
| `printWidth`    | `80`       | Cílová šířka řádku, podle které se rozvržení upravuje.                |
| `tabWidth`      | `2`        | Počet mezer na úroveň odsazení (a měřená šířka tabulátoru).     |
| `useTabs`       | `false`    | Odsazovat tabulátory místo mezer.                            |
| `semi`          | `true`     | Středníky za příkazy.                                          |
| `singleQuote`   | `false`    | Upřednostnit `'` před `"`, pokud vyžaduje méně escape sekvencí.              |
| `trailingComma` | `'all'`    | `'all'`, `'es5'` nebo `'none'`.                                 |
| `bracketSpacing`| `true`     | Mezery uvnitř složených závorek objektu: `{ a }` oproti `{a}`.             |
| `arrowParens`   | `'always'` | `'always'` nebo `'avoid'` u šipkových funkcí s jedním parametrem.  |

## CSS

`formatSource($css, 'css')` formátuje styly podle rozvržení stylů Prettieru: jeden selektor na řádek v seznamech selektorů, jedno deklarované pravidlo na řádek, normalizované mezery kolem kombinátorů a hodnot, jednoduché seznamy hodnot vyplněné do řádku, seznamy stínů a přechodů s čárkami po jednom na řádek, argumenty funkcí buď všechny zalomené, nebo všechny v řádku, zachované prázdné řádky a komentáře a nedotčené předřazené zápisy neznámých pravidel at-rule, například Tailwind `@apply`. Dlouhé složené selektory se zalamují u potomkových kombinátorů a příliš dlouhé argumenty pseudo-tříd se zalamují uvnitř závorek.

## JSON

`formatSource($json, 'json')` používá parser a tiskové nástroje JavaScript znovu s pravidly Prettieru pro JSON: klíče zůstávají v uvozovkách, řetězce mají vždy dvojité uvozovky bez ohledu na `singleQuote`, čárky na konci se nikdy nevyskytují a komentáře `//` uvnitř dokumentu zůstávají zachované.

## Sémantika rozvržení

Tiskový nástroj implementuje model dokumentu Prettieru: skupiny se zploští, pokud se vejdou do šířky řádku, jinak se zalomí; argumenty volání těsně přiléhají k závěrečné funkci nebo argumentu objektu; řetězce přístupů k členům se při překročení šířky řádku zalamují před každou tečkou; objekty zapsané na více řádcích zůstávají víceřádkové a mezi příkazy se zachová nejvýše jeden prázdný řádek. Na vstupu formátovaném Prettierem se stejnými možnostmi vytváří formátovač bajtově totožný výstup pro skutečný kód; jeho testovací sada to přesně ověřuje pomocí testovacích dat vygenerovaných samotným Prettierem.

## Komentáře

Komentáře se shromažďují během tokenizace (`Parser::setCollectComments(true)`, zpřístupněné parserem pro nástroje) a znovu se připojují ke stromu jako úvodní, závěrečné nebo volně připojené. Řádkové komentáře zůstávají na vlastních řádcích, závěrečné komentáře na stejném řádku zůstávají u svého příkazu, prázdné řádky kolem komentářů se zachovávají a bloky `/** ... */` se znovu odsazují tak, aby jejich okraj `*` lícoval.

## Záruky

Pro každý formátovaný výstup platí tři invarianty, které vynucuje testovací sada:

- Výstup lze znovu parsovat na ekvivalentní program (bez ohledu na pozice).
- Ve výstupu zůstane zachován každý komentář ze vstupu.
- Formátování je idempotentní: opakované formátování již naformátovaného výstupu nic nezmění.

## Výkon

Formátování probíhá rychlostí parseru: skutečné soubory se formátují v řádu desítek milisekund a ručně psaný JavaScript běžného projektu se zpracuje celý za výrazně méně než sekundu v jediném procesu.
