markdown-org-extract 0.1.1

CLI utility for extracting tasks from markdown files with Emacs Org-mode support
# Рефакторинг проекта markdown-extract

## Выполненные изменения

### 1. Кастомные типы ошибок (Критично)

**Было:** `Result<T, Box<dyn std::error::Error>>`
**Стало:** `Result<T, AppError>`

Создан модуль `src/error.rs` с enum `AppError`:
- `Io(io::Error)` - ошибки ввода-вывода
- `InvalidDirectory(String)` - неверный каталог
- `InvalidGlob(String)` - неверный glob паттерн
- `InvalidDate(String)` - неверная дата
- `InvalidTimezone(String)` - неверная таймзона
- `DateRange(String)` - неверный диапазон дат
- `Serialization(String)` - ошибки сериализации
- `Regex(String)` - ошибки regex
- `Walk(String)` - ошибки обхода файловой системы

Реализованы `From` трейты для автоматической конвертации:
- `From<io::Error>`
- `From<serde_json::Error>`
- `From<ignore::Error>`

**Преимущества:**
- Типобезопасная обработка ошибок
- Понятные сообщения об ошибках
- Упрощенная отладка

### 2. Enum для форматов вывода (Критично)

**Было:** `String` с проверкой в runtime
**Стало:** `OutputFormat` enum

Создан модуль `src/format.rs`:
```rust
pub enum OutputFormat {
    Json,
    Markdown,
    Html,
}
```

Реализован `FromStr` для парсинга из командной строки.

**Преимущества:**
- Проверка на этапе компиляции
- Невозможно передать неверный формат
- Упрощенный match в коде

### 3. Разделение timestamp.rs на подмодули (Важно)

**Было:** Один файл 17KB
**Стало:** Модульная структура

```
src/timestamp/
├── mod.rs          # Публичный API
├── parser.rs       # Парсинг временных меток
├── repeater.rs     # Логика повторений
└── extract.rs      # Извлечение из текста
```

**Преимущества:**
- Улучшенная читаемость
- Логическое разделение ответственности
- Упрощенное тестирование отдельных компонентов

### 4. Оптимизация клонирования Task (Важно)

**Было:** Тройное клонирование в agenda.rs
```rust
let mut task_copy = task_with_offset.task.clone();
task_copy.timestamp_time = None;
task_copy.timestamp_end_time = None;
agenda.overdue.push(TaskWithOffset {
    task: task_copy,
    days_offset: task_with_offset.days_offset,
});
```

**Стало:** Вынесено в функцию
```rust
fn create_task_without_time(task: &Task, days_offset: Option<i64>) -> TaskWithOffset {
    let mut task_copy = task.clone();
    task_copy.timestamp_time = None;
    task_copy.timestamp_end_time = None;
    TaskWithOffset { task: task_copy, days_offset }
}
```

**Преимущества:**
- Устранено дублирование кода
- Единая точка модификации
- Улучшенная читаемость

### 5. Улучшение валидации glob паттернов (Важно)

**Было:** Ограниченная функциональность, неясные ошибки
**Стало:** Типизированные ошибки через `AppError::InvalidGlob`

**Преимущества:**
- Понятные сообщения об ошибках
- Согласованная обработка ошибок

### 6. Улучшение regex паттернов (Важно)

**Было:** `[A-Za-z]+` - принимает любые буквы
**Стало:** Точный список дней недели

```rust
r"(?: (?:Mon|Tue|Wed|Thu|Fri|Sat|Sun|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday))?"
```

**Преимущества:**
- Более строгая валидация
- Предотвращение ложных срабатываний

### 7. Упрощение обработки ошибок в main.rs

**Было:** Множественные `eprintln!` и `map_err`
**Стало:** Использование `?` оператора с `AppError`

**Преимущества:**
- Более чистый код
- Автоматическая конвертация ошибок
- Единообразная обработка

## Статистика изменений

- Создано новых файлов: 5
  - `src/error.rs`
  - `src/format.rs`
  - `src/timestamp/parser.rs`
  - `src/timestamp/repeater.rs`
  - `src/timestamp/extract.rs`

- Модифицировано файлов: 4
  - `src/main.rs`
  - `src/cli.rs`
  - `src/agenda.rs`
  - `src/timestamp.rs` (переделан в модуль)

- Все тесты проходят: ✅ 36 passed
- Компиляция без ошибок: ✅
- Предупреждения: 2 (неиспользуемые поля, не критично)

## Не выполнено (по запросу)

- Интеграционные тесты
- Желательные улучшения:
  - Trait для рендеринга
  - Прогресс-бар
  - Расширенная документация
  - Benchmark тесты

## Результат

Проект стал более поддерживаемым, типобезопасным и структурированным. Все критичные и важные замечания из code review устранены.