@twisuki/neo-filter
v1.0.2
Published
A lightweight, chainable, synchronous array filter utility for elegant data processing
Readme
neo-filter
A lightweight, chainable, synchronous array filter utility with multi-field sorting, pagination, and OR-branch support.
Install
pnpm install @twisuki/neo-filterQuick Start
import { Filter } from "@twisuki/neo-filter";
const results = new Filter<DataItem>(rawData)
.filter((item) => item.active)
.sorter("createdAt", "DESC")
.offset(0)
.limit(10)
.all();API
filter(predicate)
Adds a filter predicate to the operation chain. Multiple filter() calls compose with AND logic — an item must satisfy every predicate.
new Filter(students)
.filter((s) => s.subject1 >= 60)
.filter((s) => s.subject2 >= 60)
.all();sorter(key, direction)
Adds a sort rule. Rules are appended in insertion order as comparison priority. When two items are equal under the highest-priority rule, the next rule breaks the tie.
Repeating the same key updates only its direction, preserving its original priority position.
// Primary: role ASC, tie-break: name ASC
new Filter(users)
.sorter("role", "ASC")
.sorter("name", "ASC")
.all();
// Repeating the same key keeps its original priority
new Filter(data)
.sorter("name", "ASC")
.sorter("name", "DESC") // updates direction only, priority stays first
.all();offset(n) / limit(n)
offset skips n items from the start. Multiple calls are cumulative (added together).
limit caps the result size. Multiple calls take the minimum value.
// Page 2 with 10 items per page
new Filter(data)
.offset(10)
.limit(10)
.all();or(...branches)
Merges multiple OR branches into the pipeline. Each branch is a function that receives a Filter instance and returns it with its own predicates applied.
Branches are combined with OR logic against the existing predicates on this.
new Filter(students)
.filter((s) => s.classId === 1)
.or(
(f) => f.filter((s) => s.isClassMonitor),
(f) => f.filter((s) => s.isStudyCommissar),
(f) => f.filter((s) => s.isLifeCommissar),
)
.all();execute()
Runs the pipeline: filter → sort → slice, resets intermediate state, and returns this for further chaining.
If there are no pending operations, it is a no-op.
all()
Terminal method. Executes the pipeline and returns all matching items.
first()
Terminal method. Executes the pipeline and returns the first matching item, or null if empty.
map(...keys)
Terminal method. Executes the pipeline and returns a projected array containing only the specified keys from each item.
new Filter(users)
.filter((u) => u.active)
.map("id", "name");
// Returns: Array<Pick<User, "id" | "name">>Extending
Subclass Filter to add reusable domain-specific methods:
class StudentFilter extends Filter<Student> {
public isPassed(subject: Student.Subjects): this {
return this.filter((s) => s[subject] && s[subject] >= 60);
}
}
new StudentFilter(students)
.isPassed("subject1")
.isPassed("subject2")
.all();Architecture
execute() processes data in three stages:
- Filter — iterate
_data, retain items satisfying every_operationspredicate - Sort — apply
Array.sortwith a multi-field comparator via_sorterMap (insertion order = priority order) - Slice — apply
_offsetand_limitviaArray.slice
State is reset after each execution so the instance can be reused.
License
MIT
