@nitra/cursor 3.22.0 → 3.23.1
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/AGENTS.template.md +4 -0
- package/CHANGELOG.md +37 -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 +4 -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,175 @@
|
|
|
1
|
+
# check-reporter.mjs
|
|
2
|
+
|
|
3
|
+
## Огляд
|
|
4
|
+
|
|
5
|
+
Модуль `check-reporter.mjs` — це невелика спільна (shared) бібліотека-фабрика для check-скриптів (`check-*.mjs`) і для `lint-docker`. Вона надає уніфікований спосіб репортити результати перевірок: успіхи (`pass`) та помилки (`fail`), а також акумулювати фінальний код виходу процесу (`exit code`).
|
|
6
|
+
|
|
7
|
+
Основна ідея: викликаючи фабрику `createCheckReporter()`, споживач отримує об’єкт з трьома методами — `pass`, `fail` і `getExitCode`. Будь-який виклик `fail` переводить внутрішній лічильник у стан помилки (`exitCode = 1`), і подальший `getExitCode()` повертатиме `1`. Якщо `fail` жодного разу не викликали — `getExitCode()` поверне `0`.
|
|
8
|
+
|
|
9
|
+
Модуль навмисно тримає API мінімальним і не нав’язує конкретний формат виводу: рядок успіху форматується делегованою функцією `pass` з `../utils/pass.mjs`, а помилка виводиться у форматі ` ❌ <msg>` через `console.log`.
|
|
10
|
+
|
|
11
|
+
Важлива поведінкова деталь: `getExitCode` — це **метод-геттер у вигляді функції**, а не геттер-властивість через `get`. Тому слід викликати саме `reporter.getExitCode()` у момент завершення, а не деструктурувати `const { exitCode } = reporter` — інакше отримаєш undefined або застаріле значення, оскільки `exitCode` як поле в об’єкті не експонується назовні (це замикання).
|
|
12
|
+
|
|
13
|
+
## Експорти / API
|
|
14
|
+
|
|
15
|
+
Модуль експортує одну іменовану (named) функцію:
|
|
16
|
+
|
|
17
|
+
- `createCheckReporter()` — фабрика, що повертає об’єкт-репортер.
|
|
18
|
+
|
|
19
|
+
Структура об’єкта, який повертає `createCheckReporter()`:
|
|
20
|
+
|
|
21
|
+
| Поле | Тип | Опис |
|
|
22
|
+
| ------------- | ----------------------- | -------------------------------------------------------------------------------------------------- |
|
|
23
|
+
| `pass` | `typeof pass` | Реекспорт функції `pass` з `../utils/pass.mjs`. Друкує рядок успіху у форматі, визначеному `pass`. |
|
|
24
|
+
| `fail` | `(msg: string) => void` | Друкує рядок помилки з префіксом ` ❌` і виставляє внутрішній `exitCode = 1`. |
|
|
25
|
+
| `getExitCode` | `() => number` | Повертає `0`, якщо `fail` жодного разу не викликали, інакше `1`. |
|
|
26
|
+
|
|
27
|
+
JSDoc-сигнатура у файлі:
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
/**
|
|
31
|
+
* @returns {{
|
|
32
|
+
* pass: typeof pass,
|
|
33
|
+
* fail: (msg: string) => void,
|
|
34
|
+
* getExitCode: () => number
|
|
35
|
+
* }}
|
|
36
|
+
*/
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Функції
|
|
40
|
+
|
|
41
|
+
### `createCheckReporter()`
|
|
42
|
+
|
|
43
|
+
**Сигнатура:**
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
export function createCheckReporter(): {
|
|
47
|
+
pass: typeof pass,
|
|
48
|
+
fail: (msg: string) => void,
|
|
49
|
+
getExitCode: () => number,
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Параметри:** немає.
|
|
54
|
+
|
|
55
|
+
**Повертає:** новий об’єкт-репортер з трьома методами. Кожен виклик `createCheckReporter()` створює **окреме замикання** з власним внутрішнім `exitCode`, тобто різні репортери незалежні один від одного.
|
|
56
|
+
|
|
57
|
+
**Side effects:** при створенні — жодних. Side effects виникають лише при виклику методів повернутого об’єкта (`fail` пише в stdout через `console.log`; `pass` робить те, що визначено в `../utils/pass.mjs`).
|
|
58
|
+
|
|
59
|
+
**Внутрішня логіка:**
|
|
60
|
+
|
|
61
|
+
1. Створюється локальна змінна `let exitCode = 0`.
|
|
62
|
+
2. Повертається об’єктний літерал з трьома методами:
|
|
63
|
+
- `pass` — пряма посилання на імпортовану функцію `pass`.
|
|
64
|
+
- `fail(msg)` — виконує `console.log(\` ❌ ${msg}\`)`і присвоює`exitCode = 1`.
|
|
65
|
+
- `getExitCode()` — повертає поточне значення `exitCode`.
|
|
66
|
+
|
|
67
|
+
### Метод `pass` (повертається з фабрики)
|
|
68
|
+
|
|
69
|
+
**Сигнатура:** успадковує сигнатуру функції `pass` з `../utils/pass.mjs` (`typeof pass`).
|
|
70
|
+
|
|
71
|
+
**Поведінка:** повний контракт — за `../utils/pass.mjs`. У межах цього модуля `pass` просто реекспортується без обгортки і не впливає на `exitCode`.
|
|
72
|
+
|
|
73
|
+
### Метод `fail(msg)` (повертається з фабрики)
|
|
74
|
+
|
|
75
|
+
**Сигнатура:**
|
|
76
|
+
|
|
77
|
+
```js
|
|
78
|
+
fail(msg: string): void
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Параметри:**
|
|
82
|
+
|
|
83
|
+
- `msg: string` — текст повідомлення про помилку.
|
|
84
|
+
|
|
85
|
+
**Повертає:** `undefined`.
|
|
86
|
+
|
|
87
|
+
**Side effects:**
|
|
88
|
+
|
|
89
|
+
- Пише в stdout рядок виду ` ❌ <msg>` через `console.log` (два пробіли індентації + хрестик-емодзі + пробіл + повідомлення).
|
|
90
|
+
- Виставляє внутрішній `exitCode = 1` у замиканні фабрики.
|
|
91
|
+
|
|
92
|
+
**Семантика:** після першого виклику `fail` репортер «фіксує» загальний стан як помилковий — це безповоротна операція в межах одного інстансу.
|
|
93
|
+
|
|
94
|
+
### Метод `getExitCode()` (повертається з фабрики)
|
|
95
|
+
|
|
96
|
+
**Сигнатура:**
|
|
97
|
+
|
|
98
|
+
```js
|
|
99
|
+
getExitCode(): number
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Параметри:** немає.
|
|
103
|
+
|
|
104
|
+
**Повертає:** `0` (якщо `fail` не викликали жодного разу) або `1` (якщо викликали хоча б один раз).
|
|
105
|
+
|
|
106
|
+
**Side effects:** немає.
|
|
107
|
+
|
|
108
|
+
**Чому функція, а не властивість:** значення `exitCode` зберігається в замиканні. Звичайне поле об’єкта закарбувало б початкове `0` і не відображало б подальших змін. Геттер-функція забезпечує «живе» зчитування актуального стану.
|
|
109
|
+
|
|
110
|
+
## Залежності
|
|
111
|
+
|
|
112
|
+
### Внутрішні (з репо)
|
|
113
|
+
|
|
114
|
+
- `../utils/pass.mjs` — імпортується named-імпорт `pass`. Це функція, що друкує рядок успіху в уніфікованому форматі. Для деталей формату див. документацію `pass.mjs`.
|
|
115
|
+
|
|
116
|
+
### Зовнішні (Node/runtime)
|
|
117
|
+
|
|
118
|
+
- Глобальний `console.log` — для виводу помилок у `fail()`.
|
|
119
|
+
|
|
120
|
+
### Без побічних залежностей
|
|
121
|
+
|
|
122
|
+
Модуль чистий від npm-пакетів, не звертається до файлової системи, мережі чи `process.exit` — повернений `getExitCode()` лише **повідомляє** код, але **не завершує** процес самостійно. Завершення процесу — відповідальність викликаючого скрипта.
|
|
123
|
+
|
|
124
|
+
## Потік виконання / Використання
|
|
125
|
+
|
|
126
|
+
### Типовий сценарій у check-скрипті
|
|
127
|
+
|
|
128
|
+
```js
|
|
129
|
+
import { createCheckReporter } from '../lib/check-reporter.mjs'
|
|
130
|
+
|
|
131
|
+
const reporter = createCheckReporter()
|
|
132
|
+
|
|
133
|
+
if (somethingWrong) {
|
|
134
|
+
reporter.fail('Опис проблеми')
|
|
135
|
+
} else {
|
|
136
|
+
reporter.pass('Усе ок')
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Важливо: викликати getExitCode() саме як функцію
|
|
140
|
+
process.exit(reporter.getExitCode())
|
|
141
|
+
// або: return reporter.getExitCode()
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Як використовується в `lint-docker` та інших споживачах
|
|
145
|
+
|
|
146
|
+
Один інстанс `reporter` створюється на запуск перевірки. У циклі по ресурсах (файлах, правилах, конфігах тощо) виконуються виклики `pass` / `fail` залежно від результату. По завершенні — одноразовий `getExitCode()`, значення якого передається в `process.exit(...)` або повертається з `async`-функції-точки входу.
|
|
147
|
+
|
|
148
|
+
### Антипатерн (нерекомендовано)
|
|
149
|
+
|
|
150
|
+
```js
|
|
151
|
+
// ❌ НЕ робити так — exitCode не «знімається» цим способом,
|
|
152
|
+
// бо це не геттер-властивість, а замикання поверх локальної змінної.
|
|
153
|
+
const { exitCode } = reporter
|
|
154
|
+
process.exit(exitCode) // буде undefined
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Правильно:
|
|
158
|
+
|
|
159
|
+
```js
|
|
160
|
+
process.exit(reporter.getExitCode())
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Семантика exit code
|
|
164
|
+
|
|
165
|
+
- `0` — усі перевірки пройшли (або жодного `fail` не було).
|
|
166
|
+
- `1` — щонайменше один `fail`. Подальші виклики `fail` не «накопичують» вище 1 — це бінарний прапорець «була помилка / не було».
|
|
167
|
+
|
|
168
|
+
### Формат виводу
|
|
169
|
+
|
|
170
|
+
- Успіх: формат повністю делегований `pass` з `../utils/pass.mjs`.
|
|
171
|
+
- Помилка: ` ❌ <msg>` (два пробіли + ❌ + пробіл + повідомлення), завжди через `console.log` (stdout, з переведенням рядка).
|
|
172
|
+
|
|
173
|
+
### Ізольованість інстансів
|
|
174
|
+
|
|
175
|
+
Кожен виклик `createCheckReporter()` повертає новий незалежний об’єкт із власним `exitCode`. Це означає, що в одному процесі можна тримати кілька паралельних/незалежних репортерів — наприклад, по одному на правило/секцію — і агрегувати їхні фінальні коди вручну (через `Math.max` чи логічне OR), якщо потрібно.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# discover-check-rules-from-cursor.mjs
|
|
2
|
+
|
|
3
|
+
## Огляд
|
|
4
|
+
|
|
5
|
+
Модуль `discover-check-rules-from-cursor.mjs` визначає, які саме id правил повинні бути запущені командою `npx @nitra/cursor fix`, коли користувач викликає її **без аргументів**. Він узгоджує два джерела:
|
|
6
|
+
|
|
7
|
+
1. **Файлова система проєкту** — базові імена `*.mdc` у директорії `.cursor/rules/` (тобто правила, які реально присутні у конкретному репо).
|
|
8
|
+
2. **Реєстр пакета** — список id правил, для яких у пакеті `@nitra/cursor` існує programmatic перевірка (JS-концерн або policy з `target.json`); цей список зазвичай приходить із функції `discoverCheckableRules`.
|
|
9
|
+
|
|
10
|
+
Результат — впорядкований унікальний масив id, у якому:
|
|
11
|
+
|
|
12
|
+
- порядок диктується порядком файлів `*.mdc` у директорії правил (як їх передали ззовні, зазвичай відсортованими);
|
|
13
|
+
- залишаються лише ті id, для яких у пакеті є реальна перевірка;
|
|
14
|
+
- видалено префікс `n-`, оскільки внутрішня команда `check <id>` оперує «короткими» id (наприклад, `bun`, а не `n-bun`).
|
|
15
|
+
|
|
16
|
+
Файл містить чисті pure-функції без побічних ефектів — без `fs`, без `process`, без I/O. Все читання директорії правил і реєстру здійснюється викликачем; цей модуль лише поєднує два готових списки.
|
|
17
|
+
|
|
18
|
+
## Експорти / API
|
|
19
|
+
|
|
20
|
+
Модуль має три публічних експорти у форматі ES modules (`.mjs`):
|
|
21
|
+
|
|
22
|
+
| Експорт | Тип | Призначення |
|
|
23
|
+
| ----------------------------------- | ---------- | ------------------------------------------------------------------------------------------------ |
|
|
24
|
+
| `MANAGED_RULE_FILE_PREFIX` | `string` | Константа `'n-'` — префікс імен файлів `.mdc`, які вважаються «керованими» пакетом. |
|
|
25
|
+
| `mdcBasenameToCheckId` | `function` | Перетворює базове ім'я `*.mdc` (із розширенням або без) у id для CLI-команди `check`. |
|
|
26
|
+
| `discoverCheckRulesFromCursorRules` | `function` | Будує впорядкований список id перевірок як перетин «доступних у пакеті» та «присутніх на диску». |
|
|
27
|
+
|
|
28
|
+
Усі експорти — іменовані (`export const` / `export function`); default-export відсутній.
|
|
29
|
+
|
|
30
|
+
## Функції
|
|
31
|
+
|
|
32
|
+
### `mdcBasenameToCheckId(mdcBasename)`
|
|
33
|
+
|
|
34
|
+
**Сигнатура:**
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
export function mdcBasenameToCheckId(mdcBasename: string): string
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Параметри:**
|
|
41
|
+
|
|
42
|
+
- `mdcBasename` — рядок, який може бути:
|
|
43
|
+
- чистим базовим іменем файлу, наприклад `'n-bun.mdc'` або `'my-rule.mdc'`;
|
|
44
|
+
- відносним/абсолютним шляхом, наприклад `'.cursor/rules/n-bun.mdc'` (функція сама візьме сегмент після останнього `/`).
|
|
45
|
+
|
|
46
|
+
**Поведінка:**
|
|
47
|
+
|
|
48
|
+
1. Якщо у вхідному рядку є символ `/`, береться підрядок після останнього `/` — таким чином приймаються як «чисті» імена, так і шляхи.
|
|
49
|
+
2. Якщо отриманий рядок закінчується на `.mdc`, розширення відсікається.
|
|
50
|
+
3. Якщо те, що залишилось, починається з `MANAGED_RULE_FILE_PREFIX` (`'n-'`), цей префікс також знімається.
|
|
51
|
+
4. Повертається отриманий «короткий» id.
|
|
52
|
+
|
|
53
|
+
**Повертає:**
|
|
54
|
+
|
|
55
|
+
- `string` — id, придатний для команди `check <id>`. Приклади:
|
|
56
|
+
- `'n-bun.mdc'` → `'bun'`
|
|
57
|
+
- `'.cursor/rules/n-vue.mdc'` → `'vue'`
|
|
58
|
+
- `'my-rule.mdc'` → `'my-rule'`
|
|
59
|
+
- `'n-text'` (без розширення) → `'text'`
|
|
60
|
+
|
|
61
|
+
**Side effects:** немає. Функція суто детермінована, не звертається до файлової системи, не мутує аргументи.
|
|
62
|
+
|
|
63
|
+
**Крайні випадки:**
|
|
64
|
+
|
|
65
|
+
- Backslashes (`\\`) як роздільник шляху **не** розпізнаються — функція оперує лише `/`. Це безпечно для шляхів, які прийшли від утиліт на кшталт `fs.readdir`, що повертають базові імена, або з `path.posix`-стилю.
|
|
66
|
+
- Якщо вхід уже без `.mdc`, він обробляється тим самим алгоритмом (просто пропускається крок зняття розширення).
|
|
67
|
+
- Якщо файл, прибравши `.mdc`, дорівнює саме `'n-'`, повернеться порожній рядок — це не очікувана реальна ситуація, бо керованих правил із порожнім id не буває.
|
|
68
|
+
|
|
69
|
+
### `discoverCheckRulesFromCursorRules(available, mdcBasenames)`
|
|
70
|
+
|
|
71
|
+
**Сигнатура:**
|
|
72
|
+
|
|
73
|
+
```js
|
|
74
|
+
export function discoverCheckRulesFromCursorRules(
|
|
75
|
+
available: string[],
|
|
76
|
+
mdcBasenames: string[],
|
|
77
|
+
): string[]
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Параметри:**
|
|
81
|
+
|
|
82
|
+
- `available` — масив id, які пакет уміє перевіряти (програмні перевірки JS-концерну або policy з `target.json`). Зазвичай — результат `discoverCheckableRules` із сусіднього модуля `discover-checkable-rules.mjs`. Очікується алфавітний порядок, але алгоритм не залежить від нього.
|
|
83
|
+
- `mdcBasenames` — масив базових імен файлів `*.mdc`, які реально присутні у `.cursor/rules/` поточного проєкту. Очікується, що масив уже відсортований викликачем (порядок цього масиву визначає порядок результату).
|
|
84
|
+
|
|
85
|
+
**Поведінка:**
|
|
86
|
+
|
|
87
|
+
1. Створюється `Set` `seen` для дедуплікації результату.
|
|
88
|
+
2. Створюється масив `ordered` для збереження порядку входу `mdcBasenames`.
|
|
89
|
+
3. Для кожного `basename`:
|
|
90
|
+
- обчислюється id через `mdcBasenameToCheckId(basename)`;
|
|
91
|
+
- якщо id присутній у `available` **і** ще не доданий — додається в `ordered` та позначається у `seen`.
|
|
92
|
+
4. Повертається `ordered`.
|
|
93
|
+
|
|
94
|
+
**Повертає:**
|
|
95
|
+
|
|
96
|
+
- `string[]` — впорядкований масив унікальних id перевірок:
|
|
97
|
+
- **тільки** ті, що одночасно (а) мають programmatic-перевірку в пакеті і (б) представлені файлом `*.mdc` у `.cursor/rules/`;
|
|
98
|
+
- порядок диктується `mdcBasenames` (тобто реальним порядком файлів у директорії, як його передав викликач);
|
|
99
|
+
- кожен id зустрічається не більше одного разу.
|
|
100
|
+
|
|
101
|
+
**Side effects:** немає. Функція pure, не читає диск, не мутує аргументи (`Set`/`Array` створюються локально).
|
|
102
|
+
|
|
103
|
+
**Крайні випадки:**
|
|
104
|
+
|
|
105
|
+
- Якщо `mdcBasenames` порожній — повертається `[]`.
|
|
106
|
+
- Якщо жоден `id`, отриманий з імен `.mdc`, не присутній у `available` — повертається `[]` (типово для проєктів, де `.cursor/rules/` містить лише сторонні правила без programmatic-перевірок у пакеті).
|
|
107
|
+
- Дублікати у `mdcBasenames` (наприклад, два файли, що дають один і той самий id після відсікання префікса) включаються лише один раз.
|
|
108
|
+
|
|
109
|
+
## Залежності
|
|
110
|
+
|
|
111
|
+
- **Зовнішні (npm/Node):** немає. Файл не використовує жодних імпортів — ні з Node core (`fs`, `path` тощо), ні з npm-пакетів.
|
|
112
|
+
- **Внутрішні (проєкт):** немає прямих імпортів. Очікується, що:
|
|
113
|
+
- аргумент `available` формується сусіднім модулем `discover-checkable-rules.mjs` (експорт `discoverCheckableRules`);
|
|
114
|
+
- аргумент `mdcBasenames` формується викликачем читанням `.cursor/rules/` (через `fs.readdirSync`/`fs.promises.readdir` із подальшим фільтром `.endsWith('.mdc')` та сортуванням).
|
|
115
|
+
|
|
116
|
+
Така архітектура свідомо відокремлює I/O від чистої логіки: цей модуль легко тестувати без файлової системи.
|
|
117
|
+
|
|
118
|
+
## Потік виконання / Використання
|
|
119
|
+
|
|
120
|
+
Типовий сценарій — `npx @nitra/cursor fix` без аргументів. CLI-входу потрібно вирішити, які id перевірок запустити за замовчуванням; для цього він:
|
|
121
|
+
|
|
122
|
+
1. Отримує список програмно перевірюваних правил пакета (`available = discoverCheckableRules(...)`).
|
|
123
|
+
2. Читає директорію `.cursor/rules/` поточного проєкту й відбирає файли з розширенням `.mdc` (`mdcBasenames`), сортує їх.
|
|
124
|
+
3. Викликає `discoverCheckRulesFromCursorRules(available, mdcBasenames)` і отримує **підсумковий** список id.
|
|
125
|
+
4. Для кожного id послідовно запускає команду `check <id>` (наприклад, через `run-rule-cli.mjs`).
|
|
126
|
+
|
|
127
|
+
Приклад інлайн-використання (псевдокод викликача):
|
|
128
|
+
|
|
129
|
+
```js
|
|
130
|
+
import { readdirSync } from 'node:fs'
|
|
131
|
+
import { discoverCheckableRules } from './discover-checkable-rules.mjs'
|
|
132
|
+
import { discoverCheckRulesFromCursorRules } from './discover-check-rules-from-cursor.mjs'
|
|
133
|
+
|
|
134
|
+
const available = discoverCheckableRules(/* … */)
|
|
135
|
+
const mdcBasenames = readdirSync('.cursor/rules')
|
|
136
|
+
.filter(f => f.endsWith('.mdc'))
|
|
137
|
+
.sort()
|
|
138
|
+
const idsToRun = discoverCheckRulesFromCursorRules(available, mdcBasenames)
|
|
139
|
+
// idsToRun: наприклад, ['adr', 'bun', 'ci4', 'text', 'vue']
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Приклад трансформації імен:
|
|
143
|
+
|
|
144
|
+
| Файл у `.cursor/rules/` | id після `mdcBasenameToCheckId` | Потрапляє у результат? |
|
|
145
|
+
| -------------------------- | ------------------------------- | -------------------------------------------------- |
|
|
146
|
+
| `n-bun.mdc` | `bun` | Так, якщо `available.includes('bun')` |
|
|
147
|
+
| `n-vue.mdc` | `vue` | Так, якщо `available.includes('vue')` |
|
|
148
|
+
| `my-rule.mdc` | `my-rule` | Лише якщо пакет реєструє `my-rule` як перевірюване |
|
|
149
|
+
| `.cursor/rules/n-text.mdc` | `text` | Так, якщо `available.includes('text')` |
|
|
150
|
+
| `n-bun.mdc` (двічі) | `bun` | У результаті — один раз |
|
|
151
|
+
|
|
152
|
+
Таким чином модуль є тонким, але критичним «клейовим» шаром між:
|
|
153
|
+
|
|
154
|
+
- **диском проєкту** (що користувач реально хоче перевіряти, судячи з вмісту `.cursor/rules/`)
|
|
155
|
+
- **реєстром пакета** (що пакет фізично вміє перевіряти автоматично).
|
|
156
|
+
|
|
157
|
+
Файл свідомо тримається без I/O і без зовнішніх залежностей, щоб залишатись повністю детермінованим і легко покритим юніт-тестами (див. сусідню директорію `tests/`).
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# discover-checkable-rules.mjs
|
|
2
|
+
|
|
3
|
+
## Огляд
|
|
4
|
+
|
|
5
|
+
Модуль `discover-checkable-rules.mjs` — це discovery-шар для CLI-команди `fix`. Його завдання — швидко просканувати файлову структуру каталогу `npm/rules/` та виявити «прогонні» правила, тобто правила, у яких є щонайменше один JS-концерн або policy-концерн. Правила, які складаються тільки з декларативних артефактів (`.mdc` + `auto.md`) без жодного прогонного концерну, відсіюються.
|
|
6
|
+
|
|
7
|
+
Виокремлюються два типи концернів:
|
|
8
|
+
|
|
9
|
+
- **JS concerns** — окремі файли `rules/<id>/js/<concern>.mjs`. Кожен файл — один концерн (flat-конвенція).
|
|
10
|
+
- **Policy concerns** — підкаталоги `rules/<id>/policy/<concern>/`, у яких присутній файл `target.json` (поруч із якого зазвичай лежить `<concern>.rego`).
|
|
11
|
+
|
|
12
|
+
Модуль свідомо не парсить вміст `target.json` і не читає JS-файли — це лише швидкий «структурний» скан (шляхи + назви) без I/O-вмісту. Парсинг покладено на runner.
|
|
13
|
+
|
|
14
|
+
Файли-помічники з префіксом `_` (зокрема каталог `_lib/`), тестові файли `*.test.mjs`, а також приховані файли/каталоги (`.`-префікс) ігноруються.
|
|
15
|
+
|
|
16
|
+
Історичний контекст конвенції розкладки JS-концернів:
|
|
17
|
+
|
|
18
|
+
- `js/<concern>/check.mjs` — версії 1.13.80–1.13.89 (вкладений каталог на концерн);
|
|
19
|
+
- `js/<concern>.mjs` — версії 1.13.90+ (flat: концерн = файл, а не каталог).
|
|
20
|
+
|
|
21
|
+
Допоміжні файли, тести, шаблони й дані винесені в окремі топ-level папки правила: `js/_lib/`, `tests/`, `templates/`, `data/`.
|
|
22
|
+
|
|
23
|
+
## Експорти / API
|
|
24
|
+
|
|
25
|
+
Модуль експортує дві асинхронні функції:
|
|
26
|
+
|
|
27
|
+
| Експорт | Тип | Призначення |
|
|
28
|
+
| ----------------------------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
|
|
29
|
+
| `discoverOneRule(ruleDir, ruleId)` | `async (string, string) => Promise<CheckableRule>` | Будує опис одного правила за заданим шляхом каталогу та id, без обходу `rules/`. |
|
|
30
|
+
| `discoverCheckableRules(bundledRulesDir)` | `async (string) => Promise<CheckableRule[]>` | Сканує цілий каталог `npm/rules/` і повертає масив правил, для яких є JS- або policy-концерни. |
|
|
31
|
+
|
|
32
|
+
Внутрішніми (не експортованими) залишаються функції `listJsConcerns` і `listPolicyConcerns`.
|
|
33
|
+
|
|
34
|
+
### Типи (JSDoc `@typedef`)
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
JsConcern { name: string } // basename файла js/<name>.mjs без розширення
|
|
38
|
+
PolicyConcern { name: string } // imʼя підкаталогу policy/<name>/
|
|
39
|
+
CheckableRule {
|
|
40
|
+
id: string, // = basename каталогу rules/<id>/
|
|
41
|
+
jsConcerns: JsConcern[], // алфавітно
|
|
42
|
+
policyConcerns: PolicyConcern[], // алфавітно
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Функції
|
|
47
|
+
|
|
48
|
+
### `listJsConcerns(jsDir)` (internal)
|
|
49
|
+
|
|
50
|
+
- **Сигнатура:** `async function listJsConcerns(jsDir: string): Promise<JsConcern[]>`
|
|
51
|
+
- **Параметри:**
|
|
52
|
+
- `jsDir` — абсолютний шлях до каталогу `rules/<id>/js/`.
|
|
53
|
+
- **Повертає:** масив `JsConcern[]`, відсортований алфавітно за `name` через `Array.prototype.toSorted` із компаратором `localeCompare`.
|
|
54
|
+
- **Логіка:**
|
|
55
|
+
1. Якщо каталог `jsDir` не існує (`existsSync` повертає `false`) — повертається `[]`.
|
|
56
|
+
2. Читається вміст через `readdir(jsDir, { withFileTypes: true })` — тобто отримуються `Dirent`-обʼєкти з метаінформацією.
|
|
57
|
+
3. Пропускаються:
|
|
58
|
+
- сутності, що не є файлом (`!entry.isFile()`);
|
|
59
|
+
- файли без розширення `.mjs`;
|
|
60
|
+
- тестові файли `*.test.mjs`;
|
|
61
|
+
- службові файли з префіксом `_` (наприклад вміст `_lib/`, хоча сам `_lib` як каталог не буде файлом і відсіється раніше);
|
|
62
|
+
- приховані файли з префіксом `.`.
|
|
63
|
+
4. Для решти файлів обчислюється `name = entry.name.slice(0, -'.mjs'.length)` — basename без розширення.
|
|
64
|
+
- **Side effects:** лише файлові читання (`existsSync`, `readdir`), без запису.
|
|
65
|
+
|
|
66
|
+
### `listPolicyConcerns(policyDir)` (internal)
|
|
67
|
+
|
|
68
|
+
- **Сигнатура:** `async function listPolicyConcerns(policyDir: string): Promise<PolicyConcern[]>`
|
|
69
|
+
- **Параметри:**
|
|
70
|
+
- `policyDir` — абсолютний шлях до каталогу `rules/<id>/policy/`.
|
|
71
|
+
- **Повертає:** масив `PolicyConcern[]`, відсортований алфавітно за `name`.
|
|
72
|
+
- **Логіка:**
|
|
73
|
+
1. Якщо `policyDir` не існує — повертається `[]`.
|
|
74
|
+
2. Читається вміст з `withFileTypes: true`.
|
|
75
|
+
3. Пропускаються будь-які записи, що не є каталогом, а також приховані каталоги (префікс `.`).
|
|
76
|
+
4. Для кожного підкаталогу перевіряється наявність файла `target.json` через `existsSync(join(policyDir, entry.name, 'target.json'))`. Якщо `target.json` є — підкаталог зараховується як policy-концерн.
|
|
77
|
+
- **Side effects:** лише файлові читання, без запису.
|
|
78
|
+
|
|
79
|
+
### `discoverOneRule(ruleDir, ruleId)` (exported)
|
|
80
|
+
|
|
81
|
+
- **Сигнатура:** `export async function discoverOneRule(ruleDir: string, ruleId: string): Promise<CheckableRule>`
|
|
82
|
+
- **Параметри:**
|
|
83
|
+
- `ruleDir` — абсолютний шлях до каталогу правила `rules/<id>/`;
|
|
84
|
+
- `ruleId` — ідентифікатор правила, зазвичай `basename(ruleDir)`. Передається явно, бо функція не виводить його з шляху самостійно.
|
|
85
|
+
- **Повертає:** обʼєкт `CheckableRule` з полями `id`, `jsConcerns`, `policyConcerns`. На відміну від `discoverCheckableRules`, тут не виконується фільтрація «має бути хоч щось» — повертається опис як є (можуть бути порожні масиви концернів).
|
|
86
|
+
- **Логіка:** паралельно (точніше — послідовно `await`-ить) запускає `listJsConcerns(join(ruleDir, 'js'))` і `listPolicyConcerns(join(ruleDir, 'policy'))` та збирає результати в обʼєкт.
|
|
87
|
+
- **Використання:** викликається `runStandardRule`-flow для per-rule entry-point, коли потрібно отримати опис конкретного правила, а не сканувати весь каталог.
|
|
88
|
+
- **Side effects:** лише читання файлової системи.
|
|
89
|
+
|
|
90
|
+
### `discoverCheckableRules(bundledRulesDir)` (exported)
|
|
91
|
+
|
|
92
|
+
- **Сигнатура:** `export async function discoverCheckableRules(bundledRulesDir: string): Promise<CheckableRule[]>`
|
|
93
|
+
- **Параметри:**
|
|
94
|
+
- `bundledRulesDir` — абсолютний шлях до кореневого каталогу всіх правил (зазвичай `npm/rules/`).
|
|
95
|
+
- **Повертає:** масив `CheckableRule[]`, відсортований алфавітно за `id`. Включаються тільки правила, у яких `jsConcerns.length > 0 || policyConcerns.length > 0`.
|
|
96
|
+
- **Логіка:**
|
|
97
|
+
1. Якщо `bundledRulesDir` не існує — повертається `[]`.
|
|
98
|
+
2. Читається вміст каталогу з `withFileTypes: true`.
|
|
99
|
+
3. Пропускаються сутності, які не є каталогом, та приховані каталоги (префікс `.`).
|
|
100
|
+
4. Для кожного підкаталогу формується `ruleDir = join(bundledRulesDir, entry.name)` і викликається `discoverOneRule(ruleDir, entry.name)`.
|
|
101
|
+
5. Правила, у яких немає жодного JS- або policy-концерну (декларативні-only), відсіюються.
|
|
102
|
+
- **Side effects:** лише читання файлової системи (без запису, без мережевих викликів).
|
|
103
|
+
|
|
104
|
+
## Залежності
|
|
105
|
+
|
|
106
|
+
Виключно зовнішні стандартні модулі Node.js:
|
|
107
|
+
|
|
108
|
+
- `node:fs` → `existsSync` — синхронна перевірка існування шляху;
|
|
109
|
+
- `node:fs/promises` → `readdir` — асинхронне читання вмісту каталогу (з `withFileTypes: true` повертає `Dirent[]`);
|
|
110
|
+
- `node:path` → `join` — кросплатформова конкатенація шляхів.
|
|
111
|
+
|
|
112
|
+
Внутрішніх імпортів з інших модулів проєкту немає. Це робить модуль чистим discovery-шаром без бізнес-логіки, що дозволяє безпечно його тестувати ізольовано (потрібна лише підготовлена файлова структура у тимчасовому каталозі).
|
|
113
|
+
|
|
114
|
+
Зворотні залежності (хто використовує цей модуль): runner-флоу CLI `fix` (зокрема `runStandardRule`), який після discovery читає `target.json` для policy-концернів і виконує JS-концерни.
|
|
115
|
+
|
|
116
|
+
## Потік виконання / Використання
|
|
117
|
+
|
|
118
|
+
### Типовий сценарій 1. Повний скан правил для CLI `fix`
|
|
119
|
+
|
|
120
|
+
```javascript
|
|
121
|
+
import { discoverCheckableRules } from './discover-checkable-rules.mjs'
|
|
122
|
+
|
|
123
|
+
const rules = await discoverCheckableRules('/abs/path/to/npm/rules')
|
|
124
|
+
for (const rule of rules) {
|
|
125
|
+
// rule.id, rule.jsConcerns, rule.policyConcerns
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Послідовність дій усередині:
|
|
130
|
+
|
|
131
|
+
1. `discoverCheckableRules` перевіряє існування кореневого каталогу.
|
|
132
|
+
2. Перебирає підкаталоги верхнього рівня (= потенційні правила).
|
|
133
|
+
3. Для кожного підкаталогу викликає `discoverOneRule`, який своєю чергою:
|
|
134
|
+
- сканує `rules/<id>/js/` через `listJsConcerns`;
|
|
135
|
+
- сканує `rules/<id>/policy/` через `listPolicyConcerns`;
|
|
136
|
+
4. Якщо знайдено хоч один концерн — правило додається у вихідний масив.
|
|
137
|
+
5. Масив сортується за `id`.
|
|
138
|
+
|
|
139
|
+
### Типовий сценарій 2. Per-rule entry-point
|
|
140
|
+
|
|
141
|
+
```javascript
|
|
142
|
+
import { discoverOneRule } from './discover-checkable-rules.mjs'
|
|
143
|
+
|
|
144
|
+
const rule = await discoverOneRule('/abs/path/to/npm/rules/n-js-lint', 'n-js-lint')
|
|
145
|
+
// rule.id === 'n-js-lint'
|
|
146
|
+
// rule.jsConcerns — список JS-концернів у js/
|
|
147
|
+
// rule.policyConcerns — список policy-концернів у policy/
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Цей шлях оминає енумерацію всього `rules/`, що корисно коли id правила вже відомий (наприклад, передано аргументом CLI).
|
|
151
|
+
|
|
152
|
+
### Гарантії та обмеження
|
|
153
|
+
|
|
154
|
+
- **Чистота:** функції — read-only (не пишуть у ФС, не виконують код концернів). Це дозволяє безпечно викликати їх повторно.
|
|
155
|
+
- **Сортування:** усі результати алфавітно відсортовані через `toSorted` із `localeCompare`. Це робить вивід детермінованим між запусками й між платформами (хоч порядок `readdir` залежить від ФС).
|
|
156
|
+
- **Толерантність до відсутніх каталогів:** будь-яка з директорій (`rules/`, `js/`, `policy/`) може бути відсутня — повертається порожній масив без помилки.
|
|
157
|
+
- **Тести/хелпери:** файли з префіксом `_` і `*.test.mjs` гарантовано виключаються із JS-концернів.
|
|
158
|
+
- **Що _не_ робиться:** не валідуються імена концернів, не парситься `target.json`, не перевіряється наявність `<name>.rego` поруч із `target.json`. Це робота runner-а.
|
|
159
|
+
|
|
160
|
+
### Eage cases
|
|
161
|
+
|
|
162
|
+
- Файл з префіксом `.` у `js/` — пропускається.
|
|
163
|
+
- Підкаталог у `js/` (наприклад `_lib/`) — не є файлом, відсіюється першою перевіркою `entry.isFile()`.
|
|
164
|
+
- Підкаталог у `policy/` без `target.json` — пропускається; наявність `<name>.rego` без `target.json` не зараховується.
|
|
165
|
+
- Порожнє правило (тільки `.mdc`/`auto.md` без `js/` і `policy/`) — не потрапляє у вихід `discoverCheckableRules`, але буде повернене з порожніми масивами в `discoverOneRule`.
|