agent-quality-kit 0.6.0 → 0.7.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/README.md +18 -2
- package/README.ru.md +16 -0
- package/kit/docs/ai/agent-harness-playbook.md +1 -1
- package/kit/docs/ready-made-rules.md +29 -4
- package/kit/gates/README.md +40 -0
- package/kit/gates/ci-actually-fails/README.md +12 -0
- package/kit/gates/ci-actually-fails/check.sh +26 -3
- package/kit/gates/ci-actually-fails/green/.github/workflows/ci.yml +16 -0
- package/kit/gates/ci-actually-fails/red/.github/workflows/soft.yml +15 -0
- package/kit/gates/color-from-token/check.sh +13 -1
- package/kit/gates/commit-explains-itself/README.md +13 -3
- package/kit/gates/commit-explains-itself/check.sh +8 -4
- package/kit/gates/complexity-limit/README.md +5 -0
- package/kit/gates/complexity-limit/check.sh +21 -2
- package/kit/gates/complexity-limit/green/test_fixtures.py +14 -0
- package/kit/gates/deps-are-pinned/README.md +14 -1
- package/kit/gates/deps-are-pinned/check.sh +6 -1
- package/kit/gates/deps-are-pinned/green/pyproject-with-requirements/pyproject.toml +12 -0
- package/kit/gates/deps-are-pinned/green/pyproject-with-requirements/requirements.txt +3 -0
- package/kit/gates/deps-are-pinned/red/pyproject-loose/pyproject.toml +12 -0
- package/kit/gates/deps-are-pinned/red/pyproject-loose/requirements.txt +3 -0
- package/kit/gates/duplicate-code/README.md +11 -2
- package/kit/gates/duplicate-code/check.sh +31 -4
- package/kit/gates/duplicate-code/gate.yml +8 -0
- package/kit/gates/duplicate-code/green/imports_a.go +20 -0
- package/kit/gates/duplicate-code/green/imports_b.go +19 -0
- package/kit/gates/entry-links-exist/README.md +5 -0
- package/kit/gates/entry-links-exist/check.sh +6 -0
- package/kit/gates/entry-links-exist/green/AGENTS.md +3 -0
- package/kit/gates/file-size-limit/README.md +9 -2
- package/kit/gates/file-size-limit/check.sh +13 -1
- package/kit/gates/gate-not-weakened/check.sh +13 -1
- package/kit/gates/hook-actually-fires/README.md +74 -0
- package/kit/gates/hook-actually-fires/check.sh +183 -0
- package/kit/gates/hook-actually-fires/gate.yml +15 -0
- package/kit/gates/hook-actually-fires/green/.claude/hooks/hooks.json +3 -0
- package/kit/gates/hook-actually-fires/green/.claude/settings.json +74 -0
- package/kit/gates/hook-actually-fires/green/.claude/settings.local.json +74 -0
- package/kit/gates/hook-actually-fires/red/.claude/hooks/hooks.json +4 -0
- package/kit/gates/hook-actually-fires/red/.claude/settings.json +53 -0
- package/kit/gates/no-phantom-package/README.md +84 -0
- package/kit/gates/no-phantom-package/check.sh +161 -0
- package/kit/gates/no-phantom-package/gate.yml +20 -0
- package/kit/gates/no-phantom-package/green/AGENTS.md +15 -0
- package/kit/gates/no-phantom-package/red/AGENTS.md +15 -0
- package/kit/gates/no-print-in-prod/README.md +33 -39
- package/kit/gates/no-print-in-prod/gate.yml +14 -6
- package/kit/gates/personal-config-not-shared/README.md +66 -0
- package/kit/gates/personal-config-not-shared/check.sh +103 -0
- package/kit/gates/personal-config-not-shared/gate.yml +16 -0
- package/kit/gates/personal-config-not-shared/green/.aqk-tracked +9 -0
- package/kit/gates/personal-config-not-shared/red/.aqk-tracked +6 -0
- package/kit/gates/secrets-not-in-code/check.sh +13 -1
- package/kit/gates/swallowed-error/README.md +36 -18
- package/kit/gates/swallowed-error/gate.yml +13 -3
- package/kit/gates/test-has-assertion/check.sh +13 -1
- package/kit/gates/test-not-adjusted/README.md +79 -0
- package/kit/gates/test-not-adjusted/check.sh +136 -0
- package/kit/gates/test-not-adjusted/gate.yml +19 -0
- package/kit/gates/test-not-adjusted/green/after/calc.py +6 -0
- package/kit/gates/test-not-adjusted/green/after/tests/test_calc.py +9 -0
- package/kit/gates/test-not-adjusted/green/before/calc.py +2 -0
- package/kit/gates/test-not-adjusted/green/before/tests/test_calc.py +5 -0
- package/kit/gates/test-not-adjusted/red/after/calc.py +2 -0
- package/kit/gates/test-not-adjusted/red/after/tests/test_calc.py +5 -0
- package/kit/gates/test-not-adjusted/red/before/calc.py +2 -0
- package/kit/gates/test-not-adjusted/red/before/tests/test_calc.py +7 -0
- package/kit/gates/todo-without-task/README.md +6 -0
- package/kit/gates/todo-without-task/check.sh +13 -1
- package/kit/ratchet/ratchet.sh +70 -2
- package/kit/rules/general.md +9 -0
- package/kit/rules-en/general.md +82 -0
- package/kit/rules-en/security.md +33 -0
- package/kit/rules-en/testing.md +48 -0
- package/llms.txt +1 -1
- package/package.json +3 -2
- package/tool/commands/badge.mjs +7 -1
- package/tool/commands/doctor.mjs +49 -9
- package/tool/commands/gates.mjs +10 -4
- package/tool/commands/project.mjs +8 -1
- package/tool/commands/prove.mjs +67 -0
- package/tool/commands/report.mjs +4 -1
- package/tool/i18n/en-docs.mjs +70 -0
- package/tool/i18n/en.mjs +49 -54
- package/tool/i18n/ru-docs.mjs +70 -0
- package/tool/i18n/ru.mjs +48 -54
- package/tool/i18n/templates-en.mjs +1 -1
- package/tool/i18n/templates-ru.mjs +1 -1
- package/tool/lib/core.mjs +7 -1
- package/tool/lib/manifest.mjs +36 -5
- package/tool/lib/prove.mjs +160 -0
- package/tool/lib/repo.mjs +31 -2
- package/tool/lib/scope.mjs +37 -2
- package/tool/lib/templates.mjs +2 -0
- package/tool/program.mjs +5 -0
- package/tool/selfcheck/gates.sh +66 -0
- package/tool/selfcheck/mutation.sh +21 -1
- package/tool/selfcheck/smoke.sh +279 -39
- package/tool/selfcheck/units-level.mjs +60 -0
- package/tool/selfcheck/units.mjs +113 -2
- package/kit/gates/no-print-in-prod/check.sh +0 -38
- package/kit/gates/no-print-in-prod/green/docs.ts +0 -15
- package/kit/gates/no-print-in-prod/green/main.go +0 -8
- package/kit/gates/no-print-in-prod/green/main.rs +0 -4
- package/kit/gates/no-print-in-prod/red/main.go +0 -8
- package/kit/gates/no-print-in-prod/red/main.rs +0 -4
- package/kit/gates/swallowed-error/check.sh +0 -54
- package/kit/gates/swallowed-error/green/run.js +0 -8
- package/kit/gates/swallowed-error/red/run.js +0 -3
- /package/kit/gates/commit-explains-itself/green/{COMMIT_MSG → .aqk-commit-msg} +0 -0
- /package/kit/gates/commit-explains-itself/red/{COMMIT_MSG → .aqk-commit-msg} +0 -0
package/tool/selfcheck/units.mjs
CHANGED
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
|
|
12
12
|
import test from "node:test";
|
|
13
13
|
import assert from "node:assert/strict";
|
|
14
|
-
import { parseManifest, manifestWithGate, unknownKeys, entryLifecycle } from "../lib/manifest.mjs";
|
|
14
|
+
import { parseManifest, manifestWithGate, unknownKeys, entryLifecycle, advisorySet, KNOWN_KEYS } from "../lib/manifest.mjs";
|
|
15
15
|
import { triggerVerdict, recipeFor, stems, overlap, EXT_LANG, whichSync } from "../lib/repo.mjs";
|
|
16
|
-
import { scopeOutput } from "../lib/scope.mjs";
|
|
16
|
+
import { scopeOutput, splitAdvice } from "../lib/scope.mjs";
|
|
17
17
|
import { assessBaseline, ITEMS, BASELINE_TOTAL } from "../lib/baseline.mjs";
|
|
18
18
|
import { CATALOGS, pickLang, L } from "../i18n/index.mjs";
|
|
19
19
|
import { badgeMarkdown, BADGE_RE, placesToCheck } from "../commands/badge.mjs";
|
|
@@ -358,3 +358,114 @@ test("сужение по дифу: гейт без путей в выводе
|
|
|
358
358
|
assert.equal(r.scopable, false);
|
|
359
359
|
assert.equal(scopeOutput(["src/old.py:1: печать"], new Set(["src/new.py"])).scopable, true);
|
|
360
360
|
});
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
// --- совет по починке не теряется в обрезке ----------------------------------
|
|
364
|
+
// ЗАЧЕМ. Все девятнадцать записей каталога печатают строку «почини: …» последней. `doctor --run`
|
|
365
|
+
// показывает три первые строки вывода и обрезает остальное — то есть ровно ту строку, ради
|
|
366
|
+
// которой человек и смотрит на красное, он не видит никогда. Находка без действия — это повод
|
|
367
|
+
// закрыть окно, а не починить.
|
|
368
|
+
test("совет по починке отделяется от находок и не обрезается", () => {
|
|
369
|
+
const out = [
|
|
370
|
+
"src/a.py:3: печать",
|
|
371
|
+
"src/b.py:9: печать",
|
|
372
|
+
"src/c.py:1: печать",
|
|
373
|
+
"src/d.py:7: печать",
|
|
374
|
+
" почини: замени на вызов системы логов",
|
|
375
|
+
" тогда запись попадёт в общий журнал",
|
|
376
|
+
];
|
|
377
|
+
const r = splitAdvice(out);
|
|
378
|
+
assert.equal(r.findings.length, 4);
|
|
379
|
+
assert.equal(r.advice.length, 2);
|
|
380
|
+
// Продолжение совета едет вместе с ним: без второй строки первая обрывается на полуслове.
|
|
381
|
+
assert.equal(r.advice[1].includes("общий журнал"), true);
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
test("совет по починке опознаётся на обоих языках", () => {
|
|
385
|
+
assert.equal(splitAdvice(["a.py:1: x", " fix: replace with a logger call"]).advice.length, 1);
|
|
386
|
+
assert.equal(splitAdvice(["a.py:1: x", " почини: замени на логгер"]).advice.length, 1);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
// Вывод без совета — это не ошибка разбора, а признак записи, которая не говорит, что делать.
|
|
390
|
+
// Разбор обязан вернуть пустой совет, а не выдумать его из последней строки.
|
|
391
|
+
test("вывод без совета не превращается в совет", () => {
|
|
392
|
+
const r = splitAdvice(["src/a.py:3: печать", "src/b.py:9: печать"]);
|
|
393
|
+
assert.equal(r.advice.length, 0);
|
|
394
|
+
assert.equal(r.findings.length, 2);
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
// Совет бывает не только в конце: `deps-are-pinned` печатает его внутри вспомогательной
|
|
399
|
+
// функции, вызываемой шесть раз, и находки идут ПОСЛЕ. Пока советом считалось «всё от первой
|
|
400
|
+
// метки до конца», сорок находок уезжали в жёлтый список без обрезки — ровно та стена красного,
|
|
401
|
+
// против которой написан этот модуль. Найдено ревью 2026-09-06.
|
|
402
|
+
test("совет, вставленный посреди вывода, не проглатывает находки", () => {
|
|
403
|
+
const r = splitAdvice([
|
|
404
|
+
" почини: закрепи версии",
|
|
405
|
+
"src/a.py:1: x",
|
|
406
|
+
"src/b.py:2: x",
|
|
407
|
+
"src/c.py:3: x",
|
|
408
|
+
" почини: и вот это тоже",
|
|
409
|
+
" вторая строка совета",
|
|
410
|
+
]);
|
|
411
|
+
assert.equal(r.findings.length, 3);
|
|
412
|
+
assert.equal(r.advice.length, 3);
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
// Продолжение совета не должно съедать находку, стоящую сразу за ним.
|
|
416
|
+
test("находка сразу после совета остаётся находкой", () => {
|
|
417
|
+
const r = splitAdvice([" почини: сделай так", " пояснение", "src/z.py:9: x"]);
|
|
418
|
+
assert.equal(r.findings.length, 1);
|
|
419
|
+
assert.equal(r.findings[0].includes("src/z.py"), true);
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
// --- правило, введённое совещательным ----------------------------------------
|
|
424
|
+
// ЗАЧЕМ. Правило вводят в проект, где старый код ему не соответствует. Храповик отвечает на
|
|
425
|
+
// это одним способом: старое становится долгом. Второй способ — показывать, не роняя, пока
|
|
426
|
+
// команда договаривается. Сегодня его нет вовсе: находка либо роняет сборку, либо не существует.
|
|
427
|
+
//
|
|
428
|
+
// ПОЧЕМУ ОБЪЯВЛЕНИЕМ, А НЕ ФЛАГОМ ПРОГОНА. Флаг «не роняй ничего» — это `continue-on-error`,
|
|
429
|
+
// против которого написана наша же запись ci-actually-fails: он понижает всё разом, не виден
|
|
430
|
+
// в дифе и не назван в сводке. Список в манифесте виден, именуется и считается всегда.
|
|
431
|
+
test("совещательные гейты читаются из манифеста списком", () => {
|
|
432
|
+
const man = parseManifest("aqk: 1\nadvisory:\n - complexity-limit\n - duplicate-code\n");
|
|
433
|
+
const a = advisorySet(man);
|
|
434
|
+
assert.equal(a.has("complexity-limit"), true);
|
|
435
|
+
assert.equal(a.has("duplicate-code"), true);
|
|
436
|
+
assert.equal(a.has("secrets-not-in-code"), false);
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
test("список в одну строку читается так же", () => {
|
|
440
|
+
const a = advisorySet(parseManifest("advisory: [complexity-limit, duplicate-code]\n"));
|
|
441
|
+
assert.equal(a.size, 2);
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
// Отсутствие блока — это ноль совещательных, а не «все совещательные».
|
|
445
|
+
test("без блока advisory совещательных нет", () => {
|
|
446
|
+
assert.equal(advisorySet(parseManifest("aqk: 1\n")).size, 0);
|
|
447
|
+
assert.equal(advisorySet(null).size, 0);
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
// Поле обязано быть известным манифесту: иначе опечатка «advisery:» молча означала бы
|
|
451
|
+
// «совещательных нет», и правило, которое человек считал введённым, роняло бы сборку.
|
|
452
|
+
test("advisory — известное поле манифеста", () => {
|
|
453
|
+
assert.equal(KNOWN_KEYS.includes("advisory"), true);
|
|
454
|
+
assert.deepEqual(unknownKeys({ aqk: 1, advisory: [] }), []);
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
// --- правила на языке проекта ------------------------------------------------
|
|
459
|
+
// ЗАЧЕМ. Русский текст правил в англоязычном проекте — это первое, что там откроет человек,
|
|
460
|
+
// и первое, чего он не прочитает. Русская версия остаётся источником истины, английская —
|
|
461
|
+
// переводом. Совпадение содержания машина не сторожит, а вот НАБОР ФАЙЛОВ обязана: добавили
|
|
462
|
+
// правило на одном языке и забыли про другой — половина мира получит комплект без него.
|
|
463
|
+
test("наборы файлов правил совпадают на обоих языках", async () => {
|
|
464
|
+
const { readdir } = await import("node:fs/promises");
|
|
465
|
+
const { fileURLToPath } = await import("node:url");
|
|
466
|
+
const at = (d) => fileURLToPath(new URL(`../../kit/${d}`, import.meta.url));
|
|
467
|
+
const ru = (await readdir(at("rules"))).filter((f) => f.endsWith(".md")).sort();
|
|
468
|
+
const en = (await readdir(at("rules-en"))).filter((f) => f.endsWith(".md")).sort();
|
|
469
|
+
assert.deepEqual(en, ru);
|
|
470
|
+
assert.equal(ru.length > 0, true);
|
|
471
|
+
});
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env sh
|
|
2
|
-
# Отладочная печать переживает задачу и уезжает в прод: она не ошибка сборки и
|
|
3
|
-
# не видна в ревью диффа на 400 строк. В проде это либо шум, либо утечка данных
|
|
4
|
-
# мимо системы логов.
|
|
5
|
-
DIR="${1:-.}"
|
|
6
|
-
. "$(dirname "$0")/../_skip.sh" 2>/dev/null || SKIP_NAMES=".git .aqk node_modules .venv"
|
|
7
|
-
# Красный образец — намеренно сломанный код в репозитории. Сканирующий гейт обязан его
|
|
8
|
-
# пропускать, иначе будет вечно краснеть на том, что сам же и положил. Исключение снимается,
|
|
9
|
-
# когда проверяют сам образец: тогда каталог red и есть цель проверки.
|
|
10
|
-
|
|
11
|
-
# Где печать законна и дефектом не является: вспомогательные скрипты, оснастка, примеры,
|
|
12
|
-
# записные книжки. Это НЕ общий список исключений: секрет в scripts/ — такой же секрет,
|
|
13
|
-
# а печать там — обычный способ говорить с человеком.
|
|
14
|
-
#
|
|
15
|
-
# На настоящем проекте без этого различия 285 находок из 330 пришли из scripts/ и оснастки.
|
|
16
|
-
# Гейт, который на 86% состоит из ложных сработок, выключают целиком.
|
|
17
|
-
TOOLING="--exclude-dir=scripts --exclude-dir=tools --exclude-dir=bin --exclude-dir=examples --exclude-dir=notebooks --exclude-dir=docs --exclude-dir=.claude --exclude-dir=gates"
|
|
18
|
-
# `gates-reference` отсюда убран: это имя каталога ОДНОГО проекта, зашитое в общий
|
|
19
|
-
# инструмент. Такому место в .aqkignore самого проекта — он появился позже этой строки.
|
|
20
|
-
|
|
21
|
-
# Проект называет СВОИ каталоги, где печать — интерфейс, а не отладка: у программы командной
|
|
22
|
-
# строки это её исходники целиком. Объявляется в манифесте, рядом с командой, и потому видно
|
|
23
|
-
# глазами: AQK_PRINT_OK_DIRS="tool cli" bash .../check.sh .
|
|
24
|
-
#
|
|
25
|
-
# ЗАЧЕМ ОТДЕЛЬНО ОТ ХРАПОВИКА. Сначала такие места записали долгом — и каждая новая строка
|
|
26
|
-
# вывода красила проверку, требуя переснять реестр. Но долг — это то, что собираются погасить;
|
|
27
|
-
# печать из программы командной строки убирать никто не будет. Долг, который нельзя погасить
|
|
28
|
-
# работой, — не долг, а неверная мера: журнал, 2026-09-03.
|
|
29
|
-
for D in ${AQK_PRINT_OK_DIRS:-}; do
|
|
30
|
-
TOOLING="$TOOLING --exclude-dir=$D"
|
|
31
|
-
done
|
|
32
|
-
HITS=$(grep -rnE $(skip_grep "$DIR") $(include_code) $TOOLING '(^|[^A-Za-z_.])(print\(|console\.log\(|fmt\.Print|println!|print!|dbg!|System\.out\.print|Console\.Write)' "$DIR" 2>/dev/null | drop_comments | own_samples_filter "$DIR")
|
|
33
|
-
if [ -n "$HITS" ]; then
|
|
34
|
-
echo "$HITS"
|
|
35
|
-
echo " почини: замени на вызов системы логов — тогда запись попадёт в общий журнал и уровень можно приглушить."
|
|
36
|
-
exit 1
|
|
37
|
-
fi
|
|
38
|
-
exit 0
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// Печать внутри комментария — не печать. Пример в документации к функции и закомментированная
|
|
2
|
-
// строка отладки одинаково не выполняются: находка здесь означает, что проверка читает текст,
|
|
3
|
-
// а не код. Найдено прогоном по audit_project — семь находок из JSDoc и закомментированных строк.
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Скачивает файл.
|
|
7
|
-
*
|
|
8
|
-
* @example
|
|
9
|
-
* const result = await download(id);
|
|
10
|
-
* console.log('Done:', result.file_url);
|
|
11
|
-
*/
|
|
12
|
-
export async function download(id: string): Promise<string> {
|
|
13
|
-
// console.log('отладка', id);
|
|
14
|
-
return `/files/${id}`;
|
|
15
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env sh
|
|
2
|
-
# Тихо проглоченная ошибка — отказ, о котором никто не узнал. Система продолжает работать
|
|
3
|
-
# «как будто всё хорошо», а причина всплывает через недели и в другом месте.
|
|
4
|
-
DIR="${1:-.}"
|
|
5
|
-
. "$(dirname "$0")/../_skip.sh" 2>/dev/null || SKIP_NAMES=".git .aqk node_modules .venv"
|
|
6
|
-
|
|
7
|
-
# Список файлов собираем заранее. awk без файловых аргументов читает поток ввода и ждёт его
|
|
8
|
-
# вечно: на проекте без файлов этих языков проверка зависала навсегда — в конвейере и в хуке
|
|
9
|
-
# коммита, где поток ввода открыт. Найдено прогоном по проекту на Go.
|
|
10
|
-
FILES=$(find "$DIR" $(skip_find "$DIR") -type f -print 2>/dev/null | only_code | own_samples_filter "$DIR")
|
|
11
|
-
[ -z "$FILES" ] && exit 0
|
|
12
|
-
|
|
13
|
-
printf '%s\n' "$FILES" | xargs -r awk '
|
|
14
|
-
FILENAME ~ /\/(\.git|\.aqk|node_modules|dist|build|vendor)\// { next }
|
|
15
|
-
|
|
16
|
-
# python: except ...: с пустым телом
|
|
17
|
-
prev ~ /^[[:space:]]*except([[:space:]]|:)/ && $0 ~ /^[[:space:]]*(pass|\.\.\.)[[:space:]]*$/ {
|
|
18
|
-
print FILENAME ":" FNR ": перехват без обработки — " gensub(/^[[:space:]]+/, "", 1, prev)
|
|
19
|
-
}
|
|
20
|
-
# python в одну строку
|
|
21
|
-
/^[[:space:]]*except[^:]*:[[:space:]]*(pass|\.\.\.)[[:space:]]*$/ {
|
|
22
|
-
print FILENAME ":" FNR ": перехват без обработки — " gensub(/^[[:space:]]+/, "", 1, $0)
|
|
23
|
-
}
|
|
24
|
-
# js/java/go-подобные: catch (...) { } пустой
|
|
25
|
-
/catch[[:space:]]*(\([^)]*\))?[[:space:]]*\{[[:space:]]*\}/ {
|
|
26
|
-
print FILENAME ":" FNR ": перехват без обработки — " gensub(/^[[:space:]]+/, "", 1, $0)
|
|
27
|
-
}
|
|
28
|
-
# go: пустое тело после проверки ошибки, либо ошибка присвоена в пустоту
|
|
29
|
-
prev ~ /if[[:space:]]+err[[:space:]]*!=[[:space:]]*nil/ && $0 ~ /^[[:space:]]*\}[[:space:]]*$/ {
|
|
30
|
-
print FILENAME ":" FNR ": ошибка проверена и выброшена — " gensub(/^[[:space:]]+/, "", 1, prev)
|
|
31
|
-
}
|
|
32
|
-
/^[[:space:]]*_[[:space:]]*=[[:space:]]*err[[:space:]]*$/ {
|
|
33
|
-
print FILENAME ":" FNR ": ошибка присвоена в пустоту — " gensub(/^[[:space:]]+/, "", 1, $0)
|
|
34
|
-
}
|
|
35
|
-
# rust: результат отброшен без разбора
|
|
36
|
-
/\.ok\(\);[[:space:]]*$/ || /let[[:space:]]+_[[:space:]]*=[^;]*\?[[:space:]]*;/ {
|
|
37
|
-
print FILENAME ":" FNR ": результат отброшен без разбора — " gensub(/^[[:space:]]+/, "", 1, $0)
|
|
38
|
-
}
|
|
39
|
-
# обещания: .catch(() => {})
|
|
40
|
-
/\.catch\([^)]*=>[[:space:]]*\{[[:space:]]*\}\)/ {
|
|
41
|
-
print FILENAME ":" FNR ": перехват без обработки — " gensub(/^[[:space:]]+/, "", 1, $0)
|
|
42
|
-
}
|
|
43
|
-
{ prev = $0 }
|
|
44
|
-
' > /tmp/.swallowed.$$ 2>/dev/null
|
|
45
|
-
|
|
46
|
-
if [ -s /tmp/.swallowed.$$ ]; then
|
|
47
|
-
cat /tmp/.swallowed.$$
|
|
48
|
-
echo " почини: либо обработай и запиши в лог, либо пробрось дальше."
|
|
49
|
-
echo " тихий перехват — это отказ, о котором никто не узнает, пока не станет поздно."
|
|
50
|
-
rm -f /tmp/.swallowed.$$
|
|
51
|
-
exit 1
|
|
52
|
-
fi
|
|
53
|
-
rm -f /tmp/.swallowed.$$
|
|
54
|
-
exit 0
|
|
File without changes
|
|
File without changes
|