
# Transformatorji

Transformatorji omogočajo preoblikovanje označenega izhoda na vsaki stopnji — od
izvornega niza prek mreže žetonov do končnega drevesa HAST in HTML.
shikiphp prenaša model transformatorjev Shiki po vseh priklopih, zato se transformatorji obnašajo
enako kot njihovi ustrezniki v JavaScript.

Podajte jih prek možnosti [`transformers`](https://shikiphp.inline0.dev/sl/docs/options#transformers):

```php
use Shikiphp\Shikiphp;
use Shikiphp\Transformer\Notation\NotationHighlight;
use Shikiphp\Transformer\Notation\NotationDiff;

$code = <<<'JS'
console.log('this line is highlighted') // [!code highlight]
console.log('old line') // [!code --]
console.log('new line') // [!code ++]
JS;

echo Shikiphp::codeToHtml($code, [
    'lang'         => 'js',
    'theme'        => 'vitesse-dark',
    'transformers' => [
        new NotationHighlight(),
        new NotationDiff(),
    ],
]);
```

## Cevovod

Vsak transformator je objekt, ki implementira `Shikiphp\Transformer\Transformer`.
Cevovod izvede priklope po vrsti med pripravo enega bloka:

| Priklop | Podpis | Kdaj |
| --- | --- | --- |
| `preprocess` | `(string $code, array &$options, $context): ?string` | pred tokenizacijo; lahko prepiše izvorno kodo in spremeni možnosti |
| `tokens` | `(array $tokens, $context): ?array` | po tokenizaciji, na 2D mreži `ThemedToken` |
| `root` | `(Element $el, $context): ?Element` | na korenu HAST |
| `pre` | `(Element $el, $context): ?Element` | na elementu `<pre>` |
| `code` | `(Element $el, $context): ?Element` | na elementu `<code>` |
| `line` | `(Element $el, int $line, $context): ?Element` | za vsak element vrstice (z začetkom pri 1) |
| `span` | `(Element $el, int $line, int $col, Element $lineEl, ThemedToken $token, $context): ?Element` | za vsak razpon žetona |
| `postprocess` | `(string $html, array $options, $context): ?string` | nad končnim serializiranim nizom HTML |

Vsi priklopi so neobvezni. Če vrnete vrednost, ta nadomesti vhod; če vrnete `null`,
ostane nespremenjen.

`enforce()` nadzira vrstni red transformatorjev: `'pre'` se izvede prvi, `'post'`
zadnji, `null` (privzeto) pa vmes, po vrstnem redu registracije.

## Pisanje transformatorja

Razširite `Shikiphp\Transformer\AbstractTransformer`, da preglasite samo potrebne priklope;
ostali ne naredijo ničesar. Kontekst transformatorja omogoča dostop do
`addClassToHast()` za dodajanje razredov elementom.

```php
use Shikiphp\Hast\Element;
use Shikiphp\Shikiphp;
use Shikiphp\Transformer\AbstractTransformer;
use Shikiphp\Transformer\TransformerContext;

final class AddLanguageClass extends AbstractTransformer
{
    public function pre(Element $element, TransformerContext $context): ?Element
    {
        if ($context->lang !== null) {
            $context->addClassToHast($element, 'language-' . $context->lang);
        }

        return $element;
    }
}

echo Shikiphp::codeToHtml('const answer = 42', [
    'lang'         => 'js',
    'theme'        => 'nord',
    'transformers' => [new AddLanguageClass()],
]);
// <pre class="shiki nord language-js" …>
```

## Vgrajeni transformatorji

### Transformatorji zapisa

Ti berejo posebne komentarje `// [!code …]` v izvorni kodi (skladnja komentarjev
jezika se zazna samodejno) in jih pretvorijo v razrede,
sam komentar pa odstranijo. Gre za neposreden prenos nabora zapisov `@shikijs/transformers`.

#### `NotationHighlight`

`Shikiphp\Transformer\Notation\NotationHighlight` — `// [!code highlight]` (ali
`// [!code hl]`) doda razred `highlighted` svoji vrstici.

```js
console.log('kept plain')
console.log('this line is highlighted') // [!code highlight]
```

#### `NotationDiff`

`Shikiphp\Transformer\Notation\NotationDiff` — `// [!code ++]` označi vrstico kot
 dodano (`diff add`), `// [!code --]` pa kot odstranjeno (`diff remove`).

```js
console.log('old line') // [!code --]
console.log('new line') // [!code ++]
```

#### `NotationFocus`

`Shikiphp\Transformer\Notation\NotationFocus` — `// [!code focus]` doda
razred `focused`.

```js
console.log('focus on me') // [!code focus]
```

#### `NotationErrorLevel`

`Shikiphp\Transformer\Notation\NotationErrorLevel` — `// [!code error]`,
`// [!code warning]` in `// [!code info]` dodajo razred `highlighted` ter
`error` / `warning` / `info`.

```js
throwSomething() // [!code error]
maybeRisky()     // [!code warning]
```

#### `NotationWordHighlight`

`Shikiphp\Transformer\Notation\NotationWordHighlight` — `// [!code word:foo]`
(po želji `// [!code word:foo:2]` za omejitev na naslednjih N vrstic) ovije vsako
pojavitve niza `foo` v element span z atributom `highlighted-word`.

```js
// [!code word:config]
const config = loadConfig()
```

### Pretvorniki metapodatkov

Ti berejo **metapodatkovni niz** ograje kode, podan prek
[`meta`](https://shikiphp.inline0.dev/sl/docs/options#meta) (`meta['__raw']`), podobno kot Shiki bere
besedilo za jezikom v ograjenem bloku kode.

#### `MetaHighlight`

`Shikiphp\Transformer\MetaHighlight` — poudari vrstice, navedene v obsegu metapodatkov,
na primer `{1,3-5}`, in doda razred `highlighted`.

```php
use Shikiphp\Shikiphp;
use Shikiphp\Transformer\MetaHighlight;

$code = "const a = 1\nconst b = 2\nconst c = 3\nconst d = 4\nconst e = 5";

echo Shikiphp::codeToHtml($code, [
    'lang'         => 'js',
    'theme'        => 'nord',
    'meta'         => ['__raw' => '{1,3-5}'],
    'transformers' => [new MetaHighlight()],
]);
```

#### `MetaWordHighlight`

`Shikiphp\Transformer\MetaWordHighlight` — poudari besede, navedene v metapodatkovnem
nizu s sintakso `/word/`, in doda `highlighted-word`.

### Presledki in struktura

#### `RenderWhitespace`

`Shikiphp\Transformer\RenderWhitespace` — ovije presledke in tabulatorje v
elemente span (privzeta razreda sta `space` in `tab`), da jih je mogoče vidno prikazati.
Konstruktor sprejme `(classSpace, classTab, position)`, kjer je `position`
`'all'` (privzeto), `'boundary'`, `'trailing'` ali `'leading'`.

#### `CompactLineOptions`

`Shikiphp\Transformer\CompactLineOptions` — uporabi razrede za določene vrstice
s seznama vnosov `{line, classes}`.

```php
use Shikiphp\Transformer\CompactLineOptions;

$transformer = new CompactLineOptions([
    ['line' => 1, 'classes' => 'highlighted'],
    ['line' => 3, 'classes' => ['highlighted', 'error']],
]);
```

Številčenje vrstic se začne z 1. Objekt podajte v možnosti `transformers`, tako
kot kateri koli drug pretvornik.

#### `RemoveNotationEscape`

`Shikiphp\Transformer\RemoveNotationEscape` — odstrani ubežne znake iz oblike `[\!code …]`,
ki se uporablja za zapis komentarja z dobesednim zapisom notacije, ne da bi sprožila pretvornik notacije.

#### `RemoveLineBreak`

`Shikiphp\Transformer\RemoveLineBreak` — odstrani besedilna vozlišča prelomov vrstic
med vrsticami (`transformerRemoveLineBreak` za Shiki).

### `StyleToClass`

`Shikiphp\Transformer\StyleToClass` — premakne vgrajene sloge v ustvarjene razrede
in zbere slogovno predlogo, ki jo pridobite z `getCSS()`. Imena razredov zgoščujejo slog z uporabo `cyrb53` za Shiki, zato je izhod bajt za bajtom enak kot pri `@shikijs/transformers`
4.2.0, vključno z njegovim obsegom:

- Slog `<pre>` vedno postane razred.
- Razponi žetonov se pretvorijo le, če vsebujejo vnaprej pripravljen slog, kar velja pri preslikavi `themes`. Pri enem samem `theme` razponi žetonov ohranijo vgrajeni `style="color:…"`, tako kot v Shiki.

```php
use Shikiphp\Shikiphp;
use Shikiphp\Transformer\StyleToClass;

$code = 'const answer = 42';
$styleToClass = new StyleToClass();

$html = Shikiphp::codeToHtml($code, [
    'lang'         => 'js',
    'themes'       => ['light' => 'github-light', 'dark' => 'github-dark'],
    'transformers' => [$styleToClass],
]);

$css = $styleToClass->getCSS(); // collected stylesheet for the classes above
```

Konstruktor sprejme `(classPrefix, classSuffix, classReplacer)`; privzeta
predpona je `__shiki_`.
