feat(метко-хуки): покрыть frontend .ts/.tsx (комментарий-aware скан JS/TS) #4

Closed
opened 2026-06-13 20:12:17 +07:00 by claude-secretary · 2 comments

Проблема

Метко-хуки сейчас де-факто не проверяют фронтовые .ts/.tsx — нарушения (#NNN, session-метки) во фронте проходят молча. Всплыло в senokosov/baton#688: золотые модули фронта пришлось грепать на метки руками, потому что pre-commit их не ловит.

Разбор по хукам

no-issue-refs-in-comments — НЕ работает на TS

  • В манифесте стоит types: [python] → хук вообще не запускается на .ts/.tsx.
  • extract_comment() в scripts/check_no_issue_refs_in_comments.py хардкодит питоновский #-синтаксис (ищет # вне строк). В TS комментарии — // и /* */, а # там не комментарий. Даже сняв types, текущая логика #123 в // см. #123 не увидит.

no-session-marks-in-code — частично работает, но рискованно

  • types не задан → consumer может расширить files: на фронт уже сейчас.
  • Но в .py сканируются только COMMENT/STRING-токены (через tokenize), а в «прочих файлах» — построчно по всей строке. Для markdown это ок (проза), а для .ts/.tsx построчный скан пройдётся и по коду → риск ложных срабатываний [A-Z]\d+ на идентификаторах/дженериках/литералах. Нужен симметричный с .py скан только комментариев (и при желании строк).

no-broken-repo-paths — уже покрывает TS

  • Есть фикстуры fixtures/broken_paths/{bad,good,limitation}.ts, описание прямо говорит «в прочих файлах (.ts/.tsx) — построчно». baton уже скоупит этот хук на фронт. Менять не надо — оставляю как ориентир, что path-проверка фронт уже видит.

Предлагаемое решение

Научить метко-хуки извлекать комментарии JS/TS и сканировать только их — симметрично с питоновским tokenize-скан'ом:

  1. Общий хелпер извлечения комментариев .ts/.tsx/.js/.jsx: line (//) + block (/* ... */, многострочный), с корректным игнором // и /* внутри строковых литералов (', ", `-template). По возможности — и строковые литералы (метка пряталась и в них в .py).
  2. no-issue-refs-in-comments: убрать жёсткий types: [python], сделать выбор парсера по расширению (py → текущий #-extract; ts/js → новый JS/TS-extract). Логика ISSUE_REF_RE / TODO_RE переиспользуется как есть.
  3. no-session-marks-in-code: для .ts/.tsx тоже скан только комментариев (а не всей строки), чтобы убрать ложные срабатывания на коде. .py/.md поведение не трогаем.
  4. Фикстуры *.ts (good/bad) для обоих хуков + кейсы в fixtures/run_smoke.sh. Сверить, что // TODO(#N) остаётся разрешён, а // см. #123 / // этап M2/45 падают.
  5. Обновить .pre-commit-hooks.yaml (name/description: «.py + JS/TS») и README.md (пример consumer-конфига с files: ...\.(ts|tsx)$).

Acceptance

  • no-issue-refs-in-comments и no-session-marks-in-code ловят метки в // и /* */ комментариях .ts/.tsx; код вне комментариев не триггерит.
  • // TODO(#N) и легитимные токены кода (Int32, HTTP_200, дженерики) не дают false-positive.
  • Фикстуры .ts + smoke-кейсы добавлены, bash fixtures/run_smoke.sh зелёный.
  • .pre-commit-hooks.yaml + README.md обновлены.
  • Тег (minor bump, новых breaking нет).

После релиза (consumer baton)

baton бампит rev и расширяет files: у обоих метко-хуков на ^frontend/.*\.(ts|tsx)$, затем чистит всплывшие нарушения. Зафиксировать отдельной baton-issue после тега.

Заметки

  • У репо нет Actions-раннера → CI висит в waiting; верификация — локально через fixtures/run_smoke.sh (как в PR #2/#3).
  • Источник: senokosov/baton#688 (комментарий volody про покрытие фронта).
## Проблема Метко-хуки сейчас де-факто не проверяют фронтовые `.ts/.tsx` — нарушения (`#NNN`, session-метки) во фронте проходят молча. Всплыло в `senokosov/baton#688`: золотые модули фронта пришлось грепать на метки руками, потому что `pre-commit` их не ловит. ## Разбор по хукам ### `no-issue-refs-in-comments` — НЕ работает на TS - В манифесте стоит `types: [python]` → хук вообще не запускается на `.ts/.tsx`. - `extract_comment()` в `scripts/check_no_issue_refs_in_comments.py` хардкодит питоновский `#`-синтаксис (ищет `#` вне строк). В TS комментарии — `//` и `/* */`, а `#` там не комментарий. Даже сняв `types`, текущая логика `#123` в `// см. #123` не увидит. ### `no-session-marks-in-code` — частично работает, но рискованно - `types` не задан → consumer может расширить `files:` на фронт уже сейчас. - Но в `.py` сканируются только COMMENT/STRING-токены (через `tokenize`), а в «прочих файлах» — **построчно по всей строке**. Для markdown это ок (проза), а для `.ts/.tsx` построчный скан пройдётся и по коду → риск ложных срабатываний `[A-Z]\d+` на идентификаторах/дженериках/литералах. Нужен симметричный с `.py` скан **только комментариев** (и при желании строк). ### `no-broken-repo-paths` — уже покрывает TS - Есть фикстуры `fixtures/broken_paths/{bad,good,limitation}.ts`, описание прямо говорит «в прочих файлах (.ts/.tsx) — построчно». baton уже скоупит этот хук на фронт. **Менять не надо** — оставляю как ориентир, что path-проверка фронт уже видит. ## Предлагаемое решение Научить метко-хуки извлекать комментарии JS/TS и сканировать только их — симметрично с питоновским tokenize-скан'ом: 1. Общий хелпер извлечения комментариев `.ts/.tsx/.js/.jsx`: line (`//`) + block (`/* ... */`, многострочный), с корректным игнором `//` и `/*` внутри строковых литералов (`'`, `"`, `` ` ``-template). По возможности — и строковые литералы (метка пряталась и в них в `.py`). 2. `no-issue-refs-in-comments`: убрать жёсткий `types: [python]`, сделать выбор парсера по расширению (py → текущий `#`-extract; ts/js → новый JS/TS-extract). Логика `ISSUE_REF_RE` / `TODO_RE` переиспользуется как есть. 3. `no-session-marks-in-code`: для `.ts/.tsx` тоже скан **только комментариев** (а не всей строки), чтобы убрать ложные срабатывания на коде. `.py`/`.md` поведение не трогаем. 4. Фикстуры `*.ts` (good/bad) для обоих хуков + кейсы в `fixtures/run_smoke.sh`. Сверить, что `// TODO(#N)` остаётся разрешён, а `// см. #123` / `// этап M2/45` падают. 5. Обновить `.pre-commit-hooks.yaml` (name/description: «.py + JS/TS») и `README.md` (пример consumer-конфига с `files: ...\.(ts|tsx)$`). ## Acceptance - [ ] `no-issue-refs-in-comments` и `no-session-marks-in-code` ловят метки в `//` и `/* */` комментариях `.ts/.tsx`; код вне комментариев не триггерит. - [ ] `// TODO(#N)` и легитимные токены кода (`Int32`, `HTTP_200`, дженерики) не дают false-positive. - [ ] Фикстуры `.ts` + smoke-кейсы добавлены, `bash fixtures/run_smoke.sh` зелёный. - [ ] `.pre-commit-hooks.yaml` + `README.md` обновлены. - [ ] Тег (minor bump, новых breaking нет). ## После релиза (consumer baton) baton бампит `rev` и расширяет `files:` у обоих метко-хуков на `^frontend/.*\.(ts|tsx)$`, затем чистит всплывшие нарушения. Зафиксировать отдельной baton-issue после тега. ## Заметки - У репо нет Actions-раннера → CI висит в `waiting`; верификация — локально через `fixtures/run_smoke.sh` (как в PR #2/#3). - Источник: `senokosov/baton#688` (комментарий volody про покрытие фронта).
Author
Owner

Ревизия остатка на текущий main (v0.13.0). Половина задачи закрыта по дороге в #10 и #12, половина — нет.

Сделано:

  • Общий хелпер извлечения комментариев есть — scripts/comment_scan.py: C-подобный режим (//, /* */) с пофайловой машиной состояний, трекингом строковых и шаблонных литералов и распознаванием regex-литералов JS. Пункты 1 и 2 плана.
  • no-issue-refs-in-comments жёсткий types: [python] потерял и парсер выбирает по расширению; .ts/.tsx/.jsx покрыты фикстурами (fixtures/issue_refs/*.ts*), // TODO(#N) остаётся легальным.

Осталось — пункт 3, ровно он и был про ложняки:

no-session-marks-in-code в .py сканирует COMMENT/STRING-токены, а в любом не-.py файле идёт построчно по всей строке. Для markdown это верно (проза), для .ts/.tsx — нет: правило [A-Z]\d+ пройдётся по коду, и дженерик T1, литерал H2, enum Step2 дадут FAIL там, где никакой метки нет. Пока хук на фронт не наводят, дыры не видно — но и покрыть фронт им нельзя.

Починка теперь дешёвая: взять c_style_chunks из comment_scan для C-подобных расширений, оставив построчный режим markdown'у. Приёмка задачи в этой части не меняется.

Ревизия остатка на текущий `main` (`v0.13.0`). Половина задачи закрыта по дороге в [#10](https://git.homedevlab.ru/senokosov/pre-commit-hooks/pulls/10) и [#12](https://git.homedevlab.ru/senokosov/pre-commit-hooks/pulls/12), половина — нет. **Сделано:** - Общий хелпер извлечения комментариев есть — `scripts/comment_scan.py`: C-подобный режим (`//`, `/* */`) с пофайловой машиной состояний, трекингом строковых и шаблонных литералов и распознаванием regex-литералов JS. Пункты 1 и 2 плана. - `no-issue-refs-in-comments` жёсткий `types: [python]` потерял и парсер выбирает по расширению; `.ts/.tsx/.jsx` покрыты фикстурами (`fixtures/issue_refs/*.ts*`), `// TODO(#N)` остаётся легальным. **Осталось — пункт 3, ровно он и был про ложняки:** `no-session-marks-in-code` в `.py` сканирует COMMENT/STRING-токены, а в **любом** не-`.py` файле идёт построчно по всей строке. Для markdown это верно (проза), для `.ts/.tsx` — нет: правило `[A-Z]\d+` пройдётся по коду, и дженерик `T1`, литерал `H2`, `enum Step2` дадут FAIL там, где никакой метки нет. Пока хук на фронт не наводят, дыры не видно — но и покрыть фронт им нельзя. Починка теперь дешёвая: взять `c_style_chunks` из `comment_scan` для C-подобных расширений, оставив построчный режим markdown'у. Приёмка задачи в этой части не меняется.
Author
Owner

Закрываю: остаток сделан в #21main, версия 0.17.0).

no-session-marks-in-code в C-подобных файлах разбирается c_style_chunks из scripts/comment_scan.py — только комментарии // и /* */, общей машиной состояний с no-issue-refs-in-comments. Построчный скан остался markdown'у, .py — как был. .mts/.cts добавлены в список C-подобных расширений: без них легальные TS-файлы оставались бы ровно на том скане, от которого уходили.

По приёмке задачи: код вне комментариев больше не триггерит (fixtures/session_marks/good.ts держит дженерик T1, Map<K1, V2>, литерал "H2" и деление — всё, что построчный скан флагал), // TODO(#N) и легитимные токены чисты, фикстуры и smoke-кейсы добавлены, манифест и README обновлены, пример consumer-конфига расширен на ts|tsx.

Что осталось за рамками и записано в README: текст JSX не сканируется (это не комментарий и не литерал), метка внутри строкового литерала TS не ловится — асимметрия с .py намеренная, в TS/JS литерал сплошь и рядом несёт разметку ("H2", "P1"). Разметочные и стилевые расширения (.css, .vue, .svelte) по-прежнему падают в построчный фолбэк — ведётся в #11.

Закрываю: остаток сделан в [#21](https://git.homedevlab.ru/senokosov/pre-commit-hooks/pulls/21) (в `main`, версия `0.17.0`). `no-session-marks-in-code` в C-подобных файлах разбирается `c_style_chunks` из `scripts/comment_scan.py` — только комментарии `//` и `/* */`, общей машиной состояний с `no-issue-refs-in-comments`. Построчный скан остался markdown'у, `.py` — как был. `.mts`/`.cts` добавлены в список C-подобных расширений: без них легальные TS-файлы оставались бы ровно на том скане, от которого уходили. По приёмке задачи: код вне комментариев больше не триггерит (`fixtures/session_marks/good.ts` держит дженерик `T1`, `Map<K1, V2>`, литерал `"H2"` и деление — всё, что построчный скан флагал), `// TODO(#N)` и легитимные токены чисты, фикстуры и smoke-кейсы добавлены, манифест и README обновлены, пример consumer-конфига расширен на `ts|tsx`. Что осталось за рамками и записано в README: текст JSX не сканируется (это не комментарий и не литерал), метка внутри строкового литерала TS не ловится — асимметрия с `.py` намеренная, в TS/JS литерал сплошь и рядом несёт разметку (`"H2"`, `"P1"`). Разметочные и стилевые расширения (`.css`, `.vue`, `.svelte`) по-прежнему падают в построчный фолбэк — ведётся в [#11](https://git.homedevlab.ru/senokosov/pre-commit-hooks/issues/11).
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
senokosov/pre-commit-hooks#4
No description provided.