classify-filename
v0.1.2
Published
Sort filenames into named buckets by rules — strings, regex, or predicates. Zero dependencies.
Maintainers
Readme
classify-filename
Sort filenames into named buckets by rules. Zero dependencies, tiny footprint.
npm install classify-filenameQuick start
import { classify } from 'classify-filename';
const files = [
'NOC_2024.pdf',
'noc_letter.pdf',
'agreement_v1.docx',
'invoice_2.pdf',
'invoice_10.pdf',
'random.txt',
];
const result = classify(files, [
{ name: 'noc', match: /^noc/i },
{ name: 'agreements', match: 'agreement' },
{ name: 'invoices', match: /^invoice/i },
]);
// result.sections:
// {
// noc: ['noc_letter.pdf', 'NOC_2024.pdf'],
// agreements: ['agreement_v1.docx'],
// invoices: ['invoice_2.pdf', 'invoice_10.pdf'], // natural sort: 2 before 10
// uncategorized: ['random.txt'],
// }API
classify(filenames, sections, options?)
Parameters
filenames: string[]— the filenames to sort.sections: Section[]— buckets with matching rules. Order matters — earlier sections win on conflict.options: ClassifyOptions— see below.
Returns ClassifyResult — { sections: Record<string, string[]> }, plus matches when explain: true.
Matchers
A section's match can be:
- a string — substring match (case-insensitive by default)
- a RegExp —
.test()-ed against the filename; respects its own flags - a function —
(filename) => booleanfor arbitrary logic - an array of the above — OR-combined
{ name: 'legal', match: ['agreement', 'contract', /nda/i] }Options
| Option | Default | Behavior |
| --- | --- | --- |
| caseSensitive | false | Applies only to string matchers. RegExp matchers respect their own flags. |
| fallback | 'uncategorized' | Bucket for unmatched files. Pass false to drop them. |
| multiMatch | false | If true, a file lands in every matching section, not just the first. |
| sort | 'asc' | Natural-sort ascending. 'desc', a comparator, or false to disable. |
| explain | false | When true, result includes a matches map from filename → section name. |
Priority is section order
The first section whose predicate returns true wins:
// noc_agreement.pdf lands in 'noc', not 'agreements'.
classify(['noc_agreement.pdf'], [
{ name: 'noc', match: 'noc' }, // checked first
{ name: 'agreements', match: 'agreement' },
]);Put narrow rules first, broad rules last.
Debugging with explain
const result = classify(files, sections, { explain: true });
console.log(result.matches);
// { 'noc_agreement.pdf': 'noc', 'random.txt': 'uncategorized', ... }Why not just .filter()?
.filter() gives you one bucket. Real file sorting needs multiple named buckets, priority rules, natural sort, and a fallback for unmatched files — that's boilerplate you'd rewrite every time. classify-filename wraps it in a single call.
Not in v1
- No glob support — use a RegExp for now.
- No file-object input (size, date) — filename-only. Coming in v1.1.
- No CLI — this is a library. A
binwrapper may follow.
See ROADMAP.md for what's planned.
License
MIT
