
# Oblikovalnik

Phasis vključuje izvorni oblikovalnik JavaScript, zgrajen na lastnem razčlenjevalniku. Izvorno kodo ponovno izpiše z načinom razporeditve, združljivim s prettier, v celoti v PHP: brez Node.js, interpretiranih paketov oblikovalnika ali zunanjih procesov.

## formatSource

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

Enotni vstopni ukaz na `Phasis\Formatter\Formatter`. `$sourceType` izbere jezik: `script` ali `module` za JavaScript, `json` ali `css`. JavaScript razčleni kodo glede na podani cilj, znova pripne komentarje in jo izpiše glede na nastavljeno širino izpisa.

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

Neveljavna izvorna koda sproži enako `Phasis\Exceptions\SyntaxError` kot razčlenjevalnik, z vrstico, stolpcem in odmikom.

## FormatOptions

Možnosti razporeditve posnemajo prettier 3.x in privzeto uporabljajo njegove privzete vrednosti:

| Možnost        | Privzeto   | Pomen                                                        |
| --------------- | ---------- | -------------------------------------------------------------- |
| `printWidth`    | `80`       | Ciljna širina vrstic, glede na katero se prilagodi razporeditev. |
| `tabWidth`      | `2`        | Število presledkov na raven zamika (in izmerjena širina tabulatorja). |
| `useTabs`       | `false`    | Za zamik uporabi tabulatorje namesto presledkov.                 |
| `semi`          | `true`     | Podpičja za zaključek stavkov.                                          |
| `singleQuote`   | `false`    | Kjer zahteva manj ubežnih znakov, daj prednost `'` pred `"`. |
| `trailingComma` | `'all'`    | `'all'`, `'es5'` ali `'none'`.                                      |
| `bracketSpacing`| `true`     | Presledki znotraj zavitih oklepajev objektov: `{ a }` proti `{a}`. |
| `arrowParens`   | `'always'` | `'always'` ali `'avoid'` za enoparametrske funkcije s puščico. |

## CSS

`formatSource($css, 'css')` oblikuje slogovne liste po razporeditvi slogovnih listov v prettier: en izbirnik na vrstico v seznamih izbirnikov, ena deklaracija na vrstico, poenoteni presledki okoli kombinatorjev in vrednosti, kratki seznami vrednosti, združeni v vrstice, seznami senc in prelivov, ločeni z vejicami in zapisani po eno na vrstico, argumenti funkcij, ki se razporedijo v celoti ali pa sploh ne, ohranjene prazne vrstice in komentarji ter nespremenjene uvodne direktive neznanih pravil at, kot je Tailwind z `@apply`. Dolgi sestavljeni izbirniki se prelomijo pri kombinatorjih potomcev, predolgi argumenti psevdorazredov pa se ovijejo znotraj oklepajev.

## JSON

`formatSource($json, 'json')` ponovno uporablja razčlenjevalnik in izpisovalnike iz JavaScript s pravili za json v prettier: ključi ostanejo v narekovajih, nizi ostanejo v dvojnih narekovajih ne glede na `singleQuote`, zaključne vejice se ne pojavijo, komentarji `//` znotraj dokumenta pa se ohranijo.

## Pravila razporeditve

Izpisovalnik uporablja model dokumenta prettier: skupine se sploščijo, če ustrezajo širini izpisa, sicer se prelomijo; argumenti klicev se tesno držijo končnega argumenta funkcije ali objekta; verige članov se pri predolgih vrsticah prelomijo pred vsako piko; večvrstični objekti ostanejo večvrstični; med stavki pa se ohrani največ ena prazna vrstica. Pri vhodu, oblikovanem s prettier z ustreznimi možnostmi, je izhod oblikovalnika po bajtih enak pri kodi iz resničnega sveta; njegova zbirka testov skladnosti to preverja s primeri, ustvarjenimi neposredno s prettier.

## Komentarji

Komentarji se zberejo med tokenizacijo (`Parser::setCollectComments(true)`, dostopni v razčlenjevalniku za orodja) in znova pripnejo drevesu kot začetne, končne ali viseče priloge. Vrstični komentarji ohranijo svoje vrstice, končni komentarji v isti vrstici ostanejo pri svojem stavku, prazne vrstice okoli komentarjev se ohranijo, bloki `/** ... */` pa se znova zamaknejo tako, da so njihove robne oznake `*` poravnane.

## Zagotovila

Za vsak oblikovani izhod veljajo tri invarianti, ki jih preverja zbirka testov:

- Izhod se znova razčleni v enakovreden program (razen lokacij).
- Vsi komentarji iz vhoda se ohranijo v izhodu.
- Oblikovanje je idempotentno: ponovno oblikovanje oblikovanega izhoda ne spremeni ničesar.

## Zmogljivost

Oblikovanje poteka s hitrostjo razčlenjevalnika: datoteke iz resničnega sveta se oblikujejo v nekaj deset milisekundah, ročno napisan JavaScript značilnega projekta pa se od začetka do konca oblikuje v manj kot sekundi v enem procesu.
