@7n/rules-lang-js 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/package.json +1 -1
- package/rules/bun/package_json/package_json.mdc +2 -2
- package/rules/bun/package_json/package_json.rego +26 -10
- package/rules/npm-module/npm_package_json/npm_package_json.mdc +1 -1
- package/rules/npm-module/npm_package_json/npm_package_json.rego +14 -5
- package/rules/storybook/adopt/docs/main.md +1 -2
- package/rules/storybook/adopt/main.mjs +37 -5
- package/rules/storybook/ci/concern.json +15 -0
- package/rules/storybook/ci/docs/fix-ci.md +39 -0
- package/rules/storybook/ci/docs/index.md +10 -0
- package/rules/storybook/ci/docs/main.md +50 -0
- package/rules/storybook/ci/fix-ci.mjs +105 -0
- package/rules/storybook/ci/main.mjs +112 -0
- package/rules/storybook/ci/template/lint-storybook.yml.snippet.yml +41 -0
- package/rules/storybook/ci/template/setup-playwright-chromium.action.yml +34 -0
- package/rules/storybook/hygiene/concern.json +1 -1
- package/rules/storybook/main.json +1 -1
- package/rules/storybook/main.mdc +24 -3
- package/rules/storybook/mocking/mocking.mdc +24 -0
- package/rules/storybook/scaffold/concern.json +1 -1
- package/rules/storybook/scaffold/docs/fix-scaffold.md +1 -1
- package/rules/storybook/scaffold/docs/main.md +1 -1
- package/rules/storybook/scaffold/fix-scaffold.mjs +50 -0
- package/rules/storybook/scaffold/main.mjs +68 -6
- package/rules/storybook/scaffold/template/docs/empty-vite.config.md +28 -0
- package/rules/storybook/scaffold/template/docs/index.md +5 -4
- package/rules/storybook/scaffold/template/docs/main.md +1 -2
- package/rules/storybook/scaffold/template/docs/preview.md +1 -2
- package/rules/storybook/scaffold/template/empty-vite.config.js +18 -0
- package/rules/storybook/scaffold/template/main.js +76 -6
- package/rules/storybook/scaffold/template/preview.js +13 -5
- package/rules/storybook/vitest-config/concern.json +1 -1
- package/rules/storybook/vitest-config/docs/fix-vitest-config.md +1 -2
- package/rules/storybook/vitest-config/docs/main.md +1 -2
- package/rules/storybook/vitest-config/fix-vitest-config.mjs +22 -6
- package/rules/storybook/vitest-config/main.mjs +33 -2
- package/rules/storybook/vitest-config/template/docs/storybook-project-entry.md +1 -2
- package/rules/storybook/vitest-config/template/docs/vitest.config.baseline.md +1 -2
- package/rules/storybook/vitest-config/template/storybook-project-entry.js +6 -2
- package/rules/storybook/vitest-config/template/vitest.config.baseline.mjs +2 -1
- package/rules/storybook/vitest-config/vitest-config.mdc +7 -3
|
@@ -3,10 +3,15 @@
|
|
|
3
3
|
* канон-storybook-для-vue-компонентних-бібліотек). Згенеровано правилом `storybook` —
|
|
4
4
|
* `npx @7n/rules fix storybook` відтворює цей файл, якщо його видалено чи зламано канон.
|
|
5
5
|
*/
|
|
6
|
-
import { setup } from '@storybook/vue3'
|
|
7
|
-
import { Dialog,
|
|
6
|
+
import { setup } from '@storybook/vue3-vite'
|
|
7
|
+
import { Dialog, Notify, Quasar } from 'quasar'
|
|
8
8
|
import iconSet from 'quasar/icon-set/svg-material-icons'
|
|
9
|
-
|
|
9
|
+
// Імпорт через підшлях пакета — НЕ named-import `iconSet` напряму з `quasar`: quasar
|
|
10
|
+
// 2.18.x не має цього імені як runtime-binding (лише компонент `IconSet` з великої
|
|
11
|
+
// літери), і `@quasar/vite-plugin`-transform падає з "Unknown import from Quasar" на
|
|
12
|
+
// такому специфікаторі. Підшлях (як і кастомний `iconSet` вище) обходить transform повністю.
|
|
13
|
+
import quasarBuiltinIconSet from 'quasar/icon-set/material-icons'
|
|
14
|
+
import { initialize, mswLoader } from 'msw-storybook-addon'
|
|
10
15
|
|
|
11
16
|
import 'quasar/dist/quasar.css'
|
|
12
17
|
|
|
@@ -36,9 +41,12 @@ setup(app => {
|
|
|
36
41
|
})
|
|
37
42
|
})
|
|
38
43
|
|
|
39
|
-
/** @type {import('@storybook/vue3').Preview} */
|
|
44
|
+
/** @type {import('@storybook/vue3-vite').Preview} */
|
|
40
45
|
const preview = {
|
|
41
|
-
|
|
46
|
+
// mswLoader (не mswDecorator — deprecated у msw-storybook-addon 2.x, буде видалений
|
|
47
|
+
// у наступному релізі): loaders виконуються per-story ДО рендеру й інтегруються з
|
|
48
|
+
// async story-рендерингом Storybook, на відміну від декоратора.
|
|
49
|
+
loaders: [mswLoader],
|
|
42
50
|
parameters: {
|
|
43
51
|
controls: { matchers: { color: /(background|color)$/iu, date: /Date$/u } }
|
|
44
52
|
}
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
"fixability": "config",
|
|
4
4
|
"lint": {
|
|
5
5
|
"scope": "full",
|
|
6
|
-
"glob": ["package.json", "**/*.vue", "
|
|
6
|
+
"glob": ["**/package.json", "**/*.vue", "**/.storybook/**", "**/vitest.config.*", "**/vitest.stryker.config.*"]
|
|
7
7
|
}
|
|
8
8
|
}
|
|
@@ -3,9 +3,8 @@ type: JS Module
|
|
|
3
3
|
title: fix-vitest-config.mjs
|
|
4
4
|
resource: plugins/lang-js/rules/storybook/vitest-config/fix-vitest-config.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
6
|
+
crc: 35b10da8
|
|
7
7
|
model: openai-codex/gpt-5.4-mini
|
|
8
|
-
tier: cloud-min
|
|
9
8
|
score: 100
|
|
10
9
|
issues: judge:inaccurate:0.98
|
|
11
10
|
judgeModel: openai-codex/gpt-5.4-mini
|
|
@@ -3,9 +3,8 @@ type: JS Module
|
|
|
3
3
|
title: main.mjs
|
|
4
4
|
resource: plugins/lang-js/rules/storybook/vitest-config/main.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
6
|
+
crc: 543716c9
|
|
7
7
|
model: openai-codex/gpt-5.4-mini
|
|
8
|
-
tier: cloud-min
|
|
9
8
|
score: 85
|
|
10
9
|
issues: internal-name:detectStoriesGlob,anchor-miss:(vitest-config.mdc),judge:inaccurate:0.99
|
|
11
10
|
judgeModel: openai-codex/gpt-5.4-mini
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
findTestObject,
|
|
22
22
|
LEADING_COMMA_RE,
|
|
23
23
|
parseModule,
|
|
24
|
+
PLAYWRIGHT_PROVIDER_IMPORT,
|
|
24
25
|
REASON_STORYBOOK_PROJECT_MISSING,
|
|
25
26
|
REASON_STRYKER_CONFIG_MISSING,
|
|
26
27
|
REASON_UNIT_PROJECT_MISSING,
|
|
@@ -145,14 +146,29 @@ function arrayInsertBeforeClose(arr, indent, entries) {
|
|
|
145
146
|
}
|
|
146
147
|
|
|
147
148
|
/**
|
|
148
|
-
* Гарантує наявність import-у
|
|
149
|
-
*
|
|
150
|
-
*
|
|
149
|
+
* Гарантує наявність import-у на самому початку файлу — ESM толерантний до
|
|
150
|
+
* порядку import-ів, тож prepend завжди синтаксично коректний незалежно від
|
|
151
|
+
* наявних import-ів.
|
|
151
152
|
* @param {string} src вихідний текст
|
|
153
|
+
* @param {string} marker підрядок, наявність якого означає "import уже є"
|
|
154
|
+
* @param {string} importLine рядок import-у (з `\n` наприкінці), що вставляється, якщо `marker` відсутній
|
|
152
155
|
* @returns {string} текст з гарантованим import-ом
|
|
153
156
|
*/
|
|
154
|
-
function
|
|
155
|
-
return src.includes(
|
|
157
|
+
function ensureImport(src, marker, importLine) {
|
|
158
|
+
return src.includes(marker) ? src : `${importLine}${src}`
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Гарантує наявність обох import-ів, потрібних новому storybook-запису
|
|
163
|
+
* `test.projects`: `storybookTest` (`@storybook/addon-vitest/vitest-plugin`) і
|
|
164
|
+
* `playwright`-provider factory (`@vitest/browser-playwright`, vitest@^4 —
|
|
165
|
+
* рядкове API `provider: 'playwright'` застаріле).
|
|
166
|
+
* @param {string} src вихідний текст
|
|
167
|
+
* @returns {string} текст з гарантованими import-ами
|
|
168
|
+
*/
|
|
169
|
+
function ensureStorybookEntryImports(src) {
|
|
170
|
+
const withStorybookTest = ensureImport(src, '@storybook/addon-vitest/vitest-plugin', STORYBOOK_TEST_IMPORT)
|
|
171
|
+
return ensureImport(withStorybookTest, '@vitest/browser-playwright', PLAYWRIGHT_PROVIDER_IMPORT)
|
|
156
172
|
}
|
|
157
173
|
|
|
158
174
|
/**
|
|
@@ -224,7 +240,7 @@ async function computeVitestConfigAugment(absPkgDir, vitestConfigPath) {
|
|
|
224
240
|
if (!plan) return null
|
|
225
241
|
|
|
226
242
|
let next = applyEdits(src, [plan.edit])
|
|
227
|
-
if (plan.needsImport) next =
|
|
243
|
+
if (plan.needsImport) next = ensureStorybookEntryImports(next)
|
|
228
244
|
|
|
229
245
|
// Safety: результат має компілюватися; інакше не пишемо (fail-closed, як у test/stryker_config).
|
|
230
246
|
let recheck
|
|
@@ -18,6 +18,9 @@ const VITE_CONFIG_NAMES = ['vite.config.js', 'vite.config.ts', 'vite.config.mjs'
|
|
|
18
18
|
/** Import, який має бути присутній у файлі, щоб `storybookTest(...)` резолвився. */
|
|
19
19
|
export const STORYBOOK_TEST_IMPORT = "import { storybookTest } from '@storybook/addon-vitest/vitest-plugin'\n"
|
|
20
20
|
|
|
21
|
+
/** Import, який має бути присутній у файлі, щоб `playwright(...)`-factory (vitest@^4) резолвилась. */
|
|
22
|
+
export const PLAYWRIGHT_PROVIDER_IMPORT = "import { playwright } from '@vitest/browser-playwright'\n"
|
|
23
|
+
|
|
21
24
|
// Стабільні reasons (namespace: ruleId/concernId/reason).
|
|
22
25
|
export const REASON_VITEST_CONFIG_MISSING = 'vitest-config-missing'
|
|
23
26
|
export const REASON_STRYKER_CONFIG_MISSING = 'stryker-config-missing'
|
|
@@ -29,12 +32,20 @@ export const REASON_STORYBOOK_PROJECT_MARKER_MISSING = 'storybook-project-marker
|
|
|
29
32
|
|
|
30
33
|
// Маркери канонічного storybook-проєкту (текстовий пошук у зрізі джерела самого
|
|
31
34
|
// елемента масиву — стійко до форматування/AST-варіацій, як і scaffold/main.mjs).
|
|
32
|
-
//
|
|
35
|
+
// Експортовані — переюз у `adopt/main.mjs`.
|
|
33
36
|
const UNIT_NAME_RE = /name\s*:\s*['"]unit['"]/u
|
|
34
37
|
const STORYBOOK_NAME_RE = /name\s*:\s*['"]storybook['"]/u
|
|
35
38
|
export const CHROMIUM_RE = /chromium/u
|
|
36
39
|
export const BROWSER_KEY_RE = /\bbrowser\s*:/u
|
|
37
40
|
export const STORIES_RE = /stories/iu
|
|
41
|
+
// `storybookTest({ configDir: ... })` без явного `include` — легітимний патерн:
|
|
42
|
+
// Storybook підхоплює stories-glob автоматично зі своєї `.storybook/main.js`-конфігурації
|
|
43
|
+
// (той самий stories-glob, що й `detectStoriesGlob`), явний include у vitest-конфізі не
|
|
44
|
+
// обов'язковий (реальний кейс components/npm/vitest.config.js — пілот adopt-діагностики).
|
|
45
|
+
export const STORYBOOK_TEST_CONFIG_DIR_RE = /storybookTest\([^)]*configDir/u
|
|
46
|
+
// vitest@^4: `browser.provider` — factory-виклик (`playwright()` з `@vitest/browser-playwright`),
|
|
47
|
+
// не рядок `'playwright'` (застаріле API попередніх мажорів).
|
|
48
|
+
export const PROVIDER_FACTORY_RE = /provider\s*:\s*playwright\s*\(/u
|
|
38
49
|
const STORIES_GLOB_PREFIX_RE = /^\.\.\//u
|
|
39
50
|
// Module-scope (prefer-static-regex): рядок-відступ цілком whitespace; leading
|
|
40
51
|
// кома (можливо з whitespace) — спільні з fix-vitest-config.mjs патерном augment-у.
|
|
@@ -173,6 +184,22 @@ export function classifyProjects(src, arr) {
|
|
|
173
184
|
return { hasUnit, storybookSlice }
|
|
174
185
|
}
|
|
175
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Чи присутній валідний маркер джерела stories у зрізі `storybook`-проєкту:
|
|
189
|
+
* явний stories-glob (`include: [...]`, {@link STORIES_RE}) АБО виклик
|
|
190
|
+
* `storybookTest({ configDir })` без явного `include` — Storybook підхоплює glob
|
|
191
|
+
* автоматично зі своєї конфігурації, явний include не обов'язковий (реальний
|
|
192
|
+
* кейс components/npm/vitest.config.js — пілот adopt-діагностики). Раніше гола
|
|
193
|
+
* вимога підрядка `stories` давала хибний позитив на цьому валідному патерні.
|
|
194
|
+
* Спільна логіка для `main.mjs` (lint) і `adopt/main.mjs` (diff-діагностика) —
|
|
195
|
+
* не дублювати комбінацію двох regex у двох місцях.
|
|
196
|
+
* @param {string} storybookSlice текстовий зріз елемента `storybook` у `test.projects`
|
|
197
|
+
* @returns {boolean} true — маркер джерела stories присутній (явно чи неявно)
|
|
198
|
+
*/
|
|
199
|
+
export function hasStoriesMarker(storybookSlice) {
|
|
200
|
+
return STORIES_RE.test(storybookSlice) || STORYBOOK_TEST_CONFIG_DIR_RE.test(storybookSlice)
|
|
201
|
+
}
|
|
202
|
+
|
|
176
203
|
/**
|
|
177
204
|
* Будує спільний контекст перевірки одного пакета (label/relPrefix/шлях vitest-конфіга).
|
|
178
205
|
* @param {import('../scope/main.mjs').InScopePackage} entry пакет у скоупі
|
|
@@ -272,7 +299,11 @@ async function checkVitestConfigContent(pkgCtx, reporter) {
|
|
|
272
299
|
const missingHints = []
|
|
273
300
|
if (!CHROMIUM_RE.test(storybookSlice)) missingHints.push('chromium-інстанс')
|
|
274
301
|
if (!BROWSER_KEY_RE.test(storybookSlice)) missingHints.push('browser-mode')
|
|
275
|
-
if (!
|
|
302
|
+
if (!hasStoriesMarker(storybookSlice))
|
|
303
|
+
missingHints.push('stories-джерело (include або storybookTest({ configDir }))')
|
|
304
|
+
if (!PROVIDER_FACTORY_RE.test(storybookSlice)) {
|
|
305
|
+
missingHints.push("provider-factory (vitest v4: import { playwright } from '@vitest/browser-playwright')")
|
|
306
|
+
}
|
|
276
307
|
if (missingHints.length > 0) {
|
|
277
308
|
reporter.fail(
|
|
278
309
|
`[${label}] ${relVitestFile}: storybook-project без канонічних маркерів — бракує: ${missingHints.join(', ')} (vitest-config.mdc)`,
|
|
@@ -3,9 +3,8 @@ type: JS Module
|
|
|
3
3
|
title: storybook-project-entry.js
|
|
4
4
|
resource: plugins/lang-js/rules/storybook/vitest-config/template/storybook-project-entry.js
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
6
|
+
crc: 2646d55c
|
|
7
7
|
model: openai-codex/gpt-5.5
|
|
8
|
-
tier: cloud-avg
|
|
9
8
|
score: 100
|
|
10
9
|
issues: judge:inaccurate:0.98
|
|
11
10
|
judgeModel: openai-codex/gpt-5.4-mini
|
|
@@ -3,9 +3,8 @@ type: JS Module
|
|
|
3
3
|
title: vitest.config.baseline.mjs
|
|
4
4
|
resource: plugins/lang-js/rules/storybook/vitest-config/template/vitest.config.baseline.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
6
|
+
crc: 89da594d
|
|
7
7
|
model: openai-codex/gpt-5.4-mini
|
|
8
|
-
tier: cloud-min
|
|
9
8
|
score: 100
|
|
10
9
|
issues: judge:inaccurate:0.98
|
|
11
10
|
judgeModel: openai-codex/gpt-5.4-mini
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
// Канонічний вигляд запису `storybook`-проєкту у `test.projects` (storybook.mdc,
|
|
2
2
|
// vitest-config-концерн, ADR Кластер 5): browser-mode, лише chromium, stories-glob
|
|
3
3
|
// (`__STORYBOOK_STORIES_GLOB__` — токен, `detectStoriesGlob` зі scaffold-концерна
|
|
4
|
-
// без префіксу `../`).
|
|
4
|
+
// без префіксу `../`). `provider: playwright()` — factory-виклик з
|
|
5
|
+
// `@vitest/browser-playwright`, не рядок `'playwright'`: vitest@^4 прибрав рядкове
|
|
6
|
+
// API провайдера, `@vitest/browser-playwright` — окремий пакет (не входить у
|
|
7
|
+
// `@vitest/browser`). Сам файл — валідний модуль лише для JS-лінту репозиторію
|
|
5
8
|
// правил; `fix-vitest-config.mjs` зчитує лише вміст `export default {...}`.
|
|
6
9
|
import { storybookTest } from '@storybook/addon-vitest/vitest-plugin'
|
|
10
|
+
import { playwright } from '@vitest/browser-playwright'
|
|
7
11
|
|
|
8
12
|
export default {
|
|
9
13
|
extends: true,
|
|
@@ -14,7 +18,7 @@ export default {
|
|
|
14
18
|
browser: {
|
|
15
19
|
enabled: true,
|
|
16
20
|
headless: true,
|
|
17
|
-
provider:
|
|
21
|
+
provider: playwright(),
|
|
18
22
|
instances: [{ browser: 'chromium' }]
|
|
19
23
|
},
|
|
20
24
|
setupFiles: ['.storybook/vitest.setup.js']
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { defineConfig, mergeConfig } from 'vitest/config'
|
|
2
2
|
import { storybookTest } from '@storybook/addon-vitest/vitest-plugin'
|
|
3
|
+
import { playwright } from '@vitest/browser-playwright'
|
|
3
4
|
import viteConfig from './__VITE_CONFIG_IMPORT__'
|
|
4
5
|
|
|
5
6
|
// Канонічний vitest-конфіг Vue-компонентної бібліотеки у скоупі Storybook
|
|
@@ -25,7 +26,7 @@ export default mergeConfig(
|
|
|
25
26
|
browser: {
|
|
26
27
|
enabled: true,
|
|
27
28
|
headless: true,
|
|
28
|
-
provider:
|
|
29
|
+
provider: playwright(),
|
|
29
30
|
instances: [{ browser: 'chromium' }]
|
|
30
31
|
},
|
|
31
32
|
setupFiles: ['.storybook/vitest.setup.js']
|
|
@@ -7,10 +7,14 @@
|
|
|
7
7
|
Vue-компонентна бібліотека вже має `vitest.config.{mjs,js,ts}` за каноном `vue/testing.mdc` (`mergeConfig(viteConfig, defineConfig({ test: {...} }))` з `environment: 'happy-dom'`). Storybook-хвиля **дописує** до цього `test`-блоку named-project `unit`+`storybook` — існуючі поля (`include`, `environment`, `coverage`) лишаються без змін, `projects` — нова властивість поруч:
|
|
8
8
|
|
|
9
9
|
- `{ extends: true, test: { name: 'unit' } }` — успадковує решту `test`-опцій пакета як є.
|
|
10
|
-
- `storybook`-проєкт — **browser-mode, лише chromium** (`browser: { enabled: true, provider:
|
|
10
|
+
- `storybook`-проєкт — **browser-mode, лише chromium** (`browser: { enabled: true, provider: playwright(), instances: [{ browser: 'chromium' }] }`) і `include` на stories-glob пакета (та сама layout-детекція, що й `scaffold/main.mjs#detectStoriesGlob`, лише без префіксу `../` — vitest-конфіг лежить у корені пакета, а не в `.storybook/`).
|
|
11
11
|
|
|
12
12
|
Firefox/webkit свідомо не додаються — ADR і main.mdc хвилі 1 фіксують лише chromium; розширення на інші браузери — поза обсягом цього концерну.
|
|
13
13
|
|
|
14
|
+
**`provider` — factory-виклик, не рядок.** vitest@^4 прибрав рядкове API browser-провайдера: `provider: 'playwright'` більше не резолвиться, потрібен `import { playwright } from '@vitest/browser-playwright'` і `provider: playwright()` (окремий npm-пакет, не входить у `@vitest/browser`). Канон і автофікс генерують факторі-форму; рядкова форма (застаріле API попередніх мажорів) — `storybook-project-marker-missing`.
|
|
15
|
+
|
|
16
|
+
**Явний `include` не обов'язковий, якщо є `storybookTest({ configDir })`.** Реальний кейс пілота (components/npm/vitest.config.js): `storybook`-проєкт без явного `include` — Storybook підхоплює stories-glob автоматично зі своєї `.storybook/main.js`-конфігурації. Перевірка (`hasStoriesMarker`) визнає запис валідним, якщо є АБО явний stories-glob, АБО виклик `storybookTest({ configDir: ... })`.
|
|
17
|
+
|
|
14
18
|
### Чому окремий `vitest.stryker.config`
|
|
15
19
|
|
|
16
20
|
`@stryker-mutator/vitest-runner` крашиться, коли конфіг, який він завантажує, містить browser-mode `projects` (сам факт присутності `storybook`-проєкту в основному vitest-конфізі ламає mutation-прогін, незалежно від того, чи Stryker фактично торкається storybook-файлів). Тому концерн генерує **сусідній** ізольований `vitest.stryker.config.<ext>` — той самий `mergeConfig(viteConfig, defineConfig({ test: {...} }))`, але **без** `projects`/browser-mode: лише unit-набір (`include`, `happy-dom`, `coverage`), на якому mutation-testing працює штатно.
|
|
@@ -19,7 +23,7 @@ Firefox/webkit свідомо не додаються — ADR і main.mdc хви
|
|
|
19
23
|
|
|
20
24
|
### Що перевіряє й що виправляє концерн
|
|
21
25
|
|
|
22
|
-
Перевірка (`main.mjs`) — AST-аналіз (`oxc-parser`) наявного vitest-конфіга: знаходить `test`-блок (незалежно від того, чи він огорнутий у `defineConfig`/`mergeConfig`, чи це простий об'єкт), дивиться на `test.projects` і класифікує елементи за `name: 'unit'`/`name: 'storybook'`; для `storybook`-елемента перевіряє маркери `chromium`/`browser
|
|
26
|
+
Перевірка (`main.mjs`) — AST-аналіз (`oxc-parser`) наявного vitest-конфіга: знаходить `test`-блок (незалежно від того, чи він огорнутий у `defineConfig`/`mergeConfig`, чи це простий об'єкт), дивиться на `test.projects` і класифікує елементи за `name: 'unit'`/`name: 'storybook'`; для `storybook`-елемента перевіряє маркери `chromium`/`browser`/`provider`-factory/stories-джерело (явний glob або `storybookTest({ configDir })`) текстовим пошуком. Стійка до форматування й порядку полів — не вимагає конкретного стилю запису, лише семантичну присутність маркерів.
|
|
23
27
|
|
|
24
28
|
Автофікс (`fix-vitest-config.mjs`, fixability `config`) виправляє й дописує **лише відсутнє**:
|
|
25
29
|
|
|
@@ -30,4 +34,4 @@ Firefox/webkit свідомо не додаються — ADR і main.mdc хви
|
|
|
30
34
|
|
|
31
35
|
Як і в `test/stryker_config`, правка — точкові string-splice-и (insert-only) поверх існуючого тексту, а не переписаний AST-serializer, щоб не зачепити форматування й коментарі решти файлу; результат повторно парситься, і при невалідному виводі запис скасовується (fail-closed).
|
|
32
36
|
|
|
33
|
-
**Свідомо без автофіксу:** `test.projects` — не статичний масив (spread/змінна), test-блок не вдалось знайти структурно, або `storybook`-запис уже присутній, але без якогось із маркерів (chromium/browser/stories
|
|
37
|
+
**Свідомо без автофіксу:** `test.projects` — не статичний масив (spread/змінна), test-блок не вдалось знайти структурно, або `storybook`-запис уже присутній, але без якогось із маркерів (chromium/browser/provider-factory/stories-джерело) — надійно виправити частковий вручну написаний запис програмно ризиковано, тож це лишається порушенням для ручного review (той самий компроміс, що й marker-порушення в `scaffold`).
|