@nitra/cursor 1.28.7 → 1.28.8
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 +9 -0
- package/package.json +1 -1
- package/rules/test/js/stryker_config.mjs +45 -3
- package/rules/test/test.mdc +9 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
Формат — [Keep a Changelog](https://keepachangelog.com/uk/1.1.0/), нумерація — [SemVer](https://semver.org/lang/uk/).
|
|
6
6
|
|
|
7
|
+
## [1.28.8] - 2026-05-28
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **`rules/test/js/data/stryker_config/stryker-vue-macros-ignorer.mjs`** — новий локальний Stryker `Ignore`-плагін `vue-macros`. `shouldIgnore(path)` повертає non-empty message для `CallExpression`, де `callee` — `Identifier` з ім'ям у наборі Vue `<script setup>`-макросів: `defineProps`, `defineEmits`, `defineModel`, `defineSlots`, `defineExpose`, `defineOptions`. Експортує `strykerPlugins: [{kind: 'Ignore', name: 'vue-macros', value: {shouldIgnore}}]` — це формат, який очікує stryker-core plugin-loader (`module.strykerPlugins`); без імпорту `@stryker-mutator/api`.
|
|
12
|
+
- **`rules/test/js/data/stryker_config/stryker.config.vue.baseline.mjs`** — vue-варіант baseline `stryker.config.mjs`: дефолтні поля + `plugins: ['@stryker-mutator/vitest-runner', './stryker-vue-macros-ignorer.mjs']` і `ignorers: ['vue-macros']` (поряд із vitest-runner тепер треба явно вказати runner, бо ручний `plugins` затирає Stryker default).
|
|
13
|
+
- **`rules/test/js/stryker_config.mjs`** — концерн `stryker_config` тепер детектить `.vue` файли під `<jsRoot>/src/**` (skip `node_modules`/`dist`/`reports`) і у JS-roots із SFC ставить vue-варіант baseline + копіює `stryker-vue-macros-ignorer.mjs` поряд із конфігом. Backward-compat: jsRoot без `.vue` отримує дефолтний baseline без `plugins`/`ignorers`. Обидва файли копіюються через `ensureBaselineFile` — idempotent, ручні модифікації не перетираються. Tests: `+5` сценаріїв у `rules/test/js/tests/stryker_config.test.mjs` (vue-detection happy path, no-vue → дефолт, mixed monorepo, `.vue` лише у node_modules — НЕ vue, idempotency для vue-файлів) + новий `rules/test/js/tests/stryker-vue-macros-ignorer.test.mjs` (всі 6 макросів, non-macro callee, non-CallExpression, MemberExpression callee, anonymous callee).
|
|
14
|
+
- **`rules/test/test.mdc`** (`version` 2.5 → 2.6) і дзеркало `.cursor/rules/n-test.mdc` — нова підсекція "Vue SFC (`<script setup>` macros)" у "Налаштування mutation-testing" з описом коли тригериться vue-варіант, які макроси скіпаються, чому без плагіна `@vue/compiler-sfc` падає на coverage-тернарнику Stryker. Мотивація — інакше boilerplate `// Stryker disable next-line` потрібен у кожному SFC.
|
|
15
|
+
|
|
7
16
|
## [1.28.7] - 2026-05-28
|
|
8
17
|
|
|
9
18
|
### Fixed
|
package/package.json
CHANGED
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
* (всі workspaces з package.json, або cwd у single-package) і копіює canonical
|
|
5
5
|
* baseline `stryker.config.mjs` + `vitest.config.js` у кожен root, де файлу немає.
|
|
6
6
|
*
|
|
7
|
+
* Для JS-roots із `.vue` файлами (Vue 3 + `<script setup>`) копіюється vue-варіант
|
|
8
|
+
* baseline, який реєструє локальний Ignore-плагін `vue-macros` — інакше Stryker
|
|
9
|
+
* огортає виклики `defineProps`/`defineEmits`/... у coverage-тернарник і
|
|
10
|
+
* `@vue/compiler-sfc` падає при компіляції SFC. Плагін копіюється у той самий
|
|
11
|
+
* jsRoot як `stryker-vue-macros-ignorer.mjs`.
|
|
12
|
+
*
|
|
7
13
|
* Self-gating: концерн silently skips коли `js-lint` не enabled — це навмисно,
|
|
8
14
|
* щоб не шуміти у single-language проєктах без JS coverage tooling.
|
|
9
15
|
*
|
|
@@ -11,7 +17,7 @@
|
|
|
11
17
|
* лишаються на Stryker defaults (`src/**\/*.{js,mjs,ts,jsx,tsx,cjs}`).
|
|
12
18
|
*/
|
|
13
19
|
import { existsSync } from 'node:fs'
|
|
14
|
-
import { copyFile } from 'node:fs/promises'
|
|
20
|
+
import { copyFile, glob } from 'node:fs/promises'
|
|
15
21
|
import { dirname, join, relative } from 'node:path'
|
|
16
22
|
import { fileURLToPath } from 'node:url'
|
|
17
23
|
|
|
@@ -22,6 +28,9 @@ import { resolveAllJsRoots } from '../../../scripts/utils/resolve-js-root.mjs'
|
|
|
22
28
|
|
|
23
29
|
const HERE = dirname(fileURLToPath(import.meta.url))
|
|
24
30
|
const STRYKER_BASELINE_PATH = join(HERE, 'data', 'stryker_config', 'stryker.config.baseline.mjs')
|
|
31
|
+
const STRYKER_VUE_BASELINE_PATH = join(HERE, 'data', 'stryker_config', 'stryker.config.vue.baseline.mjs')
|
|
32
|
+
const STRYKER_VUE_PLUGIN_PATH = join(HERE, 'data', 'stryker_config', 'stryker-vue-macros-ignorer.mjs')
|
|
33
|
+
const STRYKER_VUE_PLUGIN_FILENAME = 'stryker-vue-macros-ignorer.mjs'
|
|
25
34
|
const VITEST_BASELINE_PATH = join(HERE, 'data', 'vitest_config', 'vitest.config.baseline.js')
|
|
26
35
|
|
|
27
36
|
// Stryker-output патерн для .gitignore: увесь каталог reports/stryker/ — це
|
|
@@ -30,6 +39,23 @@ const VITEST_BASELINE_PATH = join(HERE, 'data', 'vitest_config', 'vitest.config.
|
|
|
30
39
|
// перелічування під-патернів. Подвійний-зірочка-префікс — для monorepo workspaces.
|
|
31
40
|
const STRYKER_GITIGNORE_ENTRIES = ['**/reports/stryker/']
|
|
32
41
|
|
|
42
|
+
// .vue detection: scope — `<jsRoot>/src/**/*.vue` (як і Stryker mutate defaults для src/);
|
|
43
|
+
// skip build-артефактів і чужих node_modules, щоб не вмикати vue-варіант через transitive deps.
|
|
44
|
+
const VUE_GLOB_PATTERN = 'src/**/*.vue'
|
|
45
|
+
const VUE_GLOB_IGNORE = ['**/node_modules/**', '**/dist/**', '**/reports/**']
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Чи містить jsRoot хоч один `.vue` файл під `src/` (skipping node_modules/dist/reports).
|
|
49
|
+
* @param {string} jsRoot абсолютний шлях до workspace-каталогу
|
|
50
|
+
* @returns {Promise<boolean>} true якщо знайдено хоча б один `.vue`
|
|
51
|
+
*/
|
|
52
|
+
async function hasVueFiles(jsRoot) {
|
|
53
|
+
for await (const _rel of glob(VUE_GLOB_PATTERN, { cwd: jsRoot, exclude: VUE_GLOB_IGNORE })) {
|
|
54
|
+
return true
|
|
55
|
+
}
|
|
56
|
+
return false
|
|
57
|
+
}
|
|
58
|
+
|
|
33
59
|
/**
|
|
34
60
|
* Копіює baseline у target, якщо target ще не існує. Idempotent.
|
|
35
61
|
* @param {ReturnType<typeof createCheckReporter>} reporter check-reporter для логу pass/fail
|
|
@@ -67,7 +93,12 @@ export async function check() {
|
|
|
67
93
|
return reporter.getExitCode()
|
|
68
94
|
}
|
|
69
95
|
|
|
70
|
-
for (const baselinePath of [
|
|
96
|
+
for (const baselinePath of [
|
|
97
|
+
STRYKER_BASELINE_PATH,
|
|
98
|
+
STRYKER_VUE_BASELINE_PATH,
|
|
99
|
+
STRYKER_VUE_PLUGIN_PATH,
|
|
100
|
+
VITEST_BASELINE_PATH
|
|
101
|
+
]) {
|
|
71
102
|
if (!existsSync(baselinePath)) {
|
|
72
103
|
reporter.fail(`canonical baseline не знайдено (${baselinePath}) — перевстанови @nitra/cursor`)
|
|
73
104
|
return reporter.getExitCode()
|
|
@@ -75,13 +106,24 @@ export async function check() {
|
|
|
75
106
|
}
|
|
76
107
|
|
|
77
108
|
for (const jsRoot of jsRoots) {
|
|
109
|
+
const isVueRoot = await hasVueFiles(jsRoot)
|
|
110
|
+
const strykerBaseline = isVueRoot ? STRYKER_VUE_BASELINE_PATH : STRYKER_BASELINE_PATH
|
|
78
111
|
await ensureBaselineFile(
|
|
79
112
|
reporter,
|
|
80
113
|
cwd,
|
|
81
|
-
|
|
114
|
+
strykerBaseline,
|
|
82
115
|
join(jsRoot, 'stryker.config.mjs'),
|
|
83
116
|
'stryker.config.mjs'
|
|
84
117
|
)
|
|
118
|
+
if (isVueRoot) {
|
|
119
|
+
await ensureBaselineFile(
|
|
120
|
+
reporter,
|
|
121
|
+
cwd,
|
|
122
|
+
STRYKER_VUE_PLUGIN_PATH,
|
|
123
|
+
join(jsRoot, STRYKER_VUE_PLUGIN_FILENAME),
|
|
124
|
+
STRYKER_VUE_PLUGIN_FILENAME
|
|
125
|
+
)
|
|
126
|
+
}
|
|
85
127
|
await ensureBaselineFile(reporter, cwd, VITEST_BASELINE_PATH, join(jsRoot, 'vitest.config.js'), 'vitest.config.js')
|
|
86
128
|
}
|
|
87
129
|
|
package/rules/test/test.mdc
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: JS-тести (*.test.mjs) живуть у tests/. Правило `test` керує stryker.config.mjs + vitest.config.js (якщо js-lint enabled) і .cargo/mutants.toml (якщо rust enabled).
|
|
3
|
-
version: '2.
|
|
3
|
+
version: '2.6'
|
|
4
4
|
globs: "**/{.n-cursor.json,package.json,Cargo.toml,stryker.config.mjs,vitest.config.js,.cargo/mutants.toml},**/*.test.mjs"
|
|
5
5
|
alwaysApply: false
|
|
6
6
|
---
|
|
@@ -101,6 +101,14 @@ Canonical `vitest.config.js` (для довідки — `pool: 'forks'` + `inclu
|
|
|
101
101
|
|
|
102
102
|
Канон Stryker config (Vitest runner + perTest): [stryker.config.baseline.mjs](./js/data/stryker_config/stryker.config.baseline.mjs)
|
|
103
103
|
|
|
104
|
+
### Vue SFC (`<script setup>` macros)
|
|
105
|
+
|
|
106
|
+
Якщо у JS-root знайдено бодай один `.vue` під `src/` (skip `node_modules`/`dist`/`reports`) — концерн ставить **vue-варіант** baseline ([`stryker.config.vue.baseline.mjs`](./js/data/stryker_config/stryker.config.vue.baseline.mjs)) замість звичайного і додатково копіює локальний Stryker `Ignore`-плагін [`stryker-vue-macros-ignorer.mjs`](./js/data/stryker_config/stryker-vue-macros-ignorer.mjs) поряд із конфігом.
|
|
107
|
+
|
|
108
|
+
Плагін реєструється як `plugins: ['@stryker-mutator/vitest-runner', './stryker-vue-macros-ignorer.mjs']` + `ignorers: ['vue-macros']` і виключає з мутацій виклики `<script setup>`-макросів: **`defineProps`**, **`defineEmits`**, **`defineModel`**, **`defineSlots`**, **`defineExpose`**, **`defineOptions`**. Без плагіна Stryker огортає аргументи макроса у coverage-тернарник (`stryMutAct_9fa48(...) ? {} : (stryCov_9fa48(...), {...})`), а `@vue/compiler-sfc` падає з `defineProps() in <script setup> cannot reference locally declared variables` — макроси мають бути статично-аналізованими на етапі compile-sfc. Альтернатива з boilerplate `// Stryker disable next-line` у кожному SFC не масштабується.
|
|
109
|
+
|
|
110
|
+
JS-root без `.vue` отримує дефолтний baseline без `plugins`/`ignorers` (backward-compatible). Обидва файли копіюються idempotent — наявний `stryker.config.mjs` / `stryker-vue-macros-ignorer.mjs` не перетирається.
|
|
111
|
+
|
|
104
112
|
### Vitest baseline та `package.json#scripts`
|
|
105
113
|
|
|
106
114
|
Поряд зі Stryker концерн `stryker_config` без дублювання копіює `vitest.config.js` (теж тільки якщо файлу немає). Canonical: [vitest.config.baseline.js](./js/data/vitest_config/vitest.config.baseline.js) — `environment: 'node'`, `coverage.provider: 'v8'` з lcov+text-summary репортами, `include: ['**/*.test.{js,mjs}', 'tests/**/*.test.{js,mjs}']` (підхоплює обидві розкладки — тести у `tests/`-піддиректоріях і top-level integration suites у `<root>/tests/`).
|