@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
|
@@ -44,7 +44,6 @@
|
|
|
44
44
|
* незалежно від verbosity) і виводить у stdout окреме попередження на кожен такий файл із порадою
|
|
45
45
|
* додати схему в `npm/schemas/v8r-catalog.json`.
|
|
46
46
|
*/
|
|
47
|
-
import { spawnSync } from 'node:child_process'
|
|
48
47
|
import { existsSync, readFileSync, writeFileSync } from 'node:fs'
|
|
49
48
|
import { tmpdir } from 'node:os'
|
|
50
49
|
import { basename, delimiter, dirname, isAbsolute, join } from 'node:path'
|
|
@@ -53,6 +52,7 @@ import { fileURLToPath } from 'node:url'
|
|
|
53
52
|
|
|
54
53
|
import { isRunAsCli } from '../../../scripts/cli-entry.mjs'
|
|
55
54
|
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
55
|
+
import { spawnAsync } from '../../../scripts/utils/spawn-async.mjs'
|
|
56
56
|
import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
|
|
57
57
|
|
|
58
58
|
/** Розширення, які валідує v8r — фільтр delta-списку файлів у `lint(ctx)`. */
|
|
@@ -183,31 +183,30 @@ export function stripBunNodeShimDirs(pathValue) {
|
|
|
183
183
|
* (`lint()`) для вбудовування у violation-повідомлення, яке бачить LLM fix-worker: без нього
|
|
184
184
|
* fix-ladder отримує лише "щось не пройшло" й не має шансів вгадати, що саме (спостережено —
|
|
185
185
|
* усі 4 rung-и незмінно падають у timeout на v8r-порушеннях).
|
|
186
|
+
* Async (не блокує event loop) — детектор може виконуватись у parallel lane `detectAll()`
|
|
187
|
+
* (ADR 260716-1354).
|
|
186
188
|
* @param {string[]} targets glob-и або конкретні шляхи файлів
|
|
187
189
|
* @param {string} configPath шлях до `V8R_CONFIG_FILE`
|
|
188
190
|
* @param {boolean} [verbose] друкувати повний raw stdout/stderr v8r при помилці; інакше — лише
|
|
189
191
|
* рядки `✖ …` без `ℹ`-шуму (Pre-warming the cache, Processing <file>, Found schema in …)
|
|
190
|
-
* @returns {{ exitError: true } | { exitError: false, code: number, detail: string }}
|
|
191
|
-
* spawn або код v8r (0/98 — трактує викликач) + деталь `✖ …`-рядків
|
|
192
|
+
* @returns {Promise<{ exitError: true } | { exitError: false, code: number, detail: string }>}
|
|
193
|
+
* помилка spawn або код v8r (0/98 — трактує викликач) + деталь `✖ …`-рядків
|
|
192
194
|
*/
|
|
193
|
-
function runOneV8rInvocation(targets, configPath, verbose = false) {
|
|
195
|
+
async function runOneV8rInvocation(targets, configPath, verbose = false) {
|
|
194
196
|
const bunPath = resolveCmd('bun') ?? process.execPath
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
if (result.error) {
|
|
204
|
-
process.stderr.write(`${result.error.message}\n`)
|
|
197
|
+
let result
|
|
198
|
+
try {
|
|
199
|
+
result = await spawnAsync(bunPath, ['x', 'v8r', ...targets], {
|
|
200
|
+
env: { ...env, PATH: stripBunNodeShimDirs(env.PATH), V8R_CONFIG_FILE: configPath }
|
|
201
|
+
})
|
|
202
|
+
} catch (error) {
|
|
203
|
+
process.stderr.write(`${error.message}\n`)
|
|
205
204
|
return { exitError: true }
|
|
206
205
|
}
|
|
207
206
|
|
|
208
207
|
warnAboutRemoteSchemaFallback(result.stderr ?? '')
|
|
209
208
|
|
|
210
|
-
const exitCode = result.
|
|
209
|
+
const exitCode = result.exitCode ?? 1
|
|
211
210
|
let detail = ''
|
|
212
211
|
if (exitCode !== 0 && exitCode !== 98) {
|
|
213
212
|
detail = extractFailureLines(`${result.stdout ?? ''}\n${result.stderr ?? ''}`)
|
|
@@ -225,12 +224,15 @@ function runOneV8rInvocation(targets, configPath, verbose = false) {
|
|
|
225
224
|
* Запускає послідовні виклики v8r по glob-ам (full-режим); не змінює process.exitCode.
|
|
226
225
|
* Один виклик на glob навмисно (не batch) — v8r падає з кодом 98, якщо хоч один переданий
|
|
227
226
|
* glob не знаходить файлів, і тоді решта розширень не перевіряються в тому ж виклику.
|
|
227
|
+
* Async (не блокує event loop) — детектор може виконуватись у parallel lane `detectAll()`
|
|
228
|
+
* (ADR 260716-1354). Виклики по glob-ам лишаються строго послідовними (не Promise.all) — той
|
|
229
|
+
* самий один-виклик-на-glob підхід, лише блокуючий spawnSync замінено на await у циклі.
|
|
228
230
|
* @param {string[]} [globs] патерни; за замовчуванням DEFAULT_V8R_GLOBS
|
|
229
231
|
* @param {boolean} [verbose] друкувати повний raw вивід v8r при помилці (див. runOneV8rInvocation)
|
|
230
|
-
* @returns {{ code: number, detail: string }} `code`: 0 — OK, 1 — помилка spawn, 2 — немає
|
|
232
|
+
* @returns {Promise<{ code: number, detail: string }>} `code`: 0 — OK, 1 — помилка spawn, 2 — немає
|
|
231
233
|
* каталогу схем, інше — код v8r; `detail` — рядки `✖ …` (порожньо, якщо `code` не про валідацію)
|
|
232
234
|
*/
|
|
233
|
-
export function runV8rWithGlobs(globs = DEFAULT_V8R_GLOBS, verbose = false) {
|
|
235
|
+
export async function runV8rWithGlobs(globs = DEFAULT_V8R_GLOBS, verbose = false) {
|
|
234
236
|
if (!existsSync(V8R_CATALOG_PATH)) {
|
|
235
237
|
process.stderr.write(
|
|
236
238
|
`run-v8r: не знайдено каталог схем за шляхом ${V8R_CATALOG_PATH} (очікується npm/schemas/v8r-catalog.json у пакеті)\n`
|
|
@@ -241,7 +243,7 @@ export function runV8rWithGlobs(globs = DEFAULT_V8R_GLOBS, verbose = false) {
|
|
|
241
243
|
const configPath = writeResolvedV8rConfig()
|
|
242
244
|
|
|
243
245
|
for (const pattern of globs) {
|
|
244
|
-
const r = runOneV8rInvocation([pattern], configPath, verbose)
|
|
246
|
+
const r = await runOneV8rInvocation([pattern], configPath, verbose)
|
|
245
247
|
if (r.exitError) return { code: 1, detail: '' }
|
|
246
248
|
if (r.code !== 0 && r.code !== 98) return { code: r.code, detail: r.detail }
|
|
247
249
|
}
|
|
@@ -251,12 +253,14 @@ export function runV8rWithGlobs(globs = DEFAULT_V8R_GLOBS, verbose = false) {
|
|
|
251
253
|
/**
|
|
252
254
|
* Запускає v8r по конкретному списку файлів (delta-режим) — один виклик, не по одному glob-у,
|
|
253
255
|
* бо кожен переданий шлях уже існує (не glob), тож код 98 "порожній glob" тут не виникає.
|
|
256
|
+
* Async (не блокує event loop) — детектор може виконуватись у parallel lane `detectAll()`
|
|
257
|
+
* (ADR 260716-1354).
|
|
254
258
|
* @param {string[]} files абсолютні або відносні до cwd v8r-процесу шляхи файлів
|
|
255
259
|
* @param {boolean} [verbose] друкувати повний raw вивід v8r при помилці (див. runOneV8rInvocation)
|
|
256
|
-
* @returns {{ code: number, detail: string }} `code`: 0 — OK, 1 — помилка spawn, 2 — немає
|
|
260
|
+
* @returns {Promise<{ code: number, detail: string }>} `code`: 0 — OK, 1 — помилка spawn, 2 — немає
|
|
257
261
|
* каталогу схем, інше — код v8r; `detail` — рядки `✖ …` (порожньо, якщо `code` не про валідацію)
|
|
258
262
|
*/
|
|
259
|
-
export function runV8rWithFiles(files, verbose = false) {
|
|
263
|
+
export async function runV8rWithFiles(files, verbose = false) {
|
|
260
264
|
if (files.length === 0) return { code: 0, detail: '' }
|
|
261
265
|
if (!existsSync(V8R_CATALOG_PATH)) {
|
|
262
266
|
process.stderr.write(
|
|
@@ -266,7 +270,7 @@ export function runV8rWithFiles(files, verbose = false) {
|
|
|
266
270
|
}
|
|
267
271
|
|
|
268
272
|
const configPath = writeResolvedV8rConfig()
|
|
269
|
-
const r = runOneV8rInvocation(files, configPath, verbose)
|
|
273
|
+
const r = await runOneV8rInvocation(files, configPath, verbose)
|
|
270
274
|
if (r.exitError) return { code: 1, detail: '' }
|
|
271
275
|
return { code: r.code === 98 ? 0 : r.code, detail: r.detail }
|
|
272
276
|
}
|
|
@@ -285,28 +289,29 @@ function v8rFailMessage(detail) {
|
|
|
285
289
|
/**
|
|
286
290
|
* Detector text/run-v8r: read-only v8r по `ctx.files` (delta) або за дефолтними glob-ами (full).
|
|
287
291
|
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст lint-прогону
|
|
288
|
-
* @returns {import('../../../scripts/lib/lint-surface/types.mjs').LintResult} результат detector-а
|
|
292
|
+
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат detector-а
|
|
289
293
|
*/
|
|
290
|
-
export function lint(ctx) {
|
|
294
|
+
export async function lint(ctx) {
|
|
291
295
|
const reporter = createViolationReporter(ctx)
|
|
292
296
|
const { fail } = reporter
|
|
293
297
|
|
|
294
298
|
const verbose = ctx.verbose === true
|
|
295
299
|
|
|
296
300
|
if (ctx.files === undefined) {
|
|
297
|
-
const { code, detail } = runV8rWithGlobs(DEFAULT_V8R_GLOBS, verbose)
|
|
301
|
+
const { code, detail } = await runV8rWithGlobs(DEFAULT_V8R_GLOBS, verbose)
|
|
298
302
|
if (code !== 0) fail(v8rFailMessage(detail), 'v8r')
|
|
299
303
|
return reporter.result()
|
|
300
304
|
}
|
|
301
305
|
|
|
302
306
|
const files = ctx.files.filter(f => V8R_EXT_RE.test(f))
|
|
303
307
|
if (files.length === 0) return reporter.result()
|
|
304
|
-
const { code, detail } = runV8rWithFiles(files, verbose)
|
|
308
|
+
const { code, detail } = await runV8rWithFiles(files, verbose)
|
|
305
309
|
if (code !== 0) fail(v8rFailMessage(detail), 'v8r')
|
|
306
310
|
return reporter.result()
|
|
307
311
|
}
|
|
308
312
|
|
|
309
313
|
if (isRunAsCli(import.meta.url)) {
|
|
310
314
|
const globs = process.argv.length > 2 ? process.argv.slice(2) : DEFAULT_V8R_GLOBS
|
|
311
|
-
|
|
315
|
+
const { code } = await runV8rWithGlobs(globs)
|
|
316
|
+
process.exitCode = code
|
|
312
317
|
}
|
|
@@ -3,7 +3,7 @@ type: JS Module
|
|
|
3
3
|
title: resolve-plugins.mjs
|
|
4
4
|
resource: npm/scripts/lib/resolve-plugins.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
6
|
+
crc: 17248373
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
Резолв плагінів @7n/rules: визначає, які пакети-плагіни активні у проєкті, де їхні `rules/`-каталоги, які capabilities вони надають і які handlers надають.
|
|
@@ -6,47 +6,18 @@
|
|
|
6
6
|
* `execSync` (прямо або через спільний helper), бо це блокує event loop цілком і
|
|
7
7
|
* зробило б паралельний пул ілюзорним.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* `
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
|
|
19
|
-
const DIRECT_SPAWN_CONCERNS = [
|
|
20
|
-
'text/run-dotenv-linter',
|
|
21
|
-
'text/oxfmt',
|
|
22
|
-
'text/cspell-fix',
|
|
23
|
-
'text/run-v8r',
|
|
24
|
-
'text/run-shellcheck',
|
|
25
|
-
'image-compress/check',
|
|
26
|
-
'php/phpcs',
|
|
27
|
-
'php/project',
|
|
28
|
-
'php/cs_fixer',
|
|
29
|
-
'js/jscpd_duplicates',
|
|
30
|
-
'k8s/manifests',
|
|
31
|
-
'style/lint',
|
|
32
|
-
'bun/licensee',
|
|
33
|
-
'python/ruff',
|
|
34
|
-
'python/project',
|
|
35
|
-
'python/mypy',
|
|
36
|
-
'security/scan',
|
|
37
|
-
'rust/check',
|
|
38
|
-
'rego/conftest_verify'
|
|
39
|
-
]
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Concern-и, чий detector сам не викликає `spawnSync`/`execSync`, але делегує спільному
|
|
43
|
-
* helper-у, який його викликає: `docker/lib/docker-hadolint.mjs` (hadolint) і
|
|
44
|
-
* `rego/lib/run-external-tool.mjs` (regal/opa).
|
|
9
|
+
* Список зараз порожній: усі 22 concern-и, що на момент ADR мали прямий чи
|
|
10
|
+
* shared-helper `spawnSync`/`execSync`, мігровано на `spawnAsync`
|
|
11
|
+
* (`npm/scripts/utils/spawn-async.mjs`). Інвентар лишається як живий guard —
|
|
12
|
+
* `tests/blocking-inventory.test.mjs` сканує активні concern-и репо і провалиться,
|
|
13
|
+
* щойно новий (чи regressed) concern звернеться до `spawnSync`/`execSync` без
|
|
14
|
+
* відповідного запису тут.
|
|
15
|
+
*
|
|
16
|
+
* Протокол для нового blocking concern-а: перевести на `spawnAsync` → оновити
|
|
17
|
+
* caller-и (`await`) → якщо міграція ще не завершена, додати запис сюди на час
|
|
18
|
+
* переходу; guard-тест сам підтвердить, коли можна прибрати.
|
|
45
19
|
*/
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
/** Повний serial-lane список: `${ruleId}/${concernId}` — 19 прямих + 3 через shared helper = 22. */
|
|
49
|
-
export const SERIAL_LANE_CONCERNS = new Set([...DIRECT_SPAWN_CONCERNS, ...SHARED_HELPER_CONCERNS])
|
|
20
|
+
export const SERIAL_LANE_CONCERNS = new Set()
|
|
50
21
|
|
|
51
22
|
/**
|
|
52
23
|
* Чи concern лишається у serial lane `detectAll()` (недоведений non-blocking).
|
|
@@ -55,5 +26,6 @@ export const SERIAL_LANE_CONCERNS = new Set([...DIRECT_SPAWN_CONCERNS, ...SHARED
|
|
|
55
26
|
* @returns {boolean} true — serial lane; false — parallel-safe
|
|
56
27
|
*/
|
|
57
28
|
export function isSerialLane(ruleId, concernId) {
|
|
29
|
+
// eslint-disable-next-line sonarjs/no-empty-collection -- навмисно порожній зараз (протокол вище); живий registry, не dead code
|
|
58
30
|
return SERIAL_LANE_CONCERNS.has(`${ruleId}/${concernId}`)
|
|
59
31
|
}
|
|
@@ -3,9 +3,8 @@ type: JS Module
|
|
|
3
3
|
title: blocking-inventory.mjs
|
|
4
4
|
resource: npm/scripts/lib/lint-surface/blocking-inventory.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
6
|
+
crc: dce1fafd
|
|
7
7
|
model: openai-codex/gpt-5.4-mini
|
|
8
|
-
tier: cloud-min
|
|
9
8
|
score: 100
|
|
10
9
|
issues: judge:inaccurate:0.98
|
|
11
10
|
judgeModel: openai-codex/gpt-5.4-mini
|
|
@@ -3,9 +3,8 @@ type: JS Module
|
|
|
3
3
|
title: spawn-async.mjs
|
|
4
4
|
resource: npm/scripts/utils/spawn-async.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
6
|
+
crc: 0e8ce2ef
|
|
7
7
|
model: openai-codex/gpt-5.4-mini
|
|
8
|
-
tier: cloud-min
|
|
9
8
|
score: 100
|
|
10
9
|
issues: judge:inaccurate:0.98
|
|
11
10
|
judgeModel: openai-codex/gpt-5.4-mini
|
|
@@ -43,15 +43,18 @@ class AbortError extends Error {
|
|
|
43
43
|
* @param {number} [opts.killGraceMs] пауза між `SIGTERM` і ескалацією до `SIGKILL` (дефолт 5000)
|
|
44
44
|
* @param {string} [opts.cwd] робочий каталог дочірнього процесу
|
|
45
45
|
* @param {Record<string, string>} [opts.env] оточення дочірнього процесу
|
|
46
|
+
* @param {string} [opts.input] дані для запису в stdin дочірнього процесу (`utf8`, аналог
|
|
47
|
+
* `spawnSync`-опції `input`); stdin закривається (`end`) одразу після запису
|
|
46
48
|
* @returns {Promise<SpawnAsyncResult>} нормалізований результат виконання
|
|
47
49
|
*/
|
|
48
50
|
export async function spawnAsync(cmd, args, opts = {}) {
|
|
49
|
-
const { signal, timeoutMs, killGraceMs = 5000, ...spawnOpts } = opts
|
|
51
|
+
const { signal, timeoutMs, killGraceMs = 5000, input, ...spawnOpts } = opts
|
|
50
52
|
if (signal?.aborted) throw new AbortError()
|
|
51
53
|
|
|
52
54
|
const child = spawn(cmd, args, spawnOpts)
|
|
53
55
|
child.stdout?.setEncoding('utf8')
|
|
54
56
|
child.stderr?.setEncoding('utf8')
|
|
57
|
+
if (input !== undefined) child.stdin?.end(input, 'utf8')
|
|
55
58
|
|
|
56
59
|
let stdout = ''
|
|
57
60
|
let stderr = ''
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: main.mjs
|
|
4
|
-
resource: npm/rules/python/applies/main.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: 871eb5c6
|
|
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
|
-
Перевіряє наявність файлу `pyproject.toml` у корені репозиторію для визначення, чи має застосовуватися правило до проєктів, що використовують Python. Публічні функції `applies` та `main` реалізують цю логіку.
|
|
16
|
-
|
|
17
|
-
## Поведінка
|
|
18
|
-
|
|
19
|
-
applies визначає, чи застосовне правило, перевіряючи наявність файлу `pyproject.toml` у корені репозиторію.
|
|
20
|
-
main повідомляє про успішне знаходження файлу `pyproject.toml`, що підтверджує застосування правила для Python.
|
|
21
|
-
|
|
22
|
-
## Публічний API
|
|
23
|
-
|
|
24
|
-
- applies — визначає загальні налаштування та конфігурацію.
|
|
25
|
-
- main — виводить загальний контекст, тоді як спеціалізовані блоки виконують конкретні перевірки.
|
|
26
|
-
|
|
27
|
-
## Гарантії поведінки
|
|
28
|
-
|
|
29
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
|
@@ -1,24 +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
|
-
/**
|
|
8
|
-
* @param {string} [cwd] корінь репозиторію (`process.cwd()` у звичайному прогоні)
|
|
9
|
-
* @returns {Promise<boolean>} `true` — правило застосовне; `false` — пропустити
|
|
10
|
-
*/
|
|
11
|
-
export function applies(cwd = process.cwd()) {
|
|
12
|
-
return Promise.resolve(existsSync(join(cwd, 'pyproject.toml')))
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Друкує короткий context-pass — самі перевірки виконують інші concerns.
|
|
17
|
-
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту.
|
|
18
|
-
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат context-pass
|
|
19
|
-
*/
|
|
20
|
-
export function lint(ctx) {
|
|
21
|
-
const reporter = createViolationReporter(ctx)
|
|
22
|
-
reporter.pass('pyproject.toml знайдено в корені — застосовую python.mdc')
|
|
23
|
-
return Promise.resolve(reporter.result())
|
|
24
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: uv-run.mjs
|
|
4
|
-
resource: npm/rules/python/lib/uv-run.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: 6aba3ab1
|
|
7
|
-
model: openai-codex/gpt-5.4-mini
|
|
8
|
-
tier: cloud-min
|
|
9
|
-
score: 100
|
|
10
|
-
issues: judge:inaccurate:0.97
|
|
11
|
-
judgeModel: openai-codex/gpt-5.4-mini
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Огляд
|
|
15
|
-
|
|
16
|
-
Спільний preflight для Python-детекторів `mypy` і `ruff`, виділений зі спільного дубльованого коду з `main.mjs`. Використовує `PY_EXT_RE`, щоб залишати лише Python-цілі; для `ctx.files` запускає перевірку по вибраних файлах, а без них — по всьому проєкту через `.`. За наявності `uvToolAvailable` готує запуск обох детекторів через `uv run --frozen`; `preparePythonRun` формує однаковий контракт підготовки для обох інструментів.
|
|
17
|
-
|
|
18
|
-
## Поведінка
|
|
19
|
-
|
|
20
|
-
- `PY_EXT_RE` — визначає, чи файл належить до Python-цілей для delta-лінту.
|
|
21
|
-
- `uvToolAvailable` — перевіряє, чи доступний Python-інструмент у середовищі `uv`.
|
|
22
|
-
- `preparePythonRun` — готує спільний preflight для Python-лінтерів: пропускає без `pyproject.toml`, відсікає нерелевантні файли, перевіряє наявність `uv` і доступність інструменту, після чого повертає готові цілі для запуску через `uv run --frozen`.
|
|
23
|
-
|
|
24
|
-
## Публічний API
|
|
25
|
-
|
|
26
|
-
- PY_EXT_RE — Відібрає лише Python-файли з delta-списку для `lint`.
|
|
27
|
-
- uvToolAvailable — Підтверджує, що `uv` доступний у середовищі.
|
|
28
|
-
- preparePythonRun — Готує запуск Python-цілі: звіряє `pyproject.toml`, визначає delta або full-обсяг, знаходить `uv` і перевіряє, чи є потрібний `tool`; якщо підготовка не вдалася, викликач завершує `reporter.result` раніше.
|
|
29
|
-
|
|
30
|
-
## Гарантії поведінки
|
|
31
|
-
|
|
32
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Спільний preflight обох python-детекторів (`mypy`, `ruff`) — обидва per-file: приймають
|
|
3
|
-
* `ctx.files`, інакше `.` (весь проєкт), обидва йдуть через `uv run --frozen`. Виділено зі
|
|
4
|
-
* спільного дубльованого коду (jscpd) обох `main.mjs`.
|
|
5
|
-
*/
|
|
6
|
-
import { spawnSync } from 'node:child_process'
|
|
7
|
-
import { existsSync } from 'node:fs'
|
|
8
|
-
import { join } from 'node:path'
|
|
9
|
-
|
|
10
|
-
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
11
|
-
|
|
12
|
-
/** Розширення `.py` — фільтр delta-списку файлів у `lint(ctx)`. */
|
|
13
|
-
export const PY_EXT_RE = /\.py$/u
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @param {string} uv шлях до бінарника uv.
|
|
17
|
-
* @param {string} tool ім'я інструменту в uv-середовищі.
|
|
18
|
-
* @returns {boolean} true якщо інструмент доступний
|
|
19
|
-
*/
|
|
20
|
-
export function uvToolAvailable(uv, tool) {
|
|
21
|
-
const r = spawnSync(uv, ['run', '--frozen', tool, '--version'], { stdio: 'ignore', shell: false })
|
|
22
|
-
return r.status === 0
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Спільний preflight: pyproject.toml, delta/full-цілі, резолв `uv`, доступність `tool` у
|
|
27
|
-
* uv-середовищі. Викликач рано виходить (`reporter.result()`), коли повертається `null` —
|
|
28
|
-
* `fail()` для випадку відсутнього `uv` уже викликаний усередині.
|
|
29
|
-
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту.
|
|
30
|
-
* @param {(msg: string, opts: object) => void} fail колбек реєстрації порушення.
|
|
31
|
-
* @param {string} tool ім'я інструменту (`mypy`|`ruff`) для перевірки доступності.
|
|
32
|
-
* @returns {{uv: string, targets: string[]}|null} preflight-результат, або null (рано вийти).
|
|
33
|
-
*/
|
|
34
|
-
export function preparePythonRun(ctx, fail, tool) {
|
|
35
|
-
if (!existsSync(join(ctx.cwd, 'pyproject.toml'))) return null
|
|
36
|
-
|
|
37
|
-
const targets = ctx.files === undefined ? ['.'] : ctx.files.filter(f => PY_EXT_RE.test(f))
|
|
38
|
-
if (targets.length === 0) return null
|
|
39
|
-
|
|
40
|
-
const uv = resolveCmd('uv')
|
|
41
|
-
if (!uv) {
|
|
42
|
-
fail('lint-python: `uv` не знайдено в PATH (потрібен при наявному pyproject.toml, python.mdc)', 'uv-missing')
|
|
43
|
-
return null
|
|
44
|
-
}
|
|
45
|
-
if (!uvToolAvailable(uv, tool)) return null // tool недоступний у uv-середовищі → пропущено
|
|
46
|
-
|
|
47
|
-
return { uv, targets }
|
|
48
|
-
}
|
package/rules/python/main.json
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{ "auto": { "glob": "pyproject.toml" } }
|
package/rules/python/main.mdc
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Python — пакет-менеджер uv (без Poetry), PEP 621, lint-python
|
|
3
|
-
globs: "**/*.py,pyproject.toml,uv.lock,.github/workflows/lint-python.yml"
|
|
4
|
-
alwaysApply: false
|
|
5
|
-
version: '1.0'
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
Python-проєкти ведуться **виключно** на [uv](https://docs.astral.sh/uv/) — єдиний пакет-менеджер і резолвер. **Poetry заборонено.** Середовище: `uv sync --frozen` (строго з `uv.lock`).
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: main.mjs
|
|
4
|
-
resource: npm/rules/python/mypy/main.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: 7cc910e3
|
|
7
|
-
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
-
score: 100
|
|
9
|
-
issues: judge:inaccurate:0.99
|
|
10
|
-
judgeModel: openai-codex/gpt-5.4-mini
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Огляд
|
|
14
|
-
|
|
15
|
-
Please provide the draft section "overview" that needs revision, according to the context and requirements.
|
|
16
|
-
|
|
17
|
-
## Поведінка
|
|
18
|
-
|
|
19
|
-
1. Перевіряє наявність файлу `pyproject.toml` у кореневій директорії проєкту. Якщо його немає, перевірка не виконується.
|
|
20
|
-
2. Визначає цільові файли для перевірки: або всі `.py` файли у проєкті, або лише ті, що передані в контекст.
|
|
21
|
-
3. Перевіряє наявність у системному шляху інструмента `uv` та доступності `mypy` у середовищі `uv`. Якщо `uv` або `mypy` недоступні, перевірка пропускається.
|
|
22
|
-
4. Запускає `mypy` через `uv run --frozen` для визначених цільових файлів, передаючи поточну робочу директорію проєкту як робочу директорію для виконання.
|
|
23
|
-
5. Якщо `mypy` завершується з ненульовим кодом, фіксується порушення з виводом команди та кодом помилки.
|
|
24
|
-
6. Якщо `mypy` завершується успішно, результати перевірки вважаються позитивними.
|
|
25
|
-
|
|
26
|
-
## Публічний API
|
|
27
|
-
|
|
28
|
-
lint — виявляє помилки в коді Python за допомогою mypy.
|
|
29
|
-
|
|
30
|
-
## Гарантії поведінки
|
|
31
|
-
|
|
32
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lint-поверхня python/mypy: read-only detector (`mypy`, через `uv run --frozen`). Per-file:
|
|
3
|
-
* приймає `ctx.files`, інакше `.` (весь проєкт). Виділено з колишнього bundled `python/check`
|
|
4
|
-
* (spec docs/specs/2026-07-02-text-check-per-file-split-design.md "Рішення python/php/rego") —
|
|
5
|
-
* mypy сам транзитивно підвантажує імпортовані модулі (follow-imports), тож дає коректні
|
|
6
|
-
* діагнози й на підмножині переданих файлів. Немає fix capability (mypy — detect-only).
|
|
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
|
-
* Detector python/mypy (read-only).
|
|
15
|
-
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту.
|
|
16
|
-
* @returns {import('../../../scripts/lib/lint-surface/types.mjs').LintResult} результат із порушеннями
|
|
17
|
-
*/
|
|
18
|
-
export function lint(ctx) {
|
|
19
|
-
const reporter = createViolationReporter(ctx)
|
|
20
|
-
const { fail } = reporter
|
|
21
|
-
const cwd = ctx.cwd
|
|
22
|
-
|
|
23
|
-
const prepared = preparePythonRun(ctx, fail, 'mypy')
|
|
24
|
-
if (!prepared) return reporter.result()
|
|
25
|
-
const { uv, targets } = prepared
|
|
26
|
-
|
|
27
|
-
const r = spawnSync(uv, ['run', '--frozen', 'mypy', ...targets], { cwd, encoding: 'utf8', shell: false })
|
|
28
|
-
if (r.status !== 0) {
|
|
29
|
-
const code = typeof r.status === 'number' ? r.status : 1
|
|
30
|
-
const out = `${r.stdout ?? ''}${r.stderr ?? ''}`.trim().slice(0, 2000)
|
|
31
|
-
const outSuffix = out ? `\n${out}` : ''
|
|
32
|
-
fail(`lint-python: mypy — помилка (код ${code}, python.mdc)${outSuffix}`, 'mypy-violation')
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return reporter.result()
|
|
36
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: main.mjs
|
|
4
|
-
resource: npm/rules/python/project/main.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: b47f2997
|
|
7
|
-
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
-
tier: local-min
|
|
9
|
-
score: 100
|
|
10
|
-
judgeModel: openai-codex/gpt-5.4-mini
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Огляд
|
|
14
|
-
|
|
15
|
-
Огляд
|
|
16
|
-
Цей детектор забезпечує перевірку цілісності оточення Python на рівні всього проекту. Він діагностує відповідність файлів блокування та ліцензій, виконуючи аудит на основі повного набору залежностей, а не лише змін у межах дельти.
|
|
17
|
-
|
|
18
|
-
Поведінка
|
|
19
|
-
Система перевіряє наявність файлу `pyproject.toml` у робочому каталозі; відсутність файлу призводить до успішного завершення.
|
|
20
|
-
Визначає виконуваний файл `uv`; у разі відсутності він повідомляє про це (python.mdc).
|
|
21
|
-
Виконує аудит цілісності файлу блокування за допомогою `uv lock --check`. Виявлені порушення фіксуються (python.mdc), і виконання негайно припиняється.
|
|
22
|
-
Виконує збірку оточення через `uv sync --frozen`. Будь-які помилки фіксуються (python.mdc), зупиняючи процес.
|
|
23
|
-
Сканує ліцензії усіх залежностей за допомогою `pip-licenses`. Якщо інструмент недоступний, перевірка пропускається. При помилці інструменту фіксується порушення (python.mdc). Якщо знайдено пакети, ліцензії яких не відповідають критеріям Blue Oak Bronze+, фіксується порушення (python.mdc) із переліком відповідних пакетів.
|
|
24
|
-
Процес роботи є read-only, він не змінює файлової системи чи бази даних. Усі помилки перехоплюються з механізмом fail-safe, і винятки назовні не генеруються. На етапі виконання жодного кешування не відбувається.
|
|
25
|
-
|
|
26
|
-
## Поведінка
|
|
27
|
-
|
|
28
|
-
Поведінка:
|
|
29
|
-
1. Перевіряє наявність файлу `pyproject.toml` у робочому каталозі. Якщо його немає, операція завершується успішно.
|
|
30
|
-
2. Знаходить виконуваний файл `uv`. Якщо він не знайдений, операція завершується з повідомленням про відсутність `uv` (python.mdc).
|
|
31
|
-
3. Виконує перевірку цілісності блокування за допомогою `uv lock --check`. Якщо виникає помилка, фіксує порушення (python.mdc) та завершує роботу.
|
|
32
|
-
4. Виконує збірку оточення за допомогою `uv sync --frozen`. Якщо виникає помилка, фіксує порушення (python.mdc) та завершує роботу.
|
|
33
|
-
5. Виконує перевірку ліцензій залежностей за допомогою `pip-licenses`. Якщо інструмент недоступний, перевірка пропускається. Якщо виникає помилка виконання, фіксує порушення (python.mdc). Якщо знайдено пакети з ліцензіями, що не відповідають критеріям Blue Oak Bronze+, фіксує порушення (python.mdc), перелічуючи знахідки.
|
|
34
|
-
6. Повертає результат виконання перевірок.
|
|
35
|
-
|
|
36
|
-
## Публічний API
|
|
37
|
-
|
|
38
|
-
lint — знаходить проблеми в коді Python для даного проєкту.
|
|
39
|
-
|
|
40
|
-
## Гарантії поведінки
|
|
41
|
-
|
|
42
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
|
43
|
-
- Перехоплює помилки і не пропускає винятків назовні (fail-safe).
|