@nitra/cursor 12.8.9 → 12.9.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/CHANGELOG.md +8 -1
- package/bin/n-cursor.js +18 -10
- package/package.json +5 -5
- package/rules/abie/docs/index.md +0 -1
- package/rules/abie/lib/docs/http-route.md +11 -12
- package/rules/abie/lib/http-route.mjs +3 -0
- package/rules/abie/policy/health_check_policy/health_check_policy.mdc +3 -1
- package/rules/abie/policy/health_check_policy/health_check_policy.rego +27 -0
- package/rules/adr/docs/index.md +0 -1
- package/rules/adr/js/madr_format.mdc +13 -1
- package/rules/bun/docs/index.md +0 -1
- package/rules/bun/policy/package_json/package_json.rego +12 -0
- package/rules/capacitor/docs/index.md +0 -1
- package/rules/changelog/docs/index.md +0 -1
- package/rules/ci4/docs/index.md +0 -1
- package/rules/doc-files/docs/index.md +0 -1
- package/rules/doc-files/docs/main.md +7 -9
- package/rules/doc-files/main.mjs +2 -3
- package/rules/docker/docs/index.md +0 -1
- package/rules/efes/docs/index.md +0 -1
- package/rules/feedback/docs/index.md +0 -1
- package/rules/ga/docs/index.md +0 -1
- package/rules/graphql/docs/index.md +0 -1
- package/rules/hasura/docs/index.md +0 -1
- package/rules/hasura/js/docs/index.md +3 -2
- package/rules/hasura/js/docs/migrations.md +30 -0
- package/rules/hasura/js/migrations.mjs +47 -0
- package/rules/image-avif/docs/index.md +0 -1
- package/rules/image-compress/docs/index.md +0 -1
- package/rules/js/docs/index.md +0 -1
- package/rules/js/js/dep-policy.mjs +87 -0
- package/rules/js/js/docs/dep-policy.md +36 -0
- package/rules/js/js/docs/index.md +1 -0
- package/rules/js/policy/package_json/package_json.rego +16 -0
- package/rules/js-bun-db/docs/index.md +0 -1
- package/rules/js-bun-redis/docs/index.md +0 -1
- package/rules/js-mssql/docs/index.md +0 -1
- package/rules/js-run/docs/index.md +0 -1
- package/rules/k8s/docs/index.md +0 -1
- package/rules/nginx-default-tpl/docs/index.md +0 -1
- package/rules/npm-module/docs/index.md +0 -1
- package/rules/php/docs/index.md +0 -1
- package/rules/python/docs/index.md +0 -1
- package/rules/rego/docs/index.md +0 -1
- package/rules/rego/js/docs/index.md +3 -3
- package/rules/rego/js/docs/tooling.md +28 -0
- package/rules/rego/js/tooling.mjs +24 -0
- package/rules/rego/policy/package_json/package_json.rego +21 -0
- package/rules/rego/policy/package_json/target.json +4 -0
- package/rules/release/docs/index.md +0 -1
- package/rules/rust/docs/index.md +0 -1
- package/rules/rust/policy/lint_rust_yml/lint_rust_yml.rego +24 -0
- package/rules/rust/policy/package_json/package_json.rego +20 -0
- package/rules/rust/policy/package_json/target.json +4 -0
- package/rules/security/docs/index.md +0 -1
- package/rules/style/docs/index.md +0 -1
- package/rules/style/js/docs/index.md +2 -3
- package/rules/style/js/docs/tooling.md +14 -10
- package/rules/style/js/tooling.mjs +8 -2
- package/rules/style/policy/lint_style_yml/lint_style_yml.rego +5 -0
- package/rules/tauri/docs/index.md +0 -1
- package/rules/test/docs/index.md +0 -1
- package/rules/test/js/docs/index.md +2 -0
- package/rules/test/js/docs/no-console-store-restore.md +32 -0
- package/rules/test/js/docs/sandbox-aware-test.md +32 -0
- package/rules/test/js/no-console-store-restore.mjs +88 -0
- package/rules/test/js/sandbox-aware-test.mjs +89 -0
- package/rules/text/docs/index.md +0 -1
- package/rules/tool-surface/docs/index.md +0 -1
- package/rules/vue/docs/index.md +0 -1
- package/rules/worktree/docs/index.md +0 -1
- package/scripts/docs/hook.md +29 -0
- package/scripts/docs/index.md +1 -2
- package/scripts/hook.mjs +72 -0
- package/scripts/lib/docs/index.md +0 -1
- package/scripts/lib/docs/run-lint.md +9 -8
- package/scripts/lib/docs/run-rule.md +7 -7
- package/scripts/lib/fix/docs/index.md +0 -1
- package/scripts/lib/run-lint.mjs +15 -2
- package/scripts/lib/run-rule.mjs +1 -2
- package/skills/adr-normalize/SKILL.md +1 -0
- package/skills/coverage-fix/SKILL.md +1 -0
- package/skills/doc-aggregate/SKILL.md +1 -0
- package/skills/doc-files/SKILL.md +1 -0
- package/skills/lint/SKILL.md +24 -19
- package/skills/llm-patch/SKILL.md +1 -0
- package/skills/publish-telegram/SKILL.md +1 -0
- package/skills/start-check/SKILL.md +1 -0
- package/skills/taze/SKILL.md +3 -2
- package/types/bin/n-cursor.d.ts +1 -1
- package/rules/abie/docs/fix.md +0 -37
- package/rules/adr/docs/fix.md +0 -37
- package/rules/bun/docs/fix.md +0 -30
- package/rules/capacitor/docs/fix.md +0 -36
- package/rules/changelog/docs/fix.md +0 -37
- package/rules/ci4/docs/fix.md +0 -32
- package/rules/doc-files/docs/fix.md +0 -29
- package/rules/docker/docs/fix.md +0 -35
- package/rules/efes/docs/fix.md +0 -37
- package/rules/feedback/docs/fix.md +0 -30
- package/rules/ga/docs/fix.md +0 -30
- package/rules/graphql/docs/fix.md +0 -37
- package/rules/hasura/docs/fix.md +0 -39
- package/rules/image-avif/docs/fix.md +0 -28
- package/rules/image-compress/docs/fix.md +0 -27
- package/rules/js/docs/fix.md +0 -37
- package/rules/js-bun-db/docs/fix.md +0 -30
- package/rules/js-bun-redis/docs/fix.md +0 -32
- package/rules/js-mssql/docs/fix.md +0 -30
- package/rules/js-run/docs/fix.md +0 -36
- package/rules/k8s/docs/fix.md +0 -31
- package/rules/nginx-default-tpl/docs/fix.md +0 -35
- package/rules/npm-module/docs/fix.md +0 -34
- package/rules/php/docs/fix.md +0 -35
- package/rules/python/docs/fix.md +0 -38
- package/rules/rego/docs/fix.md +0 -31
- package/rules/release/docs/fix.md +0 -28
- package/rules/rust/docs/fix.md +0 -32
- package/rules/security/docs/fix.md +0 -33
- package/rules/style/docs/fix.md +0 -28
- package/rules/tauri/docs/fix.md +0 -39
- package/rules/test/docs/fix.md +0 -31
- package/rules/text/docs/fix.md +0 -37
- package/rules/tool-surface/docs/fix.md +0 -32
- package/rules/vue/docs/fix.md +0 -32
- package/rules/worktree/docs/fix.md +0 -40
- package/scripts/docs/post-tool-use-fix.md +0 -32
- package/scripts/docs/worktree-cli.md +0 -27
- package/scripts/lib/docs/worktree.md +0 -42
- package/scripts/lib/fix/docs/run-fix-check.md +0 -33
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: JS Module
|
|
3
|
+
title: dep-policy.mjs
|
|
4
|
+
resource: npm/rules/js/js/dep-policy.mjs
|
|
5
|
+
docgen:
|
|
6
|
+
crc: 82035584
|
|
7
|
+
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
+
score: 100
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Огляд
|
|
12
|
+
|
|
13
|
+
Модуль сканує JavaScript та TypeScript файли проєкту для перевірки відповідності політикам залежностей. Він знаходить усі імпорти у файлах і порівнює їх із переліком заборонених специфікаторів. При виявленні порушень політики, вони реєструються. Модуль працює у режимі, що перехоплює помилки (fail-safe), і не кидає винятків назовні. Він є лише для читання (Read-only) і не змінює файлову систему чи бази даних. Результат роботи визначається кодом виходу, що інформує про наявність чи відсутність порушень політики (dep-policy.mdc) та успішну перевірку (js.mdc).
|
|
14
|
+
|
|
15
|
+
## Поведінка
|
|
16
|
+
|
|
17
|
+
1. Ініціалізує звітність.
|
|
18
|
+
2. Визначає кореневу директорію проєкту.
|
|
19
|
+
3. Зчитує список шляхів, які слід ігнорувати під час сканування.
|
|
20
|
+
4. Знаходить усі файли з розширеннями JavaScript/TypeScript у кореневій директорії, ігноруючи визначені шляхи.
|
|
21
|
+
5. Для кожного знайденого файлу:
|
|
22
|
+
а. Зчитує вміст файлу.
|
|
23
|
+
б. Витягує всі імпортовані специфікатори з вмісту файлу.
|
|
24
|
+
в. Перевіряє кожен витягнутий специфікатор на відповідність списку заборонених специфікаторів (dep-policy.mdc).
|
|
25
|
+
г. Якщо специфікатор заборонений, реєструє помилку, вказуючи відносний шлях до файлу та заборонений імпорт. Збільшує лічильник порушень.
|
|
26
|
+
6. Якщо порушень не знайдено, реєструє повідомлення про успішну перевірку (js.mdc).
|
|
27
|
+
7. Повертає код виходу, що відображає наявність порушень.
|
|
28
|
+
|
|
29
|
+
## Публічний API
|
|
30
|
+
|
|
31
|
+
check — сканує файли на наявність заборонених імпортів (dep-policy.mdc).
|
|
32
|
+
|
|
33
|
+
## Гарантії поведінки
|
|
34
|
+
|
|
35
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
36
|
+
- Перехоплює помилки і не пропускає винятків назовні (fail-safe).
|
|
@@ -9,6 +9,7 @@ resource: npm/rules/js/js/
|
|
|
9
9
|
| Файл | Тип |
|
|
10
10
|
|---|---|
|
|
11
11
|
| [check.mjs](check.md) | JS Module |
|
|
12
|
+
| [dep-policy.mjs](dep-policy.md) | JS Module |
|
|
12
13
|
| [lint-findings.mjs](lint-findings.md) | JS Module |
|
|
13
14
|
| [tooling.mjs](tooling.md) | JS Module |
|
|
14
15
|
| [utils_imports.mjs](utils_imports.md) | JS Module |
|
|
@@ -61,6 +61,22 @@ deny contains msg if {
|
|
|
61
61
|
msg := sprintf("package.json: @nitra/eslint-config має бути >= %s (зараз %q) (js.mdc)", [eslint_min_display, range])
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
# ── deny: @nitra/as-integrations-fastify заборонений (dep-policy.mdc) ───
|
|
65
|
+
|
|
66
|
+
banned_fastify_pkg := "@nitra/as-integrations-fastify"
|
|
67
|
+
|
|
68
|
+
deny contains msg if {
|
|
69
|
+
deps := object.get(input, "dependencies", {})
|
|
70
|
+
banned_fastify_pkg in object.keys(deps)
|
|
71
|
+
msg := sprintf("package.json: dependencies.%s заборонений — використовуй @as-integrations/fastify (js.mdc dep-policy)", [banned_fastify_pkg])
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
deny contains msg if {
|
|
75
|
+
deps := object.get(input, "peerDependencies", {})
|
|
76
|
+
banned_fastify_pkg in object.keys(deps)
|
|
77
|
+
msg := sprintf("package.json: peerDependencies.%s заборонений — використовуй @as-integrations/fastify (js.mdc dep-policy)", [banned_fastify_pkg])
|
|
78
|
+
}
|
|
79
|
+
|
|
64
80
|
# ── helpers ──────────────────────────────────────────────────────────────
|
|
65
81
|
|
|
66
82
|
# Канонічний мін-поріг `@nitra/eslint-config` із snippet (напр. "^3.10.0").
|
package/rules/k8s/docs/index.md
CHANGED
package/rules/php/docs/index.md
CHANGED
package/rules/rego/docs/index.md
CHANGED
|
@@ -6,7 +6,7 @@ resource: npm/rules/rego/js/
|
|
|
6
6
|
|
|
7
7
|
# npm/rules/rego/js
|
|
8
8
|
|
|
9
|
-
| Файл
|
|
10
|
-
|
|
9
|
+
| Файл | Тип |
|
|
10
|
+
|---|---|
|
|
11
11
|
| [applies.mjs](applies.md) | JS Module |
|
|
12
|
-
| [
|
|
12
|
+
| [tooling.mjs](tooling.md) | JS Module |
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: JS Module
|
|
3
|
+
title: tooling.mjs
|
|
4
|
+
resource: npm/rules/rego/js/tooling.mjs
|
|
5
|
+
docgen:
|
|
6
|
+
crc: 4c098cd0
|
|
7
|
+
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
+
score: 100
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Огляд
|
|
12
|
+
|
|
13
|
+
Перевіряє наявність конфігураційного файлу `.regal/config.yaml` у корені проєкту. Ця функція визначає можливість подальшої ініціалізації системи. У разі відсутності файлу, повертає повідомлення, що вимагає створення конфігураційного файлу (rego.mdc).
|
|
14
|
+
|
|
15
|
+
## Поведінка
|
|
16
|
+
|
|
17
|
+
1. Викликає перевірку на наявність файлу `.regal/config.yaml` у корені проєкту.
|
|
18
|
+
2. Якщо файл `.regal/config.yaml` існує, повідомляє про успіх (rego.mdc).
|
|
19
|
+
3. Якщо файл `.regal/config.yaml` не існує, повідомляє про помилку та рекомендує створити його у корені проєкту (rego.mdc).
|
|
20
|
+
4. Повертає код виходу, що відображає загальний статус перевірки.
|
|
21
|
+
|
|
22
|
+
## Публічний API
|
|
23
|
+
|
|
24
|
+
check — констатує наявність файлу `.regal/config.yaml` у корені проєкту (rego.mdc).
|
|
25
|
+
|
|
26
|
+
## Гарантії поведінки
|
|
27
|
+
|
|
28
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** @see ./docs/tooling.md */
|
|
2
|
+
import { existsSync } from 'node:fs'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
|
|
5
|
+
import { createCheckReporter } from '../../../scripts/lib/check-reporter.mjs'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Перевіряє наявність `.regal/config.yaml` у корені проєкту.
|
|
9
|
+
* @param {string} [cwd] корінь репозиторію
|
|
10
|
+
* @returns {Promise<number>} 0 — все OK, 1 — є проблеми
|
|
11
|
+
*/
|
|
12
|
+
export async function check(cwd = process.cwd()) {
|
|
13
|
+
const reporter = createCheckReporter()
|
|
14
|
+
const { pass, fail } = reporter
|
|
15
|
+
|
|
16
|
+
const regalConfig = join(cwd, '.regal', 'config.yaml')
|
|
17
|
+
if (existsSync(regalConfig)) {
|
|
18
|
+
pass('.regal/config.yaml існує (rego.mdc)')
|
|
19
|
+
} else {
|
|
20
|
+
fail('.regal/config.yaml не існує — створи у корені проєкту (rego.mdc)')
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return reporter.getExitCode()
|
|
24
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Перевірка `package.json` (rego.mdc / rego-lint.mdc).
|
|
2
|
+
#
|
|
3
|
+
# `opa` і `regal` не додаються у dependencies / devDependencies — вони мають бути
|
|
4
|
+
# лише у PATH (встановлені глобально або через CI-крок). Rego-лінт запускається
|
|
5
|
+
# через `n-cursor lint rego`, а не через package.json-залежності.
|
|
6
|
+
package rego.package_json
|
|
7
|
+
|
|
8
|
+
import rego.v1
|
|
9
|
+
|
|
10
|
+
banned_opa_tools := {"opa", "regal"}
|
|
11
|
+
|
|
12
|
+
deny contains msg if {
|
|
13
|
+
some field in {"dependencies", "devDependencies", "peerDependencies"}
|
|
14
|
+
deps := object.get(input, field, {})
|
|
15
|
+
some name, _ in deps
|
|
16
|
+
name in banned_opa_tools
|
|
17
|
+
msg := sprintf(
|
|
18
|
+
"package.json: %s.%s заборонений — opa/regal встановлюються глобально або через CI, не через npm (rego.mdc)",
|
|
19
|
+
[field, name]
|
|
20
|
+
)
|
|
21
|
+
}
|
package/rules/rust/docs/index.md
CHANGED
|
@@ -48,6 +48,30 @@ deny contains msg if {
|
|
|
48
48
|
msg := sprintf("lint-rust.yml: жоден крок run не містить %q (rust.mdc)", [expected_run])
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
# Крок dtolnay/rust-toolchain@stable має мати with.components з rustfmt і clippy.
|
|
52
|
+
toolchain_step(step) if {
|
|
53
|
+
uses := object.get(step, "uses", "")
|
|
54
|
+
startswith(uses, "dtolnay/rust-toolchain@")
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
deny contains msg if {
|
|
58
|
+
some job in object.get(input, "jobs", {})
|
|
59
|
+
some step in object.get(job, "steps", [])
|
|
60
|
+
toolchain_step(step)
|
|
61
|
+
components := object.get(object.get(step, "with", {}), "components", "")
|
|
62
|
+
not contains(components, "rustfmt")
|
|
63
|
+
msg := "lint-rust.yml: dtolnay/rust-toolchain step потребує with.components: rustfmt, clippy (rust.mdc)"
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
deny contains msg if {
|
|
67
|
+
some job in object.get(input, "jobs", {})
|
|
68
|
+
some step in object.get(job, "steps", [])
|
|
69
|
+
toolchain_step(step)
|
|
70
|
+
components := object.get(object.get(step, "with", {}), "components", "")
|
|
71
|
+
not contains(components, "clippy")
|
|
72
|
+
msg := "lint-rust.yml: dtolnay/rust-toolchain step потребує with.components: rustfmt, clippy (rust.mdc)"
|
|
73
|
+
}
|
|
74
|
+
|
|
51
75
|
step_run_to_text(step) := step.run if is_string(step.run)
|
|
52
76
|
|
|
53
77
|
else := concat("\n", [s | some s in step.run]) if is_array(step.run)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Перевірка `package.json` для Rust-проєктів (rust.mdc / lint.mdc).
|
|
2
|
+
#
|
|
3
|
+
# `cargo`, `rustfmt`, `clippy` — частина Rust toolchain (rustup), не npm-залежностей.
|
|
4
|
+
# Вони мають бути у PATH через `rustup` локально або `dtolnay/rust-toolchain@stable` у CI.
|
|
5
|
+
package rust.package_json
|
|
6
|
+
|
|
7
|
+
import rego.v1
|
|
8
|
+
|
|
9
|
+
banned_rust_tools := {"cargo", "rustfmt", "clippy"}
|
|
10
|
+
|
|
11
|
+
deny contains msg if {
|
|
12
|
+
some field in {"dependencies", "devDependencies", "peerDependencies"}
|
|
13
|
+
deps := object.get(input, field, {})
|
|
14
|
+
some name, _ in deps
|
|
15
|
+
name in banned_rust_tools
|
|
16
|
+
msg := sprintf(
|
|
17
|
+
"package.json: %s.%s заборонений — Rust toolchain встановлюється через rustup / dtolnay/rust-toolchain@stable, не через npm (rust.mdc)",
|
|
18
|
+
[field, name]
|
|
19
|
+
)
|
|
20
|
+
}
|
|
@@ -3,25 +3,29 @@ type: JS Module
|
|
|
3
3
|
title: tooling.mjs
|
|
4
4
|
resource: npm/rules/style/js/tooling.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
7
|
-
|
|
6
|
+
crc: 27bb12d3
|
|
7
|
+
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
+
score: 95
|
|
8
9
|
---
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
## Огляд
|
|
12
|
+
|
|
13
|
+
Перевіряє налаштування для стилістичного лінтера, підтверджуючи наявність файлів конфігурації, таких як `.stylelintrc.json` та `package.json`. Це забезпечує коректний запуск перевірок відповідно до вимог, визначених у `.stylelintrc.json` та `settings.json`. (js.mdc), (style.mdc)
|
|
11
14
|
|
|
12
15
|
## Поведінка
|
|
13
16
|
|
|
14
|
-
1.
|
|
15
|
-
2.
|
|
16
|
-
3.
|
|
17
|
-
4.
|
|
17
|
+
1. Викликається функція check.
|
|
18
|
+
2. Перевіряється наявність конфігурації stylelint у package.json або зовнішньому файлі (наприклад, .stylelintrc.json, .stylelintrc.js, stylelint.config.js). Якщо конфігурація відсутня, повідомляється про необхідність додати її до package.json (js.mdc).
|
|
19
|
+
3. Якщо існує файл .stylelintignore, перевіряється, чи містить він рядок `dist/`. Якщо ні, повідомляється про необхідність додати цей рядок (style.mdc).
|
|
20
|
+
4. Перевіряється наявність файлу .github/workflows/lint-style.yml. Якщо він відсутній, повідомляється про необхідність його створення.
|
|
21
|
+
5. Функція повертає код виходу, що відображає загальний статус перевірки.
|
|
22
|
+
6. Перевірка не включає шляхи .github та .git.
|
|
18
23
|
|
|
19
24
|
## Публічний API
|
|
20
25
|
|
|
21
|
-
check —
|
|
26
|
+
check — перевіряє відповідність проєкту стандартам оформлення (style.mdc).
|
|
22
27
|
|
|
23
28
|
## Гарантії поведінки
|
|
24
29
|
|
|
25
|
-
- Read-only:
|
|
30
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
26
31
|
- Свідомо пропускає шляхи: `.github`, `.git`.
|
|
27
|
-
- Не звертається до мережі.
|
|
@@ -54,8 +54,14 @@ export async function check(cwd = process.cwd()) {
|
|
|
54
54
|
|
|
55
55
|
await checkStylelintConfigPresence(reporter, cwd)
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
const ignorePath = join(cwd, '.stylelintignore')
|
|
58
|
+
if (existsSync(ignorePath)) {
|
|
59
|
+
const ignoreContent = await readFile(ignorePath, 'utf8')
|
|
60
|
+
if (ignoreContent.split('\n').some(line => line.trim() === 'dist/')) {
|
|
61
|
+
pass('.stylelintignore існує і містить dist/')
|
|
62
|
+
} else {
|
|
63
|
+
fail('.stylelintignore не містить рядка dist/ — додай його (style.mdc)')
|
|
64
|
+
}
|
|
59
65
|
} else {
|
|
60
66
|
fail('.stylelintignore не існує — створи з вмістом: dist/')
|
|
61
67
|
}
|
|
@@ -26,6 +26,11 @@ deny contains msg if {
|
|
|
26
26
|
msg := sprintf("lint-style.yml: жоден крок run не містить %q (style.mdc)", [expected_run_blob])
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
deny contains msg if {
|
|
30
|
+
contains(all_run_text, "bunx stylelint")
|
|
31
|
+
msg := "lint-style.yml: знайдено bunx stylelint — використовуй n-cursor lint style --read-only (style.mdc)"
|
|
32
|
+
}
|
|
33
|
+
|
|
29
34
|
step_run_to_text(step) := step.run if is_string(step.run)
|
|
30
35
|
|
|
31
36
|
else := concat("\n", [s | some s in step.run]) if is_array(step.run)
|
package/rules/test/docs/index.md
CHANGED
|
@@ -10,7 +10,9 @@ resource: npm/rules/test/js/
|
|
|
10
10
|
| ----------------------------------------------------------- | --------- |
|
|
11
11
|
| [cargo_mutants_config.mjs](cargo_mutants_config.md) | JS Module |
|
|
12
12
|
| [location.mjs](location.md) | JS Module |
|
|
13
|
+
| [no-console-store-restore.mjs](no-console-store-restore.md) | JS Module |
|
|
13
14
|
| [no-process-chdir.mjs](no-process-chdir.md) | JS Module |
|
|
14
15
|
| [no-relative-fs-path.mjs](no-relative-fs-path.md) | JS Module |
|
|
16
|
+
| [sandbox-aware-test.mjs](sandbox-aware-test.md) | JS Module |
|
|
15
17
|
| [stryker_config.mjs](stryker_config.md) | JS Module |
|
|
16
18
|
| [vitest-config-pool-forks.mjs](vitest-config-pool-forks.md) | JS Module |
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: JS Module
|
|
3
|
+
title: no-console-store-restore.mjs
|
|
4
|
+
resource: npm/rules/test/js/no-console-store-restore.mjs
|
|
5
|
+
docgen:
|
|
6
|
+
crc: 39f9fb6d
|
|
7
|
+
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
+
score: 100
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Огляд
|
|
12
|
+
|
|
13
|
+
Модуль сканує репозиторій для пошуку файлів, що відповідають шаблону `*.test.{mjs,js}`. Він перевіряє вміст кожного такого файлу на наявність прямих присвоєнь методів консолі. Публічна функція `check` виявляє такі присвоєння. (test.mdc)
|
|
14
|
+
|
|
15
|
+
## Поведінка
|
|
16
|
+
|
|
17
|
+
1. Визначає, які файли є тестовими (`*.test.{mjs,js}`).
|
|
18
|
+
2. Збирає список усіх тестових файлів у репозиторії, ігноруючи конфігураційні шляхи.
|
|
19
|
+
3. Для кожного тестового файлу зчитує його вміст.
|
|
20
|
+
4. Аналізує вміст файлу, шукаючи прямі присвоєння `console.<method> = …`.
|
|
21
|
+
5. Якщо порушення знайдено, реєструє його з зазначенням файлу та номера рядка.
|
|
22
|
+
6. Якщо порушень немає, повідомляє про успішну перевірку (test.mdc).
|
|
23
|
+
7. Якщо порушення знайдено, повідомляє про кожне порушення, вказуючи, що пряме присвоєння заборонено і слід використовувати `vi.spyOn.mockReturnValue` (test.mdc, no-console-store-restore).
|
|
24
|
+
8. Повертає код виходу, що відображає результат перевірки.
|
|
25
|
+
|
|
26
|
+
## Публічний API
|
|
27
|
+
|
|
28
|
+
check — виявляє, чи не перевизначає жоден тестовий файл методи `console.*` через пряме присвоєння.
|
|
29
|
+
|
|
30
|
+
## Гарантії поведінки
|
|
31
|
+
|
|
32
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: JS Module
|
|
3
|
+
title: sandbox-aware-test.mjs
|
|
4
|
+
resource: npm/rules/test/js/sandbox-aware-test.mjs
|
|
5
|
+
docgen:
|
|
6
|
+
crc: 0c64c75c
|
|
7
|
+
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
+
score: 100
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Огляд
|
|
12
|
+
|
|
13
|
+
Модуль сканує тестові файли, що відповідають шаблону `*.test.{mjs,js}` у вказаному корені репозиторію. Він перевіряє, чи файли, що містять глибоку навігацію (визначену як використання `import.meta.dirname` або `import.meta.url` з чотирма або більше рівнями `..`), захищені викликом `withTmpDir` або `test.skipIf` з посиланням на змінну середовища `env.STRYKER_MUTATOR_WORKER`. Перевірка фіксує порушення (test.mdc) у разі відсутності необхідної ізоляції для тестових файлів з глибокою навігацією.
|
|
14
|
+
|
|
15
|
+
## Поведінка
|
|
16
|
+
|
|
17
|
+
1. Визначає тестові файли, що відповідають шаблону `*.test.{mjs,js}` у вказаному корені репозиторію.
|
|
18
|
+
2. Для кожного тестового файлу перевіряє, чи містить він глибоку навігацію за допомогою `import.meta.dirname` або `import.meta.url` з чотирма або більше рівнями `..`.
|
|
19
|
+
3. Якщо глибока навігація виявлена, перевіряє, чи захищено цей файл викликом `withTmpDir` або `test.skipIf` з посиланням на `env.STRYKER_MUTATOR_WORKER`.
|
|
20
|
+
4. Якщо глибока навігація виявлена, але файл не захищений, він реєструється як порушення (test.mdc).
|
|
21
|
+
5. Викликає `check` для запуску перевірки.
|
|
22
|
+
6. Якщо порушень немає, повідомляє про успішне виконання (test.mdc).
|
|
23
|
+
7. Якщо порушення виявлено, повідомляє про кожен виявлений файл та необхідність застосування ізоляції.
|
|
24
|
+
8. Повертає код виходу, що відображає результат перевірки.
|
|
25
|
+
|
|
26
|
+
## Публічний API
|
|
27
|
+
|
|
28
|
+
check — Виявляє тести, що використовують глибоку навігацію `import.meta` (≥4 `..`-рівнів) і не захищені механізмами `withTmpDir` або `test.skipIf`. Це запобігає збоям Git-операцій у тестах, які не мають ізоляції Stryker-sandbox. (test.mdc)
|
|
29
|
+
|
|
30
|
+
## Гарантії поведінки
|
|
31
|
+
|
|
32
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/** @see ./docs/no-console-store-restore.md */
|
|
2
|
+
import { readFile } from 'node:fs/promises'
|
|
3
|
+
import { basename, relative } from 'node:path'
|
|
4
|
+
|
|
5
|
+
import { createCheckReporter } from '../../../scripts/lib/check-reporter.mjs'
|
|
6
|
+
import { loadCursorIgnorePaths } from '../../../scripts/lib/load-cursor-config.mjs'
|
|
7
|
+
import { walkDir } from '../../../scripts/utils/walkDir.mjs'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Ловить пряме присвоєння `console.<method> = …` у `*.test.{js,mjs}`.
|
|
11
|
+
* `console.log = fn` — process-wide мутація; канон: `vi.spyOn(console, 'log')`.
|
|
12
|
+
* `(?!=)` виключає `==` та `===` (лише одиночний `=`).
|
|
13
|
+
*/
|
|
14
|
+
const CONSOLE_ASSIGN_RE =
|
|
15
|
+
/\bconsole\.(?:log|error|warn|info|debug|dir|table|trace|group|groupEnd|time|timeEnd)\s*=(?!=)/u
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Чи файл — JS-тест (`*.test.mjs` / `*.test.js`).
|
|
19
|
+
* @param {string} absPath абсолютний шлях
|
|
20
|
+
* @returns {boolean} `true` для `.test.{mjs,js}` файлів
|
|
21
|
+
*/
|
|
22
|
+
function isTestFile(absPath) {
|
|
23
|
+
const name = basename(absPath)
|
|
24
|
+
return name.endsWith('.test.mjs') || name.endsWith('.test.js')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Знаходить рядки з прямим присвоєнням `console.<method> = …`.
|
|
29
|
+
* @param {string} body вміст файлу
|
|
30
|
+
* @returns {Array<{line: number}>} знайдені порушення
|
|
31
|
+
*/
|
|
32
|
+
function findOffenders(body) {
|
|
33
|
+
const offenders = []
|
|
34
|
+
const lines = body.split('\n')
|
|
35
|
+
for (const [i, line] of lines.entries()) {
|
|
36
|
+
if (CONSOLE_ASSIGN_RE.test(line)) {
|
|
37
|
+
offenders.push({ line: i + 1 })
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return offenders
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Перевіряє, що жоден `*.test.{mjs,js}` файл не перевизначає `console.<method>`
|
|
45
|
+
* через пряме присвоєння. Канон — `vi.spyOn(console, 'log').mockReturnValue()`.
|
|
46
|
+
* @param {string} [cwdParam] корінь репозиторію
|
|
47
|
+
* @returns {Promise<number>} 0 — чисто, 1 — є порушення
|
|
48
|
+
*/
|
|
49
|
+
export async function check(cwdParam = process.cwd()) {
|
|
50
|
+
const reporter = createCheckReporter()
|
|
51
|
+
const { pass, fail } = reporter
|
|
52
|
+
|
|
53
|
+
const cwd = cwdParam
|
|
54
|
+
const ignorePaths = await loadCursorIgnorePaths(cwd)
|
|
55
|
+
|
|
56
|
+
/** @type {string[]} */
|
|
57
|
+
const testFiles = []
|
|
58
|
+
await walkDir(
|
|
59
|
+
cwd,
|
|
60
|
+
absPath => {
|
|
61
|
+
if (isTestFile(absPath)) testFiles.push(absPath)
|
|
62
|
+
},
|
|
63
|
+
ignorePaths
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
/** @type {Array<{file: string, line: number}>} */
|
|
67
|
+
const offenders = []
|
|
68
|
+
for (const absPath of testFiles) {
|
|
69
|
+
const body = await readFile(absPath, 'utf8')
|
|
70
|
+
for (const o of findOffenders(body)) {
|
|
71
|
+
offenders.push({ file: relative(cwd, absPath), ...o })
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (offenders.length === 0) {
|
|
76
|
+
pass(`Жоден з ${testFiles.length} тестових файлів не присвоює console.<method> = … (test.mdc)`)
|
|
77
|
+
return reporter.getExitCode()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
for (const { file, line } of offenders) {
|
|
81
|
+
fail(
|
|
82
|
+
`${file}:${line}: пряме присвоєння console.<method> = … заборонено — ` +
|
|
83
|
+
`використовуй vi.spyOn(console, 'method').mockReturnValue() (test.mdc, no-console-store-restore)`
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return reporter.getExitCode()
|
|
88
|
+
}
|