@nitra/cursor 12.11.0 → 12.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/bin/n-cursor.js +9 -27
  3. package/package.json +1 -1
  4. package/rules/adr/js/docs/hooks.md +0 -2
  5. package/rules/bun/js/docs/fix-layout.md +25 -0
  6. package/rules/bun/js/fix-layout.mjs +55 -0
  7. package/rules/changelog/js/docs/consistency.md +11 -13
  8. package/rules/changelog/js/docs/fix-consistency.md +27 -0
  9. package/rules/changelog/js/docs/index.md +2 -2
  10. package/rules/changelog/js/fix-consistency.mjs +50 -0
  11. package/rules/ci4/policy/vscode_extensions/docs/fix-vscode_extensions.md +21 -0
  12. package/rules/ci4/policy/vscode_extensions/fix-vscode_extensions.mjs +1 -0
  13. package/rules/ga/policy/vscode_extensions/docs/fix-vscode_extensions.md +22 -0
  14. package/rules/ga/policy/vscode_extensions/fix-vscode_extensions.mjs +1 -0
  15. package/rules/ga/policy/workflow_common/workflow_common.rego +15 -0
  16. package/rules/graphql/policy/vscode_extensions/docs/fix-vscode_extensions.md +21 -0
  17. package/rules/graphql/policy/vscode_extensions/fix-vscode_extensions.mjs +1 -0
  18. package/rules/js/js/docs/dep-policy.md +12 -10
  19. package/rules/js/policy/vscode_extensions/docs/fix-vscode_extensions.md +22 -0
  20. package/rules/js/policy/vscode_extensions/fix-vscode_extensions.mjs +1 -0
  21. package/rules/js-run/js/docs/fix-runtime.md +25 -0
  22. package/rules/js-run/js/fix-runtime.mjs +41 -0
  23. package/rules/k8s/policy/lint_k8s_yml/lint_k8s_yml.rego +57 -0
  24. package/rules/k8s/policy/lint_k8s_yml/target.json +4 -0
  25. package/rules/k8s/policy/lint_k8s_yml/template/lint-k8s.yml.snippet.yml +43 -0
  26. package/rules/nginx-default-tpl/policy/vscode_extensions/docs/fix-vscode_extensions.md +21 -0
  27. package/rules/nginx-default-tpl/policy/vscode_extensions/fix-vscode_extensions.mjs +1 -0
  28. package/rules/rego/policy/vscode_extensions/docs/fix-vscode_extensions.md +22 -0
  29. package/rules/rego/policy/vscode_extensions/fix-vscode_extensions.mjs +1 -0
  30. package/rules/rust/policy/vscode_extensions/docs/fix-vscode_extensions.md +22 -0
  31. package/rules/rust/policy/vscode_extensions/fix-vscode_extensions.mjs +1 -0
  32. package/rules/style/js/docs/fix-tooling.md +29 -0
  33. package/rules/style/js/fix-tooling.mjs +46 -0
  34. package/rules/style/policy/vscode_extensions/docs/fix-vscode_extensions.md +21 -0
  35. package/rules/style/policy/vscode_extensions/fix-vscode_extensions.mjs +1 -0
  36. package/rules/tauri/policy/vscode_extensions/docs/fix-vscode_extensions.md +21 -0
  37. package/rules/tauri/policy/vscode_extensions/fix-vscode_extensions.mjs +1 -0
  38. package/rules/text/policy/vscode_extensions/docs/fix-vscode_extensions.md +21 -0
  39. package/rules/text/policy/vscode_extensions/fix-vscode_extensions.mjs +1 -0
  40. package/rules/vue/js/docs/packages.md +0 -2
  41. package/scripts/docs/index.md +0 -2
  42. package/scripts/lib/discover-checkable-rules.mjs +1 -0
  43. package/scripts/lib/docs/discover-checkable-rules.md +13 -155
  44. package/scripts/lib/fix/discover-t0-patterns.mjs +83 -0
  45. package/scripts/lib/fix/docs/discover-t0-patterns.md +37 -0
  46. package/scripts/lib/fix/docs/llm-fix-apply.md +12 -10
  47. package/scripts/lib/fix/docs/llm-worker.md +6 -14
  48. package/scripts/lib/fix/docs/orchestrator.md +0 -2
  49. package/scripts/lib/fix/docs/t0.md +11 -10
  50. package/scripts/lib/fix/docs/vscode-ext-add.md +29 -0
  51. package/scripts/lib/fix/llm-fix-apply.mjs +34 -3
  52. package/scripts/lib/fix/llm-worker.mjs +24 -15
  53. package/scripts/lib/fix/t0.mjs +8 -119
  54. package/scripts/lib/fix/vscode-ext-add.mjs +45 -0
  55. package/rules/test/coverage/coverage.mjs +0 -317
  56. package/scripts/coverage-classify/apply.mjs +0 -67
  57. package/scripts/coverage-classify/cache.mjs +0 -77
  58. package/scripts/coverage-classify/docs/apply.md +0 -206
  59. package/scripts/coverage-classify/docs/cache.md +0 -207
  60. package/scripts/coverage-classify/docs/index.md +0 -14
  61. package/scripts/coverage-classify/docs/prompt.md +0 -136
  62. package/scripts/coverage-classify/docs/verdict-schema.md +0 -28
  63. package/scripts/coverage-classify/index.mjs +0 -114
  64. package/scripts/coverage-classify/prompt.mjs +0 -126
  65. package/scripts/coverage-classify/verdict-schema.mjs +0 -35
  66. package/scripts/coverage-fix-extract.mjs +0 -122
  67. package/scripts/coverage-fix.mjs +0 -119
  68. package/scripts/docs/coverage-fix-extract.md +0 -36
  69. package/scripts/docs/coverage-fix.md +0 -181
  70. package/skills/coverage-fix/SKILL.md +0 -131
  71. package/skills/coverage-fix/main.json +0 -1
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": ".github/workflows/lint-k8s.yml" }
4
+ }
@@ -0,0 +1,43 @@
1
+ name: Lint K8s
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - dev
7
+ - main
8
+ paths:
9
+ - '**/k8s/**/*.yaml'
10
+
11
+ pull_request:
12
+ branches:
13
+ - dev
14
+ - main
15
+
16
+ concurrency:
17
+ group: ${{ github.ref }}-${{ github.workflow }}
18
+ cancel-in-progress: true
19
+
20
+ jobs:
21
+ lint-k8s:
22
+ runs-on: ubuntu-latest
23
+ permissions:
24
+ contents: read
25
+ steps:
26
+ - uses: actions/checkout@v6
27
+ with:
28
+ persist-credentials: false
29
+
30
+ - uses: ./.github/actions/setup-bun-deps
31
+
32
+ - name: Install kubeconform
33
+ run: |
34
+ curl -sSL "https://github.com/yannh/kubeconform/releases/download/v0.7.0/kubeconform-linux-amd64.tar.gz" | tar xz
35
+ sudo mv kubeconform /usr/local/bin/
36
+
37
+ - name: Install kubescape
38
+ run: |
39
+ curl -s https://raw.githubusercontent.com/kubescape/kubescape/master/install.sh | /bin/bash
40
+ echo "$HOME/.kubescape/bin" >> $GITHUB_PATH
41
+
42
+ - name: Lint K8s
43
+ run: n-cursor lint k8s --read-only
@@ -0,0 +1,21 @@
1
+ ---
2
+ type: JS Module
3
+ title: fix-vscode_extensions.mjs
4
+ resource: npm/rules/nginx-default-tpl/policy/vscode_extensions/fix-vscode_extensions.mjs
5
+ docgen:
6
+ crc: 319883fc
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
9
+ ---
10
+
11
+ ## Огляд
12
+
13
+ Цей файл імпортує шаблони, необхідні для функціонування розширення VS Code.
14
+
15
+ ## Поведінка
16
+
17
+ 1. Імпортує шаблони для виправлення розширень VS Code з іншого скрипта.
18
+
19
+ ## Гарантії поведінки
20
+
21
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -0,0 +1 @@
1
+ export { patterns } from '../../../../scripts/lib/fix/vscode-ext-add.mjs'
@@ -0,0 +1,22 @@
1
+ ---
2
+ type: JS Module
3
+ title: fix-vscode_extensions.mjs
4
+ resource: npm/rules/rego/policy/vscode_extensions/fix-vscode_extensions.mjs
5
+ docgen:
6
+ crc: 319883fc
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
9
+ ---
10
+
11
+ ## Огляд
12
+
13
+ Цей файл імпортує визначення шаблонів з іншого модуля. Це забезпечує доступ до необхідних шаблонів для роботи системних компонентів.
14
+
15
+ ## Поведінка
16
+
17
+ 1. Імпортує визначення шаблонів з іншого модуля.
18
+ 2. Надає доступ до цих шаблонів для використання в системі.
19
+
20
+ ## Гарантії поведінки
21
+
22
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -0,0 +1 @@
1
+ export { patterns } from '../../../../scripts/lib/fix/vscode-ext-add.mjs'
@@ -0,0 +1,22 @@
1
+ ---
2
+ type: JS Module
3
+ title: fix-vscode_extensions.mjs
4
+ resource: npm/rules/rust/policy/vscode_extensions/fix-vscode_extensions.mjs
5
+ docgen:
6
+ crc: 319883fc
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
9
+ ---
10
+
11
+ ## Огляд
12
+
13
+ Цей файл імпортує визначені шаблони з іншого скрипта та надає їх для використання в інших компонентах системи.
14
+
15
+ ## Поведінка
16
+
17
+ 1. Імпортує шаблони з іншого скрипта.
18
+ 2. Експортує ці шаблони.
19
+
20
+ ## Гарантії поведінки
21
+
22
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -0,0 +1 @@
1
+ export { patterns } from '../../../../scripts/lib/fix/vscode-ext-add.mjs'
@@ -0,0 +1,29 @@
1
+ ---
2
+ type: JS Module
3
+ title: fix-tooling.mjs
4
+ resource: npm/rules/style/js/fix-tooling.mjs
5
+ docgen:
6
+ crc: d9c7a757
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
9
+ ---
10
+
11
+ ## Огляд
12
+
13
+ Модуль T0-autofix впроваджує детерміновані виправлення файлової системи для `style/js/tooling.mjs`. Він створює або доповнює `.stylelintignore` для ігнорування директорії `dist/` та додає `stylelint` до `package.json`, спираючись на `package.json`.
14
+
15
+ ## Поведінка
16
+
17
+ Поведінка
18
+
19
+ 1. `patterns` виконує детерміновані виправлення файлової системи для конфігурації стилізації.
20
+ 2. Перший елемент у `patterns` створює файл `.stylelintignore` у корені робочого каталогу, якщо він не існує. Це робиться для ігнорування директорії `dist/` у процесі стилізації.
21
+ 3. Другий елемент у `patterns` додає рядок `dist/` до файлу `.stylelintignore`, якщо він вже існує, але не містить цього шляху. Це забезпечує ігнорування директорії `dist/`.
22
+ 4. Третій елемент у `patterns` перевіряє, чи містить конфігурація `package.json` запис про `stylelint`.
23
+ 5. Якщо `package.json` не знайдено або є невалідним JSON, виправлення не виконується.
24
+ 6. Якщо `stylelint` вже присутній у `package.json`, виправлення не виконується.
25
+ 7. Якщо `stylelint` відсутній, він додається до `package.json` із конфігурацією, що посилається на `@nitra/stylelint-config`.
26
+
27
+ ## Гарантії поведінки
28
+
29
+ - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
@@ -0,0 +1,46 @@
1
+ /**
2
+ * T0-autofix паттерни для `style/js/tooling.mjs` — детерміновані FS-виправлення:
3
+ * створення або доповнення `.stylelintignore` та додавання `stylelint` до `package.json`.
4
+ */
5
+ import { appendFileSync, existsSync, readFileSync, writeFileSync } from 'node:fs'
6
+ import { join } from 'node:path'
7
+
8
+ /** @type {import('../../../scripts/lib/fix/discover-t0-patterns.mjs').T0Pattern[]} */
9
+ export const patterns = [
10
+ {
11
+ id: 'style-stylelintignore-create',
12
+ test: out => /\.stylelintignore не існує/.test(out),
13
+ apply: (_out, cwd) => {
14
+ writeFileSync(join(cwd, '.stylelintignore'), 'dist/\n', 'utf8')
15
+ return { ok: true, action: 'створено .stylelintignore' }
16
+ }
17
+ },
18
+
19
+ {
20
+ id: 'style-stylelintignore-dist-add',
21
+ test: out => /\.stylelintignore не містить рядка dist\//.test(out),
22
+ apply: (_out, cwd) => {
23
+ appendFileSync(join(cwd, '.stylelintignore'), '\ndist/\n', 'utf8')
24
+ return { ok: true, action: 'додано dist/ до .stylelintignore' }
25
+ }
26
+ },
27
+
28
+ {
29
+ id: 'style-pkg-stylelint-add',
30
+ test: out => /Немає конфігу stylelint/.test(out),
31
+ apply: (_out, cwd) => {
32
+ const pkgPath = join(cwd, 'package.json')
33
+ if (!existsSync(pkgPath)) return { ok: false, action: 'package.json не знайдено' }
34
+ let pkg
35
+ try {
36
+ pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
37
+ } catch {
38
+ return { ok: false, action: 'package.json: невалідний JSON' }
39
+ }
40
+ if (pkg.stylelint) return { ok: false, action: 'stylelint вже є в package.json' }
41
+ pkg.stylelint = { extends: '@nitra/stylelint-config' }
42
+ writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf8')
43
+ return { ok: true, action: 'додано stylelint до package.json' }
44
+ }
45
+ }
46
+ ]
@@ -0,0 +1,21 @@
1
+ ---
2
+ type: JS Module
3
+ title: fix-vscode_extensions.mjs
4
+ resource: npm/rules/style/policy/vscode_extensions/fix-vscode_extensions.mjs
5
+ docgen:
6
+ crc: 319883fc
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
9
+ ---
10
+
11
+ ## Огляд
12
+
13
+ Завантажує шаблони для виправлення розширень VS Code.
14
+
15
+ ## Поведінка
16
+
17
+ 1. Імпортує шаблони для виправлення розширень VS Code з файлу `../../../../scripts/lib/fix/vscode-ext-add.mjs`.
18
+
19
+ ## Гарантії поведінки
20
+
21
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -0,0 +1 @@
1
+ export { patterns } from '../../../../scripts/lib/fix/vscode-ext-add.mjs'
@@ -0,0 +1,21 @@
1
+ ---
2
+ type: JS Module
3
+ title: fix-vscode_extensions.mjs
4
+ resource: npm/rules/tauri/policy/vscode_extensions/fix-vscode_extensions.mjs
5
+ docgen:
6
+ crc: 319883fc
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
9
+ ---
10
+
11
+ ## Огляд
12
+
13
+ Цей файл імпортує шаблони, необхідні для модифікації розширень VS Code. Він надає механізм для застосування визначених змін до розширень VS Code.
14
+
15
+ ## Поведінка
16
+
17
+ 1. Імпортує шаблони для виправлення розширень VS Code з файлу `../../../../scripts/lib/fix/vscode-ext-add.mjs`.
18
+
19
+ ## Гарантії поведінки
20
+
21
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -0,0 +1 @@
1
+ export { patterns } from '../../../../scripts/lib/fix/vscode-ext-add.mjs'
@@ -0,0 +1,21 @@
1
+ ---
2
+ type: JS Module
3
+ title: fix-vscode_extensions.mjs
4
+ resource: npm/rules/text/policy/vscode_extensions/fix-vscode_extensions.mjs
5
+ docgen:
6
+ crc: 319883fc
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
9
+ ---
10
+
11
+ ## Огляд
12
+
13
+ Файл імпортує шаблони для виправлення розширень VS Code. Ці шаблони використовуються для корекції розширень.
14
+
15
+ ## Поведінка
16
+
17
+ 1. Імпортує шаблони для виправлення розширень VS Code з файлу `../../../../scripts/lib/fix/vscode-ext-add.mjs`.
18
+
19
+ ## Гарантії поведінки
20
+
21
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -0,0 +1 @@
1
+ export { patterns } from '../../../../scripts/lib/fix/vscode-ext-add.mjs'
@@ -8,8 +8,6 @@ docgen:
8
8
  score: 100
9
9
  ---
10
10
 
11
- ## Огляд
12
-
13
11
  Модуль визначає, чи є пакет бібліотекою компонентів Vue, виходячи з даних у `package.json`, `jsconfig.json`, `package-lock.json`, `extensions.json`. Він також перевіряє відповідність усіх пакетів, що залежать від `vue`, критеріям, описаним у `vue.mdc`, і повертає код виходу.
14
12
 
15
13
  ## Поведінка
@@ -12,8 +12,6 @@ resource: npm/scripts/
12
12
  | [auto-skills.mjs](auto-skills.md) | JS Module |
13
13
  | [build-agents-commands.mjs](build-agents-commands.md) | JS Module |
14
14
  | [cli-entry.mjs](cli-entry.md) | JS Module |
15
- | [coverage-fix-extract.mjs](coverage-fix-extract.md) | JS Module |
16
- | [coverage-fix.mjs](coverage-fix.md) | JS Module |
17
15
  | [ensure-nitra-cursor-dev-dependencies.mjs](ensure-nitra-cursor-dev-dependencies.md) | JS Module |
18
16
  | [hook.mjs](hook.md) | JS Module |
19
17
  | [post-tool-use-check.mjs](post-tool-use-check.md) | JS Module |
@@ -51,6 +51,7 @@ async function listJsConcerns(jsDir) {
51
51
  if (!entry.isFile()) continue
52
52
  if (!entry.name.endsWith('.mjs')) continue
53
53
  if (entry.name.endsWith('.test.mjs')) continue
54
+ if (entry.name.startsWith('fix-')) continue
54
55
  if (entry.name.startsWith('_')) continue
55
56
  if (entry.name.startsWith('.')) continue
56
57
  const name = entry.name.slice(0, -'.mjs'.length)
@@ -3,167 +3,25 @@ type: JS Module
3
3
  title: discover-checkable-rules.mjs
4
4
  resource: npm/scripts/lib/discover-checkable-rules.mjs
5
5
  docgen:
6
- crc: 39016d17
6
+ crc: 403ab2ee
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
7
9
  ---
8
10
 
9
- Модуль `discover-checkable-rules.mjs` — це discovery-шар для CLI-команди `fix`. Його завдання — швидко просканувати файлову структуру каталогу `npm/rules/` та виявити «прогонні» правила, тобто правила, у яких є щонайменше один JS-концерн або policy-концерн. Правила, які складаються тільки з декларативних артефактів (`.mdc` + `auto.md`) без жодного прогонного концерну, відсіюються.
11
+ ## Огляд
10
12
 
11
- Виокремлюються два типи концернів:
13
+ Шукає правила, для яких є щось «прогонне» у визначених структурах. Виявляє JS-концерни за шляхами `rules/<id>/js/<concern>.mjs` та Policy-концерни, які мають пару з `<concern>.rego` (зв'язану з конфігурацією `target.json`). Ігнорує файли з префіксом `_` та `*.test.mjs`, а також каталоги `_lib/`. Виконання є швидким скануванням структури (шляхи та назви) без парсингу вмісту.
12
14
 
13
- - **JS concerns** — окремі файли `rules/<id>/js/<concern>.mjs`. Кожен файл — один концерн (flat-конвенція).
14
- - **Policy concerns** — підкаталоги `rules/<id>/policy/<concern>/`, у яких присутній файл `target.json` (поруч із якого зазвичай лежить `<concern>.rego`).
15
+ ## Поведінка
15
16
 
16
- Модуль свідомо не парсить вміст `target.json` і не читає JS-файли це лише швидкий «структурний» скан (шляхи + назви) без I/O-вмісту. Парсинг покладено на runner.
17
+ discoverOneRule описує набір JS-концернів та policy-концернів для одного каталогу правила, використовуючи шлях до цього каталогу та його ідентифікатор.
18
+ discoverCheckableRules сканує каталог з усіма правилами та повертає список правил, які мають JS-концерни або policy-концерни, фільтруючи ті, що не містять прогонного контенту.
17
19
 
18
- Файли-помічники з префіксом `_` (зокрема каталог `_lib/`), тестові файли `*.test.mjs`, а також приховані файли/каталоги (`.`-префікс) ігноруються.
20
+ ## Публічний API
19
21
 
20
- Історичний контекст конвенції розкладки JS-концернів:
22
+ discoverOneRule створює об'єкт перевірки для одного каталогу правила.
23
+ discoverCheckableRules — знаходити правила у каталозі `rules/`, які мають відповідні скрипти у `js/` або політики у `policy/`.
21
24
 
22
- - `js/<concern>/check.mjs` — версії 1.13.80–1.13.89 (вкладений каталог на концерн);
23
- - `js/<concern>.mjs` — версії 1.13.90+ (flat: концерн = файл, а не каталог).
25
+ ## Гарантії поведінки
24
26
 
25
- Допоміжні файли, тести, шаблони й дані винесені в окремі топ-level папки правила: `js/_lib/`, `tests/`, `templates/`, `data/`.
26
-
27
- ## Експорти / API
28
-
29
- Модуль експортує дві асинхронні функції:
30
-
31
- | Експорт | Тип | Призначення |
32
- | ----------------------------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
33
- | `discoverOneRule(ruleDir, ruleId)` | `async (string, string) => Promise<CheckableRule>` | Будує опис одного правила за заданим шляхом каталогу та id, без обходу `rules/`. |
34
- | `discoverCheckableRules(bundledRulesDir)` | `async (string) => Promise<CheckableRule[]>` | Сканує цілий каталог `npm/rules/` і повертає масив правил, для яких є JS- або policy-концерни. |
35
-
36
- Внутрішніми (не експортованими) залишаються функції `listJsConcerns` і `listPolicyConcerns`.
37
-
38
- ### Типи (JSDoc `@typedef`)
39
-
40
- ```text
41
- JsConcern { name: string } // basename файла js/<name>.mjs без розширення
42
- PolicyConcern { name: string } // imʼя підкаталогу policy/<name>/
43
- CheckableRule {
44
- id: string, // = basename каталогу rules/<id>/
45
- jsConcerns: JsConcern[], // алфавітно
46
- policyConcerns: PolicyConcern[], // алфавітно
47
- }
48
- ```
49
-
50
- ## Функції
51
-
52
- ### `listJsConcerns(jsDir)` (internal)
53
-
54
- - **Сигнатура:** `async function listJsConcerns(jsDir: string): Promise<JsConcern[]>`
55
- - **Параметри:**
56
- - `jsDir` — абсолютний шлях до каталогу `rules/<id>/js/`.
57
- - **Повертає:** масив `JsConcern[]`, відсортований алфавітно за `name` через `Array.prototype.toSorted` із компаратором `localeCompare`.
58
- - **Логіка:**
59
- 1. Якщо каталог `jsDir` не існує (`existsSync` повертає `false`) — повертається `[]`.
60
- 2. Читається вміст через `readdir(jsDir, { withFileTypes: true })` — тобто отримуються `Dirent`-обʼєкти з метаінформацією.
61
- 3. Пропускаються:
62
- - сутності, що не є файлом (`!entry.isFile()`);
63
- - файли без розширення `.mjs`;
64
- - тестові файли `*.test.mjs`;
65
- - службові файли з префіксом `_` (наприклад вміст `_lib/`, хоча сам `_lib` як каталог не буде файлом і відсіється раніше);
66
- - приховані файли з префіксом `.`.
67
- 4. Для решти файлів обчислюється `name = entry.name.slice(0, -'.mjs'.length)` — basename без розширення.
68
- - **Side effects:** лише файлові читання (`existsSync`, `readdir`), без запису.
69
-
70
- ### `listPolicyConcerns(policyDir)` (internal)
71
-
72
- - **Сигнатура:** `async function listPolicyConcerns(policyDir: string): Promise<PolicyConcern[]>`
73
- - **Параметри:**
74
- - `policyDir` — абсолютний шлях до каталогу `rules/<id>/policy/`.
75
- - **Повертає:** масив `PolicyConcern[]`, відсортований алфавітно за `name`.
76
- - **Логіка:**
77
- 1. Якщо `policyDir` не існує — повертається `[]`.
78
- 2. Читається вміст з `withFileTypes: true`.
79
- 3. Пропускаються будь-які записи, що не є каталогом, а також приховані каталоги (префікс `.`).
80
- 4. Для кожного підкаталогу перевіряється наявність файла `target.json` через `existsSync(join(policyDir, entry.name, 'target.json'))`. Якщо `target.json` є — підкаталог зараховується як policy-концерн.
81
- - **Side effects:** лише файлові читання, без запису.
82
-
83
- ### `discoverOneRule(ruleDir, ruleId)` (exported)
84
-
85
- - **Сигнатура:** `export async function discoverOneRule(ruleDir: string, ruleId: string): Promise<CheckableRule>`
86
- - **Параметри:**
87
- - `ruleDir` — абсолютний шлях до каталогу правила `rules/<id>/`;
88
- - `ruleId` — ідентифікатор правила, зазвичай `basename(ruleDir)`. Передається явно, бо функція не виводить його з шляху самостійно.
89
- - **Повертає:** обʼєкт `CheckableRule` з полями `id`, `jsConcerns`, `policyConcerns`. На відміну від `discoverCheckableRules`, тут не виконується фільтрація «має бути хоч щось» — повертається опис як є (можуть бути порожні масиви концернів).
90
- - **Логіка:** паралельно (точніше — послідовно `await`-ить) запускає `listJsConcerns(join(ruleDir, 'js'))` і `listPolicyConcerns(join(ruleDir, 'policy'))` та збирає результати в обʼєкт.
91
- - **Використання:** викликається `runStandardRule`-flow для per-rule entry-point, коли потрібно отримати опис конкретного правила, а не сканувати весь каталог.
92
- - **Side effects:** лише читання файлової системи.
93
-
94
- ### `discoverCheckableRules(bundledRulesDir)` (exported)
95
-
96
- - **Сигнатура:** `export async function discoverCheckableRules(bundledRulesDir: string): Promise<CheckableRule[]>`
97
- - **Параметри:**
98
- - `bundledRulesDir` — абсолютний шлях до кореневого каталогу всіх правил (зазвичай `npm/rules/`).
99
- - **Повертає:** масив `CheckableRule[]`, відсортований алфавітно за `id`. Включаються тільки правила, у яких `jsConcerns.length > 0 || policyConcerns.length > 0`.
100
- - **Логіка:**
101
- 1. Якщо `bundledRulesDir` не існує — повертається `[]`.
102
- 2. Читається вміст каталогу з `withFileTypes: true`.
103
- 3. Пропускаються сутності, які не є каталогом, та приховані каталоги (префікс `.`).
104
- 4. Для кожного підкаталогу формується `ruleDir = join(bundledRulesDir, entry.name)` і викликається `discoverOneRule(ruleDir, entry.name)`.
105
- 5. Правила, у яких немає жодного JS- або policy-концерну (декларативні-only), відсіюються.
106
- - **Side effects:** лише читання файлової системи (без запису, без мережевих викликів).
107
-
108
- ## Залежності
109
-
110
- Виключно зовнішні стандартні модулі Node.js:
111
-
112
- - `node:fs` → `existsSync` — синхронна перевірка існування шляху;
113
- - `node:fs/promises` → `readdir` — асинхронне читання вмісту каталогу (з `withFileTypes: true` повертає `Dirent[]`);
114
- - `node:path` → `join` — кросплатформова конкатенація шляхів.
115
-
116
- Внутрішніх імпортів з інших модулів проєкту немає. Це робить модуль чистим discovery-шаром без бізнес-логіки, що дозволяє безпечно його тестувати ізольовано (потрібна лише підготовлена файлова структура у тимчасовому каталозі).
117
-
118
- Зворотні залежності (хто використовує цей модуль): runner-флоу CLI `fix` (зокрема `runStandardRule`), який після discovery читає `target.json` для policy-концернів і виконує JS-концерни.
119
-
120
- ## Потік виконання / Використання
121
-
122
- ### Типовий сценарій 1. Повний скан правил для CLI `fix`
123
-
124
- ```javascript
125
- import { discoverCheckableRules } from './discover-checkable-rules.mjs'
126
-
127
- const rules = await discoverCheckableRules('/abs/path/to/npm/rules')
128
- for (const rule of rules) {
129
- // rule.id, rule.jsConcerns, rule.policyConcerns
130
- }
131
- ```
132
-
133
- Послідовність дій усередині:
134
-
135
- 1. `discoverCheckableRules` перевіряє існування кореневого каталогу.
136
- 2. Перебирає підкаталоги верхнього рівня (= потенційні правила).
137
- 3. Для кожного підкаталогу викликає `discoverOneRule`, який своєю чергою:
138
- - сканує `rules/<id>/js/` через `listJsConcerns`;
139
- - сканує `rules/<id>/policy/` через `listPolicyConcerns`;
140
- 4. Якщо знайдено хоч один концерн — правило додається у вихідний масив.
141
- 5. Масив сортується за `id`.
142
-
143
- ### Типовий сценарій 2. Per-rule entry-point
144
-
145
- ```javascript
146
- import { discoverOneRule } from './discover-checkable-rules.mjs'
147
-
148
- const rule = await discoverOneRule('/abs/path/to/npm/rules/n-js', 'n-js')
149
- // rule.id === 'n-js'
150
- // rule.jsConcerns — список JS-концернів у js/
151
- // rule.policyConcerns — список policy-концернів у policy/
152
- ```
153
-
154
- Цей шлях оминає енумерацію всього `rules/`, що корисно коли id правила вже відомий (наприклад, передано аргументом CLI).
155
-
156
- ### Гарантії та обмеження
157
-
158
- - **Чистота:** функції — read-only (не пишуть у ФС, не виконують код концернів). Це дозволяє безпечно викликати їх повторно.
159
- - **Сортування:** усі результати алфавітно відсортовані через `toSorted` із `localeCompare`. Це робить вивід детермінованим між запусками й між платформами (хоч порядок `readdir` залежить від ФС).
160
- - **Толерантність до відсутніх каталогів:** будь-яка з директорій (`rules/`, `js/`, `policy/`) може бути відсутня — повертається порожній масив без помилки.
161
- - **Тести/хелпери:** файли з префіксом `_` і `*.test.mjs` гарантовано виключаються із JS-концернів.
162
- - **Що _не_ робиться:** не валідуються імена концернів, не парситься `target.json`, не перевіряється наявність `<name>.rego` поруч із `target.json`. Це робота runner-а.
163
-
164
- ### Eage cases
165
-
166
- - Файл з префіксом `.` у `js/` — пропускається.
167
- - Підкаталог у `js/` (наприклад `_lib/`) — не є файлом, відсіюється першою перевіркою `entry.isFile()`.
168
- - Підкаталог у `policy/` без `target.json` — пропускається; наявність `<name>.rego` без `target.json` не зараховується.
169
- - Порожнє правило (тільки `.mdc`/`auto.md` без `js/` і `policy/`) — не потрапляє у вихід `discoverCheckableRules`, але буде повернене з порожніми масивами в `discoverOneRule`.
27
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Discovery T0-autofix паттернів з rule-level `fix-*.mjs` файлів.
3
+ *
4
+ * Сканує `npm/rules/{rule}/js/fix-*.mjs` і `npm/rules/{rule}/policy/{concern}/fix-*.mjs`
5
+ * по всіх правилах, динамічно імпортує кожен і збирає масиви `patterns`.
6
+ * `t0.mjs` ініціалізує результат через top-level await (один раз при завантаженні модуля).
7
+ */
8
+ import { existsSync } from 'node:fs'
9
+ import { readdir } from 'node:fs/promises'
10
+ import { join } from 'node:path'
11
+
12
+ /**
13
+ * @typedef {{ id: string, test: (output: string) => boolean, apply: (output: string, cwd: string) => Promise<{ok: boolean, action: string}> | {ok: boolean, action: string} }} T0Pattern
14
+ */
15
+
16
+ /**
17
+ * Повертає абсолютні шляхи до `fix-*.mjs` файлів у директорії (плоско, без рекурсії).
18
+ * @param {string} dir абсолютний шлях до директорії
19
+ * @returns {Promise<string[]>}
20
+ */
21
+ async function findFixFiles(dir) {
22
+ if (!existsSync(dir)) return []
23
+ const entries = await readdir(dir, { withFileTypes: true })
24
+ return entries
25
+ .filter(e => e.isFile() && e.name.startsWith('fix-') && e.name.endsWith('.mjs'))
26
+ .map(e => join(dir, e.name))
27
+ }
28
+
29
+ /**
30
+ * Повертає абсолютні шляхи до `policy/{concern}/fix-*.mjs` у правилі.
31
+ * @param {string} policyDir абсолютний шлях `rules/{rule}/policy/`
32
+ * @returns {Promise<string[]>}
33
+ */
34
+ async function findPolicyFixFiles(policyDir) {
35
+ if (!existsSync(policyDir)) return []
36
+ const entries = await readdir(policyDir, { withFileTypes: true })
37
+ const paths = []
38
+ for (const entry of entries) {
39
+ if (!entry.isDirectory()) continue
40
+ paths.push(...(await findFixFiles(join(policyDir, entry.name))))
41
+ }
42
+ return paths
43
+ }
44
+
45
+ /**
46
+ * Збирає всі T0-паттерни з `fix-*.mjs` файлів усіх правил у `rulesDir`.
47
+ * @param {string} rulesDir абсолютний шлях до `npm/rules/`
48
+ * @returns {Promise<T0Pattern[]>} об'єднаний масив паттернів
49
+ */
50
+ export async function discoverT0Patterns(rulesDir) {
51
+ if (!existsSync(rulesDir)) return []
52
+ const ruleEntries = await readdir(rulesDir, { withFileTypes: true })
53
+ /** @type {T0Pattern[]} */
54
+ const allPatterns = []
55
+
56
+ for (const ruleEntry of ruleEntries) {
57
+ if (!ruleEntry.isDirectory() || ruleEntry.name.startsWith('.')) continue
58
+ const ruleDir = join(rulesDir, ruleEntry.name)
59
+
60
+ const fixPaths = [
61
+ ...(await findFixFiles(join(ruleDir, 'js'))),
62
+ ...(await findPolicyFixFiles(join(ruleDir, 'policy')))
63
+ ]
64
+
65
+ for (const fixPath of fixPaths) {
66
+ try {
67
+ const mod = await import(fixPath)
68
+ if (Array.isArray(mod.patterns)) allPatterns.push(...mod.patterns)
69
+ } catch (err) {
70
+ console.error(`[discover-t0-patterns] не вдалося імпортувати ${fixPath}: ${err.message}`)
71
+ }
72
+ }
73
+ }
74
+
75
+ // Дедуплікація за id: shared утиліти (напр. vscode-ext-add) re-export'яться з ≥2 правил
76
+ // і потрапляють у список кілька разів — залишаємо перше входження.
77
+ const seen = new Set()
78
+ return allPatterns.filter(p => {
79
+ if (seen.has(p.id)) return false
80
+ seen.add(p.id)
81
+ return true
82
+ })
83
+ }
@@ -0,0 +1,37 @@
1
+ ---
2
+ type: JS Module
3
+ title: discover-t0-patterns.mjs
4
+ resource: npm/scripts/lib/fix/discover-t0-patterns.mjs
5
+ docgen:
6
+ crc: f2a262bb
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
9
+ ---
10
+
11
+ ## Огляд
12
+
13
+ Модуль сканує директорію правил для пошуку файлів `fix-*.mjs`, що містять визначення T0-паттернів. Він динамічно імпортує ці файли з папок `js` та `policy/{concern}` для кожного правила. Ініціалізація результату відбувається за допомогою _top-level await_ у `t0.mjs`. Функція збирає масив об'єктів, що описують усі знайдені паттерни.
14
+
15
+ ## Поведінка
16
+
17
+ 1. Перевіряє існування директорії, вказаної як `rulesDir`. Якщо директорія не існує, повертає порожній масив.
18
+ 2. Зчитує список усіх елементів у директорії `rulesDir`.
19
+ 3. Для кожного елемента, який є директорією та не починається з крапки, виконується наступне:
20
+ а. Визначається повний шлях до директорії правила.
21
+ б. Знаходяться всі файли `fix-*.mjs` у піддиректорії `js` цього правила.
22
+ в. Знаходяться всі файли `fix-*.mjs` у піддиректоріях `policy/{concern}` цього правила.
23
+ г. Для кожного знайденого файлу `fix-*.mjs` виконується динамічний імпорт.
24
+ д. Якщо імпорт успішний, збирається масив `patterns` з імпортованого модуля та додається до загального списку паттернів.
25
+ е. У разі помилки імпорту, помилка виводиться в консоль, але процес продовжується.
26
+ 4. Після обробки всіх правил, виконується дедуплікація загального списку паттернів за їхніми ідентифікаторами.
27
+ 5. Повертається фінальний, унікальний масив T0-паттернів.
28
+
29
+ ## Публічний API
30
+
31
+ discoverT0Patterns — збирає всі T0-паттерни з файлів `fix-*.mjs` у директорії правил.
32
+
33
+ ## Гарантії поведінки
34
+
35
+ - Read-only: не виконує операцій запису (ФС/БД).
36
+ - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
37
+ - За певних помилок повертає порожнє значення (напр. `null`) замість винятку.