feat(comment_scan): свои режимы комментариев для стилей и разметки #26

Merged
claude-secretary merged 1 commit from feat/markup-style-comment-mode into main 2026-08-27 14:04:51 +07:00

Закрывает #11.

Что было нельзя

.css, .scss, .html, .vue, .svelte падали в #-фолбэк, где решётка открывает комментарий. Флагалось всё подряд — и ни одно из этого комментарием не является:

.btn { color: #336699; }   /* hex-цвет      */
#main {  }                /* id-селектор   */
<p>Задача #456</p>         <!-- текст страницы -->

README прямо советовал такие расширения не подключать. Теперь их можно скоупить.

Три режима

  • Стили (.css, .scss, .sass, .less) — /* */; // только в препроцессорах и не внутри url(). Именно из-за url(//cdn.example.com/x) здесь не переиспользован c_style_chunks: он принял бы // за начало комментария и съел остаток строки. В чистом CSS // не комментарий вовсе.
  • Разметка (.html, .htm, .vue, .svelte, .xml, .svg) — <!-- -->, а встроенные <script> и <style> отдаются своим сканерам с пересчётом номеров строк относительно всего файла. Кейсы пиннят обе строки в embedded.vue: :6: внутри script, :12: внутри style.
  • Всё прочее — прежний #-фолбэк (shell/yaml/toml).

Выбор режима — одна точка

Раньше каждый хук решал сам, и расхождение росло: no-broken-repo-paths разбирал любой не-python файл как C-подобный, независимо от того, чем он был. Теперь это chunks_for(path, source) в comment_scan — режим есть свойство языка, а не хука.

no-session-marks-in-code подключён к тому же слою, поэтому CSS-селектор grid-area: A1 перестал быть «tracking-меткой», а комментарий с R31 ловится.

Проверка

Фикстуры fixtures/markup/: hex-цвета и id-селекторы, url(//cdn…), текст страницы, текст после закрытия -->, комментарии всех трёх видов, встроенные блоки во .vue.

Мутации, каждая роняет smoke: вернуть стили и разметку в hash-режим (4 кейса), убрать строчные комментарии scss, убрать разбор встроенных блоков (2 кейса), не закрывать комментарий по -->, убрать url-режим.

Две последние мутации сначала выживали — фикстуры их не различали: после --> в файле ничего не стояло, а фрагмент в url() был нечисловым, то есть ссылкой не считался в принципе. Добавлены url.scss (сегмент пути похож на метку — её вырезание не спасает) и текст после закрытия комментария в good.html.

Версия

0.18.00.21.0: 0.19.0 за #24, 0.20.0 за #25. Мержить последним из трёх; если порядок изменится, номер поправлю.

Смежные пункты из тела задачи (зависимость no-broken-repo-paths от неверсионируемых .git/info/exclude и core.excludesFile; асимметрия пробелов в todo-needs-issue) в этот PR не входят — они про другие хуки. Заведу отдельно.

Закрывает [#11](https://git.homedevlab.ru/senokosov/pre-commit-hooks/issues/11). ## Что было нельзя `.css`, `.scss`, `.html`, `.vue`, `.svelte` падали в `#`-фолбэк, где решётка открывает комментарий. Флагалось всё подряд — и ни одно из этого комментарием не является: ```css .btn { color: #336699; } /* hex-цвет */ #main { … } /* id-селектор */ ``` ```html <p>Задача #456</p> <!-- текст страницы --> ``` README прямо советовал такие расширения не подключать. Теперь их можно скоупить. ## Три режима - **Стили** (`.css`, `.scss`, `.sass`, `.less`) — `/* */`; `//` только в препроцессорах и **не внутри `url()`**. Именно из-за `url(//cdn.example.com/x)` здесь не переиспользован `c_style_chunks`: он принял бы `//` за начало комментария и съел остаток строки. В чистом CSS `//` не комментарий вовсе. - **Разметка** (`.html`, `.htm`, `.vue`, `.svelte`, `.xml`, `.svg`) — `<!-- -->`, а встроенные `<script>` и `<style>` отдаются своим сканерам с пересчётом номеров строк относительно всего файла. Кейсы пиннят обе строки в `embedded.vue`: `:6:` внутри script, `:12:` внутри style. - **Всё прочее** — прежний `#`-фолбэк (shell/yaml/toml). ## Выбор режима — одна точка Раньше каждый хук решал сам, и расхождение росло: `no-broken-repo-paths` разбирал **любой** не-python файл как C-подобный, независимо от того, чем он был. Теперь это `chunks_for(path, source)` в `comment_scan` — режим есть свойство языка, а не хука. `no-session-marks-in-code` подключён к тому же слою, поэтому CSS-селектор `grid-area: A1` перестал быть «tracking-меткой», а комментарий с `R31` ловится. ## Проверка Фикстуры `fixtures/markup/`: hex-цвета и id-селекторы, `url(//cdn…)`, текст страницы, текст после закрытия `-->`, комментарии всех трёх видов, встроенные блоки во `.vue`. Мутации, каждая роняет smoke: вернуть стили и разметку в hash-режим (4 кейса), убрать строчные комментарии scss, убрать разбор встроенных блоков (2 кейса), не закрывать комментарий по `-->`, убрать url-режим. Две последние мутации сначала **выживали** — фикстуры их не различали: после `-->` в файле ничего не стояло, а фрагмент в `url()` был нечисловым, то есть ссылкой не считался в принципе. Добавлены `url.scss` (сегмент пути похож на метку — её вырезание не спасает) и текст после закрытия комментария в `good.html`. ## Версия `0.18.0` → **`0.21.0`**: `0.19.0` за [#24](https://git.homedevlab.ru/senokosov/pre-commit-hooks/pulls/24), `0.20.0` за [#25](https://git.homedevlab.ru/senokosov/pre-commit-hooks/pulls/25). Мержить последним из трёх; если порядок изменится, номер поправлю. Смежные пункты из тела задачи (зависимость `no-broken-repo-paths` от неверсионируемых `.git/info/exclude` и `core.excludesFile`; асимметрия пробелов в `todo-needs-issue`) в этот PR не входят — они про другие хуки. Заведу отдельно.
feat(comment_scan): свои режимы комментариев для стилей и разметки
All checks were successful
ci / smoke (push) Successful in 17s
ci / smoke (pull_request) Successful in 16s
cfea45146b
Закрывает hooks#11.

.css/.scss/.html/.vue/.svelte падали в `#`-фолбэк, где решётка открывает
комментарий. Флагался каждый hex-цвет (`color: #336699`), id-селектор
(`#main`) и текст страницы (`<p>Задача #456</p>`), то есть подключить
эти расширения было нельзя вовсе — README прямо советовал их не
скоупить.

Три режима:

- стили (.css/.scss/.sass/.less) — `/* */`; `//` только в
  препроцессорах, и не внутри url(): `url(//cdn.example.com/x)` —
  протокол-относительный адрес, а C-подобный сканер съел бы остаток
  строки. Поэтому не переиспользован c_style_chunks;
- разметка (.html/.htm/.vue/.svelte/.xml/.svg) — `<!-- -->`, а
  встроенные <script> и <style> отдаются своим сканерам с пересчётом
  номеров строк относительно всего файла;
- всё прочее — прежний `#`-фолбэк (shell/yaml/toml).

Выбор режима переехал в общую точку `chunks_for(path, source)`: раньше
каждый хук решал сам, и расхождение росло — no-broken-repo-paths
разбирал ЛЮБОЙ не-python файл как C-подобный, независимо от того, чем
он был.

Мутации, каждая роняет smoke: вернуть стили/разметку в hash-режим (4
кейса), убрать строчные комментарии scss, убрать разбор встроенных
блоков (2 кейса), не закрывать комментарий по `-->`, убрать url-режим.
Две последние сначала выживали — фикстуры их не различали, добавлены
`url.scss` и текст после `-->` в good.html.

Версия 0.18.0 → 0.21.0 (0.19.0 за #24, 0.20.0 за #25).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
claude-secretary force-pushed feat/markup-style-comment-mode from cfea45146b
All checks were successful
ci / smoke (push) Successful in 17s
ci / smoke (pull_request) Successful in 16s
to f5cb22c36a
All checks were successful
ci / smoke (pull_request) Successful in 17s
ci / smoke (push) Successful in 17s
2026-08-27 14:02:24 +07:00
Compare
Author
Owner

Ревью (субагент, свежий контекст): 3 блокера. Все подтвердил воспроизведением и исправил.

B1 — незакрытый и самозакрытый <script> ослепляли разбор до конца файла. Воспроизвёл оба репро: комментарий после такого тега пропускался молча, exit 0. Диапазон без закрывающего тега теперь не растягивается до EOF, а блок просто не сканируется — недосканированный блок лучше молчаливого пропуска всего остатка. Самозакрытие /> распознаётся отдельно: иначе поиск закрытия уезжал на конец следующего блока, и текст между ними считался содержимым <script>. Обе формы закреплены фикстурами, включая selfclosing_then_block.html, который различает именно эту пару.

B2 — README противоречил новому поведению. Абзац в no-session-marks-in-code («такие расширения либо не скоупь… отдельный режим — #11») описывал ровно то, что PR отменяет, и ссылался на закрываемую задачу как на будущую. Переписан. У no-broken-repo-paths дописано, что режимов теперь пять и что для него это поведенческое изменение — раньше <!-- см. docs/old.md --> в .html хук не видел вовсе.

B3 — гейт no-broken-repo-paths расширился незаметно. Подтверждаю замер: .sh и .yaml в первой редакции начинали падать, хотя удалённый комментарий в main фиксировал это как намеренно не сделанное. Переворачивать чужое осознанное решение в PR не про это — неправильно, поэтому у chunks_for появился hash_fallback, и хук зовёт его с False: shell и yaml не разбираются, как и раньше (кейс markup_shell_comment_not_scanned). А стили и разметку хук теперь видит — это и есть суть задачи, и в README это записано как поведенческое изменение с предупреждением консьюмеру.

Ниты:

  • N1<style lang="scss"> разбирается правилами препроцессора; мёртвый аргумент path у markup_chunks убран, вместо него читаются атрибуты тега.
  • N2 — состояние url сбрасывается на переводе строки (незакрытый url( больше не глушит файл), и url( матчится только на границе токена — background-url( не считается.
  • N3 — ограничения разметочного режима записаны в README: атрибут со строкой <!-- даёт громкий ложняк, блок без закрытия не сканируется.
  • N4 — квадратичность убрана: вместо проверки принадлежности на каждом символе — монотонный указатель по отсортированным диапазонам. Замер на том же входе: 12.7 с → 0.19 с (126 КБ / 4000 блоков); 770 КБ / 20000 блоков — 3 с.
  • N5 — за именем тега требуется разделитель: <style-guide> и <scripts> больше не считаются нашими тегами.
  • N6 — из 11 названных выживающих мутаций закрыты все: регистр тега, guard встроенных блоков, string-state и EOF-flush в style_chunks, EOF-flush в markup_chunks, номера строк многострочных комментариев в обоих режимах, незакрытый блок, самозакрытый тег, lang="scss", разделитель после имени тега, url-режим. Четыре из них после первой правки всё ещё выживали — фикстуры их не различали; добавлены selfclosing_then_block.html, markup_comment_in_js_string.html, embedded_scss.vue, similar_tag_name.html.
  • N7 — у no-broken-repo-paths появились кейсы на новых режимах (paths.html, paths_good.html) и на сохранённой границе (hash_lang.sh).
  • N8 — шапки comment_scan («три режима» → пять, с описанием обоих новых) и check_no_broken_repo_paths обновлены.
  • N9 — дедупликация чанков: условный комментарий IE со вложенным <script> больше не даёт двойной строки.
  • N11 — смежные пункты #11 заведены отдельно: #27 (check-ignore/core.excludesFile и пробелы в TODO(...)). Слинковано в теле PR.
  • N12 — пример конфига: no-session-marks-in-code скоупится на css|scss|vue, с оговоркой про .sql/.yaml.

N10 (порядок мержа)#24 уже в main (0.19.0), ветка отребейзена на него, конфликты по импортам разрешены объединением (read_source + chunks_for). Мержу после #25; тег v0.21.0 проставлю следом.

Ревью (субагент, свежий контекст): 3 блокера. Все подтвердил воспроизведением и исправил. **B1 — незакрытый и самозакрытый `<script>` ослепляли разбор до конца файла.** Воспроизвёл оба репро: комментарий после такого тега пропускался молча, exit 0. Диапазон без закрывающего тега теперь не растягивается до EOF, а блок просто не сканируется — недосканированный блок лучше молчаливого пропуска всего остатка. Самозакрытие `/>` распознаётся отдельно: иначе поиск закрытия уезжал на конец **следующего** блока, и текст между ними считался содержимым `<script>`. Обе формы закреплены фикстурами, включая `selfclosing_then_block.html`, который различает именно эту пару. **B2 — README противоречил новому поведению.** Абзац в `no-session-marks-in-code` («такие расширения либо не скоупь… отдельный режим — #11») описывал ровно то, что PR отменяет, и ссылался на закрываемую задачу как на будущую. Переписан. У `no-broken-repo-paths` дописано, что режимов теперь пять и что для него это поведенческое изменение — раньше `<!-- см. docs/old.md -->` в `.html` хук не видел вовсе. **B3 — гейт `no-broken-repo-paths` расширился незаметно.** Подтверждаю замер: `.sh` и `.yaml` в первой редакции начинали падать, хотя удалённый комментарий в `main` фиксировал это как **намеренно не сделанное**. Переворачивать чужое осознанное решение в PR не про это — неправильно, поэтому у `chunks_for` появился `hash_fallback`, и хук зовёт его с `False`: shell и yaml не разбираются, как и раньше (кейс `markup_shell_comment_not_scanned`). А стили и разметку хук теперь видит — это и есть суть задачи, и в README это записано как поведенческое изменение с предупреждением консьюмеру. **Ниты:** - **N1** — `<style lang="scss">` разбирается правилами препроцессора; мёртвый аргумент `path` у `markup_chunks` убран, вместо него читаются атрибуты тега. - **N2** — состояние `url` сбрасывается на переводе строки (незакрытый `url(` больше не глушит файл), и `url(` матчится только на границе токена — `background-url(` не считается. - **N3** — ограничения разметочного режима записаны в README: атрибут со строкой `<!--` даёт громкий ложняк, блок без закрытия не сканируется. - **N4** — квадратичность убрана: вместо проверки принадлежности на каждом символе — монотонный указатель по отсортированным диапазонам. Замер на том же входе: **12.7 с → 0.19 с** (126 КБ / 4000 блоков); 770 КБ / 20000 блоков — 3 с. - **N5** — за именем тега требуется разделитель: `<style-guide>` и `<scripts>` больше не считаются нашими тегами. - **N6** — из 11 названных выживающих мутаций закрыты все: регистр тега, guard встроенных блоков, string-state и EOF-flush в `style_chunks`, EOF-flush в `markup_chunks`, номера строк многострочных комментариев в обоих режимах, незакрытый блок, самозакрытый тег, `lang="scss"`, разделитель после имени тега, url-режим. Четыре из них после первой правки **всё ещё выживали** — фикстуры их не различали; добавлены `selfclosing_then_block.html`, `markup_comment_in_js_string.html`, `embedded_scss.vue`, `similar_tag_name.html`. - **N7** — у `no-broken-repo-paths` появились кейсы на новых режимах (`paths.html`, `paths_good.html`) и на сохранённой границе (`hash_lang.sh`). - **N8** — шапки `comment_scan` («три режима» → пять, с описанием обоих новых) и `check_no_broken_repo_paths` обновлены. - **N9** — дедупликация чанков: условный комментарий IE со вложенным `<script>` больше не даёт двойной строки. - **N11** — смежные пункты #11 заведены отдельно: [#27](https://git.homedevlab.ru/senokosov/pre-commit-hooks/issues/27) (`check-ignore`/`core.excludesFile` и пробелы в `TODO(...)`). Слинковано в теле PR. - **N12** — пример конфига: `no-session-marks-in-code` скоупится на `css|scss|vue`, с оговоркой про `.sql`/`.yaml`. **N10 (порядок мержа)** — [#24](https://git.homedevlab.ru/senokosov/pre-commit-hooks/pulls/24) уже в `main` (`0.19.0`), ветка отребейзена на него, конфликты по импортам разрешены объединением (`read_source` + `chunks_for`). Мержу после [#25](https://git.homedevlab.ru/senokosov/pre-commit-hooks/pulls/25); тег `v0.21.0` проставлю следом.
claude-secretary force-pushed feat/markup-style-comment-mode from f5cb22c36a
All checks were successful
ci / smoke (pull_request) Successful in 17s
ci / smoke (push) Successful in 17s
to 6d055f36ca
All checks were successful
ci / smoke (pull_request) Successful in 17s
ci / smoke (push) Successful in 18s
2026-08-27 14:04:26 +07:00
Compare
claude-secretary deleted branch feat/markup-style-comment-mode 2026-08-27 14:04:51 +07:00
Sign in to join this conversation.
No reviewers
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!26
No description provided.