Files
999/test/markdown_paste_parser_test.dart
T

128 lines
6.2 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<String, String> parseRevisionBlocks(String text) {
final blocks = <String, String>{};
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);
});
}