From ce44143a09f90b1c5a03e1f51a5ae65e993f3927 Mon Sep 17 00:00:00 2001 From: Repinoid Date: Wed, 21 Oct 2026 15:49:29 +0300 Subject: [PATCH] Plan lst file filtering --- PLAN-LST-FILTER.md | 121 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 PLAN-LST-FILTER.md diff --git a/PLAN-LST-FILTER.md b/PLAN-LST-FILTER.md new file mode 100644 index 0000000..24e77c9 --- /dev/null +++ b/PLAN-LST-FILTER.md @@ -0,0 +1,121 @@ +# План: фильтрация файлов через `.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 штатной сборкой.