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