# План: фильтрация файлов через `.lst` ## Цель Добавить в file picker режим manifest-фильтра: - пользователь выбирает папку целиком; - если в корне выбранной папки есть `.lst`, он ограничивает набор файлов; - если `.lst` нет, сохраняется текущее поведение: выбираются все поддерживаемые файлы; - сам `.lst` никогда не отправляется на обработку. ## Правила `.lst` Одна строка — одно правило. - пустые строки игнорируются; - строки, начинающиеся с `#`, являются комментариями; - `!` в начале строки означает отрицательное правило; - пути относительны к выбранной папке; - абсолютные пути и сегменты `..` запрещены; - разделители `\` нормализуются в `/`; - расширения сравниваются без учёта регистра; - несколько совпавших правил не создают дубли. Пример: ```text *.pdf reports/name*.docx !archive/** !**/*draft*.* ``` ## Glob-маски Поддержать общепринятые шаблоны: - `*` — любое количество символов, кроме `/`; - `?` — один символ, кроме `/`; - `**` — любое количество каталогов; - `[abc]` и `[a-z]` — классы и диапазоны символов; - `[!a]` и `[^a]` — отрицательные классы; - обычный путь без glob-символов — точное совпадение. Семантика: - `*.pdf` — PDF в выбранной папке и подпапках; - `reports/*.pdf` — PDF внутри `reports`; - `**/*.pdf` — PDF на любой глубине; - `name*.pdf` — файлы с префиксом `name`. Положительные правила формируют набор кандидатов. Отрицательные правила удаляют совпавшие файлы из результата. ## Алгоритм 1. Получить все файлы выбранной папки и подпапок через `webkitdirectory`. 2. Нормализовать `webkitRelativePath`, убрав имя корневой выбранной папки. 3. Найти `.lst` только в корне выбранной папки, без учёта регистра. 4. Если `.lst` нет, передать в текущую логику все поддерживаемые файлы. 5. Если `.lst` найден: - прочитать UTF-8 и убрать BOM; - разобрать строки и скомпилировать glob в RegExp; - отбросить некорректные правила с предупреждением и номером строки; - выбрать поддерживаемые файлы, совпавшие хотя бы с одним положительным правилом; - удалить совпадения с отрицательными правилами; - удалить `.lst` из результата; - сохранить исходный порядок файлов и убрать дубли по нормализованному пути. 6. Передать итоговый список в существующий цикл построения таблицы без изменений. Если все положительные правила отсутствуют или некорректны, результат пустой. Автоматический fallback на все файлы запрещён. Если положительное правило не совпало ни с одним файлом, показать предупреждение, но продолжить обработку остальных правил. Неподдерживаемые файлы не добавлять. `.lst` во вложенной папке не является manifest-фильтром и обрабатывается как обычный неподдерживаемый файл. Содержимое ZIP отдельно не фильтровать: ZIP выбирается как один файл и далее обрабатывается существующим механизмом раскрытия архивов. ## Где менять код Алгоритм фильтра вынести в чистый модуль рядом с текущим picker, например: ```text upload/frontend/table/lst_filter.js ``` Точка подключения — `on_folder_change.js`, до существующего цикла построения дерева. DOM и upload-транспорт в модуль фильтра не добавлять. Сборочные `site/static/dist/*.js` изменять только штатной сборкой. ## Минимальные тесты Проверить: 1. Папка без `.lst` сохраняет старое поведение. 2. `.lst` не попадает в результат. 3. `*.pdf`, `name*.pdf`, `?`, `**` и классы символов. 4. Положительные и отрицательные правила вместе. 5. Комментарии, пустые строки, BOM, CRLF и пробелы. 6. Регистр расширения (`A.PDF` совпадает с `*.pdf`). 7. Кириллицу, пробелы и вложенные каталоги. 8. Дубли и перекрывающиеся маски. 9. Запрет `/etc/x`, `C:/x`, `../x`, `a/../b`. 10. Битую маску без падения всего picker. 11. Правило без совпадений с предупреждением. 12. Только отрицательные или полностью битые правила дают пустой результат. 13. `.lst` во вложенной папке не включает manifest-режим. 14. ZIP выбирается целиком, без фильтрации его внутреннего содержимого. ## Ограничения реализации - Не менять backend-контракт. - Не добавлять базу данных, отдельный сервис или новый формат конфигурации. - Не переписывать существующий picker. - Изменить минимальное число файлов. - Сначала реализовать алгоритм и тесты, затем обновить dist штатной сборкой.