
# Transformatoriai

Transformatoriai leidžia keisti paryškintą išvestį kiekviename etape — nuo
neapdorotos šaltinio eilutės, per žetonų tinklelį iki galutinio HAST medžio ir HTML.
shikiphp perkelia Shiki transformatorių modelį, kabliuką po kabliuko, todėl transformatoriai veikia
taip pat kaip jų JavaScript atitikmenys.

Perduokite juos per parinktį [`transformers`](https://shikiphp.inline0.dev/lt/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(),
    ],
]);
```

## Proceso eiga

Kiekvienas transformatorius yra objektas, įgyvendinantis `Shikiphp\Transformer\Transformer`.
Srautas vykdo kabliukus eilės tvarka kuriant vieną bloką:

| Kabliukas | Signatūra | Kada |
| --- | --- | --- |
| `preprocess` | `(string $code, array &$options, $context): ?string` | prieš žetonų skaidymą; gali perrašyti šaltinį ir keisti parinktis |
| `tokens` | `(array $tokens, $context): ?array` | po žetonų skaidymo, 2D `ThemedToken` tinklelyje |
| `root` | `(Element $el, $context): ?Element` | HAST šakniniame elemente |
| `pre` | `(Element $el, $context): ?Element` | elemente `<pre>` |
| `code` | `(Element $el, $context): ?Element` | elemente `<code>` |
| `line` | `(Element $el, int $line, $context): ?Element` | kiekviename eilutės elemente (numeruojama nuo 1) |
| `span` | `(Element $el, int $line, int $col, Element $lineEl, ThemedToken $token, $context): ?Element` | kiekviename žetono intervale |
| `postprocess` | `(string $html, array $options, $context): ?string` | galutinėje serializuotoje HTML eilutėje |

Visi kabliukai pasirenkami. Grąžinus reikšmę, ji pakeičia įvestį; grąžinus `null`,
įvestis lieka nepakeista.

`enforce()` valdo transformatorių eiliškumą: `'pre'` vykdomas pirmas, `'post'`
paskutinis, o `null` (numatytoji reikšmė) vykdomas tarp jų registravimo tvarka.

## Transformatoriaus kūrimas

Išplėskite `Shikiphp\Transformer\AbstractTransformer` ir perrašykite tik tuos kabliukus,
kurių reikia; kiti nieko nedarys. Transformatoriaus kontekste pateikiama
`addClassToHast()`, skirta elementų klasėms pridėti.

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

## Integruoti transformatoriai

### Notacijos transformatoriai

Jie aptinka specialius `// [!code …]` komentarus šaltinyje (komentarų sintaksė
kalboje nustatoma automatiškai) ir paverčia juos klasėmis,
o patį komentarą pašalina. Tai tiesioginiai `@shikijs/transformers`
notacijų rinkinio perkėlimai.

#### `NotationHighlight`

`Shikiphp\Transformer\Notation\NotationHighlight` — `// [!code highlight]` (arba
`// [!code hl]`) eilutei prideda klasę `highlighted`.

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

#### `NotationDiff`

`Shikiphp\Transformer\Notation\NotationDiff` — `// [!code ++]` pažymi eilutę kaip
pridėtą (`diff add`), o `// [!code --]` — kaip pašalintą (`diff remove`).

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

#### `NotationFocus`

`Shikiphp\Transformer\Notation\NotationFocus` — `// [!code focus]` prideda
klasę `focused`.

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

#### `NotationErrorLevel`

`Shikiphp\Transformer\Notation\NotationErrorLevel` — `// [!code error]`,
`// [!code warning]` ir `// [!code info]` prideda klasę `highlighted` bei
`error` / `warning` / `info`.

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

#### `NotationWordHighlight`

`Shikiphp\Transformer\Notation\NotationWordHighlight` — `// [!code word:foo]`
(pasirinktinai `// [!code word:foo:2]`, kad apimtų tik kitas N eilučių) kiekvieną
`foo` atvejį apgaubia intervalu su `highlighted-word`.

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

### Metaduomenų transformatoriai

Jie nuskaito kodo bloko **metaduomenų eilutę**, perduodamą per parinktį
[`meta`](https://shikiphp.inline0.dev/lt/docs/options#meta) (`meta['__raw']`), kaip Shiki nuskaito
tekstą po aptverto kodo bloko kalbos žymos.

#### `MetaHighlight`

`Shikiphp\Transformer\MetaHighlight` — paryškina metaduomenų intervale nurodytas eilutes,
pavyzdžiui, `{1,3-5}`, ir prideda klasę `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` — paryškina metaduomenų eilutėje nurodytus žodžius
naudodamas sintaksę `/word/` ir prideda `highlighted-word`.

### Tarpai ir struktūra

#### `RenderWhitespace`

`Shikiphp\Transformer\RenderWhitespace` — tarpų ir tabuliacijos simbolius apgaubia
intervalais (pagal numatytuosius nustatymus klasės `space` ir `tab`), kad jie būtų matomi.
Konstruktoriui perduodamas `(classSpace, classTab, position)`, kur `position` yra
`'all'` (numatytoji reikšmė), `'boundary'`, `'trailing'` arba `'leading'`.

#### `CompactLineOptions`

`Shikiphp\Transformer\CompactLineOptions` — priskiria klases konkrečioms eilutėms
pagal `{line, classes}` įrašų sąrašą.

```php
use Shikiphp\Transformer\CompactLineOptions;

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

Eilučių numeracija prasideda nuo 1. Perduokite objektą per parinktį `transformers`, kaip ir bet kurį
kitą transformatorių.

#### `RemoveNotationEscape`

`Shikiphp\Transformer\RemoveNotationEscape` — panaikina `[\!code …]` formos eskeipinimą,
naudojamą pažodiniam notacijos komentarui užrašyti, kad jis nesuaktyvintų notacijos
transformatoriaus.

#### `RemoveLineBreak`

`Shikiphp\Transformer\RemoveLineBreak` — pašalina eilučių lūžių teksto mazgus
tarp eilučių (Shiki elemento `transformerRemoveLineBreak`).

### `StyleToClass`

`Shikiphp\Transformer\StyleToClass` — perkelia įterptuosius stilius į sugeneruotas klases
ir surenka stiliaus lentelę, kurią galima gauti naudojant `getCSS()`. Klasių pavadinimai maišos funkcija apskaičiuojami iš stiliaus,
naudojant Shiki `cyrb53`, todėl išvestis baitas į baitą sutampa su `@shikijs/transformers`
4.2.0, įskaitant jo taikymo sritį:

- `<pre>` stilius visada paverčiamas klase.
- Žetonų intervalai konvertuojami tik tada, kai turi iš anksto sukurtą stilių, kaip būna
  naudojant `themes` atvaizdį. Naudojant vieną `theme`, žetonų intervalai išlaiko
  įterptąjį `style="color:…"`, kaip ir 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
```

Konstruktoriui perduodamas `(classPrefix, classSuffix, classReplacer)`; numatytasis
prefiksas yra `__shiki_`.
