import 'package:flutter_test/flutter_test.dart'; void main() { test('Markdown parser extracts all 5 blocks without loss or substring collisions', () { const input = '''```markdown ## 1. ЯДРО / ФОРМУЛА ЗАКОНА: (1-2 чеканных предложения) Огонь — это первородная сингулярность трансформации материи в чистую радиацию духа. ## 2. ОРАКУЛ (МОНОЛИТНОЕ ЭССЕ): (5-8 абзацев) Праиндоевропейский корень *egni- фиксирует не субстанцию, а событие горения. В шумерском мифе бог Гибил нисходит в тигель трансформации. В алхимии огонь выступает универсальным растворителем формы ради освобождения скрытой субстанции. ## 3. ТЕНЕВАЯ ЛОВУШКА И ИСКАЖЕНИЕ: (Теневая ловушка принципа) Теневая ловушка принципа — испепеление контекста, мания тотального контроля через разрушение. ## 4. ЭКЗИСТЕНЦИАЛЬНЫЙ ВОПРОС: (Острый коан) Что именно в твоей структуре ты отказываешься отдать пламени обновления? ## 5. РИТУАЛЬНЫЙ ФИЗИЧЕСКИЙ ЖЕСТ: (Конкретное микродействие) Взять сухую щепку, разломить её надвое и бросить в открытый огонь, не оборачиваясь. Метрика: 4120 символов ```'''; Map parseRevisionBlocks(String text) { final blocks = {}; if (text.trim().isEmpty) return blocks; var src = text.trim(); if (src.startsWith('```')) { src = src.replaceFirst(RegExp(r'^```[a-zA-Z]*\n?'), ''); if (src.endsWith('```')) { src = src.substring(0, src.length - 3).trim(); } } final lines = src.replaceAll('\r\n', '\n').split('\n'); String? detectSlot(String line) { final stripped = line.trim(); if (stripped.isEmpty || stripped.length > 95) return null; final isHeaderFormat = stripped.startsWith('#') || stripped.startsWith('*') || stripped.startsWith('[') || RegExp(r'^(?:\d+[\.\)]|[IVX]+[\.\)])').hasMatch(stripped) || (stripped.length < 70 && (stripped.endsWith(':') || stripped == stripped.toUpperCase())) || RegExp(r'\b(?:ЯДРО|ОРАКУЛ|ТЕНЬ|ВОПРОС|ЖЕСТ|КОАН)\b', caseSensitive: false).hasMatch(stripped); if (!isHeaderFormat) return null; if (RegExp(r'(?:^|[^\wа-яА-ЯёЁ])(?:ЯДР[ОАЕУ]|ФОРМУЛ[А-Яа-я]*|ОНТОЛОГИ[А-Яа-я]*)(?:[^\wа-яА-ЯёЁ]|$)', caseSensitive: false).hasMatch(stripped)) { return 'ЯДРО'; } if (RegExp(r'(?:^|[^\wа-яА-ЯёЁ])(?:ВОПРОС[А-Яа-я]*|КОАН[А-Яа-я]*|РЕФЛЕКСИ[А-Яа-я]*)(?:[^\wа-яА-ЯёЁ]|$)', caseSensitive: false).hasMatch(stripped)) { return 'ВОПРОС'; } if (RegExp(r'(?:^|[^\wа-яА-ЯёЁ])(?:ТЕН[ЬЯЕИЮ]|ТЕНЕВ[А-Яа-я]*|ЛОВУШК[А-Яа-я]*|ИСКАЖЕН[А-Яа-я]*|СЛЕП[А-Яа-я]*\s+ЗОН[А-Яа-я]*)(?:[^\wа-яА-ЯёЁ]|$)', caseSensitive: false).hasMatch(stripped)) { return 'ТЕНЬ'; } if (RegExp(r'(?:^|[^\wа-яА-ЯёЁ])(?:ЖЕСТ[А-Яа-я]*|МИКРОДЕЙСТВИ[А-Яа-я]*|ДЕЙСТВИ[ЕЯ]|ПРАКТИК[А-Яа-я]*)(?:[^\wа-яА-ЯёЁ]|$)', caseSensitive: false).hasMatch(stripped)) { return 'ЖЕСТ'; } if (RegExp(r'(?:^|[^\wа-яА-ЯёЁ])(?:ОРАКУЛ[А-Яа-я]*|СТАТЬ[ЯЕИЮ]|ЭССЕ|ТОЛКОВАНИ[А-Яа-я]*|ОБОГАЩЕНИ[А-Яа-я]*)(?:[^\wа-яА-ЯёЁ]|$)', caseSensitive: false).hasMatch(stripped)) { return 'ОРАКУЛ'; } return null; } final headers = <({int lineIdx, String slot})>[]; for (int i = 0; i < lines.length; i++) { final slot = detectSlot(lines[i]); if (slot != null) { headers.add((lineIdx: i, slot: slot)); } } for (int i = 0; i < headers.length; i++) { final startLineIdx = headers[i].lineIdx + 1; final slot = headers[i].slot; final endLineIdx = (i + 1 < headers.length) ? headers[i + 1].lineIdx : lines.length; var content = lines.sublist(startLineIdx, endLineIdx).join('\n').trim(); content = content.replaceFirst( RegExp(r'^\s*\([^)]*(?:предложен|абзац|коан|действи|формул|ловушк|стать)[^)]*\)\s*\n?', caseSensitive: false), '', ).trim(); content = content.replaceAll( RegExp(r'(?:\n|\r\n)\s*(?:Метрика|Количество символов|Символов|Длина текста)[:—–\s][\s\S]*$', caseSensitive: false), '', ).trim(); if (content.isNotEmpty) { if (!blocks.containsKey(slot) || content.length > blocks[slot]!.length) { blocks[slot] = content; } } } return blocks; } final result = parseRevisionBlocks(input); expect(result.length, 5); expect(result.containsKey('ЯДРО'), true); expect(result.containsKey('ОРАКУЛ'), true); expect(result.containsKey('ТЕНЬ'), true); expect(result.containsKey('ВОПРОС'), true); expect(result.containsKey('ЖЕСТ'), true); expect(result['ЯДРО']!.startsWith('Огонь — это первородная'), true); expect(result['ОРАКУЛ']!.contains('Праиндоевропейский корень'), true); expect(result['ТЕНЬ']!.contains('Теневая ловушка принципа'), true); expect(result['ВОПРОС']!.contains('Что именно в твоей структуре'), true); expect(result['ЖЕСТ']!.contains('Взять сухую щепку'), true); expect(result['ЖЕСТ']!.contains('Метрика'), false); }); }