Languages: English · Русский · 简体中文
Когда вы нашли баг, перед тем как чинить, напишите тест, который
его воспроизводит — тест должен падать на main и проходить
после фикса. Включите оба изменения в один PR.
Тест должен жить рядом со связанными тестами (например, в
tests/edge_cases/<topic>.rs или tests/ser/<topic>.rs). Короткий
комментарий к тесту объясняет характер падения, чтобы читатель через
десять месяцев понимал, почему этот случай важен.
Почему: молчаливые регрессии — самое смертельное, что может случиться с библиотекой, отгружаемой множеству пользователей. Документированная растяжка не стоит ничего в долгосрочной перспективе.
Если PR трогает что-либо из:
src/parser//src/thin/parser.rs— горячий путь парсингаsrc/ser/text_serializer.rs/src/render/— горячий путь сериализацииsrc/thin/deserializer.rs/src/de/— горячий путь десериализацииsrc/value/— динамический тип значения
… в описании PR должен быть блок с before/after числами criterion по затронутым бенчам:
parse_to_struct/100_upstreams_typed
before: 275 µs
after: 198 µs
change: -28%Цель — не быть самым быстрым любой ценой, а сделать изменения подотчётными. Регрессия 5 % допустима, если она покупает ясность или корректность, но должна быть видна и обоснована.
Используйте удобный скрипт:
./bench.sh # quick run (warmup 1s, measurement 2s, 20 samples)
./bench.sh full # criterion defaults — longer, more accurate
./bench.sh parse # filter: only parse benches
./bench.sh render # filter: only render benches
./bench.sh "parse|render" # any criterion regexCriterion хранит числа прошлого прогона в target/criterion/ и
автоматически сравнивает их при следующем прогоне, так что в выводе
будет change: +/- X %.
Если вы трогаете что-либо под pub в lib.rs, в описании PR
укажите — это:
- semver-совместимо (добавления, ослабленные bounds, правки документации); или
- ломает semver (переименования / удаления, изменённые сигнатуры,
ужесточённые bounds) — в этом случае bump версии идёт в следующий
MINOR, пока мы pre-1.0.
Обновите CHANGELOG.md в том же PR под ## [Unreleased].
Коммиты должны быть атомарными: bug-fix и его тест вместе, новая фича и её тесты вместе. Переименование — отдельный коммит. Рефакторинг, который попутно чинит баг, — вероятно, должен быть двумя коммитами.
git log --oneline должен читаться как changelog. Пишите именно так.
Набор тестов соответствия спецификации находится в git-субмодуле spec/
(ktav-lang/spec). Клонируйте
вместе с субмодулем, чтобы cargo test мог его запустить:
git clone --recurse-submodules https://github.com/ktav-lang/rustЕсли репозиторий уже склонирован без --recurse-submodules:
git submodule update --initcargo test # все тесты (включая conformance)
cargo test --test spec_conformance # только языково-нейтральный набор
cargo test --test edge_cases # одна категория
cargo test multiline # по фильтру имени
cargo test --doc # doc-тестыКатегории тестов:
src/**/tests.rs— приватные unit-тесты на модуль.tests/de/*— десериализация по фичам.tests/ser/*— сериализация по фичам.tests/roundtrip/*— round-trip (T → text → T).tests/edge_cases/*— комбинаторные edge case-ы (литералы со скобками, ключевые слова в map-ах, глубокая вложенность, особые строки…).tests/fixtures.rs— end-to-end по реальным.confфайлам.tests/spec_conformance.rs— языково-нейтральный набор изktav-lang/spec(valid-фикстуры совпадают с JSON-оракулом; invalid-фикстуры отклоняются; valid-фикстуры переживают round-trip).
Источник: benches/parse.rs (criterion). Сценарии охватывают:
parse_to_value— сырой parse вValue(владеющее, публичное дерево).parse_to_struct— parse по thin-пути в типизированную структуру.render— сериализация типизированной структуры в текст.roundtrip— parse + render.multiline_dedent— разбор многострочных строк при разном количестве строк.
Правило декомпозиции: один экспортируемый элемент на файл.
Приватные хелперы живут рядом с типом, который ими пользуется.
Папки группируют тесно связанные элементы (весь src/thin/ — это
zero-copy путь десериализации).
src/
├── lib.rs public entry points
├── value/ owned Value enum (public)
├── parser/ Value-building parser
├── render/ Value → text
├── thin/ zero-copy de path (ThinValue → T)
├── ser/ T → Value (public) + T → text (direct)
├── de/ Value → T (via ValueDeserializer)
└── error/ Error + serde implsДевиз Ktav: «будь другом конфига, а не его экзаменатором». Перед тем как предлагать новую фичу, спросите:
- Добавляет ли это новое правило, которое читателю придётся держать в голове?
- Можно ли всё ещё понять строку без её соседей?
Новые правила всегда дорого стоят. Отклоняйте всё, что не проходит эти две проверки.
Если вы явно не заявите иное, любой вклад, намеренно отправленный для включения в этот проект, в соответствии с определением лицензии Apache-2.0, будет лицензирован на условиях MIT OR Apache-2.0 без каких-либо дополнительных условий или ограничений.