Files

3.9 KiB
Raw Permalink Blame History

Проект: /root/WORK/memo (Kotlin/JVM). Заказ по чанкеру markdown.

Создать РОВНО ОДИН новый файл: memo-core/src/main/kotlin/memo/core/Chunker.kt и РОВНО ОДИН новый тестовый файл: memo-core/src/test/kotlin/memo/core/ChunkerTest.kt

Chunker.kt

package memo.core

data class Chunk( val heading: String, // текст заголовка без решёток, обрезанный по краям val line: Int, // 1-based номер строки, ГДЕ СТОИТ ЗАГОЛОВОК; 1, если заголовка нет val text: String, // текст раздела без строки-заголовка val ord: Int, // порядковый номер чанка в файле, с 0 )

fun chunkMarkdown(text: String): List

Правила:

  • Разделитель — строка, начинающаяся с одного, двух или трёх символов '#' и следующего за ними пробела (заголовки '#'..'###'). Более длинные последовательности решёток заголовками НЕ считаются.
  • Заголовок попадает в field heading, его строка — в field line. В text строки-заголовки не входят (text обрезается по краям; пустые строки в начале и конце удаляются).
  • Текст ДО первого заголовка даёт чанк с heading = "" и line = 1 (только если он непустой после обрезки).
  • Пустые чанки (text пустой после trim) НЕ возвращаются.
  • Боковые ограничения по размеру: если text длиннее 4000 символов, он режется на несколько чанков по 4000 символов с перекрытием 600 символов (хвост предыдущего повторяется в начале следующего); все части одного раздела имеют ОДИН И ТОТ ЖЕ heading и line, ord растёт.
  • Никаких зависимостей; чистый Kotlin.

ChunkerTest.kt — ровно 5 тестов, имена ровно такие

  1. splitsByHeadingLevels — вход с '# A', '## B', '### C' → 3 чанка, heading = ["A","B","C"], line = [1,3,5], ord = [0,1,2].
  2. textBeforeFirstHeadingBecomesChunkWithEmptyHeading — ввод "преамбула\n# Заголовок\nтело" → 2 чанка, первый: heading = "" (пустая строка), line 1; второй heading "Заголовок".
  3. fourHashesIsNotAHeading — строка '#### не заголовок' остаётся частью текста предыдущего раздела.
  4. emptySectionsAreDropped — ввод с двумя заголовками подряд без текста между ними → 1 чанк.
  5. longSectionIsSplitWithOverlap — раздел из 6000 символов 'а' → 2 чанка, длина первого 4000, длина второго 2600, и последние 600 символов первого равны первым 600 символам второго (перекрытие).

После: ./gradlew :memo-core:test --rerun-tasks — все тесты (4 старых + 5 новых) зелёные. Коммит: git add -A && git commit -m "core: чанкер markdown по заголовкам с перекрытием".

СТРОГИЕ ЗАПРЕТЫ:

  • Не выводить план текстом; сразу создавай файлы.
  • Не трогать существующие файлы (Embedder.kt, Db.kt, CoreSmokeTest.kt, build.gradle.kts) и любые другие.
  • Не добавлять зависимости.
  • Не создавать другие файлы.