
# Transzformátorok

A transzformátorok a kiemelt kimenetet minden szakaszban átalakíthatják: a nyers forrássztringtől a tokenrácson át a végső HAST-fáig és az HTML-ig.
Az shikiphp hookról hookra veszi át a Shiki transzformátormodelljét, ezért a transzformátorok ugyanúgy működnek, mint a JavaScript megfelelőik.

Adja át őket a [`transformers`](https://shikiphp.inline0.dev/hu/docs/options#transformers) beállításon keresztül:

```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(),
    ],
]);
```

## A folyamat

Minden transzformátor egy `Shikiphp\Transformer\Transformer` interfészt megvalósító objektum.
A folyamat egyetlen blokk felépítése során, sorrendben futtatja a hookokat:

| Hook | Aláírás | Mikor |
| --- | --- | --- |
| `preprocess` | `(string $code, array &$options, $context): ?string` | tokenizálás előtt; átírhatja a forrást és módosíthatja a beállításokat |
| `tokens` | `(array $tokens, $context): ?array` | tokenizálás után, a 2D `ThemedToken` rácson |
| `root` | `(Element $el, $context): ?Element` | a HAST gyökérelemen |
| `pre` | `(Element $el, $context): ?Element` | a `<pre>` elemen |
| `code` | `(Element $el, $context): ?Element` | a `<code>` elemen |
| `line` | `(Element $el, int $line, $context): ?Element` | soronként, az elemen (1-től számozva) |
| `span` | `(Element $el, int $line, int $col, Element $lineEl, ThemedToken $token, $context): ?Element` | tokenenként, a span elemen |
| `postprocess` | `(string $html, array $options, $context): ?string` | a végső szerializált HTML sztringen |

Minden hook opcionális. A visszaadott érték lecseréli a bemenetet; az `null` visszaadása változatlanul hagyja.

Az `enforce()` szabályozza a transzformátorok közötti sorrendet: először az `'pre'` fut, utoljára az `'post'`, az `null` pedig (alapértelmezés szerint) közéjük kerül, a regisztráció sorrendjében.

## Transzformátor írása

Terjessze ki az `Shikiphp\Transformer\AbstractTransformer` típust, így csak a szükséges hookokat kell felülírnia; a többi üres művelet marad. A transzformátor környezete biztosítja az `addClassToHast()` metódust, amellyel osztályokat adhat az elemekhez.

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

## Beépített transzformátorok

### Jelölés-transzformátorok

Ezek a forrás speciális `// [!code …]` megjegyzéseit olvassák be (a megjegyzések szintaxisát automatikusan felismerik), majd osztályokká alakítják őket, magát a megjegyzést pedig eltávolítják. A `@shikijs/transformers` jelöléskészlet közvetlen átültetései.

#### `NotationHighlight`

`Shikiphp\Transformer\Notation\NotationHighlight` — a `// [!code highlight]` (vagy a `// [!code hl]`) hozzáadja a `highlighted` osztályt a sorhoz.

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

#### `NotationDiff`

`Shikiphp\Transformer\Notation\NotationDiff` — a `// [!code ++]` hozzáadottként jelöl egy sort (`diff add`), az `// [!code --]` pedig töröltként jelöli (`diff remove`).

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

#### `NotationFocus`

`Shikiphp\Transformer\Notation\NotationFocus` — a `// [!code focus]` hozzáadja a `focused` osztályt.

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

#### `NotationErrorLevel`

`Shikiphp\Transformer\Notation\NotationErrorLevel` — a `// [!code error]`, a `// [!code warning]` és a `// [!code info]` hozzáadja a `highlighted` osztályt, valamint a `error` / `warning` / `info` értékeket.

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

#### `NotationWordHighlight`

`Shikiphp\Transformer\Notation\NotationWordHighlight` — `// [!code word:foo]`
(opcionálisan `// [!code word:foo:2]` a következő N sorra való korlátozáshoz) minden
`foo`-előfordulást `highlighted-word` attribútumot hordozó span elembe csomagol.

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

### Metaadat-transzformátorok

Ezek a kódkerítésen keresztül megadott **metaadat-sztringet** olvassák be a [`meta`](https://shikiphp.inline0.dev/hu/docs/options#meta) beállítással (`meta['__raw']`), ahogyan az Shiki is beolvassa a bekerített kódblokk nyelve utáni szöveget.

#### `MetaHighlight`

`Shikiphp\Transformer\MetaHighlight` — kiemeli a metaadat-tartományban megadott sorokat, például a `{1,3-5}` sorait; ehhez hozzáadja a `highlighted` osztályt.

```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` — a metaadat-sztringben megadott szavakat emeli ki `/word/` szintaxissal, és hozzáadja a `highlighted-word` értéket.

### Szóközök és struktúra

#### `RenderWhitespace`

`Shikiphp\Transformer\RenderWhitespace` — a szóköz- és tabulátorkaraktereket span elemekbe csomagolja (alapértelmezés szerint az `space` és `tab` osztállyal), hogy láthatóan jelenjenek meg.
A konstruktor az `(classSpace, classTab, position)` értéket fogadja; az `position` értéke `'all'` (alapértelmezett), `'boundary'`, `'trailing'` vagy `'leading'` lehet.

#### `CompactLineOptions`

`Shikiphp\Transformer\CompactLineOptions` — osztályokat rendel meghatározott sorokhoz egy `{line, classes}` bejegyzéseket tartalmazó listából.

```php
use Shikiphp\Transformer\CompactLineOptions;

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

A sorszámozás 1-től indul. Az objektumot ugyanúgy a `transformers` beállítással adja át, mint bármely más transzformátort.

#### `RemoveNotationEscape`

`Shikiphp\Transformer\RemoveNotationEscape` — visszaalakítja az `[\!code …]` formát, amellyel egy szó szerinti jelölésmegjegyzést lehet írni a jelölés-transzformátor aktiválása nélkül.

#### `RemoveLineBreak`

`Shikiphp\Transformer\RemoveLineBreak` — eltávolítja a sortörést tartalmazó szövegcsomópontokat a sorok közül (az Shiki `transformerRemoveLineBreak` értékét).

### `StyleToClass`

`Shikiphp\Transformer\StyleToClass` — a beágyazott stílusokat generált osztályokká alakítja, és összegyűjti a stíluslapot, amely az `getCSS()` segítségével kérhető le. Az osztályneveket a stílus és az Shiki `cyrb53` értéke alapján hash-eli, így a kimenet bájtról bájtra megegyezik az `@shikijs/transformers` 4.2.0 értékével, beleértve a hatókört is:

- Az `<pre>` stílus mindig osztállyá alakul.
- A tokenek span elemei csak akkor alakulnak át, ha előre összeállított stílussal rendelkeznek, ami `themes` térkép esetén áll fenn. Egyetlen `theme` esetén a tokenek span elemei megtartják beágyazott `style="color:…"` értékeiket, ahogyan az Shiki esetében is.

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

A konstruktor `(classPrefix, classSuffix, classReplacer)` értéket fogad; az alapértelmezett előtag: `__shiki_`.
