
# Pārveidotāji

Pārveidotāji ļauj pārveidot izcelto izvadi katrā posmā — no
neapstrādātas avota virknes līdz tokenu režģim, galīgajam HAST kokam un HTML.
shikiphp pārņem Shiki pārveidotāju modeli, saglabājot katru āķi, tāpēc pārveidotāji darbojas tāpat kā to JavaScript līdzinieki.

Padodiet tos, izmantojot opciju [`transformers`](https://shikiphp.inline0.dev/lv/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(),
    ],
]);
```

## Darbplūsma

Katrs pārveidotājs ir objekts, kas implementē `Shikiphp\Transformer\Transformer`.
Veidojot vienu bloku, konveijers secīgi izsauc šos āķus:

| Āķis | Paraksts | Kad |
| --- | --- | --- |
| `preprocess` | `(string $code, array &$options, $context): ?string` | pirms tokenizācijas; var pārrakstīt avotu un mainīt opcijas |
| `tokens` | `(array $tokens, $context): ?array` | pēc tokenizācijas, 2D `ThemedToken` režģī |
| `root` | `(Element $el, $context): ?Element` | HAST saknē |
| `pre` | `(Element $el, $context): ?Element` | elementā `<pre>` |
| `code` | `(Element $el, $context): ?Element` | elementā `<code>` |
| `line` | `(Element $el, int $line, $context): ?Element` | katram rindas elementam (numerācija sākas ar 1) |
| `span` | `(Element $el, int $line, int $col, Element $lineEl, ThemedToken $token, $context): ?Element` | katram tokena span elementam |
| `postprocess` | `(string $html, array $options, $context): ?string` | galīgajā serializētajā HTML virknē |

Visi āķi nav obligāti. Atgriežot vērtību, ievade tiek aizstāta; atgriežot `null`,
tā paliek nemainīga.

`enforce()` nosaka secību starp pārveidotājiem: `'pre'` darbojas pirmais, `'post'`
darbojas pēdējais, bet `null` (pēc noklusējuma) darbojas pa vidu reģistrēšanas secībā.

## Pārveidotāja izveide

Paplašiniet `Shikiphp\Transformer\AbstractTransformer`, lai pārrakstītu tikai nepieciešamos āķus;
pārējie nedara neko. Transformatora konteksts nodrošina `addClassToHast()` elementu klašu pievienošanai.

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

## Iebūvētie pārveidotāji

### Apzīmējumu pārveidotāji

Tie nolasa avotā īpašus `// [!code …]` komentārus (komentāru sintakse tiek
automātiski noteikta pēc valodas) un pārvērš tos klasēs,
pašu komentāru noņemot. Tie ir tiešs `@shikijs/transformers`
apzīmējumu kopas ports.

#### `NotationHighlight`

`Shikiphp\Transformer\Notation\NotationHighlight` — `// [!code highlight]` (vai
`// [!code hl]`) pievieno rindai klasi `highlighted`.

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

#### `NotationDiff`

`Shikiphp\Transformer\Notation\NotationDiff` — `// [!code ++]` atzīmē rindu kā
pievienotu (`diff add`), bet `// [!code --]` — kā noņemtu (`diff remove`).

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

#### `NotationFocus`

`Shikiphp\Transformer\Notation\NotationFocus` — `// [!code focus]` pievieno klasi
`focused`.

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

#### `NotationErrorLevel`

`Shikiphp\Transformer\Notation\NotationErrorLevel` — `// [!code error]`,
`// [!code warning]` un `// [!code info]` pievieno klasi `highlighted`, kā arī
`error` / `warning` / `info`.

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

#### `NotationWordHighlight`

`Shikiphp\Transformer\Notation\NotationWordHighlight` — `// [!code word:foo]`
(neobligāti norādiet `// [!code word:foo:2]`, lai ierobežotu līdz nākamajām N rindām); katru
`foo` sastopamības vietu aptver span elements ar klasi `highlighted-word`.

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

### Meta pārveidotāji

Tie nolasa koda bloka **meta virkni**, kas padota ar opciju
[`meta`](https://shikiphp.inline0.dev/lv/docs/options#meta) (`meta['__raw']`), līdzīgi kā Shiki nolasa tekstu aiz iežogota koda bloka valodas nosaukuma.

#### `MetaHighlight`

`Shikiphp\Transformer\MetaHighlight` — izceļ meta diapazonā norādītās rindas,
piemēram, `{1,3-5}`, pievienojot klasi `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` — izceļ meta
virknē norādītos vārdus, izmantojot sintaksi `/word/`, un pievieno `highlighted-word`.

### Atstarpes un struktūra

#### `RenderWhitespace`

`Shikiphp\Transformer\RenderWhitespace` — aptver atstarpes un tabulācijas rakstzīmes ar
span elementiem (pēc noklusējuma klases `space` un `tab`), lai tās varētu redzami atveidot.
Konstruktors pieņem `(classSpace, classTab, position)`, kur `position` ir
`'all'` (pēc noklusējuma), `'boundary'`, `'trailing'` vai `'leading'`.

#### `CompactLineOptions`

`Shikiphp\Transformer\CompactLineOptions` — piešķir klases noteiktām rindām,
balstoties uz `{line, classes}` ierakstu sarakstu.

```php
use Shikiphp\Transformer\CompactLineOptions;

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

Rindu numerācija sākas ar 1. Padodiet objektu opcijā `transformers` tāpat
kā jebkuru citu pārveidotāju.

#### `RemoveNotationEscape`

`Shikiphp\Transformer\RemoveNotationEscape` — atkodē `[\!code …]` formu,
ko izmanto, lai uzrakstītu burtisku apzīmējuma komentāru un neiedarbinātu apzīmējumu pārveidotāju.

#### `RemoveLineBreak`

`Shikiphp\Transformer\RemoveLineBreak` — noņem rindu pārtraukumu teksta mezglus
starp rindām (Shiki `transformerRemoveLineBreak`).

### `StyleToClass`

`Shikiphp\Transformer\StyleToClass` — pārceļ iekļautos stilus uz ģenerētām klasēm
un apkopo stilu lapu, ko varat iegūt ar `getCSS()`. Klašu nosaukumos stila jaucējvērtība tiek aprēķināta ar Shiki `cyrb53`, tāpēc izvade ir byte-for-byte identiska `@shikijs/transformers` 4.2.0 izvadei, ieskaitot tās tvērumu:

- `<pre>` stils vienmēr kļūst par klasi.
- Tokenu span elementi tiek pārveidoti tikai tad, ja tiem ir iepriekš izveidots stils, kā tas ir `themes` atbilstības kartes gadījumā. Ja ir viens `theme`, tokenu span elementi saglabā savu iekļauto `style="color:…"`, tāpat kā Shiki gadījumā.

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

Konstruktors pieņem `(classPrefix, classSuffix, classReplacer)`; noklusējuma
prefikss ir `__shiki_`.
