@7n/rules 1.20.0 → 1.21.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 +13 -0
- package/package.json +1 -1
- package/rules/bun/licensee/docs/fix-licensee.md +1 -2
- package/rules/bun/licensee/docs/main.md +1 -1
- package/rules/bun/licensee/fix-licensee.mjs +3 -4
- package/rules/bun/licensee/main.mjs +7 -7
- package/rules/docker/lib/docker-hadolint.mjs +6 -8
- package/rules/docker/lib/docs/docker-hadolint.md +1 -1
- package/rules/docker/lint/docs/main.md +1 -1
- package/rules/docker/lint/main.mjs +1 -1
- package/rules/image-compress/check/docs/fix-check.md +1 -2
- package/rules/image-compress/check/docs/main.md +1 -1
- package/rules/image-compress/check/fix-check.mjs +27 -22
- package/rules/image-compress/check/main.mjs +14 -14
- package/rules/js/jscpd_duplicates/docs/main.md +1 -1
- package/rules/js/jscpd_duplicates/main.mjs +7 -8
- package/rules/k8s/kubeconform/docs/main.md +1 -1
- package/rules/k8s/kubeconform/main.mjs +1 -1
- package/rules/k8s/manifests/main.mjs +52 -39
- package/rules/php/cs_fixer/docs/main.md +1 -2
- package/rules/php/cs_fixer/main.mjs +8 -7
- package/rules/php/phpcs/docs/main.md +1 -2
- package/rules/php/phpcs/main.mjs +12 -11
- package/rules/php/project/docs/main.md +1 -2
- package/rules/php/project/main.mjs +19 -16
- package/rules/rego/conftest_verify/docs/main.md +1 -2
- package/rules/rego/conftest_verify/main.mjs +12 -10
- package/rules/rego/lib/docs/run-external-tool.md +1 -1
- package/rules/rego/lib/run-external-tool.mjs +10 -7
- package/rules/rego/opa_check/docs/main.md +1 -1
- package/rules/rego/opa_check/main.mjs +3 -3
- package/rules/rego/regal/docs/main.md +1 -1
- package/rules/rego/regal/main.mjs +3 -3
- package/rules/security/scan/docs/main.md +1 -1
- package/rules/security/scan/main.mjs +9 -9
- package/rules/style/lint/docs/fix-lint.md +1 -1
- package/rules/style/lint/docs/main.md +1 -1
- package/rules/style/lint/fix-lint.mjs +8 -8
- package/rules/style/lint/main.mjs +6 -6
- package/rules/text/cspell-fix/docs/fix-worker.md +1 -1
- package/rules/text/cspell-fix/docs/main.md +1 -1
- package/rules/text/cspell-fix/fix-worker.mjs +1 -1
- package/rules/text/cspell-fix/main.mjs +14 -15
- package/rules/text/oxfmt/docs/fix-oxfmt.md +1 -1
- package/rules/text/oxfmt/docs/main.md +1 -1
- package/rules/text/oxfmt/fix-oxfmt.mjs +3 -3
- package/rules/text/oxfmt/main.mjs +6 -5
- package/rules/text/run-dotenv-linter/docs/fix-run-dotenv-linter.md +1 -2
- package/rules/text/run-dotenv-linter/docs/main.md +1 -1
- package/rules/text/run-dotenv-linter/fix-run-dotenv-linter.mjs +2 -2
- package/rules/text/run-dotenv-linter/main.mjs +19 -24
- package/rules/text/run-shellcheck/docs/fix-run-shellcheck.md +1 -2
- package/rules/text/run-shellcheck/docs/main.md +1 -1
- package/rules/text/run-shellcheck/fix-run-shellcheck.mjs +3 -3
- package/rules/text/run-shellcheck/main.mjs +46 -57
- package/rules/text/run-v8r/docs/main.md +1 -1
- package/rules/text/run-v8r/main.mjs +31 -26
- package/scripts/lib/docs/resolve-plugins.md +1 -1
- package/scripts/lib/lint-surface/blocking-inventory.mjs +12 -40
- package/scripts/lib/lint-surface/docs/blocking-inventory.md +1 -2
- package/scripts/utils/docs/spawn-async.md +1 -2
- package/scripts/utils/spawn-async.mjs +4 -1
- package/rules/python/applies/concern.json +0 -4
- package/rules/python/applies/docs/main.md +0 -29
- package/rules/python/applies/main.mjs +0 -24
- package/rules/python/docs/index.md +0 -11
- package/rules/python/lib/docs/index.md +0 -9
- package/rules/python/lib/docs/uv-run.md +0 -32
- package/rules/python/lib/uv-run.mjs +0 -48
- package/rules/python/main.json +0 -1
- package/rules/python/main.mdc +0 -8
- package/rules/python/mypy/concern.json +0 -7
- package/rules/python/mypy/docs/main.md +0 -32
- package/rules/python/mypy/main.mjs +0 -36
- package/rules/python/project/concern.json +0 -6
- package/rules/python/project/docs/main.md +0 -43
- package/rules/python/project/main.mjs +0 -115
- package/rules/python/pyproject_toml/concern.json +0 -9
- package/rules/python/pyproject_toml/pyproject_toml.mdc +0 -29
- package/rules/python/pyproject_toml/pyproject_toml.rego +0 -53
- package/rules/python/pyproject_toml/template/pyproject.toml.deny.toml +0 -2
- package/rules/python/pyproject_toml/template/pyproject.toml.snippet.toml +0 -12
- package/rules/python/ruff/concern.json +0 -7
- package/rules/python/ruff/docs/fix-ruff.md +0 -34
- package/rules/python/ruff/docs/main.md +0 -35
- package/rules/python/ruff/fix-ruff.mjs +0 -63
- package/rules/python/ruff/main.mjs +0 -52
- package/rules/python/tooling/concern.json +0 -15
- package/rules/python/tooling/docs/index.md +0 -11
- package/rules/python/tooling/docs/main.md +0 -35
- package/rules/python/tooling/main.mjs +0 -45
- package/rules/python/tooling/tooling.mdc +0 -22
- package/rules/rust/applies/concern.json +0 -4
- package/rules/rust/applies/docs/index.md +0 -11
- package/rules/rust/applies/docs/main.md +0 -30
- package/rules/rust/applies/main.mjs +0 -28
- package/rules/rust/check/check.mdc +0 -16
- package/rules/rust/check/concern.json +0 -7
- package/rules/rust/check/docs/fix-check.md +0 -30
- package/rules/rust/check/docs/index.md +0 -11
- package/rules/rust/check/docs/main.md +0 -37
- package/rules/rust/check/fix-check.mjs +0 -79
- package/rules/rust/check/main.mjs +0 -81
- package/rules/rust/docs/index.md +0 -11
- package/rules/rust/lib/docs/has-cargo-toml.md +0 -134
- package/rules/rust/lib/docs/index.md +0 -11
- package/rules/rust/lib/has-cargo-toml.mjs +0 -37
- package/rules/rust/main.json +0 -1
- package/rules/rust/main.mdc +0 -8
- package/rules/rust/package_json/concern.json +0 -10
- package/rules/rust/package_json/package_json.mdc +0 -12
- package/rules/rust/package_json/package_json.rego +0 -20
- package/rules/rust/vscode_extensions/concern.json +0 -11
- package/rules/rust/vscode_extensions/docs/fix-vscode_extensions.md +0 -25
- package/rules/rust/vscode_extensions/docs/index.md +0 -11
- package/rules/rust/vscode_extensions/fix-vscode_extensions.mjs +0 -1
- package/rules/rust/vscode_extensions/template/extensions.json.snippet.json +0 -1
- package/rules/rust/vscode_extensions/vscode_extensions.mdc +0 -9
- package/rules/rust/vscode_extensions/vscode_extensions.rego +0 -15
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lint-поверхня python/project: read-only detector (`uv lock --check` + `uv sync --frozen` +
|
|
3
|
-
* `pip-licenses`), перейменовано з колишнього bundled `python/check` (spec
|
|
4
|
-
* docs/specs/2026-07-02-text-check-per-file-split-design.md §5-A). `full`, без `lint.glob` —
|
|
5
|
-
* lockfile-аудит і ліцензійна перевірка project-wide за природою, не входять у delta-план
|
|
6
|
-
* (§5): спрацьовують лише через `n-rules lint --full` або scoped `n-rules lint python`.
|
|
7
|
-
*/
|
|
8
|
-
import { spawnSync } from 'node:child_process'
|
|
9
|
-
import { existsSync } from 'node:fs'
|
|
10
|
-
import { join } from 'node:path'
|
|
11
|
-
|
|
12
|
-
import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
|
|
13
|
-
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
14
|
-
import { getBronzeAndAbove, isSpdxAllowed } from '../../../scripts/lib/blue-oak.mjs'
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* @param {string} label назва кроку.
|
|
18
|
-
* @param {string} cmd команда для запуску.
|
|
19
|
-
* @param {string[]} args аргументи команди.
|
|
20
|
-
* @param {string} cwd робочий каталог.
|
|
21
|
-
* @param {(msg: string, reason: string) => void} fail колбек реєстрації порушення.
|
|
22
|
-
* @param {string} reason машиночитна причина порушення.
|
|
23
|
-
* @returns {boolean} true якщо OK
|
|
24
|
-
*/
|
|
25
|
-
function runTool(label, cmd, args, cwd, fail, reason) {
|
|
26
|
-
const r = spawnSync(cmd, args, { cwd, encoding: 'utf8', shell: false })
|
|
27
|
-
if (r.status === 0) return true
|
|
28
|
-
const code = typeof r.status === 'number' ? r.status : 1
|
|
29
|
-
const out = `${r.stdout ?? ''}${r.stderr ?? ''}`.trim().slice(0, 2000)
|
|
30
|
-
const outSuffix = out ? `\n${out}` : ''
|
|
31
|
-
fail(`lint-python: ${label} — помилка (код ${code}, python.mdc)${outSuffix}`, reason)
|
|
32
|
-
return false
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* @param {string} uv шлях до бінарника uv.
|
|
37
|
-
* @param {string} tool ім'я інструменту в uv-середовищі.
|
|
38
|
-
* @returns {boolean} true якщо інструмент доступний
|
|
39
|
-
*/
|
|
40
|
-
function uvToolAvailable(uv, tool) {
|
|
41
|
-
const r = spawnSync(uv, ['run', '--frozen', tool, '--version'], { stdio: 'ignore', shell: false })
|
|
42
|
-
return r.status === 0
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Перевірка ліцензій залежностей через pip-licenses (read-only).
|
|
47
|
-
* @param {string} uv шлях до бінарника uv.
|
|
48
|
-
* @param {string} cwd робочий каталог.
|
|
49
|
-
* @param {(msg: string, reason: string) => void} fail колбек реєстрації порушення.
|
|
50
|
-
* @returns {boolean} true якщо OK / пропущено
|
|
51
|
-
*/
|
|
52
|
-
function checkPipLicenses(uv, cwd, fail) {
|
|
53
|
-
if (!uvToolAvailable(uv, 'pip-licenses')) return true // недоступний → пропущено
|
|
54
|
-
const r = spawnSync(uv, ['run', '--frozen', 'pip-licenses', '--from=mixed', '--format=spdx-json'], {
|
|
55
|
-
cwd,
|
|
56
|
-
encoding: 'utf8',
|
|
57
|
-
shell: false
|
|
58
|
-
})
|
|
59
|
-
if (r.status !== 0) {
|
|
60
|
-
fail('lint-python: pip-licenses — помилка виконання', 'pip-licenses-error')
|
|
61
|
-
return false
|
|
62
|
-
}
|
|
63
|
-
const allowed = getBronzeAndAbove()
|
|
64
|
-
let doc
|
|
65
|
-
try {
|
|
66
|
-
doc = JSON.parse(r.stdout)
|
|
67
|
-
} catch {
|
|
68
|
-
doc = null
|
|
69
|
-
}
|
|
70
|
-
const packages = doc?.packages ?? []
|
|
71
|
-
const violations = packages.filter(pkg => {
|
|
72
|
-
const lic = pkg.licenseDeclared ?? pkg.licenseConcluded ?? 'NOASSERTION'
|
|
73
|
-
return !isSpdxAllowed(lic, allowed)
|
|
74
|
-
})
|
|
75
|
-
if (violations.length > 0) {
|
|
76
|
-
const list = violations
|
|
77
|
-
.map(
|
|
78
|
-
pkg =>
|
|
79
|
-
` ✗ ${pkg.name}@${pkg.versionInfo ?? '?'}: ${pkg.licenseDeclared ?? pkg.licenseConcluded ?? 'NOASSERTION'}`
|
|
80
|
-
)
|
|
81
|
-
.join('\n')
|
|
82
|
-
fail(
|
|
83
|
-
`lint-python: pip-licenses — ${violations.length} пакет(ів) поза Blue Oak Bronze+ (python.mdc)\n${list}`,
|
|
84
|
-
'license-violation'
|
|
85
|
-
)
|
|
86
|
-
return false
|
|
87
|
-
}
|
|
88
|
-
return true
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Detector python/project (read-only).
|
|
93
|
-
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту.
|
|
94
|
-
* @returns {import('../../../scripts/lib/lint-surface/types.mjs').LintResult} результат із порушеннями
|
|
95
|
-
*/
|
|
96
|
-
export function lint(ctx) {
|
|
97
|
-
const reporter = createViolationReporter(ctx)
|
|
98
|
-
const { fail } = reporter
|
|
99
|
-
const cwd = ctx.cwd
|
|
100
|
-
|
|
101
|
-
if (!existsSync(join(cwd, 'pyproject.toml'))) return reporter.result()
|
|
102
|
-
|
|
103
|
-
const uv = resolveCmd('uv')
|
|
104
|
-
if (!uv) {
|
|
105
|
-
fail('lint-python: `uv` не знайдено в PATH (потрібен при наявному pyproject.toml, python.mdc)', 'uv-missing')
|
|
106
|
-
return reporter.result()
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if (!runTool('uv lock --check', uv, ['lock', '--check'], cwd, fail, 'uv-lock-violation')) return reporter.result()
|
|
110
|
-
if (!runTool('uv sync --frozen', uv, ['sync', '--frozen'], cwd, fail, 'uv-sync-violation')) return reporter.result()
|
|
111
|
-
|
|
112
|
-
checkPipLicenses(uv, cwd, fail)
|
|
113
|
-
|
|
114
|
-
return reporter.result()
|
|
115
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
## Rego-gate: перевірка `pyproject.toml`
|
|
2
|
-
|
|
3
|
-
Rego-пакет: `python.pyproject_toml`
|
|
4
|
-
|
|
5
|
-
Цільовий файл: `pyproject.toml`
|
|
6
|
-
|
|
7
|
-
Дві групи правил:
|
|
8
|
-
|
|
9
|
-
**1. Заборона Poetry** — перевіряє заборонені під-таблиці `[tool.*]` за deny-template (drift-safe через `--data template`): [pyproject.toml.deny.toml](./template/pyproject.toml.deny.toml)
|
|
10
|
-
|
|
11
|
-
**2. PEP 621** — метадані проєкту мають бути у секції **`[project]`** (PEP 621), а **не** в `[tool.poetry]`. Обовʼязкові поля:
|
|
12
|
-
|
|
13
|
-
- `[project].name` — назва пакета (непорожній рядок);
|
|
14
|
-
- `[project].version` — статична версія (непорожній рядок);
|
|
15
|
-
- `[project].requires-python` — мінімальна версія Python (наприклад `>=3.12`);
|
|
16
|
-
- `[project].dependencies` — залежності (навіть порожній список `[]`).
|
|
17
|
-
|
|
18
|
-
Канонічний цільовий вигляд: [pyproject.toml.snippet.toml](./template/pyproject.toml.snippet.toml)
|
|
19
|
-
|
|
20
|
-
## Залежності та lock-файл (uv)
|
|
21
|
-
|
|
22
|
-
Залежності додаються командою `uv add <pkg>`; dev-залежності — `uv add --dev <pkg>`. Lock-файл — **`uv.lock`** (іде в коміт, оновлюється командою `uv lock`).
|
|
23
|
-
|
|
24
|
-
## Міграція з Poetry на uv
|
|
25
|
-
|
|
26
|
-
1. Прибери `[tool.poetry]` і `poetry.lock` / `poetry.toml`.
|
|
27
|
-
2. Перенеси метадані в `[project]` (name, version, requires-python, dependencies) за PEP 621.
|
|
28
|
-
3. Згенеруй lock: `uv lock` → `uv.lock`.
|
|
29
|
-
4. Dev-залежності: `uv add --dev ruff mypy …`.
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
# Перевірка `pyproject.toml` (python.mdc).
|
|
2
|
-
#
|
|
3
|
-
# Канон надходить через --data: { "template": { "deny": ... } }
|
|
4
|
-
# Структура --data сформована з template/pyproject.toml.deny.toml.
|
|
5
|
-
# FS-перевірки (`poetry.lock`, `poetry.toml`, `uv.lock`, `package.json`) — у JS.
|
|
6
|
-
#
|
|
7
|
-
# Дві групи правил:
|
|
8
|
-
# 1. Заборона Poetry — `[tool.poetry]` (та інші заборонені під-таблиці `tool`)
|
|
9
|
-
# керується deny-template, drift-safe.
|
|
10
|
-
# 2. PEP 621 — `[project].name` і `[project].version` обовʼязкові (структурна
|
|
11
|
-
# вимога без канонічного літералу, тому inline).
|
|
12
|
-
package python.pyproject_toml
|
|
13
|
-
|
|
14
|
-
import rego.v1
|
|
15
|
-
|
|
16
|
-
# ── Заборона Poetry (deny-template керує переліком) ──────────────────────────
|
|
17
|
-
|
|
18
|
-
deny contains msg if {
|
|
19
|
-
some key, reason in object.get(data.template.deny, "tool", {})
|
|
20
|
-
key in object.keys(object.get(input, "tool", {}))
|
|
21
|
-
msg := sprintf("pyproject.toml: [tool.%s] — %s", [key, reason])
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
# ── PEP 621: обовʼязкові [project].* ─────────────────────────────────────────
|
|
25
|
-
|
|
26
|
-
deny contains msg if {
|
|
27
|
-
not project_field_set("name")
|
|
28
|
-
msg := "pyproject.toml: відсутній [project].name (PEP 621 — мігруй з [tool.poetry], python.mdc)"
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
deny contains msg if {
|
|
32
|
-
not project_field_set("version")
|
|
33
|
-
msg := "pyproject.toml: відсутній статичний [project].version (PEP 621, python.mdc)"
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
deny contains msg if {
|
|
37
|
-
not project_field_set("requires-python")
|
|
38
|
-
msg := "pyproject.toml: відсутній [project].requires-python (наприклад '>=3.12') (PEP 621, python.mdc)"
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
deny contains msg if {
|
|
42
|
-
not project_key_exists("dependencies")
|
|
43
|
-
msg := "pyproject.toml: відсутній [project].dependencies (навіть порожній список `[]`) (PEP 621, python.mdc)"
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
project_field_set(key) if {
|
|
47
|
-
value := object.get(object.get(input, "project", {}), key, "")
|
|
48
|
-
value != ""
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
project_key_exists(key) if {
|
|
52
|
-
key in object.keys(object.get(input, "project", {}))
|
|
53
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# Канонічний цільовий вигляд після міграції з Poetry на uv (PEP 621).
|
|
2
|
-
# Метадані — у [project] (а не [tool.poetry]); dev-залежності додавай через
|
|
3
|
-
# `uv add --dev <pkg>` (uv тримає їх у [dependency-groups].dev або [tool.uv]).
|
|
4
|
-
[project]
|
|
5
|
-
name = "your-package"
|
|
6
|
-
version = "0.1.0"
|
|
7
|
-
requires-python = ">=3.12"
|
|
8
|
-
dependencies = []
|
|
9
|
-
|
|
10
|
-
[build-system]
|
|
11
|
-
requires = ["hatchling"]
|
|
12
|
-
build-backend = "hatchling.build"
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: fix-ruff.mjs
|
|
4
|
-
resource: npm/rules/python/ruff/fix-ruff.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: c2dc5eb6
|
|
7
|
-
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
-
tier: local-min
|
|
9
|
-
score: 100
|
|
10
|
-
issues: judge:inaccurate:0.99
|
|
11
|
-
judgeModel: openai-codex/gpt-5.4-mini
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Огляд
|
|
15
|
-
|
|
16
|
-
T0-autofix для `python/ruff` забезпечує детерміновані виправлення та форматування файлів проєкту (`ruff check --fix` та `ruff format`), якщо інструмент `uv` доступний. Його призначення — стандартизувати код, порівнюючи зміни, внесені через автоматичні інструменти, з початковим вмістом.
|
|
17
|
-
|
|
18
|
-
## Поведінка
|
|
19
|
-
|
|
20
|
-
Поведінка
|
|
21
|
-
1. Перевіряє, чи доступна команда `uv`. Якщо ні, жодних дій не виконує.
|
|
22
|
-
2. Визначає список усіх файлів `.py` у проєкті, використовуючи інструмент `git`.
|
|
23
|
-
3. Зберігає поточний вміст усіх знайдених `.py` файлів.
|
|
24
|
-
4. Виконує команду `ruff check --fix` у всіх файлах проєкту, щоб автоматично виправити порушення.
|
|
25
|
-
5. Виконує команду `ruff format` у всіх файлах проєкту, щоб застосувати стандарт форматування.
|
|
26
|
-
6. Порівнює поточний вміст файлів із вмістом до виправлення.
|
|
27
|
-
7. Якщо вміст файлу змінився, цей файл позначається як змінений.
|
|
28
|
-
8. Якщо були змінені файли, результат повідомляється, а ці файли реєструються як змінені.
|
|
29
|
-
|
|
30
|
-
## Гарантії поведінки
|
|
31
|
-
|
|
32
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
|
33
|
-
- Перехоплює помилки і не пропускає винятків назовні (fail-safe).
|
|
34
|
-
- За певних помилок повертає порожнє значення (напр. `null`) замість винятку.
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: main.mjs
|
|
4
|
-
resource: npm/rules/python/ruff/main.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: 00e5708a
|
|
7
|
-
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
-
score: 100
|
|
9
|
-
issues: judge:inaccurate:0.98
|
|
10
|
-
judgeModel: openai-codex/gpt-5.4-mini
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Огляд
|
|
14
|
-
|
|
15
|
-
Цей детектор працює у **read-only** режимі та здійснює перевірку форматування та синтаксису Python-коду в заданому робочому каталозі. Він використовує `ruff` (зокрема, `ruff check` та `ruff format --check`) через `uv run --frozen` для аналізу цільових файлів, гарантуючи відповідність коду правилам, визначеним у `pyproject.toml`. Детектор аналізує наданий набір файлів (`ctx.files`) або весь проєкт (`.`), використовуючи транзитивне підвантаження імпортованих модулів для коректної перевірки. Результат містить зареєстровані порушення, виявлені під час перевірки.
|
|
16
|
-
|
|
17
|
-
## Поведінка
|
|
18
|
-
|
|
19
|
-
1. Якщо у робочому каталозі відсутній файл `pyproject.toml`, обробка припиняється.
|
|
20
|
-
2. Визначаються цільові файли для аналізу: або наданий список файлів, або всі файли у робочому каталозі з розширенням `.py`.
|
|
21
|
-
3. Якщо цільових файлів немає, обробка припиняється.
|
|
22
|
-
4. Перевіряється доступність бінарника `uv` у системному шляху. Якщо його немає, реєстрація порушення про помилку з `uv` і обробка припиняється.
|
|
23
|
-
5. Перевіряється доступність інструменту `ruff` у середовищі `uv`. Якщо він недоступний, обробка припиняється.
|
|
24
|
-
6. Викликається `lint` для виконання перевірки синтаксису та логіки за допомогою `ruff check` для всіх цільових файлів.
|
|
25
|
-
7. Якщо `ruff check` завершується з помилкою, це фіксується як порушення.
|
|
26
|
-
8. Викликається `lint` для перевірки форматування коду за допомогою `ruff format --check` для всіх цільових файлів.
|
|
27
|
-
9. Результат аналізу повертається з зареєстрованими порушеннями.
|
|
28
|
-
|
|
29
|
-
## Публічний API
|
|
30
|
-
|
|
31
|
-
lint — виявляє проблеми у коді за допомогою парсера python/ruff (только читання).
|
|
32
|
-
|
|
33
|
-
## Гарантії поведінки
|
|
34
|
-
|
|
35
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* T0-autofix для `python/ruff` — детерміновані `ruff check --fix` + `ruff format` (через
|
|
3
|
-
* `uv run --frozen`), перенесено з колишнього `python/check/fix-check.mjs`
|
|
4
|
-
* (spec docs/specs/2026-07-02-text-check-per-file-split-design.md "Рішення python/php/rego").
|
|
5
|
-
* Відсутній `uv` → no-op.
|
|
6
|
-
*/
|
|
7
|
-
import { spawnSync } from 'node:child_process'
|
|
8
|
-
import { readFileSync } from 'node:fs'
|
|
9
|
-
import { resolve } from 'node:path'
|
|
10
|
-
|
|
11
|
-
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Вміст файлу або null, якщо не читається.
|
|
15
|
-
* @param {string} abs абсолютний шлях
|
|
16
|
-
* @returns {string|null} вміст або null
|
|
17
|
-
*/
|
|
18
|
-
function readOrNull(abs) {
|
|
19
|
-
try {
|
|
20
|
-
return readFileSync(abs, 'utf8')
|
|
21
|
-
} catch {
|
|
22
|
-
return null
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Tracked *.py файли проєкту (через git).
|
|
28
|
-
* @param {string} cwd корінь
|
|
29
|
-
* @returns {string[]} posix-relative шляхи
|
|
30
|
-
*/
|
|
31
|
-
function listPyFiles(cwd) {
|
|
32
|
-
const r = spawnSync('git', ['ls-files', '-z', '--', '*.py'], { cwd, encoding: 'utf8' })
|
|
33
|
-
if (r.status !== 0) return []
|
|
34
|
-
return (r.stdout ?? '').split('\0').filter(Boolean)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/** @type {import('../../../scripts/lib/lint-surface/types.mjs').T0Pattern[]} */
|
|
38
|
-
export const patterns = [
|
|
39
|
-
{
|
|
40
|
-
id: 'python-ruff-fix',
|
|
41
|
-
standalone: true, // §8 Phase 2: ruff check --fix + format самі ре-аналізують, test() не потрібен
|
|
42
|
-
test: violations =>
|
|
43
|
-
violations.some(v => v.reason === 'ruff-check-violation' || v.reason === 'ruff-format-violation'),
|
|
44
|
-
apply: (violations, ctx) => {
|
|
45
|
-
const uv = resolveCmd('uv')
|
|
46
|
-
if (!uv) return { touchedFiles: [] }
|
|
47
|
-
const files = listPyFiles(ctx.cwd)
|
|
48
|
-
if (files.length === 0) return { touchedFiles: [] }
|
|
49
|
-
|
|
50
|
-
const abs = files.map(f => resolve(ctx.cwd, f))
|
|
51
|
-
const before = new Map(abs.map(a => [a, readOrNull(a)]))
|
|
52
|
-
const opts = { cwd: ctx.cwd, encoding: 'utf8', shell: false }
|
|
53
|
-
spawnSync(uv, ['run', '--frozen', 'ruff', 'check', '--fix', '.'], opts)
|
|
54
|
-
spawnSync(uv, ['run', '--frozen', 'ruff', 'format', '.'], opts)
|
|
55
|
-
|
|
56
|
-
const touchedFiles = abs.filter(a => readOrNull(a) !== before.get(a))
|
|
57
|
-
for (const a of touchedFiles) ctx.recordWrite?.(a)
|
|
58
|
-
return touchedFiles.length > 0
|
|
59
|
-
? { touchedFiles, message: `ruff check --fix + format: ${touchedFiles.length} файл(ів)` }
|
|
60
|
-
: { touchedFiles: [] }
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
]
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lint-поверхня python/ruff: read-only detector (`ruff check` + `ruff format --check`, через
|
|
3
|
-
* `uv run --frozen`). Per-file: приймає `ctx.files`, інакше `.` (весь проєкт). Виділено з
|
|
4
|
-
* колишнього bundled `python/check` (spec docs/specs/2026-07-02-text-check-per-file-split-design.md
|
|
5
|
-
* "Рішення python/php/rego") — ruff сам транзитивно підвантажує імпортовані модулі
|
|
6
|
-
* (follow-imports), тож коректний і на підмножині переданих файлів.
|
|
7
|
-
*/
|
|
8
|
-
import { spawnSync } from 'node:child_process'
|
|
9
|
-
|
|
10
|
-
import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
|
|
11
|
-
import { preparePythonRun } from '../lib/uv-run.mjs'
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* @param {string} label назва кроку.
|
|
15
|
-
* @param {string} uv шлях до бінарника uv.
|
|
16
|
-
* @param {string[]} args аргументи ruff (без `uv run --frozen ruff`-префіксу).
|
|
17
|
-
* @param {string} cwd робочий каталог.
|
|
18
|
-
* @param {(msg: string, opts: object) => void} fail колбек реєстрації порушення.
|
|
19
|
-
* @param {string} reason машиночитна причина порушення.
|
|
20
|
-
* @returns {boolean} true якщо OK
|
|
21
|
-
*/
|
|
22
|
-
function runRuffStep(label, uv, args, cwd, fail, reason) {
|
|
23
|
-
const r = spawnSync(uv, ['run', '--frozen', 'ruff', ...args], { cwd, encoding: 'utf8', shell: false })
|
|
24
|
-
if (r.status === 0) return true
|
|
25
|
-
const code = typeof r.status === 'number' ? r.status : 1
|
|
26
|
-
const out = `${r.stdout ?? ''}${r.stderr ?? ''}`.trim().slice(0, 2000)
|
|
27
|
-
const outSuffix = out ? `\n${out}` : ''
|
|
28
|
-
fail(`lint-python: ${label} — помилка (код ${code}, python.mdc)${outSuffix}`, reason)
|
|
29
|
-
return false
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Detector python/ruff (read-only).
|
|
34
|
-
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту.
|
|
35
|
-
* @returns {import('../../../scripts/lib/lint-surface/types.mjs').LintResult} результат із порушеннями
|
|
36
|
-
*/
|
|
37
|
-
export function lint(ctx) {
|
|
38
|
-
const reporter = createViolationReporter(ctx)
|
|
39
|
-
const { fail } = reporter
|
|
40
|
-
const cwd = ctx.cwd
|
|
41
|
-
|
|
42
|
-
const prepared = preparePythonRun(ctx, fail, 'ruff')
|
|
43
|
-
if (!prepared) return reporter.result()
|
|
44
|
-
const { uv, targets } = prepared
|
|
45
|
-
|
|
46
|
-
if (!runRuffStep('ruff check', uv, ['check', ...targets], cwd, fail, 'ruff-check-violation')) {
|
|
47
|
-
return reporter.result()
|
|
48
|
-
}
|
|
49
|
-
runRuffStep('ruff format --check', uv, ['format', '--check', ...targets], cwd, fail, 'ruff-format-violation')
|
|
50
|
-
|
|
51
|
-
return reporter.result()
|
|
52
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://unpkg.com/@7n/rules/schemas/concern.json",
|
|
3
|
-
"fixability": "config",
|
|
4
|
-
"lint": {
|
|
5
|
-
"scope": "full",
|
|
6
|
-
"glob": [
|
|
7
|
-
"pyproject.toml",
|
|
8
|
-
"uv.lock",
|
|
9
|
-
"poetry.lock",
|
|
10
|
-
"poetry.toml",
|
|
11
|
-
"package.json",
|
|
12
|
-
".github/workflows/lint-python.yml"
|
|
13
|
-
]
|
|
14
|
-
}
|
|
15
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: main.mjs
|
|
4
|
-
resource: npm/rules/python/tooling/main.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: 98ec5b8e
|
|
7
|
-
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
-
score: 90
|
|
9
|
-
issues: surzhik,judge:inaccurate:0.98
|
|
10
|
-
judgeModel: openai-codex/gpt-5.4-mini
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Огляд
|
|
14
|
-
|
|
15
|
-
Цей файл відповідає за перевірку відповідності проєкту встановленим правилам, визначеним у `python.mdc`. Він підтверджує наявність ключових конфігураційних файлів, зокрема `package.json`, що визначає залежності проекту. Дозволена функціональність обмежена лише читанням файлової системи та бази даних; жодних операцій запису в ці ресурси не виконується. Основна логіка роботи реалізована у публічній функції `main`.
|
|
16
|
-
|
|
17
|
-
## Поведінка
|
|
18
|
-
|
|
19
|
-
main виявляє відповідність проєкту правилам (python.mdc) за наявності необхідних файлів та конфігурацій.
|
|
20
|
-
|
|
21
|
-
1. Перевіряє наявність `pyproject.toml` у корені.
|
|
22
|
-
2. Перевіряє наявність `uv.lock`, повідомляючи про необхідність його генерації, якщо він відсутній.
|
|
23
|
-
3. Перевіряє відсутність артефактів Poetry (`poetry.lock`, `poetry.toml`), оскільки підтримується лише `uv` (python.mdc).
|
|
24
|
-
4. Перевіряє наявність `package.json` у корені.
|
|
25
|
-
5. Перевіряє наявність файлу робочого процесу `.github/workflows/lint-python.yml`, необхідного для відповідності (python.mdc).
|
|
26
|
-
Не перевіряє шляхи, що містять `.github` або `.git`.
|
|
27
|
-
|
|
28
|
-
## Публічний API
|
|
29
|
-
|
|
30
|
-
main — перевіряє, чи відповідає проєкт вимогам, визначеним у правилах `python.mdc`.
|
|
31
|
-
|
|
32
|
-
## Гарантії поведінки
|
|
33
|
-
|
|
34
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
|
35
|
-
- Свідомо пропускає шляхи: `.github`, `.git`.
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/** @see ./docs/tooling.md */
|
|
2
|
-
import { existsSync } from 'node:fs'
|
|
3
|
-
import { join } from 'node:path'
|
|
4
|
-
|
|
5
|
-
import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Перевіряє відповідність проєкту правилам python.mdc.
|
|
9
|
-
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту.
|
|
10
|
-
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат із порушеннями
|
|
11
|
-
*/
|
|
12
|
-
export function lint(ctx) {
|
|
13
|
-
const cwd = ctx.cwd
|
|
14
|
-
const reporter = createViolationReporter(ctx)
|
|
15
|
-
const { pass, fail } = reporter
|
|
16
|
-
|
|
17
|
-
if (!existsSync(join(cwd, 'pyproject.toml'))) {
|
|
18
|
-
return Promise.resolve(reporter.result())
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (existsSync(join(cwd, 'uv.lock'))) {
|
|
22
|
-
pass('uv.lock є')
|
|
23
|
-
} else {
|
|
24
|
-
fail('uv.lock не знайдено — згенеруй `uv lock` (python.mdc, без Poetry)')
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Poetry-артефакти заборонені: uv є єдиним пакет-менеджером (python.mdc).
|
|
28
|
-
for (const poetryFile of ['poetry.lock', 'poetry.toml']) {
|
|
29
|
-
if (existsSync(join(cwd, poetryFile))) {
|
|
30
|
-
fail(`${poetryFile} знайдено — прибери Poetry, мігруй на uv (python.mdc)`)
|
|
31
|
-
} else {
|
|
32
|
-
pass(`${poetryFile} відсутній`)
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (existsSync(join(cwd, 'package.json'))) {
|
|
37
|
-
pass('package.json є')
|
|
38
|
-
} else {
|
|
39
|
-
fail('package.json не знайдено в корені — додай (python.mdc)')
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Existence/структуру lint-python.yml вимагає провайдер-плагін @7n/rules-ci-github
|
|
43
|
-
// (mixin python/lint_python_yml) — ядро провайдер-агностичне.
|
|
44
|
-
return Promise.resolve(reporter.result())
|
|
45
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
## Перевірка наявності uv-toolchain і відсутності Poetry
|
|
2
|
-
|
|
3
|
-
JS-перевірка (`npm/rules/python/tooling/main.mjs`) запускається, якщо в корені репо є `pyproject.toml`. Перевіряє:
|
|
4
|
-
|
|
5
|
-
- `uv.lock` — має існувати (зафіксувати командою `uv lock`);
|
|
6
|
-
- `poetry.lock` / `poetry.toml` — мають **бути відсутніми** (Poetry заборонено);
|
|
7
|
-
- `package.json` — має бути у корені (js-обгортка lint є частиною монорепо);
|
|
8
|
-
- `.github/workflows/lint-python.yml` — має існувати (структуру перевіряє Rego-полісі `python.lint_python_yml`).
|
|
9
|
-
|
|
10
|
-
Якщо `pyproject.toml` відсутній — перевірка пропускається з кодом 0 (проєкт не Python).
|
|
11
|
-
|
|
12
|
-
## lint-python: JS-детектори за concern
|
|
13
|
-
|
|
14
|
-
Інструменти uv-екосистеми не мають єдиного CLI-обходу репо, тому python-лінт делегується у JS-детектори. Запуск — через **`n-rules lint python`** (CI — `--no-fix`); окремого `package.json`-скрипта немає.
|
|
15
|
-
|
|
16
|
-
Три концерни (кожен — окремий per-file чи project-wide детектор):
|
|
17
|
-
|
|
18
|
-
- `npm/rules/python/project/main.mjs` — `uv lock --check` + `uv sync --frozen` + ліцензійний аудит (`pip-licenses`); project-wide, поза delta-планом (лише `n-rules lint --full` або scoped `n-rules lint python`);
|
|
19
|
-
- `npm/rules/python/ruff/main.mjs` (+ `fix-ruff.mjs`) — `ruff check` + `ruff format --check` (детект), `ruff check --fix` + `ruff format` (autofix); per-file;
|
|
20
|
-
- `npm/rules/python/mypy/main.mjs` — `mypy` (лише детект, немає autofix); per-file.
|
|
21
|
-
|
|
22
|
-
Якщо `pyproject.toml` у корені відсутній — усі концерни виходять без порушень (проєкт не Python). Якщо `pyproject.toml` є, але `uv` не знайдено в PATH — це помилка. `ruff`/`mypy`-кроки запускаються лише якщо інструмент доступний у середовищі (інакше крок пропускається з повідомленням).
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: main.mjs
|
|
4
|
-
resource: npm/rules/rust/applies/main.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: 2d2dcbac
|
|
7
|
-
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
-
score: 100
|
|
9
|
-
issues: judge:inaccurate:0.97
|
|
10
|
-
judgeModel: openai-codex/gpt-5.4-mini
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Огляд
|
|
14
|
-
|
|
15
|
-
Функціональність визначає, чи підходить даний каталог для застосування правил. Публічна функція `applies` здійснює цей аналіз, тоді як функція `main` ініціює процес повної перевірки, звітуючи про результати застосування правил до каталогу. Сканування каталогу ігнорує системні та залежностні каталоги, такі як `.git` та `node_modules`, а також конфігураційний файл `Cargo.toml`.
|
|
16
|
-
|
|
17
|
-
## Поведінка
|
|
18
|
-
|
|
19
|
-
Поведінка:
|
|
20
|
-
applies визначає, чи є правило застосовним до поточного каталогу, перевіряючи наявність файлу Cargo.toml або його присутності у підкаталогах, і свідомо ігнорує каталоги .git, node_modules та .next.
|
|
21
|
-
main виконує логіку перевірки, ініціалізує репортер та інформує про застосування правил Rust, повертаючи код завершення.
|
|
22
|
-
|
|
23
|
-
## Публічний API
|
|
24
|
-
|
|
25
|
-
Будь ласка, надайте код або список елементів коду, які потрібно задокументувати.
|
|
26
|
-
|
|
27
|
-
## Гарантії поведінки
|
|
28
|
-
|
|
29
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
|
30
|
-
- Свідомо пропускає шляхи: `.git`, `node_modules`.
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/** @see ./docs/applies.md */
|
|
2
|
-
import { existsSync } from 'node:fs'
|
|
3
|
-
import { join } from 'node:path'
|
|
4
|
-
|
|
5
|
-
import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
|
|
6
|
-
|
|
7
|
-
import { hasCargoTomlInTree } from '../lib/has-cargo-toml.mjs'
|
|
8
|
-
|
|
9
|
-
const IGNORED_DIR_NAMES = new Set(['node_modules', '.git', '.next', '.turbo'])
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @param {string} [cwd] корінь репозиторію
|
|
13
|
-
* @returns {Promise<boolean>} `true` — правило застосовне; `false` — пропустити
|
|
14
|
-
*/
|
|
15
|
-
export function applies(cwd = process.cwd()) {
|
|
16
|
-
if (existsSync(join(cwd, 'Cargo.toml'))) return Promise.resolve(true)
|
|
17
|
-
return Promise.resolve(hasCargoTomlInTree(cwd, IGNORED_DIR_NAMES))
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту.
|
|
22
|
-
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат context-pass
|
|
23
|
-
*/
|
|
24
|
-
export function lint(ctx) {
|
|
25
|
-
const reporter = createViolationReporter(ctx)
|
|
26
|
-
reporter.pass('Знайдено Cargo.toml — застосовуємо правила rust.mdc')
|
|
27
|
-
return Promise.resolve(reporter.result())
|
|
28
|
-
}
|