@nitra/cursor 3.22.0 → 3.23.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/.pi-template/extensions/n-cursor-adr/docs/index.md +181 -0
- package/CHANGELOG.md +31 -3
- package/bin/docs/n-cursor.md +636 -0
- package/bin/docs/rename-yaml-extensions.md +207 -0
- package/bin/n-cursor.js +30 -3
- package/package.json +1 -1
- package/rules/abie/docs/fix.md +18 -0
- package/rules/abie/js/docs/applies.md +26 -0
- package/rules/abie/js/docs/env_dns.md +32 -0
- package/rules/abie/js/docs/firebase_hosting.md +23 -0
- package/rules/abie/js/docs/hc_pairing.md +35 -0
- package/rules/abie/js/docs/ua_http_route.md +28 -0
- package/rules/abie/js/docs/ua_node_selector.md +28 -0
- package/rules/abie/lib/docs/enabled.md +29 -0
- package/rules/abie/lib/docs/env-dns.md +35 -0
- package/rules/abie/lib/docs/hc-yaml.md +33 -0
- package/rules/abie/lib/docs/http-route.md +44 -0
- package/rules/abie/lib/docs/k8s-tree.md +40 -0
- package/rules/abie/lib/docs/kustomization-patches.md +47 -0
- package/rules/abie/lib/docs/overlay-paths.md +38 -0
- package/rules/abie/lib/docs/yaml.md +29 -0
- package/rules/adr/docs/fix.md +148 -0
- package/rules/adr/js/docs/hooks.md +259 -0
- package/rules/bun/docs/fix.md +156 -0
- package/rules/bun/js/docs/layout.md +393 -0
- package/rules/capacitor/docs/fix.md +121 -0
- package/rules/capacitor/js/docs/platforms.md +295 -0
- package/rules/changelog/changelog.mdc +2 -2
- package/rules/changelog/docs/fix.md +174 -0
- package/rules/changelog/js/consistency.mjs +114 -13
- package/rules/changelog/js/docs/consistency.md +387 -0
- package/rules/changelog/lib/docs/package-manifest.md +210 -0
- package/rules/ci4/docs/fix.md +179 -0
- package/rules/ci4/js/docs/marksman_config.md +128 -0
- package/rules/docker/docker.mdc +8 -3
- package/rules/docker/docs/fix.md +171 -0
- package/rules/docker/js/docs/lint.md +258 -0
- package/rules/docker/lib/docs/docker-hadolint.md +184 -0
- package/rules/docker/lib/docs/docker-mirror.md +247 -0
- package/rules/docker/lib/docs/docker-native-addon.md +170 -0
- package/rules/docker/lib/docs/docker-nginx-user.md +219 -0
- package/rules/docker/lint/docs/lint.md +193 -0
- package/rules/efes/docs/fix.md +203 -0
- package/rules/feedback/docs/fix.md +140 -0
- package/rules/flow/docs/fix.md +152 -0
- package/rules/ga/docs/fix.md +158 -0
- package/rules/ga/js/docs/lint.md +100 -0
- package/rules/ga/js/docs/workflows.md +217 -0
- package/rules/ga/lint/docs/lint.md +209 -0
- package/rules/ga/policy/clean_merged_branch/clean_merged_branch.rego +11 -2
- package/rules/ga/policy/clean_merged_branch/template/clean-merged-branch.yml.snippet.yml +3 -4
- package/rules/graphql/docs/fix.md +126 -0
- package/rules/graphql/js/docs/tooling.md +264 -0
- package/rules/graphql/lib/docs/graphql-gql-scan.md +219 -0
- package/rules/hasura/docs/fix.md +120 -0
- package/rules/hasura/hasura.mdc +14 -0
- package/rules/hasura/js/docs/internal_urls.md +326 -0
- package/rules/image-avif/docs/fix.md +132 -0
- package/rules/image-avif/js/docs/avif_generation.md +241 -0
- package/rules/image-compress/docs/fix.md +150 -0
- package/rules/image-compress/js/docs/package_setup.md +191 -0
- package/rules/js-bun-db/docs/fix.md +148 -0
- package/rules/js-bun-db/js/docs/safety.md +231 -0
- package/rules/js-bun-db/js-bun-db.mdc +42 -13
- package/rules/js-bun-db/lib/docs/bun-sql-scan.md +347 -0
- package/rules/js-bun-redis/docs/fix.md +123 -0
- package/rules/js-bun-redis/js/docs/imports.md +176 -0
- package/rules/js-bun-redis/lib/docs/redis-imports.md +223 -0
- package/rules/js-lint/docs/fix.md +117 -0
- package/rules/js-lint/js/docs/lint.md +250 -0
- package/rules/js-lint/js/docs/tooling.md +348 -0
- package/rules/js-lint/js/docs/utils_imports.md +207 -0
- package/rules/js-lint-ci/docs/fix.md +154 -0
- package/rules/js-lint-ci/js/docs/lint.md +144 -0
- package/rules/js-mssql/docs/fix.md +128 -0
- package/rules/js-mssql/js/docs/deps.md +263 -0
- package/rules/js-mssql/lib/docs/mssql-pool-scan.md +367 -0
- package/rules/js-run/docs/fix.md +144 -0
- package/rules/js-run/js/docs/runtime.md +388 -0
- package/rules/js-run/lib/docs/bunyan-imports.md +117 -0
- package/rules/js-run/lib/docs/check-env-scan.md +433 -0
- package/rules/js-run/lib/docs/conn-file-rules.md +300 -0
- package/rules/js-run/lib/docs/conn-imports-scan.md +204 -0
- package/rules/js-run/lib/docs/promise-settimeout-scan.md +326 -0
- package/rules/k8s/docs/fix.md +129 -0
- package/rules/k8s/js/docs/manifests.md +344 -0
- package/rules/k8s/js/manifests.mjs +6 -2
- package/rules/k8s/k8s.mdc +4 -2
- package/rules/k8s/lint/docs/lint.md +411 -0
- package/rules/k8s/policy/network_policy/template/deployment.snippet.yaml +2 -0
- package/rules/k8s/policy/network_policy/template/stateful-set.snippet.yaml +2 -0
- package/rules/nginx-default-tpl/docs/fix.md +124 -0
- package/rules/nginx-default-tpl/js/docs/template.md +378 -0
- package/rules/npm-module/docs/fix.md +98 -0
- package/rules/npm-module/js/docs/package_structure.md +274 -0
- package/rules/npm-module/js/docs/rule_meta.md +137 -0
- package/rules/npm-module/js/docs/skill_meta.md +190 -0
- package/rules/php/docs/fix.md +107 -0
- package/rules/php/js/docs/tooling.md +152 -0
- package/rules/php/lint/docs/lint.md +215 -0
- package/rules/python/docs/fix.md +163 -0
- package/rules/python/js/docs/applies.md +108 -0
- package/rules/python/js/docs/tooling.md +153 -0
- package/rules/python/lint/docs/lint.md +322 -0
- package/rules/rego/docs/fix.md +121 -0
- package/rules/rego/js/docs/applies.md +174 -0
- package/rules/rego/js/docs/lint.md +118 -0
- package/rules/rego/lint/docs/lint.md +204 -0
- package/rules/release/docs/change.md +185 -0
- package/rules/release/docs/fix.md +119 -0
- package/rules/release/docs/release.md +222 -0
- package/rules/release/lib/docs/aggregate.md +246 -0
- package/rules/release/lib/docs/change-file.md +200 -0
- package/rules/release/lib/docs/fallback.md +203 -0
- package/rules/rust/docs/fix.md +129 -0
- package/rules/rust/js/docs/applies.md +140 -0
- package/rules/rust/lib/docs/has-cargo-toml.md +130 -0
- package/rules/security/docs/fix.md +86 -0
- package/rules/security/js/docs/lint.md +171 -0
- package/rules/security/js/docs/sample_secret.md +190 -0
- package/rules/security/js/docs/trufflehog.md +137 -0
- package/rules/security/js/lint.mjs +9 -1
- package/rules/style-lint/docs/fix.md +155 -0
- package/rules/style-lint/js/docs/lint.md +184 -0
- package/rules/style-lint/js/docs/tooling.md +194 -0
- package/rules/tauri/docs/fix.md +158 -0
- package/rules/tauri/js/docs/cargo_mutants_config.md +168 -0
- package/rules/tauri/js/docs/tooling.md +228 -0
- package/rules/test/coverage/coverage.mjs +15 -3
- package/rules/test/docs/fix.md +132 -0
- package/rules/test/js/data/stryker_config/docs/stryker-vue-macros-ignorer.md +138 -0
- package/rules/test/js/data/stryker_config/docs/stryker.config.baseline.md +134 -0
- package/rules/test/js/data/stryker_config/docs/stryker.config.vue.baseline.md +160 -0
- package/rules/test/js/data/vitest_config/docs/vitest.config.baseline.md +195 -0
- package/rules/test/js/docs/cargo_mutants_config.md +173 -0
- package/rules/test/js/docs/location.md +136 -0
- package/rules/test/js/docs/no-process-chdir.md +160 -0
- package/rules/test/js/docs/no-relative-fs-path.md +271 -0
- package/rules/test/js/docs/stryker_config.md +152 -0
- package/rules/test/js/docs/vitest-config-pool-forks.md +174 -0
- package/rules/text/docs/fix.md +118 -0
- package/rules/text/js/docs/forbidden-prettier.md +143 -0
- package/rules/text/js/docs/formatting.md +256 -0
- package/rules/text/js/docs/lint.md +122 -0
- package/rules/text/lint/docs/lint.md +220 -0
- package/rules/text/lint/docs/run-dotenv-linter.md +157 -0
- package/rules/text/lint/docs/run-shellcheck.md +212 -0
- package/rules/text/lint/docs/run-v8r.md +197 -0
- package/rules/vue/docs/fix.md +127 -0
- package/rules/vue/js/docs/packages.md +335 -0
- package/rules/vue/lib/docs/vue-forbidden-imports.md +261 -0
- package/rules/worktree/docs/fix.md +161 -0
- package/schemas/rule-meta.json +5 -1
- package/scripts/auto-rules.mjs +7 -4
- package/scripts/coverage-classify/docs/apply.md +202 -0
- package/scripts/coverage-classify/docs/cache.md +203 -0
- package/scripts/coverage-classify/docs/index.md +218 -0
- package/scripts/coverage-classify/docs/prompt.md +132 -0
- package/scripts/coverage-classify/docs/verdict-schema.md +169 -0
- package/scripts/coverage-fix-extract.mjs +122 -0
- package/scripts/coverage-fix.mjs +1 -1
- package/scripts/dispatcher/docs/graph.md +346 -0
- package/scripts/dispatcher/docs/index.md +236 -0
- package/scripts/dispatcher/docs/trace.md +296 -0
- package/scripts/dispatcher/index.mjs +1 -1
- package/scripts/dispatcher/lib/active.mjs +4 -8
- package/scripts/dispatcher/lib/commands.mjs +7 -11
- package/scripts/dispatcher/lib/docs/active.md +348 -0
- package/scripts/dispatcher/lib/docs/artifact.md +232 -0
- package/scripts/dispatcher/lib/docs/budget.md +167 -0
- package/scripts/dispatcher/lib/docs/capability.md +196 -0
- package/scripts/dispatcher/lib/docs/commands.md +210 -0
- package/scripts/dispatcher/lib/docs/events.md +182 -0
- package/scripts/dispatcher/lib/docs/executor.md +190 -0
- package/scripts/dispatcher/lib/docs/flow-lock.md +161 -0
- package/scripts/dispatcher/lib/docs/flow-resolve.md +267 -0
- package/scripts/dispatcher/lib/docs/gate.md +231 -0
- package/scripts/dispatcher/lib/docs/level.md +335 -0
- package/scripts/dispatcher/lib/docs/plan-panel.md +181 -0
- package/scripts/dispatcher/lib/docs/plan.md +200 -0
- package/scripts/dispatcher/lib/docs/planner.md +269 -0
- package/scripts/dispatcher/lib/docs/review.md +255 -0
- package/scripts/dispatcher/lib/docs/reviewer.md +240 -0
- package/scripts/dispatcher/lib/docs/snapshot.md +247 -0
- package/scripts/dispatcher/lib/docs/spec.md +203 -0
- package/scripts/dispatcher/lib/docs/state-store.md +303 -0
- package/scripts/dispatcher/lib/docs/subagent-runner.md +173 -0
- package/scripts/dispatcher/lib/executor.mjs +6 -1
- package/scripts/dispatcher/lib/flow-resolve.mjs +3 -1
- package/scripts/dispatcher/lib/level.mjs +29 -3
- package/scripts/dispatcher/lib/review.mjs +1 -1
- package/scripts/dispatcher/lib/subagent-runner.mjs +5 -3
- package/scripts/docs/auto-rules.md +376 -0
- package/scripts/docs/auto-skills.md +173 -0
- package/scripts/docs/build-agents-commands.md +183 -0
- package/scripts/docs/cli-entry.md +153 -0
- package/scripts/docs/coverage-fix.md +177 -0
- package/scripts/docs/ensure-nitra-cursor-dev-dependencies.md +189 -0
- package/scripts/lib/changed-files.mjs +4 -1
- package/scripts/lib/docs/changed-files.md +149 -0
- package/scripts/lib/docs/check-mdc-template-refs.md +222 -0
- package/scripts/lib/docs/check-reporter.md +175 -0
- package/scripts/lib/docs/discover-check-rules-from-cursor.md +157 -0
- package/scripts/lib/docs/discover-checkable-rules.md +165 -0
- package/scripts/lib/docs/ensure-tool.md +254 -0
- package/scripts/lib/docs/generated-markdown.md +275 -0
- package/scripts/lib/docs/gha-workflow.md +326 -0
- package/scripts/lib/docs/inline-template-links.md +303 -0
- package/scripts/lib/docs/list-rule-ids.md +156 -0
- package/scripts/lib/docs/load-cursor-config.md +147 -0
- package/scripts/lib/docs/mirror-parity.md +167 -0
- package/scripts/lib/worktree.mjs +26 -0
- package/scripts/worktree-cli.mjs +12 -2
- package/skills/coverage-fix/SKILL.md +34 -45
- package/skills/docgen/SKILL.md +44 -23
- package/skills/docgen/bench/etalon/firebase_hosting.md +19 -0
- package/skills/docgen/bench/etalon/k8s-tree.md +24 -0
- package/skills/docgen/bench/etalon/overlay-paths.md +24 -0
- package/skills/docgen/js/docgen-ignore.mjs +54 -0
- package/skills/docgen/js/docgen-scan.mjs +37 -21
- package/skills/llm-patch/SKILL.md +23 -2
- package/skills/start-check/SKILL.md +26 -53
- package/skills/start-check/js/check.mjs +211 -0
- package/skills/taze/SKILL.md +9 -3
- package/skills/taze/js/diff.mjs +154 -0
- package/types/bin/n-cursor.d.ts +1 -1
- package/skills/fix-tests/SKILL.md +0 -119
- package/skills/fix-tests/meta.json +0 -1
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# cargo_mutants_config.mjs
|
|
2
|
+
|
|
3
|
+
## Огляд
|
|
4
|
+
|
|
5
|
+
Модуль реалізує концерн `cargo_mutants_config` правила `tauri.mdc`. Його завдання — гарантувати, що для кожного workspace-пакета монорепо, у якому існує `<workspace>/src-tauri/Cargo.toml`, поряд лежить канонічний Tauri-специфічний конфіг `cargo-mutants` за шляхом `<workspace>/src-tauri/.cargo/mutants.toml`. Конфіг забороняє повторну збірку бінарників (`--bins`) і doc-tests (`--doc`) під кожного мутанта (це перетворює секунди на хвилини) і виключає з mutation-testing platform-bridge файли, які тестуються smoke/e2e, а не unit-тестами.
|
|
6
|
+
|
|
7
|
+
Семантика виключень фіксована для всіх Tauri-проєктів:
|
|
8
|
+
|
|
9
|
+
- `src/main.rs` — binary shell entrypoint (smoke/e2e, не mutation unit);
|
|
10
|
+
- `src/lib.rs` — Tauri `pub fn run`, runtime entrypoint, який запускає увесь app shell (один мутант там тримає увесь Tauri runtime і ділить sandbox-fail з `src/main.rs`);
|
|
11
|
+
- `src/**/{android,ios,mobile}.rs` — mobile plugin bridge / platform glue;
|
|
12
|
+
- `src/**/{macos,windows,linux,desktop}.rs` — desktop platform bridge / OS integration glue.
|
|
13
|
+
|
|
14
|
+
Файл побудований за патерном concern-checker у репо: експортує одну функцію `check(cwd)`, яка:
|
|
15
|
+
|
|
16
|
+
- self-gates (тихо пропускає, якщо у монорепо немає жодного `src-tauri/Cargo.toml` — нейтральний baseline за потреби створить test rule);
|
|
17
|
+
- ідемпотентна — створює файл лише за відсутності, інакше дописує лише ті top-level ключі, яких бракує, не змінюючи існуючих значень користувача;
|
|
18
|
+
- репортує результат через спільний `createCheckReporter` і повертає process exit code (`0` — OK або skip, `1` — порушення).
|
|
19
|
+
|
|
20
|
+
## Експорти / API
|
|
21
|
+
|
|
22
|
+
| Експорт | Тип | Опис |
|
|
23
|
+
| ------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
24
|
+
| `check(cwd?)` | `async function` | Єдиний публічний експорт. Запускає концерн над переданим або поточним коренем проєкту. Повертає `Promise<number>` — exit code, сумісний з CLI-обгорткою. |
|
|
25
|
+
|
|
26
|
+
Внутрішні (не експортуються) допоміжні функції: `findSrcTauriDirs`, `detectMissingKeys`, `buildAppended`, `buildBaseline`, `processOneSrcTauri`.
|
|
27
|
+
|
|
28
|
+
Внутрішні константи модульного рівня:
|
|
29
|
+
|
|
30
|
+
- `TAURI_BASELINE_HEADER` — рядковий заголовок (коментар) для нового файла з посиланням на `tauri.mdc` і поясненням, чому виключаються `--bins` та `--doc`.
|
|
31
|
+
- `TAURI_KEY_SNIPPETS` — заморожений (`Object.freeze`) словник `{ ключ → канонічний TOML-сніпет з блоковими коментарями }` для двох канонічних top-level ключів: `additional_cargo_test_args` і `exclude_globs`.
|
|
32
|
+
- `TAURI_CANONICAL_KEYS` — заморожений масив ключів `TAURI_KEY_SNIPPETS` зі збереженим порядком (`Object.keys(TAURI_KEY_SNIPPETS)`); використовується для впорядкованого детектування відсутніх ключів і генерації baseline.
|
|
33
|
+
|
|
34
|
+
Канонічний вміст сніпетів:
|
|
35
|
+
|
|
36
|
+
- `additional_cargo_test_args = ["--lib", "--tests"]` — `cargo mutants` під час прогону тестів обмежується library + integration tests, без бінарників і doc-tests.
|
|
37
|
+
- `exclude_globs = [...]` — список glob-патернів, які виключаються з mutation-testing (див. розділ «Огляд»).
|
|
38
|
+
|
|
39
|
+
## Функції
|
|
40
|
+
|
|
41
|
+
### `check(cwd = process.cwd())`
|
|
42
|
+
|
|
43
|
+
- **Сигнатура:** `async function check(cwd?: string): Promise<number>`.
|
|
44
|
+
- **Параметри:**
|
|
45
|
+
- `cwd` _(string, опційний, default `process.cwd()`)_ — абсолютний шлях до кореня монорепо. Дефолт забезпечує CLI-сумісність (виклик без аргументів з-під будь-якого `bin`).
|
|
46
|
+
- **Повертає:** `Promise<number>` — exit code від `reporter.getExitCode()` (`0` — успіх або self-skip, `1` — є зафіксовані `reporter.fail(...)`).
|
|
47
|
+
- **Алгоритм:**
|
|
48
|
+
1. Створює інстанс репортера через `createCheckReporter()`.
|
|
49
|
+
2. Знаходить усі `src-tauri/` директорії через `findSrcTauriDirs(cwd)`.
|
|
50
|
+
3. Якщо їх немає — повертає `reporter.getExitCode()` без жодних змін (self-gate / silent skip).
|
|
51
|
+
4. Інакше — послідовно обробляє кожен каталог через `processOneSrcTauri(dir, cwd, reporter)`.
|
|
52
|
+
5. Повертає підсумковий exit code від репортера.
|
|
53
|
+
- **Side effects:** може створювати теку `<src-tauri>/.cargo/` і записувати в `<src-tauri>/.cargo/mutants.toml`; пише повідомлення (`pass`/`fail`) у спільний репортер.
|
|
54
|
+
|
|
55
|
+
### `findSrcTauriDirs(cwd)`
|
|
56
|
+
|
|
57
|
+
- **Сигнатура:** `async function findSrcTauriDirs(cwd: string): Promise<string[]>`.
|
|
58
|
+
- **Параметри:** `cwd` — корінь проєкту.
|
|
59
|
+
- **Повертає:** масив абсолютних шляхів до `src-tauri/` каталогів, які мають власний `Cargo.toml`.
|
|
60
|
+
- **Алгоритм:**
|
|
61
|
+
1. Запитує всі workspace-пакети через `getMonorepoPackageRootDirs(cwd)` (включно з самим коренем).
|
|
62
|
+
2. Для кожного `root` перевіряє наявність `join(cwd, root, 'src-tauri', 'Cargo.toml')` через `existsSync`.
|
|
63
|
+
3. Якщо файл існує — додає `join(cwd, root, 'src-tauri')` до результату.
|
|
64
|
+
- **Side effects:** немає (read-only через `existsSync` і виклик util-функції монорепо-обходу).
|
|
65
|
+
|
|
66
|
+
### `detectMissingKeys(targetPath)`
|
|
67
|
+
|
|
68
|
+
- **Сигнатура:** `async function detectMissingKeys(targetPath: string): Promise<string[]>`.
|
|
69
|
+
- **Параметри:** `targetPath` — абсолютний шлях до існуючого `.cargo/mutants.toml`.
|
|
70
|
+
- **Повертає:** масив канонічних ключів (з `TAURI_CANONICAL_KEYS`), яких немає на top-level у вже існуючому TOML, зі збереженим порядком.
|
|
71
|
+
- **Алгоритм:**
|
|
72
|
+
1. Читає файл як UTF-8.
|
|
73
|
+
2. Парсить його через `parseToml` зі `smol-toml`.
|
|
74
|
+
3. Фільтрує `TAURI_CANONICAL_KEYS`, лишаючи лише ті, яких немає в розпарсеному об'єкті (`!(k in parsed)`).
|
|
75
|
+
- **Side effects:** read-only (читання файла).
|
|
76
|
+
|
|
77
|
+
### `buildAppended(existing, missingKeys)`
|
|
78
|
+
|
|
79
|
+
- **Сигнатура:** `function buildAppended(existing: string, missingKeys: string[]): string`.
|
|
80
|
+
- **Параметри:**
|
|
81
|
+
- `existing` — поточний текстовий вміст `.cargo/mutants.toml`;
|
|
82
|
+
- `missingKeys` — ключі, які треба дописати.
|
|
83
|
+
- **Повертає:** новий вміст файла (`string`) — оригінал + хвостовий блок з коментарем-маркером `# Tauri canonical cargo-mutants additions (tauri.mdc)` і конкатенованими TOML-сніпетами для всіх `missingKeys` у порядку, наданому викликачем.
|
|
84
|
+
- **Алгоритм:**
|
|
85
|
+
1. Нормалізує хвіст оригіналу: гарантує trailing `\n`.
|
|
86
|
+
2. Будує блок: порожній рядок-розділювач, заголовок-коментар, далі для кожного ключа з `missingKeys` — відповідний сніпет з `TAURI_KEY_SNIPPETS[key]`.
|
|
87
|
+
3. Конкатенує хвіст з блоком.
|
|
88
|
+
- **Side effects:** немає (чиста функція).
|
|
89
|
+
|
|
90
|
+
### `buildBaseline()`
|
|
91
|
+
|
|
92
|
+
- **Сигнатура:** `function buildBaseline(): string`.
|
|
93
|
+
- **Параметри:** немає.
|
|
94
|
+
- **Повертає:** повний текст канонічного `.cargo/mutants.toml` — `TAURI_BASELINE_HEADER`, після нього сніпети всіх `TAURI_CANONICAL_KEYS` (`additional_cargo_test_args`, `exclude_globs`), з'єднані через `'\n'`.
|
|
95
|
+
- **Side effects:** немає (чиста функція).
|
|
96
|
+
|
|
97
|
+
### `processOneSrcTauri(srcTauriDir, cwd, reporter)`
|
|
98
|
+
|
|
99
|
+
- **Сигнатура:** `async function processOneSrcTauri(srcTauriDir: string, cwd: string, reporter: { pass(msg): void, fail(msg): void }): Promise<void>`.
|
|
100
|
+
- **Параметри:**
|
|
101
|
+
- `srcTauriDir` — абсолютний шлях до `src-tauri/` каталогу;
|
|
102
|
+
- `cwd` — корінь проєкту (потрібен для красивого relative-шляху в репорт-повідомленнях);
|
|
103
|
+
- `reporter` — інстанс репортера з методами `pass(msg)`/`fail(msg)`.
|
|
104
|
+
- **Повертає:** `Promise<void>`.
|
|
105
|
+
- **Алгоритм / гілки:**
|
|
106
|
+
1. Формує `target = join(srcTauriDir, '.cargo', 'mutants.toml')` і `rel = relative(cwd, target)`.
|
|
107
|
+
2. **Файла немає:** створює директорію `<src-tauri>/.cargo/` (`mkdir … { recursive: true }`), записує повний `buildBaseline()`, репортує `pass`: `.cargo/mutants.toml створено з Tauri canonical baseline (<rel>) (tauri.mdc)`; вихід.
|
|
108
|
+
3. **Файл є:** викликає `detectMissingKeys(target)`.
|
|
109
|
+
- Якщо `missing.length === 0` — репортує `pass`: `.cargo/mutants.toml: manual cargo-mutants config preserved (<rel>)`; вихід.
|
|
110
|
+
- Інакше — читає поточний вміст, обчислює новий через `buildAppended(existing, missing)`, записує файл, репортує `pass`: `.cargo/mutants.toml: додано відсутні Tauri-ключі [<key1>, <key2>] (<rel>) (tauri.mdc)`.
|
|
111
|
+
- **Side effects:** створює директорії, записує/перезаписує файл `mutants.toml`, додає `pass`-повідомлення в репортер. У поточній реалізації функція не викликає `reporter.fail` — концерн є строго ідемпотентно-fix-овим (немає сценарію «порушення»).
|
|
112
|
+
|
|
113
|
+
## Залежності
|
|
114
|
+
|
|
115
|
+
### Node.js core (вбудовані)
|
|
116
|
+
|
|
117
|
+
- `node:fs` — `existsSync` для check'у наявності `Cargo.toml` / `mutants.toml`;
|
|
118
|
+
- `node:fs/promises` — `mkdir`, `readFile`, `writeFile` (промісована I/O для запису конфіга);
|
|
119
|
+
- `node:path` — `dirname`, `join`, `relative` (побудова цільового шляху та relative-вивід у репорт).
|
|
120
|
+
|
|
121
|
+
### External
|
|
122
|
+
|
|
123
|
+
- `smol-toml` (іменований імпорт `parse as parseToml`) — лояльний TOML-парсер для детекції наявних top-level ключів у існуючому `mutants.toml`.
|
|
124
|
+
|
|
125
|
+
### Internal (workspace utilities)
|
|
126
|
+
|
|
127
|
+
- `../../../scripts/lib/check-reporter.mjs` → `createCheckReporter()` — спільний reporter pass/fail/exit-code для concern-checker'ів.
|
|
128
|
+
- `../../../scripts/lib/workspaces.mjs` → `getMonorepoPackageRootDirs(cwd)` — повертає корінь + усі workspace-пакети монорепо.
|
|
129
|
+
|
|
130
|
+
## Потік виконання / Використання
|
|
131
|
+
|
|
132
|
+
### Типовий виклик з CLI / rule-runner
|
|
133
|
+
|
|
134
|
+
Модуль — частина правила `tauri.mdc`, його `check`-функцію викликає rule-runner (як один з концернів). Приблизний псевдо-виклик:
|
|
135
|
+
|
|
136
|
+
```js
|
|
137
|
+
import { check } from './cargo_mutants_config.mjs'
|
|
138
|
+
|
|
139
|
+
const exitCode = await check(process.cwd())
|
|
140
|
+
process.exit(exitCode)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Послідовність дій усередині одного запуску
|
|
144
|
+
|
|
145
|
+
1. `check(cwd)` створює репортер.
|
|
146
|
+
2. `findSrcTauriDirs(cwd)` обходить пакети монорепо й збирає всі `src-tauri/` з `Cargo.toml`.
|
|
147
|
+
3. Якщо пусто — `return reporter.getExitCode()` (тихий skip, нічого не пишемо).
|
|
148
|
+
4. Для кожного знайденого `src-tauri/`:
|
|
149
|
+
- якщо `.cargo/mutants.toml` відсутній → `mkdir -p` + запис canonical baseline;
|
|
150
|
+
- якщо файл існує + усі канонічні ключі присутні → нічого не змінює, репорт `manual cargo-mutants config preserved`;
|
|
151
|
+
- якщо файл існує, але деякі канонічні ключі відсутні → дописує лише відсутні ключі окремим блоком у кінці файла.
|
|
152
|
+
5. Повертає підсумковий exit code.
|
|
153
|
+
|
|
154
|
+
### Гарантії
|
|
155
|
+
|
|
156
|
+
- **Self-gating:** концерн нічого не робить, якщо в репо немає Tauri-пакетів — це не помилка.
|
|
157
|
+
- **Ідемпотентність:** повторні прогони на чистому/повному canonical файлі не змінюють вмісту.
|
|
158
|
+
- **Non-destructive:** ані наявні значення `additional_cargo_test_args`/`exclude_globs`, ані сторонні top-level ключі користувача не перезаписуються — додавання відсутніх ключів відбувається окремим append-блоком в кінці файла з коментарем-маркером.
|
|
159
|
+
- **Read-once-write-once на один каталог:** при append-сценарії файл читається повторно (один раз для парсу через `detectMissingKeys`, ще раз як текст для конкатенації), що гарантує запис рівно одного фінального вмісту.
|
|
160
|
+
|
|
161
|
+
### Точки розширення
|
|
162
|
+
|
|
163
|
+
- Додати новий канонічний top-level ключ: додати пару `key → snippet\n` у `TAURI_KEY_SNIPPETS`; `TAURI_CANONICAL_KEYS` та логіка `buildBaseline`/`buildAppended`/`detectMissingKeys` підхоплять його автоматично, зі збереженим порядком вставки.
|
|
164
|
+
- Змінити список platform-bridge файлів: відредагувати `exclude_globs` сніпет у `TAURI_KEY_SNIPPETS`.
|
|
165
|
+
|
|
166
|
+
### Rebuild Test
|
|
167
|
+
|
|
168
|
+
Файл містить достатню інформацію, щоб реконструювати правило з нуля: визначені вхідні точки виявлення Tauri-пакетів, перелік канонічних top-level ключів конфіга, форма заголовка/коментарів у згенерованому файлі, точні повідомлення репортера, гарантії ідемпотентності та non-destructive append, повний контракт експортованої функції `check(cwd)` (включно з дефолтом і поверненим типом).
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# tooling.mjs — перевірка інструментарію Tauri
|
|
2
|
+
|
|
3
|
+
## Огляд
|
|
4
|
+
|
|
5
|
+
Модуль `npm/rules/tauri/js/tooling.mjs` реалізує JS-orchestrator для правила `tauri.mdc`. Його єдина мета — перевірити, чи правильно налаштовано VSCode-конфіг `.vscode/extensions.json` у проєктах, де є Tauri.
|
|
6
|
+
|
|
7
|
+
Особливості:
|
|
8
|
+
|
|
9
|
+
- **Cross-file gating**. Перевірка вмикається лише за наявності маркера Tauri у проєкті. Якщо проєкт не використовує Tauri — модуль одразу повертає успіх і нічого не валідує.
|
|
10
|
+
- **Маркер Tauri** шукається в усіх workspace-пакетах монорепо (включно з кореневим) через `getMonorepoPackageRootDirs()` за п'ятьма ознаками: наявність каталогу `src-tauri/`, файлів `src-tauri/Cargo.toml`, `src-tauri/tauri.conf.json`, `tauri.conf.json` (legacy flat-layout) або префікса `@tauri-apps/` у `dependencies`/`devDependencies` файла `package.json`.
|
|
11
|
+
- **Plan B архітектура**. Це conditional-правило: Rego-полісі лежить глобально без `target.json` поруч і **не** є auto-discoverable через `n-cursor fix`. Тому JS-orchestrator робить FS-існування файла самостійно, а content-валідацію делегує в Rego через `runConftestBatch` (namespace `tauri.vscode_extensions`).
|
|
12
|
+
- **Звітування** іде через `createCheckReporter` — стандартний reporter з `pass`/`fail` повідомленнями та `getExitCode()` (0 — OK, 1 — є порушення).
|
|
13
|
+
|
|
14
|
+
## Експорти / API
|
|
15
|
+
|
|
16
|
+
| Символ | Тип | Опис |
|
|
17
|
+
| ------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
18
|
+
| `check` | `() => Promise<number>` | **Єдиний публічний експорт.** Запускає перевірку правил `tauri.mdc` і повертає exit-код процесу: `0` — все добре або Tauri-маркера немає, `1` — порушення. |
|
|
19
|
+
|
|
20
|
+
Внутрішні (не експортовані) функції модуля:
|
|
21
|
+
|
|
22
|
+
- `packageHasTauriDep(pkg)` — детектор `@tauri-apps/*` залежностей у `package.json`.
|
|
23
|
+
- `workspaceHasTauriMarker(cwd, ws)` — перевірка одного workspace-пакета на ознаки Tauri.
|
|
24
|
+
- `projectHasTauriMarker()` — обхід усіх workspaces для агрегованого результату.
|
|
25
|
+
|
|
26
|
+
## Функції
|
|
27
|
+
|
|
28
|
+
### `packageHasTauriDep(pkg)`
|
|
29
|
+
|
|
30
|
+
**Сигнатура.**
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
function packageHasTauriDep(pkg: Record<string, unknown> | null | undefined): boolean
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Параметри.**
|
|
37
|
+
|
|
38
|
+
- `pkg` — розпарсений вміст `package.json`. Допускає `null`, `undefined` або не-об'єктне значення — у цих випадках повертається `false`.
|
|
39
|
+
|
|
40
|
+
**Повертає.**
|
|
41
|
+
|
|
42
|
+
- `boolean` — `true`, якщо серед ключів `pkg.dependencies` або `pkg.devDependencies` знайдено хоча б один ключ із префіксом `@tauri-apps/`. Інакше — `false`.
|
|
43
|
+
|
|
44
|
+
**Логіка.**
|
|
45
|
+
|
|
46
|
+
1. Якщо `pkg` falsy або не object — `false`.
|
|
47
|
+
2. Перебирає два поля: `'dependencies'` і `'devDependencies'`.
|
|
48
|
+
3. Для кожного, якщо поле є object — ітерує `Object.keys()` і перевіряє `name.startsWith('@tauri-apps/')`.
|
|
49
|
+
4. Перший збіг → негайне `true` (early return).
|
|
50
|
+
|
|
51
|
+
**Side effects.** Немає — чиста функція. Працює лише з вхідним об'єктом.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
### `workspaceHasTauriMarker(cwd, ws)`
|
|
56
|
+
|
|
57
|
+
**Сигнатура.**
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
async function workspaceHasTauriMarker(cwd: string, ws: string): Promise<boolean>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Параметри.**
|
|
64
|
+
|
|
65
|
+
- `cwd` — абсолютний шлях до кореня репо (зазвичай `process.cwd()`).
|
|
66
|
+
- `ws` — відносний шлях workspace-пакета від кореня. Спеціальне значення `'.'` означає сам корінь (тоді `base = cwd`); для решти — `base = join(cwd, ws)`.
|
|
67
|
+
|
|
68
|
+
**Повертає.**
|
|
69
|
+
|
|
70
|
+
- `Promise<boolean>` — `true`, якщо в зазначеному workspace знайдено будь-який з маркерів Tauri:
|
|
71
|
+
1. Існує каталог `<base>/src-tauri/` (`existsSync` + `statSync(...).isDirectory()`).
|
|
72
|
+
2. Існує файл `<base>/src-tauri/Cargo.toml`.
|
|
73
|
+
3. Існує файл `<base>/src-tauri/tauri.conf.json`.
|
|
74
|
+
4. Існує файл `<base>/tauri.conf.json` (legacy flat-layout).
|
|
75
|
+
5. `<base>/package.json` існує, парситься як JSON і `packageHasTauriDep(pkg)` повертає `true`.
|
|
76
|
+
|
|
77
|
+
Якщо `package.json` не існує — повертає `false` (умова `if (!existsSync(pkgPath)) return false`).
|
|
78
|
+
|
|
79
|
+
**Side effects.**
|
|
80
|
+
|
|
81
|
+
- Синхронні FS-виклики `existsSync`, `statSync` для каталогів і файлів.
|
|
82
|
+
- Асинхронне читання файла `readFile(pkgPath, 'utf8')`.
|
|
83
|
+
- `JSON.parse` — кидає виключення на некоректному JSON у `package.json` (без явного `try/catch` всередині). Викидається вгору як rejected promise.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
### `projectHasTauriMarker()`
|
|
88
|
+
|
|
89
|
+
**Сигнатура.**
|
|
90
|
+
|
|
91
|
+
```js
|
|
92
|
+
async function projectHasTauriMarker(): Promise<boolean>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Параметри.** Немає.
|
|
96
|
+
|
|
97
|
+
**Повертає.**
|
|
98
|
+
|
|
99
|
+
- `Promise<boolean>` — `true`, якщо хоча б один workspace (включаючи корінь) має маркер Tauri.
|
|
100
|
+
|
|
101
|
+
**Логіка.**
|
|
102
|
+
|
|
103
|
+
1. Бере `cwd = process.cwd()`.
|
|
104
|
+
2. Викликає `getMonorepoPackageRootDirs(cwd)` — отримує масив workspace-шляхів (корінь `'.'` + всі workspaces з `package.json#workspaces`).
|
|
105
|
+
3. Послідовно (через `for...of`) перевіряє кожен workspace через `workspaceHasTauriMarker`. На першому `true` — короткозамикає й повертає `true`.
|
|
106
|
+
4. Якщо жоден workspace не має маркера — повертає `false`.
|
|
107
|
+
|
|
108
|
+
**Side effects.** Опосередковано — через FS-виклики у `workspaceHasTauriMarker` та `getMonorepoPackageRootDirs`.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
### `check()` — публічний експорт
|
|
113
|
+
|
|
114
|
+
**Сигнатура.**
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
export async function check(): Promise<number>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Параметри.** Немає.
|
|
121
|
+
|
|
122
|
+
**Повертає.**
|
|
123
|
+
|
|
124
|
+
- `Promise<number>` — exit-код перевірки, отриманий через `reporter.getExitCode()`:
|
|
125
|
+
- `0` — успіх (немає маркера Tauri, або всі канонічні конфіги відповідають правилам).
|
|
126
|
+
- `1` — є помилки (наприклад, `.vscode/extensions.json` не існує або не пройшов Rego-валідацію).
|
|
127
|
+
|
|
128
|
+
**Логіка покроково.**
|
|
129
|
+
|
|
130
|
+
1. Створює reporter: `const reporter = createCheckReporter()` і виймає шорткати `{ pass, fail }`.
|
|
131
|
+
2. Викликає `projectHasTauriMarker()`. Якщо маркера немає:
|
|
132
|
+
- Записує `pass('Немає маркера Tauri (src-tauri/, tauri.conf.json, @tauri-apps/*) — tauri-tooling не вимагається')`.
|
|
133
|
+
- Повертає `reporter.getExitCode()` — зазвичай `0` (бо тільки `pass`).
|
|
134
|
+
3. Якщо маркер є — записує `pass('Знайдено маркер Tauri — перевіряємо канонічні конфіги tauri.mdc')` і починає валідацію `.vscode/extensions.json`.
|
|
135
|
+
4. Перевіряє існування файла `.vscode/extensions.json` (відносний шлях від CWD):
|
|
136
|
+
- Якщо файла немає — `fail(...)` з повідомленням, що треба створити з `recommendations "tauri-apps.tauri-vscode"`, і повертає `reporter.getExitCode()` (тут уже буде `1`).
|
|
137
|
+
5. Якщо файл існує — викликає `runConftestBatch({ policyDirRel: 'tauri/vscode_extensions', namespace: 'tauri.vscode_extensions', files: ['.vscode/extensions.json'] })`. Отримує масив `violations`.
|
|
138
|
+
6. Залежно від результату:
|
|
139
|
+
- `violations.length === 0` → `pass(`${extPath} відповідає tauri.vscode_extensions (rego)`)`.
|
|
140
|
+
- Інакше — для кожного `v` із `violations` викликає `fail(v.message)`.
|
|
141
|
+
7. Повертає `reporter.getExitCode()` — `0` або `1` залежно від накопичених `fail`-викликів.
|
|
142
|
+
|
|
143
|
+
**Side effects.**
|
|
144
|
+
|
|
145
|
+
- Читає `process.cwd()` (через залежні функції).
|
|
146
|
+
- FS-доступ: `existsSync`, `statSync`, `readFile` (через детектори маркера) і `existsSync` для `.vscode/extensions.json`.
|
|
147
|
+
- Запускає зовнішній двійковий процес `conftest` (опосередковано через `runConftestBatch`).
|
|
148
|
+
- Накопичує повідомлення в reporter (stdout / накопичувач залежить від реалізації `createCheckReporter`).
|
|
149
|
+
|
|
150
|
+
## Залежності
|
|
151
|
+
|
|
152
|
+
Імпорти модуля:
|
|
153
|
+
|
|
154
|
+
- **Стандартна бібліотека Node.js:**
|
|
155
|
+
- `existsSync`, `statSync` із `node:fs` — синхронні FS-перевірки існування файлів/каталогів і типу запису.
|
|
156
|
+
- `readFile` із `node:fs/promises` — асинхронне читання `package.json`.
|
|
157
|
+
- `join` із `node:path` — побудова шляхів.
|
|
158
|
+
- **Локальні утиліти (з `../../../scripts/lib/`):**
|
|
159
|
+
- `createCheckReporter` із `check-reporter.mjs` — фабрика звітувача з `pass`/`fail`/`getExitCode`.
|
|
160
|
+
- `runConftestBatch` із `run-conftest-batch.mjs` — синхронний (за використанням у коді) виклик `conftest` для batch-валідації набору файлів проти Rego-полісі.
|
|
161
|
+
- `getMonorepoPackageRootDirs` із `workspaces.mjs` — асинхронне отримання шляхів усіх workspace-пакетів монорепо (включаючи корінь `'.'`).
|
|
162
|
+
|
|
163
|
+
Зовнішні runtime-передумови:
|
|
164
|
+
|
|
165
|
+
- Виконуваний `conftest` має бути доступний у `PATH` (інакше `runConftestBatch` зафейлиться).
|
|
166
|
+
- Rego-полісі для namespace `tauri.vscode_extensions` має бути зареєстрований у глобальній теці полісі (без `target.json` поруч — це conditional-правило).
|
|
167
|
+
|
|
168
|
+
## Потік виконання / Використання
|
|
169
|
+
|
|
170
|
+
**Типове призначення.** Модуль викликається CLI-агрегатором правил (наприклад, `n-cursor` чи аналогом) у режимі перевірки. Він — один із багатьох `check()`-модулів, кожен з яких відповідає одному `.mdc`-правилу. `tooling.mjs` відповідає за частину `tauri.mdc`, що стосується VSCode tooling.
|
|
171
|
+
|
|
172
|
+
**Приклад прямого виклику:**
|
|
173
|
+
|
|
174
|
+
```js
|
|
175
|
+
import { check } from './npm/rules/tauri/js/tooling.mjs'
|
|
176
|
+
|
|
177
|
+
const code = await check()
|
|
178
|
+
process.exit(code)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Послідовність виконання `check()`:**
|
|
182
|
+
|
|
183
|
+
1. **Ініціалізація reporter** → готовий до накопичення `pass`/`fail`.
|
|
184
|
+
2. **Gating (cross-file)** → `projectHasTauriMarker()`:
|
|
185
|
+
- `getMonorepoPackageRootDirs(cwd)` повертає шляхи всіх workspaces.
|
|
186
|
+
- Для кожного workspace перевіряємо 5 ознак (каталог `src-tauri/`, `Cargo.toml`, `tauri.conf.json` у двох локаціях, `@tauri-apps/*` у `package.json`).
|
|
187
|
+
- Перший знайдений маркер → переходимо до валідації; інакше — `pass` + exit `0`.
|
|
188
|
+
3. **FS-існування** `.vscode/extensions.json` — якщо немає, `fail` з підказкою про канонічний контент і exit `1`.
|
|
189
|
+
4. **Делегування в Rego** через `runConftestBatch`:
|
|
190
|
+
- `policyDirRel: 'tauri/vscode_extensions'` — відносний шлях до полісі.
|
|
191
|
+
- `namespace: 'tauri.vscode_extensions'` — Rego-namespace для оцінки.
|
|
192
|
+
- `files: ['.vscode/extensions.json']` — вхідні файли для batch-валідації.
|
|
193
|
+
5. **Звіт** — `pass` за нуль порушень, `fail(v.message)` для кожного `violation`.
|
|
194
|
+
6. **Повернення exit-коду** через `reporter.getExitCode()`.
|
|
195
|
+
|
|
196
|
+
**Поведінка при помилках.**
|
|
197
|
+
|
|
198
|
+
- Якщо `package.json` у якомусь workspace містить невалідний JSON — `JSON.parse` кине виключення; `projectHasTauriMarker` (і відповідно `check`) поверне rejected promise. Обробку покладено на викликальника.
|
|
199
|
+
- Якщо `conftest` не встановлено — помилку викине `runConftestBatch` (поведінка залежить від його реалізації).
|
|
200
|
+
|
|
201
|
+
**Інтеграційні зв'язки.**
|
|
202
|
+
|
|
203
|
+
- Правило в `.mdc`-форматі (зміст для людини) — `npm/rules/tauri/tauri.mdc` (або аналог; шукати в репо).
|
|
204
|
+
- Rego-полісі — десь у глобальній теці полісі під `tauri/vscode_extensions/` (адресовано через `policyDirRel`).
|
|
205
|
+
- Це conditional-правило: воно **не** реєструється автоматично в `n-cursor fix` як target-discoverable; орchestrator `tooling.mjs` сам гейтить виконання й сам викликає `conftest`.
|
|
206
|
+
|
|
207
|
+
## Rebuild Test
|
|
208
|
+
|
|
209
|
+
Опис достатній, щоб відтворити модуль з нуля:
|
|
210
|
+
|
|
211
|
+
1. Створити файл `tooling.mjs` з JSDoc-преамбулою, що описує мету та cross-file gating (5 ознак Tauri-маркера).
|
|
212
|
+
2. Імпортувати:
|
|
213
|
+
- `existsSync`, `statSync` із `node:fs`;
|
|
214
|
+
- `readFile` із `node:fs/promises`;
|
|
215
|
+
- `join` із `node:path`;
|
|
216
|
+
- `createCheckReporter` з `../../../scripts/lib/check-reporter.mjs`;
|
|
217
|
+
- `runConftestBatch` з `../../../scripts/lib/run-conftest-batch.mjs`;
|
|
218
|
+
- `getMonorepoPackageRootDirs` з `../../../scripts/lib/workspaces.mjs`.
|
|
219
|
+
3. Реалізувати `packageHasTauriDep(pkg)` — defensive guard + цикл по `['dependencies', 'devDependencies']` + перевірка `name.startsWith('@tauri-apps/')`.
|
|
220
|
+
4. Реалізувати `workspaceHasTauriMarker(cwd, ws)` — `base = ws === '.' ? cwd : join(cwd, ws)`, послідовні `existsSync`/`statSync` для каталогу `src-tauri/`, файлів `src-tauri/Cargo.toml`, `src-tauri/tauri.conf.json`, `tauri.conf.json`; fallback на `readFile(<base>/package.json)` + `JSON.parse` + `packageHasTauriDep`.
|
|
221
|
+
5. Реалізувати `projectHasTauriMarker()` — `process.cwd()`, `await getMonorepoPackageRootDirs(cwd)`, `for...of` з раннім `return true`.
|
|
222
|
+
6. Експортувати `async function check()`:
|
|
223
|
+
- Створити reporter, дістати `pass`/`fail`.
|
|
224
|
+
- Перевірити маркер; якщо немає — `pass(...)` + `return reporter.getExitCode()`.
|
|
225
|
+
- Якщо є — `pass(...)`, потім гейт `.vscode/extensions.json`: відсутній → `fail(...)` + return.
|
|
226
|
+
- Викликати `runConftestBatch({ policyDirRel: 'tauri/vscode_extensions', namespace: 'tauri.vscode_extensions', files: [extPath] })`.
|
|
227
|
+
- На порожньому масиві порушень — `pass(...)`; інакше — цикл `fail(v.message)`.
|
|
228
|
+
- Повернути `reporter.getExitCode()`.
|
|
@@ -75,7 +75,7 @@ export function formatScore({ caught, total }) {
|
|
|
75
75
|
/**
|
|
76
76
|
* Рендерить таблицю покриття + мутаційного тестування як Markdown.
|
|
77
77
|
* Якщо будь-який рядок містить непустий `survived`, додає секцію
|
|
78
|
-
* `## Вцілілі мутанти` з JSON-блоком для `/n-fix
|
|
78
|
+
* `## Вцілілі мутанти` з JSON-блоком для `/n-coverage-fix`.
|
|
79
79
|
* Якщо `allowedGaps` непустий, додає секцію `## Allowed gaps` з таблицею
|
|
80
80
|
* verdict/confidence/reason для кожного LLM-класифікованого мутанта.
|
|
81
81
|
* Без timestamp, щоб git diff рухався лише при зміні метрик.
|
|
@@ -130,10 +130,22 @@ export function renderMarkdown(rows, allowedGaps = []) {
|
|
|
130
130
|
gapsByFile.get(gap.file).push(gap)
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
lines.push(
|
|
133
|
+
lines.push(
|
|
134
|
+
'',
|
|
135
|
+
'## Allowed gaps',
|
|
136
|
+
'',
|
|
137
|
+
`> LLM-класифікатор виключив ${allowedGaps.length} survived мутант(ів) зі знаменника mutation score.`,
|
|
138
|
+
'> Категорії: equivalent (поведінково еквівалентний), defensive (impossible state), glue/wrapper (integration test покриває).'
|
|
139
|
+
)
|
|
134
140
|
|
|
135
141
|
for (const [file, gaps] of gapsByFile) {
|
|
136
|
-
lines.push(
|
|
142
|
+
lines.push(
|
|
143
|
+
'',
|
|
144
|
+
`### ${file}`,
|
|
145
|
+
'',
|
|
146
|
+
'| Line | Mutant | Verdict | Confidence | Reason |',
|
|
147
|
+
'| --- | --- | --- | --- | --- |'
|
|
148
|
+
)
|
|
137
149
|
for (const { mutant, verdict } of gaps) {
|
|
138
150
|
const sanitizedReason = verdict.reason.replaceAll('|', String.raw`\|`).replaceAll('\n', ' ')
|
|
139
151
|
lines.push(
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# fix.mjs — правило `test`
|
|
2
|
+
|
|
3
|
+
## Огляд
|
|
4
|
+
|
|
5
|
+
Файл `npm/rules/test/fix.mjs` — це точка входу правила з ідентифікатором `test` у системі правил `@nitra/cursor`. Файл одночасно виконує дві ролі:
|
|
6
|
+
|
|
7
|
+
1. **Library mode** — експортує функцію `run(ctx)`, яку викликає CLI-оркестратор `@nitra/cursor` коли пакет використовується як бібліотека (наприклад, через `npx @nitra/cursor fix test` або через композицію з іншими правилами).
|
|
8
|
+
2. **Standalone mode** — якщо файл запущено напряму (`bun npm/rules/test/fix.mjs`), він самостійно виконує повний еквівалент CLI-команди `npx @nitra/cursor fix test`: підвантажує конфіг, застосовує whitelist, друкує підсумок і повертає коректний exit-code для CI/IDE.
|
|
9
|
+
|
|
10
|
+
Обидва режими делегують усю важку роботу спільному оркестратору `runStandardRule`, який реалізує стандартизований пайплайн правила: **applies → JS-concerns → policy → mdc-refs**. Тобто конкретно цей файл не містить власної бізнес-логіки правила — він є лише декларативним «шаблонним» entry-point, який «прив'язує» директорію правила (`import.meta.dirname`) до стандартного процесу виконання.
|
|
11
|
+
|
|
12
|
+
Такий патерн (тонкий `fix.mjs` + важка логіка в `scripts/lib/`) — конвенція проєкту: кожне правило має ідентичний скелет, а конкретна перевірка зберігається в `check-{id}.mjs` / `mdc-refs.json` / supporting файлах у тій же директорії.
|
|
13
|
+
|
|
14
|
+
## Експорти / API
|
|
15
|
+
|
|
16
|
+
| Експорт | Тип | Опис |
|
|
17
|
+
| ------- | ---------------------------------------- | --------------------------------------------------------------------------------------------- |
|
|
18
|
+
| `run` | `(ctx?: RuleContext) => Promise<number>` | Library-функція запуску правила. Повертає exit-code: `0` — порушень немає, `1` — є порушення. |
|
|
19
|
+
|
|
20
|
+
Файл **не має default-експорту**. Іменований експорт `run` — це публічний контракт, який CLI-оркестратор `@nitra/cursor` очікує знайти у кожному `fix.mjs`.
|
|
21
|
+
|
|
22
|
+
### Тип `RuleContext`
|
|
23
|
+
|
|
24
|
+
Декларується у `../../scripts/lib/run-standard-rule.mjs` і реекспортується через JSDoc. Найважливіше поле:
|
|
25
|
+
|
|
26
|
+
- `walkCache` — спільний кеш обходу файлової системи, який орекстратор передає між правилами в одному прогоні, щоб не сканувати дерево повторно.
|
|
27
|
+
|
|
28
|
+
Контекст є **необов'язковим**: при standalone-запуску `runRuleCli` сам створює свіжий контекст; при library-запуску ctx підставляє зовнішній orchestrator.
|
|
29
|
+
|
|
30
|
+
## Функції
|
|
31
|
+
|
|
32
|
+
### `run(ctx)`
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
export function run(ctx) {
|
|
36
|
+
return runStandardRule(import.meta.dirname, ctx)
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
- **Сигнатура:** `run(ctx?: RuleContext): Promise<number>`
|
|
41
|
+
- **Параметри:**
|
|
42
|
+
- `ctx` _(опціональний)_ — `RuleContext`, контекст прогону. Може містити `walkCache` та інші поля, які стандартний пайплайн використовує для оптимізацій і передачі стану між правилами в межах однієї CLI-сесії.
|
|
43
|
+
- **Повертає:** `Promise<number>` — exit-code:
|
|
44
|
+
- `0` — правило відпрацювало без порушень;
|
|
45
|
+
- `1` — виявлено порушення (хоча б на одному з кроків applies/JS-concerns/policy/mdc-refs).
|
|
46
|
+
- **Side effects:** усі побічні ефекти делеговані `runStandardRule`. Зокрема: читання файлової системи (через walker), друк звіту в stdout/stderr, можливі правки файлів (якщо правило підтримує auto-fix), оновлення `walkCache`.
|
|
47
|
+
- **Ідентифікація правила:** правило ідентифікується **директорією** через `import.meta.dirname` — тобто абсолютним шляхом до теки `npm/rules/test/`. Зміна шляху чи переіменування директорії змінить ідентичність правила.
|
|
48
|
+
|
|
49
|
+
### Top-level standalone-блок
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
if (isRunAsCli(import.meta.url)) {
|
|
53
|
+
process.exit(await runRuleCli(import.meta.dirname))
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- **Тип:** не функція, а top-level `if`-блок із top-level `await`.
|
|
58
|
+
- **Умова входу:** `isRunAsCli(import.meta.url)` — повертає `true`, лише якщо цей модуль запущено як головний скрипт (а не імпортовано як залежність). Реалізація утиліти живе в `../../scripts/lib/run-rule-cli.mjs`.
|
|
59
|
+
- **Дія:** викликає `runRuleCli(import.meta.dirname)` — повний CLI-флоу одного правила (config-loading, whitelist, summary), очікує його `Promise<number>` і передає результат у `process.exit(...)`.
|
|
60
|
+
- **Side effects:** **завершує процес** через `process.exit(...)`. Тому інклюди коментарі-disable для ESLint-правил `n/no-process-exit` та `unicorn/no-process-exit` — це свідомий виняток для standalone entry-point.
|
|
61
|
+
- **Чому `await` дозволено на top-level:** файл є ESM-модулем (`.mjs`), а ESM підтримує top-level `await` нативно.
|
|
62
|
+
|
|
63
|
+
## Залежності
|
|
64
|
+
|
|
65
|
+
### Внутрішні модулі (relative imports)
|
|
66
|
+
|
|
67
|
+
| Шлях | Імпортовані сутності | Призначення |
|
|
68
|
+
| ----------------------------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
|
69
|
+
| `../../scripts/lib/run-rule-cli.mjs` | `isRunAsCli`, `runRuleCli` | Standalone CLI-обгортка: детект `import.meta.url === entry` і запуск повного CLI-флоу з config/whitelist/summary. |
|
|
70
|
+
| `../../scripts/lib/run-standard-rule.mjs` | `runStandardRule` | Стандартний пайплайн правила: послідовно прогоняє кроки `applies` → `JS-concerns` → `policy` → `mdc-refs`. Експортує тип `RuleContext`. |
|
|
71
|
+
|
|
72
|
+
Шляхи `../../scripts/lib/...` ведуть із `npm/rules/test/` у `npm/scripts/lib/` — тобто до **спільної інфраструктури правил** усередині пакета `@nitra/cursor`.
|
|
73
|
+
|
|
74
|
+
### Зовнішні залежності
|
|
75
|
+
|
|
76
|
+
Прямих імпортів зовнішніх npm-пакетів немає. Усі зовнішні залежності (наприклад, file-walker, glob-matcher, ESLint-utils) інкапсульовані всередині `runStandardRule` / `runRuleCli`.
|
|
77
|
+
|
|
78
|
+
### Платформенні API
|
|
79
|
+
|
|
80
|
+
- `import.meta.dirname` — Node.js/Bun-фіча ESM, що повертає абсолютний шлях до теки поточного модуля. Доступна в Node.js ≥ 20.11 та сучасних версіях Bun.
|
|
81
|
+
- `import.meta.url` — стандартний ESM-атрибут, URL поточного модуля (використовується для CLI-детекту).
|
|
82
|
+
- `process.exit(code)` — глобальний Node.js/Bun API.
|
|
83
|
+
- Top-level `await` — стандарт ESM (ES2022).
|
|
84
|
+
|
|
85
|
+
## Потік виконання / Використання
|
|
86
|
+
|
|
87
|
+
### Сценарій 1: Library mode (виклик з оркестратора)
|
|
88
|
+
|
|
89
|
+
1. Зовнішній CLI (`npx @nitra/cursor fix` або композитний прогон) визначає список активних правил.
|
|
90
|
+
2. Для правила `test` він `import`-ить `npm/rules/test/fix.mjs`.
|
|
91
|
+
3. Top-level `if (isRunAsCli(...))` повертає `false` (бо модуль імпортовано, а не запущено напряму) — standalone-гілка пропускається, процес не завершується.
|
|
92
|
+
4. Оркестратор викликає `run(ctx)` із підготовленим контекстом (`walkCache` тощо).
|
|
93
|
+
5. `run` делегує виклик `runStandardRule(import.meta.dirname, ctx)`.
|
|
94
|
+
6. `runStandardRule` послідовно виконує кроки пайплайна правила, читаючи допоміжні файли з директорії правила.
|
|
95
|
+
7. Результат (`Promise<number>`) повертається в оркестратор, який агрегує exit-коди усіх правил.
|
|
96
|
+
|
|
97
|
+
### Сценарій 2: Standalone mode (пряме виконання)
|
|
98
|
+
|
|
99
|
+
Команда: `bun npm/rules/test/fix.mjs` (або `node npm/rules/test/fix.mjs` за умови підтримки `import.meta.dirname`).
|
|
100
|
+
|
|
101
|
+
1. Bun/Node запускає модуль як головний.
|
|
102
|
+
2. Виконується top-level код: `isRunAsCli(import.meta.url)` → `true`.
|
|
103
|
+
3. Викликається `runRuleCli(import.meta.dirname)`:
|
|
104
|
+
- підвантажується конфіг проєкту,
|
|
105
|
+
- застосовується whitelist (якщо є),
|
|
106
|
+
- запускається пайплайн правила (фактично — той самий `runStandardRule` під капотом, але обгорнутий у CLI-логіку: парсинг прапорців, друк summary, обробка помилок),
|
|
107
|
+
- повертається `Promise<number>` із exit-code.
|
|
108
|
+
4. `await` чекає завершення Promise.
|
|
109
|
+
5. `process.exit(code)` завершує процес із отриманим кодом — це робить файл придатним для CI/pre-commit/IDE-інтеграцій, які покладаються саме на exit-code.
|
|
110
|
+
|
|
111
|
+
### Сценарій 3: Через `npx @nitra/cursor fix test`
|
|
112
|
+
|
|
113
|
+
Це **гібридний** сценарій:
|
|
114
|
+
|
|
115
|
+
1. CLI пакета `@nitra/cursor` запускається користувачем.
|
|
116
|
+
2. Він знаходить директорію правила за id (`test`) і динамічно імпортує `fix.mjs`.
|
|
117
|
+
3. CLI викликає експортовану функцію `run(ctx)` — тобто це Library mode (Сценарій 1), просто ініційований CLI-командою верхнього рівня. Standalone-гілка в самому `fix.mjs` при цьому **не активується**.
|
|
118
|
+
|
|
119
|
+
### Інваріанти та контракти
|
|
120
|
+
|
|
121
|
+
- `run` **мусить** повертати `Promise<number>` із значенням `0` або `1` — інакше CLI-оркестратор може некоректно агрегувати результати.
|
|
122
|
+
- Файл **не повинен** містити власної логіки правила: усе делегується `runStandardRule`. Конкретна перевірка живе у супутніх файлах директорії (`check-test.mjs`, `mdc-refs.json`, тощо — згідно конвенції проєкту).
|
|
123
|
+
- Top-level `await` дозволено лише в standalone-блоці й лише тому, що модуль ESM (`.mjs`).
|
|
124
|
+
- `process.exit` викликається **лише** в standalone-режимі — у library-режимі (Сценарій 1) виклик `process.exit` був би порушенням (тому існує `isRunAsCli`-guard і ESLint-disable коментар із обґрунтуванням).
|
|
125
|
+
|
|
126
|
+
### Розширення та модифікація
|
|
127
|
+
|
|
128
|
+
Файл є **темплейтним** і свідомо мінімальним. Щоб змінити поведінку правила `test`, **не редагуйте `fix.mjs`** — замість цього:
|
|
129
|
+
|
|
130
|
+
- логіку перевірок змінюйте у `check-*.mjs` тієї ж директорії;
|
|
131
|
+
- посилання на правила Cursor оновлюйте в `mdc-refs.json`;
|
|
132
|
+
- спільні зміни пайплайна вносьте в `npm/scripts/lib/run-standard-rule.mjs` (тоді вони застосуються до **всіх** правил одночасно).
|