Plan lst file filtering
This commit is contained in:
@@ -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 штатной сборкой.
|
||||||
Reference in New Issue
Block a user