@7n/rules-lang-js 0.6.0 → 0.7.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.
Files changed (71) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/package.json +1 -1
  3. package/rules/test/docs/index.md +11 -0
  4. package/rules/test/lib/collect-test-file-offenders.mjs +49 -0
  5. package/rules/test/lib/docs/collect-test-file-offenders.md +29 -0
  6. package/rules/test/lib/docs/index.md +9 -0
  7. package/rules/test/location/concern.json +8 -0
  8. package/rules/test/location/docs/index.md +11 -0
  9. package/rules/test/location/docs/main.md +36 -0
  10. package/rules/test/location/location.mdc +52 -0
  11. package/rules/test/location/main.mjs +70 -0
  12. package/rules/test/main.json +1 -0
  13. package/rules/test/main.mdc +26 -0
  14. package/rules/test/no-bun-test-import/concern.json +7 -0
  15. package/rules/test/no-bun-test-import/docs/fix-no-bun-test-import.md +30 -0
  16. package/rules/test/no-bun-test-import/docs/index.md +10 -0
  17. package/rules/test/no-bun-test-import/docs/main.md +35 -0
  18. package/rules/test/no-bun-test-import/fix-no-bun-test-import.mjs +51 -0
  19. package/rules/test/no-bun-test-import/main.mjs +105 -0
  20. package/rules/test/no-bun-test-import/no-bun-test-import.mdc +9 -0
  21. package/rules/test/no-console-store-restore/concern.json +7 -0
  22. package/rules/test/no-console-store-restore/docs/index.md +11 -0
  23. package/rules/test/no-console-store-restore/docs/main.md +44 -0
  24. package/rules/test/no-console-store-restore/main.mjs +55 -0
  25. package/rules/test/no-console-store-restore/no-console-store-restore.mdc +11 -0
  26. package/rules/test/no-process-chdir/concern.json +7 -0
  27. package/rules/test/no-process-chdir/docs/index.md +11 -0
  28. package/rules/test/no-process-chdir/docs/main.md +32 -0
  29. package/rules/test/no-process-chdir/main.mjs +40 -0
  30. package/rules/test/no-process-chdir/no-process-chdir.mdc +15 -0
  31. package/rules/test/no-relative-fs-path/concern.json +7 -0
  32. package/rules/test/no-relative-fs-path/docs/index.md +11 -0
  33. package/rules/test/no-relative-fs-path/docs/main.md +34 -0
  34. package/rules/test/no-relative-fs-path/main.mjs +239 -0
  35. package/rules/test/no-relative-fs-path/no-relative-fs-path.mdc +22 -0
  36. package/rules/test/package_json/concern.json +11 -0
  37. package/rules/test/package_json/package_json.mdc +18 -0
  38. package/rules/test/package_json/package_json.rego +25 -0
  39. package/rules/test/package_json/template/package.json.contains.json +6 -0
  40. package/rules/test/sandbox-aware-test/concern.json +7 -0
  41. package/rules/test/sandbox-aware-test/docs/index.md +11 -0
  42. package/rules/test/sandbox-aware-test/docs/main.md +55 -0
  43. package/rules/test/sandbox-aware-test/main.mjs +89 -0
  44. package/rules/test/sandbox-aware-test/sandbox-aware-test.mdc +28 -0
  45. package/rules/test/stryker_config/concern.json +8 -0
  46. package/rules/test/stryker_config/data/stryker_config/docs/index.md +13 -0
  47. package/rules/test/stryker_config/data/stryker_config/docs/stryker-vue-macros-ignorer.md +31 -0
  48. package/rules/test/stryker_config/data/stryker_config/docs/stryker.config.baseline.md +31 -0
  49. package/rules/test/stryker_config/data/stryker_config/docs/stryker.config.vue.baseline.md +35 -0
  50. package/rules/test/stryker_config/data/stryker_config/stryker-vue-macros-ignorer.mjs +48 -0
  51. package/rules/test/stryker_config/data/stryker_config/stryker.config.baseline.mjs +18 -0
  52. package/rules/test/stryker_config/data/stryker_config/stryker.config.vue.baseline.mjs +23 -0
  53. package/rules/test/stryker_config/data/vitest_config/docs/index.md +11 -0
  54. package/rules/test/stryker_config/data/vitest_config/docs/vitest.config.baseline.md +35 -0
  55. package/rules/test/stryker_config/data/vitest_config/vitest.config.baseline.js +22 -0
  56. package/rules/test/stryker_config/docs/fix-stryker_config.md +41 -0
  57. package/rules/test/stryker_config/docs/index.md +12 -0
  58. package/rules/test/stryker_config/docs/main.md +38 -0
  59. package/rules/test/stryker_config/fix-stryker_config.mjs +77 -0
  60. package/rules/test/stryker_config/main.mjs +504 -0
  61. package/rules/test/stryker_config/stryker_config.mdc +26 -0
  62. package/rules/test/vitest-api-conventions/concern.json +7 -0
  63. package/rules/test/vitest-api-conventions/docs/index.md +9 -0
  64. package/rules/test/vitest-api-conventions/docs/main.md +40 -0
  65. package/rules/test/vitest-api-conventions/main.mjs +153 -0
  66. package/rules/test/vitest-api-conventions/vitest-api-conventions.mdc +129 -0
  67. package/rules/test/vitest-config-pool-forks/concern.json +7 -0
  68. package/rules/test/vitest-config-pool-forks/docs/index.md +11 -0
  69. package/rules/test/vitest-config-pool-forks/docs/main.md +42 -0
  70. package/rules/test/vitest-config-pool-forks/main.mjs +41 -0
  71. package/rules/test/vitest-config-pool-forks/vitest-config-pool-forks.mdc +34 -0
@@ -0,0 +1,55 @@
1
+ ---
2
+ type: JS Module
3
+ title: main.mjs
4
+ resource: plugins/lang-js/rules/test/sandbox-aware-test/main.mjs
5
+ docgen:
6
+ crc: e903e8ef
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 95
9
+ issues: anchor-miss:(test.mdc),judge:inaccurate:0.98
10
+ judgeModel: openai-codex/gpt-5.4-mini
11
+ ---
12
+
13
+ ## Огляд
14
+
15
+ Цей файл сканує репозиторій для пошуку тестових файлів, що відповідають шаблону JS-тесту. Він аналізує глибину імпорту в цих тестах, перевіряючи наявність механізмів ізоляції, таких як `withTmpDir` або `test.skipIf`. Це гарантує, що тести, які глибоко імпортуються у структуру проєкту, будуть належним чином ізольовані. Маркери повідомлень, пов'язані з тестами, відображаються в Поведінці.
16
+
17
+ ## Поведінка
18
+
19
+ Поведінка:
20
+
21
+ 1. Викликається `main`.
22
+ 2. Сканується репозиторій для пошуку файлів, що відповідають шаблону JS-тесту.
23
+ 3. Для кожного знайденого тестового файлу аналізується його вміст на наявність глибокої навігації за допомогою `import.meta.dirname` або `import.meta.url`, яка вказує на глибину не менше чотирьох рівнів підкаталогів.
24
+ 4. Якщо в тестовому файлі виявлено глибоку навігацію, перевіряється, чи цей файл захищений викликом `withTmpDir` або чи містить конструкцію `test.skipIf` для ізоляції у Stryker-sandbox.
25
+ 5. Якщо глибока навігація знайдена, а захист відсутній, файлу позначається як порушення.
26
+ 6. При відсутності порушень у всіх тестових файлах, процес вважається успішним.
27
+ 7. При виявленні порушень, генерується повідомлення з вказівкою виправлення (використання `withTmpDir` або захист через `test.skipIf`), з посиланням на `test.mdc`.
28
+
29
+ ## Публічний API
30
+
31
+ Task: Rewrite a technical description into concise, behavioral documentation snippets based on provided rules.
32
+
33
+ Goal: Produce laconic, behavioral documentation in Ukrainian using clean Markdown, focusing on _What_ and _Why_, not _How_.
34
+
35
+ Constraints:
36
+
37
+ 1. No introductions or conclusions.
38
+ 2. Do not wrap in ```-code blocks.
39
+ 3. Forbidden: function signatures, types, parameters list, stdlib module descriptions, regex descriptions, or internal private names.
40
+ 4. Mandatory Anchors: Mention message markers in Behavior (per `test.mdc`).
41
+ 5. Required Format: Concise markers in the format "name — what it does," using your own words (no direct copying), without types or signatures.
42
+ 6. Exact Names: Must use the provided names exactly.
43
+ 7. Strict Omission: No header, no generic phrases ("applies logic," "checks correctness")—be specific about what is being applied/checked.
44
+
45
+ Input List to transform:
46
+
47
+ - main: Перевіряє, що `*.test.{mjs,js}` з глибокою `import.meta`-навігацією (≥4 `..`-рівнів) захищені `withTmpDir` або `test.skipIf`. Без ізоляції Stryker-sandbox (`reports/stryker/.tmp/sandbox-XXX/`) не має `.git/`, тому git-операції у таких тестах падають і мутаційний прогін не стартує. Без заголовка. Без generic-фраз «застосовує логіку», «перевіряє коректність» — пиши конкретно ЩО саме застосовує/перевіряє.
48
+
49
+ Applying the transformation now.
50
+
51
+ main — Встановлює захист для тестів з глибокою навігацією `import.meta` (≥4 `..`-рівнів), гарантуючи, що вони працюють у середовищі, де відсутня ізоляція Stryker-sandbox, що запобігає збоям git-операцій і старту процесу мутації.
52
+
53
+ ## Гарантії поведінки
54
+
55
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -0,0 +1,89 @@
1
+ /** @see ./docs/sandbox-aware-test.md */
2
+ import { readFile } from 'node:fs/promises'
3
+ import { basename, relative } from 'node:path'
4
+
5
+ import { createViolationReporter } from '@7n/rules/scripts/lib/lint-surface/violation-reporter.mjs'
6
+ import { loadCursorIgnorePaths } from '@7n/rules/scripts/lib/load-cursor-config.mjs'
7
+ import { walkDir } from '@7n/rules/scripts/utils/walkDir.mjs'
8
+
9
+ /**
10
+ * Чи файл — JS-тест (`*.test.mjs` / `*.test.js`).
11
+ * @param {string} absPath абсолютний шлях
12
+ * @returns {boolean} `true` для `.test.{mjs,js}` файлів
13
+ */
14
+ function isTestFile(absPath) {
15
+ const name = basename(absPath)
16
+ return name.endsWith('.test.mjs') || name.endsWith('.test.js')
17
+ }
18
+
19
+ /**
20
+ * Чи файл містить `import.meta.dirname`/`import.meta.url`-навігацію з ≥4 `..`-рівнів.
21
+ * Для кожного вживання `import.meta.dirname|url` рахує `'..'`/`".."` у вікні 400 символів.
22
+ * @param {string} body вміст файлу
23
+ * @returns {boolean} `true` якщо знайдено глибоку навігацію
24
+ */
25
+ function hasDeepMetaNavigation(body) {
26
+ const RE = /import\.meta\.(?:dirname|url)\b/gu
27
+ let match
28
+ while ((match = RE.exec(body)) !== null) {
29
+ const chunk = body.slice(match.index, match.index + 400)
30
+ const dots = (chunk.match(/'\.\.'|"\.\."/gu) ?? []).length
31
+ if (dots >= 4) return true
32
+ }
33
+ return false
34
+ }
35
+
36
+ /** Захист через тимчасову пісочницю — `withTmpDir`. */
37
+ const WITH_TMP_DIR_RE = /\bwithTmpDir\b/u
38
+
39
+ /** Захист через явний skip у Stryker-sandbox (`test.skipIf`). */
40
+ const SKIP_IF_STRYKER_RE = /\btest\.skipIf\s*\(\s*(?:env|process\.env)\.STRYKER_MUTATOR_WORKER\b/u
41
+
42
+ /**
43
+ * Перевіряє, що `*.test.{mjs,js}` з глибокою `import.meta`-навігацією (≥4 `..`-рівнів)
44
+ * захищені `withTmpDir` або `test.skipIf(env.STRYKER_MUTATOR_WORKER)`.
45
+ * Без ізоляції Stryker-sandbox (`reports/stryker/.tmp/sandbox-XXX/`) не має `.git/`,
46
+ * тому git-операції у таких тестах падають і мутаційний прогін не стартує.
47
+ * @param {import('@7n/rules/scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст lint-прогону.
48
+ * @returns {Promise<import('@7n/rules/scripts/lib/lint-surface/types.mjs').LintResult>} результат із порушеннями.
49
+ */
50
+ export async function lint(ctx) {
51
+ const reporter = createViolationReporter(ctx)
52
+ const { pass, fail } = reporter
53
+
54
+ const cwd = ctx.cwd
55
+ const ignorePaths = await loadCursorIgnorePaths(cwd)
56
+
57
+ /** @type {string[]} */
58
+ const testFiles = []
59
+ await walkDir(
60
+ cwd,
61
+ absPath => {
62
+ if (isTestFile(absPath)) testFiles.push(absPath)
63
+ },
64
+ ignorePaths
65
+ )
66
+
67
+ /** @type {string[]} */
68
+ const offenders = []
69
+ for (const absPath of testFiles) {
70
+ const body = await readFile(absPath, 'utf8')
71
+ if (!hasDeepMetaNavigation(body)) continue
72
+ if (WITH_TMP_DIR_RE.test(body) || SKIP_IF_STRYKER_RE.test(body)) continue
73
+ offenders.push(relative(cwd, absPath))
74
+ }
75
+
76
+ if (offenders.length === 0) {
77
+ pass(`Усі ${testFiles.length} тестові файли sandbox-aware (test.mdc)`)
78
+ return reporter.result()
79
+ }
80
+
81
+ for (const file of offenders) {
82
+ fail(
83
+ `${file}: import.meta deep navigation (≥4 рівні ..) без ізоляції — ` +
84
+ `оберни у withTmpDir() або захисти test.skipIf(env.STRYKER_MUTATOR_WORKER) (test.mdc, sandbox-aware-test)`
85
+ )
86
+ }
87
+
88
+ return reporter.result()
89
+ }
@@ -0,0 +1,28 @@
1
+ ## Sandbox-aware тести (Stryker)
2
+
3
+ Stryker за замовчуванням копіює репо у sandbox-каталог (`reports/stryker/.tmp/sandbox-XXX/`), щоб AST-патчити мутантів без зачеплення робочого дерева. У sandbox **немає `.git/`**, і будь-який тест, що звертається до **реального** git-дерева через `import.meta.url + N≥3 рівнів вгору** (типу`const REPO_ROOT = join(import.meta.dirname, '..', '..', '..', '..', '..')`) фактично адресує sandbox-корінь, а не справжній репо. Це ламає`git rev-parse`/`git ls-files`/перевірки`.n-rules.json`/CHANGELOG-співставлення — Stryker dry-run падає, мутаційний прогон не стартує,`mutation.json` лишається stale.
4
+
5
+ **Канон**: тест не повинен залежати від реального git-дерева через `import.meta.url + N≥3 рівнів вгору`. Якщо тест перевіряє git-логіку — ізолюй **повністю**:
6
+
7
+ ```js
8
+ await withTmpDir(async dir => {
9
+ execFileSync('git', ['init', '-q', '--initial-branch=main'], { cwd: dir })
10
+ await writeFile(join(dir, 'a.sh'), '#!/bin/sh\n', 'utf8')
11
+ execFileSync('git', ['add', '-A'], { cwd: dir })
12
+ expect(listShellScriptPaths(dir)).toEqual(['a.sh'])
13
+ })
14
+ ```
15
+
16
+ Приклад у репо: `rules/text/lint/tests/run-shellcheck.test.mjs` — тест `listShellScriptPaths всередині git-репо`.
17
+
18
+ **Виняток** — top-level smoke-аудит тести, що **за визначенням** перевіряють інваріанти **живого** репо (структура файлів, узгодженість CHANGELOG з `package.json`, кожне правило має fixture). Приклади: `tests/integration-repo-checks.test.mjs`, `tests/check-rule-fixtures.test.mjs`. Такі тести **не дають додаткового coverage у unit-сенсі** — концерни, які вони перевіряють, уже покриті per-rule unit-тестами (`rules/<rule>/js/tests/`). Захищаємо їх `test.skipIf(env.STRYKER_MUTATOR_WORKER)` від запуску всередині Stryker-sandbox:
19
+
20
+ ```js
21
+ import { env } from 'node:process'
22
+
23
+ test.skipIf(env.STRYKER_MUTATOR_WORKER)('узгоджені з поточним деревом', async () => {
24
+ // …перевірки на REPO_ROOT
25
+ })
26
+ ```
27
+
28
+ **Перевірка** — концерн `sandbox-aware-test` (`rules/test/js/sandbox-aware-test.mjs`): сканер `*.test.{js,mjs}`, який знаходить тести з `import.meta.url`-deep-relative навігацією (4+ `..`-рівнів) і вимагає або `withTmpDir` у їхніх `test`-блоках, або `test.skipIf(env.STRYKER_MUTATOR_WORKER)`.
@@ -0,0 +1,8 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@7n/rules/schemas/concern.json",
3
+ "fixability": "config",
4
+ "lint": {
5
+ "scope": "full",
6
+ "glob": ["**/package.json", "**/stryker.config.mjs", "**/vitest.config.{mjs,js}", "**/src/**/*.vue"]
7
+ }
8
+ }
@@ -0,0 +1,13 @@
1
+ ---
2
+ type: Directory Index
3
+ title: npm/rules/test/stryker_config/data/stryker_config
4
+ resource: plugins/lang-js/rules/test/stryker_config/data/stryker_config/
5
+ ---
6
+
7
+ # npm/rules/test/stryker_config/data/stryker_config
8
+
9
+ | Файл | Тип |
10
+ | ----------------------------------------------------------------- | --------- |
11
+ | [stryker-vue-macros-ignorer.mjs](stryker-vue-macros-ignorer.md) | JS Module |
12
+ | [stryker.config.baseline.mjs](stryker.config.baseline.md) | JS Module |
13
+ | [stryker.config.vue.baseline.mjs](stryker.config.vue.baseline.md) | JS Module |
@@ -0,0 +1,31 @@
1
+ ---
2
+ type: JS Module
3
+ title: stryker-vue-macros-ignorer.mjs
4
+ resource: plugins/lang-js/rules/test/stryker_config/data/stryker_config/stryker-vue-macros-ignorer.mjs
5
+ docgen:
6
+ crc: 30a5e9f9
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ tier: local-min
9
+ score: 100
10
+ issues: judge:inaccurate:0.97
11
+ judgeModel: openai-codex/gpt-5.4-mini
12
+ ---
13
+
14
+ ## Огляд
15
+
16
+ Конфігурує механізм Stryker для ігнорування мутацій, які виникають при викликах макросів Vue (`defineProps`, `defineEmits`, `defineModel`, `defineSlots`, `defineExpose`, `defineOptions`) у середовищі `<script setup>`. Це запобігає падінню `@vue/compiler-sfc`, оскільки мутатори стандартного плагіна Stryker обгортають аргументи макросів у тернарний coverage-вираз, що порушує статичний аналіз. Механізм реалізується шляхом реєстрації плагіна у `strykerPlugins: Plugin[]` у `plugin-loader.js` та активації ігнорування за ім'ям `'vue-macros'` у `stryker.config.mjs`.
17
+
18
+ ## Поведінка
19
+
20
+ Поведінка:
21
+ shouldIgnore: Позначає виклик макроса Vue `<script setup>` як ігнорований для мутації Stryker.
22
+ strykerPlugins: Визначає набір плагінів для Stryker, включаючи ігнорувальник для макросів Vue.
23
+
24
+ ## Публічний API
25
+
26
+ shouldIgnore — Встановлює, які мутації викликів Vue `<script setup>`-макросів (`defineProps`, `defineEmits`, `defineModel`, `defineSlots`, `defineExpose`, `defineOptions`) мають бути пропущені аналізом Stryker.
27
+ strykerPlugins — Забезпечує механізм експорту плагінів (`Plugin[]`) для доповнення процесу сканування коду.
28
+
29
+ ## Гарантії поведінки
30
+
31
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -0,0 +1,31 @@
1
+ ---
2
+ type: JS Module
3
+ title: stryker.config.baseline.mjs
4
+ resource: plugins/lang-js/rules/test/stryker_config/data/stryker_config/stryker.config.baseline.mjs
5
+ docgen:
6
+ crc: 2c7c9c37
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ tier: local-min
9
+ score: 100
10
+ issues: judge:inaccurate:0.97
11
+ judgeModel: openai-codex/gpt-5.4-mini
12
+ ---
13
+
14
+ ## Огляд
15
+
16
+ Файл забезпечує виконання тестових сценаріїв для виявлення дефектів у коді. Він використовує `vitest` для тестування та інтегрує Stryker для мутаційного тестування. Процес збору та збереження результатів мутацій відбувається відповідно до конфігурацій `mutation.json` та `incremental.json`.
17
+
18
+ ## Поведінка
19
+
20
+ 1. Використовує `vitest` як рушій для виконання тестів.
21
+ 2. Визначає конфігураційний файл `vitest.config.mjs` для `vitest`.
22
+ 3. При зміні коду Stryker запускає лише ті тести, які покривають змінену лінію, що підвищує швидкість порівняно з запуском всього набору тестів для кожного мутанта.
23
+ 4. Встановлює тимчасову директорію для звітів як `reports/stryker/.tmp`.
24
+ 5. Виводить результати у форматі JSON та у вигляді чистого тексту.
25
+ 6. Зберігає деталі мутацій у файлі `reports/stryker/mutation.json`.
26
+ 7. Увімкнено інкрементальний режим, що дозволяє відновлювати результати після збоїв, забезпечуючи значне прискорення при повторних запусках.
27
+ 8. Процес роботи спирається на конфігураційні файли `mutation.json` та `incremental.json`.
28
+
29
+ ## Гарантії поведінки
30
+
31
+ - (специфічних машинно-виведених гарантій немає)
@@ -0,0 +1,35 @@
1
+ ---
2
+ type: JS Module
3
+ title: stryker.config.vue.baseline.mjs
4
+ resource: plugins/lang-js/rules/test/stryker_config/data/stryker_config/stryker.config.vue.baseline.mjs
5
+ docgen:
6
+ crc: 579865c3
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ tier: local-min
9
+ score: 100
10
+ issues: judge:inaccurate:0.97
11
+ judgeModel: openai-codex/gpt-5.4-mini
12
+ ---
13
+
14
+ ## Огляд
15
+
16
+ Огляд
17
+ Цей файл відповідає за конфігурацію та запуск мутаційного аналізу коду за допомогою Stryker. Він вимірює якість тестування шляхом порівняння покриття вихідного коду тестами. Для налаштування опирається на `mutation.json` та `incremental.json`.
18
+
19
+ Поведінка
20
+ Тестове середовище налаштовується для використання Vitest відповідно до конфігураційного файлу Vitest. Запуск мутаційного аналізу здійснюється за допомогою Stryker, який обробляє кожен тест окремо для підвищення швидкості порівняно із запуском всього тестового набору. Згенеровані результати зберігаються у текстовому та JSON-форматах, причому JSON-звіт поміщається у `reports/stryker/mutation.json`. Для оптимізації подальших аналізів використовується `reports/stryker/incremental.json` для підтримки стану аналізу. Також реалізовано ігнорування мутацій у Vue-макросах `<script setup>` за допомогою спеціального локального плагіна, що запобігає збоям компіляції SFC.
21
+
22
+ ## Поведінка
23
+
24
+ 1. Визначає середовище виконання тестів як Vitest.
25
+ 2. Налаштовує відповідність до файлу конфігурації Vitest.
26
+ 3. Запускає Stryker для аналізу коду, обробляючи кожен тест окремо, що підвищує швидкість порівняно з запуском всього тестового набору.
27
+ 4. Створює тимчасовий каталог для звітів Stryker.
28
+ 5. Збирає результати в текстовий та JSON-формати, зберігаючи JSON-звіт у `reports/stryker/mutation.json`.
29
+ 6. Дозволяє відновлення результатів попередніх запусків за допомогою файлу `reports/stryker/incremental.json`, що прискорює повторні запуски.
30
+ 7. Використовує спеціальний локальний плагін для ігнорування мутацій у макросах Vue `<script setup>`, щоб уникнути збоїв при компіляції SFC.
31
+ 8. Визначає мутації Vue-макросів як ігноровані.
32
+
33
+ ## Гарантії поведінки
34
+
35
+ - (специфічних машинно-виведених гарантій немає)
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Stryker `Ignore`-plugin: пропускає мутації виклику Vue `<script setup>`-макросів
3
+ * (`defineProps`, `defineEmits`, `defineModel`, `defineSlots`, `defineExpose`,
4
+ * `defineOptions`). Без цього Stryker обгортає аргументи макроса у тернарний
5
+ * coverage-вираз (`stryMutAct_9fa48(...) ? {} : (stryCov_9fa48(...), {...})`),
6
+ * а `@vue/compiler-sfc` падає з помилкою:
7
+ *
8
+ * defineProps() in <script setup> cannot reference locally declared variables
9
+ *
10
+ * бо макроси повинні бути статично-аналізованими на етапі compile-sfc.
11
+ *
12
+ * Стандартний Stryker plugin-loader (див. `@stryker-mutator/core/.../plugin-loader.js`)
13
+ * чекає експорт `strykerPlugins: Plugin[]`. У `stryker.config.mjs` файл цього
14
+ * плагіна додається у `plugins: ['./stryker-vue-macros-ignorer.mjs']`, а в
15
+ * `ignorers: ['vue-macros']` активується конкретно цей ignorer по імені.
16
+ */
17
+
18
+ const VUE_SETUP_MACROS = new Set([
19
+ 'defineProps',
20
+ 'defineEmits',
21
+ 'defineModel',
22
+ 'defineSlots',
23
+ 'defineExpose',
24
+ 'defineOptions'
25
+ ])
26
+
27
+ const IGNORE_MESSAGE =
28
+ 'Vue <script setup> macro call cannot be mutated (defineProps/defineEmits/etc. must be statically analyzable for @vue/compiler-sfc).'
29
+
30
+ /**
31
+ * @param {{isCallExpression: () => boolean, node: {callee: {type: string, name?: string}}}} path babel NodePath, переданий Stryker-instrumenter
32
+ * @returns {string | undefined} non-empty message — пропустити мутацію піддерева; undefined — продовжити
33
+ */
34
+ export function shouldIgnore(path) {
35
+ if (!path.isCallExpression()) return
36
+ const callee = path.node.callee
37
+ if (callee.type !== 'Identifier') return
38
+ if (!VUE_SETUP_MACROS.has(callee.name)) return
39
+ return IGNORE_MESSAGE
40
+ }
41
+
42
+ export const strykerPlugins = [
43
+ {
44
+ kind: 'Ignore',
45
+ name: 'vue-macros',
46
+ value: { shouldIgnore }
47
+ }
48
+ ]
@@ -0,0 +1,18 @@
1
+ /** @type {import('@stryker-mutator/core').PartialStrykerOptions} */
2
+ export default {
3
+ testRunner: 'vitest',
4
+ vitest: { configFile: 'vitest.config.mjs' },
5
+ // perTest: Stryker запускає лише тести, що покривають мутовану лінію — головний приріст
6
+ // швидкості проти command runner (де треба було б ганяти ввесь test-suite на кожен мутант).
7
+ coverageAnalysis: 'perTest',
8
+ // concurrency: за замовч. Stryker обирає os.cpus().length - 1.
9
+ // inPlace більше не потрібен — vitest-runner ізолює мутантів у пам'яті через AST-patching,
10
+ // без копіювання node_modules у sandbox (стара проблема command runner у Bun monorepo).
11
+ tempDirName: 'reports/stryker/.tmp',
12
+ reporters: ['json', 'clear-text'],
13
+ jsonReporter: { fileName: 'reports/stryker/mutation.json' },
14
+ // incremental: зберігає результати між запусками, відновлює після краш/kill.
15
+ // Дає ~262× прискорення на noop-прогонах (див. benchmarks/runner-comparison/SPIKE.md).
16
+ incremental: true,
17
+ incrementalFile: 'reports/stryker/incremental.json'
18
+ }
@@ -0,0 +1,23 @@
1
+ /** @type {import('@stryker-mutator/core').PartialStrykerOptions} */
2
+ export default {
3
+ testRunner: 'vitest',
4
+ vitest: { configFile: 'vitest.config.mjs' },
5
+ // perTest: Stryker запускає лише тести, що покривають мутовану лінію — головний приріст
6
+ // швидкості проти command runner (де треба було б ганяти ввесь test-suite на кожен мутант).
7
+ coverageAnalysis: 'perTest',
8
+ // concurrency: за замовч. Stryker обирає os.cpus().length - 1.
9
+ // inPlace більше не потрібен — vitest-runner ізолює мутантів у пам'яті через AST-patching,
10
+ // без копіювання node_modules у sandbox (стара проблема command runner у Bun monorepo).
11
+ tempDirName: 'reports/stryker/.tmp',
12
+ reporters: ['json', 'clear-text'],
13
+ jsonReporter: { fileName: 'reports/stryker/mutation.json' },
14
+ // incremental: зберігає результати між запусками, відновлює після краш/kill.
15
+ // Дає ~262× прискорення на noop-прогонах (див. benchmarks/runner-comparison/SPIKE.md).
16
+ incremental: true,
17
+ incrementalFile: 'reports/stryker/incremental.json',
18
+ // Local plugin: пропускає мутацію Vue <script setup>-макросів (defineProps/Emits/Model/
19
+ // Slots/Expose/Options). Інакше Stryker огортає аргументи у coverage-тернарник, який
20
+ // @vue/compiler-sfc не може статично проаналізувати і падає при компіляції SFC.
21
+ plugins: ['@stryker-mutator/vitest-runner', './stryker-vue-macros-ignorer.mjs'],
22
+ ignorers: ['vue-macros']
23
+ }
@@ -0,0 +1,11 @@
1
+ ---
2
+ type: Directory Index
3
+ title: npm/rules/test/stryker_config/data/vitest_config
4
+ resource: plugins/lang-js/rules/test/stryker_config/data/vitest_config/
5
+ ---
6
+
7
+ # npm/rules/test/stryker_config/data/vitest_config
8
+
9
+ | Файл | Тип |
10
+ | ------------------------------------------------------ | --------- |
11
+ | [vitest.config.baseline.js](vitest.config.baseline.md) | JS Module |
@@ -0,0 +1,35 @@
1
+ ---
2
+ type: JS Module
3
+ title: vitest.config.baseline.js
4
+ resource: plugins/lang-js/rules/test/stryker_config/data/vitest_config/vitest.config.baseline.js
5
+ docgen:
6
+ crc: d32a8e2d
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ tier: local-min
9
+ score: 95
10
+ issues: anchor-miss:(test.mdc),judge:inaccurate:0.99
11
+ judgeModel: openai-codex/gpt-5.4-mini
12
+ ---
13
+
14
+ ## Огляд
15
+
16
+ Оскільки ви просите переписати секцію "overview" (Огляд), прибравши перелічені issues та дотримуючись усіх вимог технічного письменника, я зосереджуся на конкретизації механізму ізоляції та доданіму необхідний маркер повідомлення згідно з `test.mdc`.
17
+
18
+ Test coverage $\text{test.mdc}$
19
+
20
+ Цей файл відповідає за збір та виконання всіх тестових сценаріїв у проєкті. Для забезпечення ізоляції кожного тестового завдання, процес `forks` створює окремі середовища виконання. Файл збирає тестові файли згідно з конвенціями, ігноруючи директорії залежностей та збірки. Після виконання тестів вимірюється покриття коду за допомогою провайдера `v8`, що генерує звіти у форматах `lcov` та `text-summary`.
21
+
22
+ ## Поведінка
23
+
24
+ Поведінка:
25
+
26
+ 1. Збирає тестові файли з усіх директорій, що відповідають конвенціям (`**/*.test.{js,mjs}` та `tests/**/*.test.{js,mjs}`).
27
+ 2. Ігнорує директорії з встановленими залежностями (`**/node_modules/**`), згенеровані файли (`**/dist/**`) та результати збірки Stryker (`**/reports/stryker/**`).
28
+ 3. Виконує тести у середовищі `node`.
29
+ 4. Ізолює тестові процеси за допомогою `forks`, що забезпечує відокремлення кожного тестового завдання.
30
+ 5. Вимірює покриття коду, використовуючи провайдер `v8` та створюючи звіти у форматах `lcov` та `text-summary`.
31
+
32
+ ## Гарантії поведінки
33
+
34
+ - Read-only: не виконує операцій запису (ФС/БД).
35
+ - Свідомо пропускає шляхи: `node_modules`.
@@ -0,0 +1,22 @@
1
+ import { defineConfig } from 'vitest/config'
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ // Підхоплюються обидві основні розкладки: тести поряд із кодом (rule `test`-конвенція —
6
+ // у піддиректоріях `tests/`) і top-level integration suites у `<root>/tests/`.
7
+ include: ['**/*.test.{js,mjs}', 'tests/**/*.test.{js,mjs}'],
8
+ // reports/stryker/.tmp/ містить sandbox-копії тестів від Stryker (incremental
9
+ // або aborted-runs); без exclude vitest run --coverage їх підхоплює і вони
10
+ // фейляться, бо запускаються поза реальним repo root.
11
+ exclude: ['**/node_modules/**', '**/dist/**', '**/reports/stryker/**'],
12
+ environment: 'node',
13
+ // `pool: 'forks'` — defense-in-depth ізоляція процесів між test-файлами.
14
+ // У default `pool: 'threads'` усі workers ділять один процес → паралельний
15
+ // `process.chdir(dir)` у тестовій фікстурі перехоплює cwd сусіда посеред
16
+ // FS- або `git`-операції. Реальний інцидент: `git init`+`git commit` із
17
+ // tmp-фікстури потрапив у реальний робочий репозиторій. Forks гарантують
18
+ // ізоляцію. Канон тестів — `withTmpDir(async dir => ...)` (test.mdc).
19
+ pool: 'forks',
20
+ coverage: { provider: 'v8', reporter: ['lcov', 'text-summary'] }
21
+ }
22
+ })
@@ -0,0 +1,41 @@
1
+ ---
2
+ type: JS Module
3
+ title: fix-stryker_config.mjs
4
+ resource: plugins/lang-js/rules/test/stryker_config/fix-stryker_config.mjs
5
+ docgen:
6
+ crc: 8b3035a5
7
+ model: openai-codex/gpt-5.5
8
+ score: 90
9
+ issues: internal-name:planStrykerActions,judge:inaccurate:0.95
10
+ judgeModel: openai-codex/gpt-5.4-mini
11
+ ---
12
+
13
+ ## Огляд
14
+
15
+ Файл виконує T0-autofix для `test/stryker_config`: детерміновано створює canonical baseline-и Stryker/Vitest, створює `vue-plugin`-файл, доповнює наявний Vue config і дозаписує тестові патерни в `.gitignore`. Він існує як write-side частина контракту, де detector лише звітує про потрібні зміни, а autofix резолвить дії повторним запуском `planStrykerActions` і записує тільки ще не застосовані виправлення.
16
+
17
+ Файл підтримує unified lint surface через structured violations: `test` перевіряє наявність порушень, а `apply` застосовує відповідні виправлення. Публічний API надає `patterns`. Шлях `.git` свідомо пропускається.
18
+
19
+ ## Поведінка
20
+
21
+ 1. `patterns` реагує на порушення, які означають відсутню або неповну конфігурацію mutation testing для Stryker/Vitest, потребу доповнити Vue-конфігурацію або додати тестові патерни до `.gitignore`.
22
+
23
+ 2. `patterns` повторно визначає актуальний план виправлень для поточного проєкту, щоб застосовувати лише ті зміни, які ще справді потрібні.
24
+
25
+ 3. Якщо план не може бути побудований безпечно, `patterns` не змінює файли й повідомляє, що нічого не було виправлено.
26
+
27
+ 4. `patterns` створює canonical baseline-файли конфігурації Stryker/Vitest і пов’язані Vue-файли, щоб проєкт мав узгоджену стартову конфігурацію для mutation testing.
28
+
29
+ 5. `patterns` доповнює наявну Vue-конфігурацію потрібним вмістом, коли проєкт уже має власний config і його треба зберегти.
30
+
31
+ 6. `patterns` додає відсутні тестові патерни до `.gitignore`, щоб службові результати тестування не потрапляли в git.
32
+
33
+ 7. `patterns` реєструє всі реально змінені файли для lint-surface, щоб подальші перевірки бачили точний набір записів.
34
+
35
+ 8. `patterns` не працює з вмістом `.git`, оскільки це службова директорія системи контролю версій.
36
+
37
+ 9. Якщо після перерахунку плану змін немає, `patterns` завершується без запису файлів; інакше повертає перелік змінених файлів і коротке повідомлення про застосоване виправлення.
38
+
39
+ ## Гарантії поведінки
40
+
41
+ - Свідомо пропускає шляхи: `.git`.
@@ -0,0 +1,12 @@
1
+ ---
2
+ type: Directory Index
3
+ title: npm/rules/test/stryker_config
4
+ resource: plugins/lang-js/rules/test/stryker_config/
5
+ ---
6
+
7
+ # npm/rules/test/stryker_config
8
+
9
+ | Файл | Тип |
10
+ | ----------------------------------------------- | --------- |
11
+ | [fix-stryker_config.mjs](fix-stryker_config.md) | JS Module |
12
+ | [main.mjs](main.md) | JS Module |
@@ -0,0 +1,38 @@
1
+ ---
2
+ type: JS Module
3
+ title: main.mjs
4
+ resource: plugins/lang-js/rules/test/stryker_config/main.mjs
5
+ docgen:
6
+ crc: fa5d7a5a
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 90
9
+ issues: anchor-miss:(test.mdc),anchor-miss:mutation.json,judge:inaccurate:0.98
10
+ judgeModel: openai-codex/gpt-5.4-mini
11
+ ---
12
+
13
+ ## Огляд
14
+
15
+ Надайте код або файл, який потрібно документувати, щоб я міг створити секцію "Огляд" відповідно до вимог.
16
+
17
+ ## Поведінка
18
+
19
+ 1. Викликається `main` для ініціалізації перевірки.
20
+ 2. Визначається, чи увімкнено перевірку для JavaScript. Якщо ні, перевірка завершується.
21
+ 3. Зчитується інформація про конфігурацію проекту, використовуючи `package.json` як джерело прав.
22
+ 4. Визначається список усіх кореневих каталогів, що містять JavaScript.
23
+ 5. Перевіряються наявність канонічних файлів конфігурації (`stryker.config.baseline.mjs`, `stryker.config.vue.baseline.mjs`, `stryker-vue-macros-ignorer.mjs`, `vitest.config.baseline.js`). Якщо хоча б один відсутній, перевірка завершується.
24
+ 6. Для кожного кореневого JavaScript-каталогу виконується наступне:
25
+ а. Визначається, чи містить каталог файли Vue.
26
+ б. Базовий конфігураційний файл Stryker копіюється до цільового місця, замінюючи рядок з назвою конфігу на фактичну назву конфігу, знайденого в каталозі.
27
+ в. Якщо каталог Vue, виконується поглиблене доповнення конфігурації Stryker для додавання плагінів, необхідних для обробки Vue-макросів, до існуючого файлу, з гарантуванням збереження форматування.
28
+ г. Додатковий конфігураційний файл для Vue створюється/оновлюється.
29
+ д. Базовий конфігураційний файл Vitest створюється/оновлюється.
30
+ 7. Додаються до файлу `.gitignore` шаблони для ігнорування артефактів тестування Stryker та покриття.
31
+ 8. Повертається кінцевий код виходу перевірки.
32
+ 9. Код свідомо не перевіряє шляхи в каталозі `node_modules`.
33
+ 10. Усі внутрішні помилки перехоплюються, і перевірка завершується з відповідним статусом, що запобігає вильоту.
34
+
35
+ ## Гарантії поведінки
36
+
37
+ - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
38
+ - Свідомо пропускає шляхи: `node_modules`.