Skip to content

Commit 8194262

Browse files
committed
Update plugins info
1 parent 4671675 commit 8194262

12 files changed

Lines changed: 140 additions & 32 deletions

File tree

.vitepress/config.mts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ gtag('config', 'G-VYGDN3X0PR');`],
112112
{ text: 'Events', link: '/docs/events.md' },
113113
],
114114
},
115+
{
116+
text: 'Garage',
117+
items: [],
118+
},
115119
],
116120
},
117121
},
@@ -147,21 +151,21 @@ gtag('config', 'G-VYGDN3X0PR');`],
147151
text: 'Плагины',
148152
link: '/ru/docs/plugins.md',
149153
items: [
150-
{ text: 'Атрибут \#[Test]', link: '/ru/docs/plugins/test.md' },
151-
{ text: 'Assert и Expect', link: '/ru/docs/plugins/assert.md' },
152-
{ text: 'Конвенции именования', link: '/ru/docs/plugins/convention.md' },
153-
{ text: 'Встроенные тесты', link: '/ru/docs/plugins/inline.md' },
154-
{ text: 'Провайдеры данных', link: '/ru/docs/plugins/data.md' },
155-
{ text: 'Жизненный цикл', link: '/ru/docs/plugins/lifecycle.md' },
154+
{ text: 'Assert (проверки)', link: '/ru/docs/plugins/assert.md' },
155+
{ text: 'Data (провайдеры данных)', link: '/ru/docs/plugins/data.md' },
156+
{ text: 'Inline (встроенные тесты)', link: '/ru/docs/plugins/inline.md' },
156157
{ text: 'Retry', link: '/ru/docs/plugins/retry.md' },
157-
{ text: 'Бенчмарки', link: '/ru/docs/plugins/bench.md' },
158+
{ text: 'Bench', link: '/ru/docs/plugins/bench.md' },
159+
{ text: '\#[Test]', link: '/ru/docs/plugins/test.md' },
160+
{ text: 'Lifecycle', link: '/ru/docs/plugins/lifecycle.md' },
161+
{ text: 'Convention', link: '/ru/docs/plugins/convention.md' },
162+
{ text: 'Filter', link: '/ru/docs/plugins/filter.md' },
158163
],
159164
},
160165
{
161166
text: 'Руководство',
162167
items: [
163168
{ text: 'CLI справка', link: '/ru/docs/cli-reference.md' },
164-
{ text: 'Фильтрация', link: '/ru/docs/plugins/filter.md' },
165169
],
166170
},
167171
{
@@ -170,6 +174,10 @@ gtag('config', 'G-VYGDN3X0PR');`],
170174
{ text: 'События', link: '/ru/docs/events.md' },
171175
],
172176
},
177+
{
178+
text: 'Гараж',
179+
items: [],
180+
},
173181
],
174182
},
175183
outline: {

.vitepress/plugin-block.ts

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ interface PluginLabels {
2525
pluginClass: string
2626
includedIn: (set: string) => string
2727
notIncluded: string
28+
noSetup: string
2829
github: string
2930
}
3031

@@ -33,12 +34,14 @@ const labels: Record<string, PluginLabels> = {
3334
pluginClass: 'Plugin class',
3435
includedIn: (set) => `Included in <class>${set}</class> — enabled by default.`,
3536
notIncluded: 'Not included in default plugins.',
37+
noSetup: 'The plugin does not require setup.',
3638
github: 'GitHub',
3739
},
3840
ru: {
3941
pluginClass: 'Класс плагина',
4042
includedIn: (set) => `Входит в <class>${set}</class> по умолчанию.`,
4143
notIncluded: 'Не входит в состав плагинов по умолчанию.',
44+
noSetup: 'Плагин не требует настройки.',
4245
github: 'GitHub',
4346
},
4447
}
@@ -91,10 +94,10 @@ export function preScanPlugins(srcDir: string): void {
9194
const attrs = match[1]
9295
const fqn = parseAttr(attrs, 'class')
9396
const name = parseAttr(attrs, 'name')
94-
if (!fqn || !name) continue
97+
if (!name) continue
9598

9699
const included = parseAttr(attrs, 'included')
97-
registerPlugin(locale.code, { fqn, name, pagePath, included })
100+
registerPlugin(locale.code, { fqn: fqn || name, name, pagePath, included })
98101
}
99102
}
100103
}
@@ -148,7 +151,7 @@ export function pluginBlockPlugin(md: MarkdownIt) {
148151

149152
const fqn = parseAttr(line, 'class')
150153
const name = parseAttr(line, 'name')
151-
if (!fqn || !name) return false
154+
if (!name) return false
152155

153156
const included = parseAttr(line, 'included')
154157
const github = parseAttr(line, 'github')
@@ -158,24 +161,40 @@ export function pluginBlockPlugin(md: MarkdownIt) {
158161
const locale = getLocaleByPath('/' + relativePath)
159162
const pagePath = '/' + relativePath.replace(/\.md$/, '').replace(/\/index$/, '/')
160163

161-
registerPlugin(locale.code, { fqn, name, pagePath, included })
164+
registerPlugin(locale.code, { fqn: fqn || name, name, pagePath, included })
162165

163166
const l = labels[locale.code] ?? labels.en
164-
const statusHtml = included ? l.includedIn(included) : l.notIncluded
167+
168+
let statusHtml: string
169+
if (included) {
170+
statusHtml = l.includedIn(included)
171+
} else if (fqn) {
172+
statusHtml = l.notIncluded
173+
} else {
174+
statusHtml = l.noSetup
175+
}
165176

166177
let linksHtml = ''
167178
if (github) {
168179
linksHtml = ` <a href="${escapeHtml(github)}" target="_blank" rel="noopener">${l.github}</a>`
169180
}
170181

182+
// Build inline content
183+
let inlineContent: string
184+
if (fqn) {
185+
inlineContent = `${l.pluginClass}: <class>${fqn}</class>. ${statusHtml}${linksHtml}`
186+
} else {
187+
inlineContent = `${statusHtml}${linksHtml}`
188+
}
189+
171190
// Open wrapper as raw HTML
172191
const openToken = state.push('html_block', '', 0)
173192
openToken.content = `<div class="info custom-block" data-info-icon>\n<p>\n`
174193
openToken.map = [startLine, startLine + 1]
175194

176195
// Inline content — <class> will be processed by inline rules
177196
const inlineToken = state.push('inline', '', 0)
178-
inlineToken.content = `${l.pluginClass}: <class>${fqn}</class>. ${statusHtml}${linksHtml}`
197+
inlineToken.content = inlineContent
179198
inlineToken.map = [startLine, startLine + 1]
180199
inlineToken.children = []
181200

CLAUDE.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,63 @@ Renders as `Assert::blank()` with syntax highlighting. On hover, shows a tooltip
195195

196196
**Registry:** All `<signature>` blocks with FQN names (starting with `\`) are collected at build startup. The `<func>` tag content is matched by stripping arguments: `\Testo\Assert::blank()` matches `\Testo\Assert::blank(mixed $actual, string $message = ''): void`.
197197

198+
## Class References (`<class>`)
199+
200+
For referencing PHP classes inline. Renders the short class name (without namespace) with a hover tooltip showing the full FQN.
201+
202+
**Plugin:** `.vitepress/func-block.ts` — inline + block rules.
203+
204+
**Syntax:**
205+
```html
206+
<class>\Testo\Assert</class>
207+
```
208+
209+
Renders as `Assert` styled as inline code. On hover, shows a tooltip with the full class name `\Testo\Assert`.
210+
211+
**Behavior:**
212+
- Works both inline (inside text) and at the start of a line (block rule wraps in paragraph)
213+
- Namespace is stripped for display: `\Testo\Assert\AssertPlugin``AssertPlugin`
214+
- Styled as inline `<code>` with `var(--vp-code-color)` and `var(--vp-code-bg)`
215+
216+
**Styles:** `.vitepress/theme/style.css``.class-ref` class.
217+
218+
## Plugin References (`<plugin>`)
219+
220+
For linking to plugin documentation pages by name. Renders as a clickable link to the plugin's page.
221+
222+
**Plugin:** `.vitepress/func-block.ts` — inline + block rules. **Registry:** `.vitepress/plugin-block.ts` — collects `<plugin-info>` blocks.
223+
224+
**Syntax:**
225+
```html
226+
<plugin>Assert</plugin>
227+
```
228+
229+
Renders as a link to the Assert plugin page. The name is matched case-insensitively against `<plugin-info>` blocks.
230+
231+
**Behavior:**
232+
- Lookup by `name` attribute from `<plugin-info>` tags (case-insensitive)
233+
- If no match found, renders as plain text
234+
- Locale-aware: EN pages link to EN plugin pages, RU to RU
235+
236+
## Plugin Info Card (`<plugin-info>`)
237+
238+
Block-level tag for plugin documentation pages. Renders a styled info card with plugin class, inclusion status, and optional links. Also registers the plugin in the registry for `<plugin>` cross-references.
239+
240+
**Plugin:** `.vitepress/plugin-block.ts` — markdown-it block rule + registry with pre-scan.
241+
242+
**Syntax:**
243+
```html
244+
<plugin-info class="\Testo\Assert\AssertPlugin" name="Assert" included="\Testo\Application\Config\Plugin\SuitePlugins" />
245+
<plugin-info class="\Testo\Convention\ConventionPlugin" name="Convention" />
246+
<plugin-info class="\Testo\Filter\FilterPlugin" name="Filter" included="\Testo\Application\Config\Plugin\ApplicationPlugins" github="https://..." />
247+
```
248+
249+
**Attributes:**
250+
- `class` (required) — FQN of the plugin class. Rendered as `<class>` with tooltip.
251+
- `name` (required) — human-readable plugin name. Used for `<plugin>` cross-references.
252+
- `included` — FQN of the plugin set (e.g. `\Testo\Application\Config\Plugin\SuitePlugins`). Rendered as `<class>` with tooltip. Omit if the plugin must be registered manually.
253+
- `github` — URL to plugin's GitHub page (optional).
254+
198255
## VitePress Commands
199256

200257
```bash

docs/plugins/bench.md

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
11
# Benchmarks
22

33
<plugin-info class="\Testo\Bench\BenchmarkPlugin" name="Benchmark" included="\Testo\Application\Config\Plugin\SuitePlugins" />
4-
5-
6-
7-
8-
::: question Why does the attribute need a method if you can just pass a list of equal callables?
9-
The `#[Bench]` attribute on a method defines the **baseline implementation** — the reference point that others are compared against. Callables in the parameter are alternative implementations for comparison. This allows you to automatically fail the test if the baseline is slower than an alternative, and use benchmarks as checks in CI.
10-
:::

ru/docs/plugins/bench.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
11
# Бенчмарки
22

3-
<plugin-info class="\Testo\Bench\BenchmarkPlugin" name="Benchmark" included="\Testo\Application\Config\Plugin\SuitePlugins" />
3+
<plugin-info name="Bench" class="\Testo\Bench\BenchmarkPlugin" included="\Testo\Application\Config\Plugin\SuitePlugins" />
4+
5+
6+
7+
8+
::: question Зачем атрибуту нужен сам метод, если можно передать список равнозначных callable?
9+
Атрибут `#[Bench]` на методе задаёт **базовую реализацию** — эталон, с которым сравниваются остальные. Callable в параметре — это альтернативные реализации для сравнения. Это позволяет автоматически фейлить тест, если базовая реализация оказалась медленнее альтернативной, и использовать бенчмарки как проверки в CI.
10+
:::

ru/docs/plugins/convention.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Конвенции именования
22

3-
Testo может находить тесты по паттернам именования — атрибуты не нужны.
3+
Плагин обнаруживает тесты согласно конвенции по именованию классов, методов и функций без необходимости использования атрибутов.
4+
5+
<plugin-info name="Convention" class="\Testo\Convention\NamingConventionPlugin" />
46

57
Распознаваемые паттерны:
68

@@ -20,6 +22,21 @@ final class UserServiceTest
2022
function testEmailValidator(): void { /* ... */ }
2123
```
2224

25+
Вы можете настроить суффиксы и префиксы, а также разрешить или запретить обнаружение приватных методов:
26+
27+
```php
28+
new SuiteConfig(
29+
// ...
30+
plugins: [
31+
new NamingConventionPlugin(
32+
caseSuffix: 'Test',
33+
testPrefix: 'test',
34+
allowPrivate: false,
35+
),
36+
]
37+
),
38+
```
39+
2340
## Когда использовать
2441

2542
Используйте конвенции именования, когда:

ru/docs/plugins/data.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
Провайдеры данных позволяют запускать один тест с разными наборами входных данных. Каждый набор — отдельный запуск теста.
44

5+
<plugin-info name="Data" />
6+
57
## DataSet
68

79
Самый простой способ — указать данные прямо над методом:

ru/docs/plugins/inline.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
Встроенные тесты позволяют писать тесты прямо на тестируемом методе с помощью атрибута `#[TestInline]`. Отдельный тестовый класс не нужен.
44

5+
<plugin-info name="Inline" class="\Testo\Inline\InlineTestPlugin" included="\Testo\Application\Config\Plugin\SuitePlugins" />
6+
57
```php
68
#[TestInline([1, 1], 2)]
79
#[TestInline([40, 2], 42)]

ru/docs/plugins/lifecycle.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Атрибуты жизненного цикла позволяют выполнять код до и после тестов — для подготовки окружения, очистки состояния и управления ресурсами.
44

5-
<plugin-info class="\Testo\Lifecycle\LifecyclePlugin" name="Lifecycle" included="\Testo\Application\Config\Plugin\SuitePlugins" />
5+
<plugin-info name="Lifecycle" class="\Testo\Lifecycle\LifecyclePlugin" included="\Testo\Application\Config\Plugin\SuitePlugins" />
66

77
## Инстанциирование класса
88

ru/docs/plugins/retry.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Retry
22

3-
<plugin-info class="\Testo\Retry\RetryPlugin" name="Retry" included="\Testo\Application\Config\Plugin\SuitePlugins" />
3+
<plugin-info name="Retry" />
44

55
::: tip Coming Soon
66
:::

0 commit comments

Comments
 (0)