8.6 KiB
8.6 KiB
project-tasks — VS Code Extension
Хранение
Формат: Markdown + YAML frontmatter (один .task.md файл на задачу)
---
id: "..."
title: "Пофиксить баг логина"
status: todo # todo | in-progress | done | cancelled
priority: high # low | medium | high | critical
tags: [bug, frontend]
assignee: ""
created: 2026-07-12T10:00:00Z
updated: 2026-07-12T10:00:00Z
---
Описание задачи в markdown...
Структура папок:
.vscode/tasks/— проектные задачи- глобальная папка — настраивается (
projectTasks.globalPath)
Оба пути настраиваются через VS Code settings.
UI в основном окне (Split-редактор)
Через Custom Editor + WebView:
- Activity Bar — вкладка Project Tasks
- Task Dashboard — WebView в editor area со split layout:
- Левая панель — список задач с фильтрацией/группировкой
- Правая панель — содержимое выбранной задачи (редактируемый markdown)
- TreeView — быстрый просмотр по статусу
Архитектура кода
Актуальная раскладка (после рефакторинга портов/адаптеров):
src/
├── extension.ts # composition root (DI, register)
├── ports.ts # IFileSystem, ITaskRepository, IConfigProvider
├── error.ts # AppErrorVariant + AppError { variant, message }
├── model/task.ts
├── storage/
│ ├── FsTaskRepository.ts
│ ├── NodeFileSystem.ts
│ └── VscodeConfigProvider.ts
├── commands/ # use-cases без vscode UI
│ ├── createTask.ts
│ ├── openTask.ts
│ ├── deleteTask.ts
│ └── changeStatus.ts
├── dashboard/ # filter/group/view + inbound message parse
├── views/
│ └── taskTreeProvider.ts # TreeView; WebView host — отдельно
└── utils/
├── uuid.ts
└── markdown.ts # parse/serialize frontmatter
tests/helpers/InMemoryFileSystem.ts
UI (input box, quick pick, open editor) — тонкие адаптеры; бизнес-логика в
use-cases + ITaskRepository. Ошибки — AppError из error.ts.
План реализации
| Фаза | Что делаем |
|---|---|
| 1. Scaffold | Extension, TypeScript, сборка, package.json |
| 2. Storage | CRUD .task.md, парсинг frontmatter, unit-тесты storage |
| 3. TreeView | sidebar по статусу, file watcher |
| 4. Команды | createTask, deleteTask, changeStatus, openTask (use-cases → wiring UI) |
| 5. Task Dashboard | WebView split layout |
| 6. Глобальные задачи | использование globalPath |
| 7. Kanban | drag-n-drop |
| 8. Публикация | vsce publish |
Фаза 4 — команды (use-cases)
| Команда | Поведение |
|---|---|
createTask |
title + folder → defaults todo/medium; empty title / no folder |
deleteTask |
folder + id → delete; not found |
changeStatus |
folder + id + status → update; not found |
openTask |
folder + id → path + task для editor; not found |
Фаза 5 — Task Dashboard
Split layout: список (filter/group) + detail (editable markdown body).
| Модуль | Поведение |
|---|---|
filterTasks |
statuses / priorities / query (title+body) / tags (AND); пустой = all |
groupTasks |
none | status | priority; пустые группы не отдаём; фиксированный порядок |
buildDashboardView |
filter → group; selected по id из полного списка (даже если отфильтрован) |
parseDashboardInboundMessage |
ready / selectTask / setFilter / setGroupBy / saveDescription / refresh |
loadDashboard |
folder → { tasks }; AppError.NO_FOLDER |
saveTaskDescription |
folder + id + description → update body; NOT_FOUND / validation |
Unit-тестами не покрываем (нужен Extension Host / DOM WebView):
WebviewPanelcreate/dispose, HTML/CSS split layout, CSP / local resourcespostMessagewiring host ↔ webview (кроме parse inbound payload)- регистрация
projectTasks.openDashboard, status bar → open panel - live refresh watcher → push в webview
- визуальный рендер списка/редактора в editor area
Зависимости
front-matter— разбор YAML frontmatter (body + attributes)js-yaml— сериализация frontmatter обратно в YAML (dump)uuid— генерация IDneverthrow—Result/ResultAsyncдля use-casesvitest/eslint— dev
История изменений (решения, не чеклист)
Краткая летопись смен относительно изначального наброска плана. Детали
рефакторинга storage/тестов — в архиве docs/REFACTOR-AND-TEST.md (документ
закрыт, не ведём).
Изначальный набросок (v0)
- Парсинг:
gray-matter - Storage:
taskStore.ts(CRUD),configStore.ts(settings) - Сборка/скелет:
yo code-ориентированный scaffold - Дерево модулей: storage + views (tree/list/dashboard) + commands + utils
Рефакторинг storage / чистая архитектура
taskStore/configStore→ порты (IFileSystem,ITaskRepository,IConfigProvider) и адаптеры:FsTaskRepository,NodeFileSystem,VscodeConfigProvider
extension.ts— composition root (DI), tree зависит от портов- Unit-тесты: Vitest, colocation,
InMemoryFileSystemвtests/helpers/
gray-matter → front-matter + js-yaml
- Было в плане: один пакет
gray-matterна parse (+ stringify при необходимости). - Стало:
front-matterдля чтения attributes/body;js-yaml(dump) для записи frontmatter вserializeTask. - Зачем:
gray-matterдаёт лишние возможности парсинга (eval для JS и прочая «магия»), которые для задач не нужны; Vite на eval ругается, с точки зрения безопасности это нежелательно. Поэтому parse черезfront-matter, serialize черезjs-yaml(dump). Формат файла тот же: Markdown + YAML frontmatter.
neverthrow + AppError
- Use-cases возвращают
ResultAsync<T, AppError>. AppErrorVariant— const-object кодов (NOT_FOUND: "not-found").AppError—{ variant, message };messageиз шаблона с{placeholders}черезappError(variant, params?).
Прочее относительно v0
- Сборка: Vite (extension bundle), не классический
tsc-only из yo code - В модели/файле задачи зафиксирован
idв frontmatter (нужен для list/get/update/delete) - Фаза 4: use-cases в
src/commands/*тестируются без vscode; UI — отдельные адаптеры