npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

listerine

v1.0.1

Published

A powerful, type-safe in-memory query engine for JavaScript/TypeScript arrays. Listerine provides MongoDB-like query syntax for filtering, searching, and retrieving data from arrays of objects.

Readme

listerine

listerine is a powerful, type-safe, in-memory query engine with Mongo-ish syntax for performing complex (or simple!) queries on arrays of objects.

Features

  • MongoDB-like Query Syntax: Filters and stuff
  • Type Safety: Full TypeScript support with generic types
  • Logical Operators: Support for $and and $or operations
  • Nested Object Queries: Query deeply nested object properties
  • Array Operations: Comprehensive array filtering and matching
  • String Operations: Text searching, pattern matching, and length checks
  • Numeric Comparisons: Range / equality checks, mathematical operations
  • Existence Checks: Test for null, undefined, empty values

Installation

npm install listerine

Quick Start

import { listerine } from 'listerine'

type UserT = {
  id: string,
  name: string,
  age: number,
  tags: string[]
}

const hannah = { id: '1', name: 'hannah', age: 25, tags: ['admin', 'dev'] }
const lily = { id: '2', name: 'lily', age: 18, tags: ['guest'] }
const sailor = { id: '3', name: 'sailor', age: 32, tags: ['guest'] }
const userList = [hannah, lily, sailor]
const userCollection = listerine<UserT>(userList)

const query =  { age$: { $isGreaterThan: 20 } }
const adults = userCollection.find(query)
expect(adults).toEqual([hannah, sailor])

const query = { tags$: { $contains: 'guest' } }
const guests = userCollection.find(query)
expect(guests).toEqual([lily, sailor])

const members = userCollection.findById(['1', '2'])
expect(members).toEqual([hannah, lily])

const member = userCollection.findById('1')
expect(member).toEqual(hannah)

const member = userCollection.findOne({ name$: { $contains: 'i' } })
expect(member).toEqual(lily)

API Reference

listerine<DataT>(dataList: DataT[])

Creates a new listerine collection with the provided array of objects.

const collection = listerine<UserT>(userList)
expect(collection).toHaveProperty('find')
expect(collection).toHaveProperty('findById')
expect(collection).toHaveProperty('findByIds')

NOTE: listerine will apply an id property to any object in dataList that does not already have one.

collection.find(query: QueryT)

Finds and returns an array of all documents matching the query criteria.

const collection = listerine<UserT>(userList)
const results = collection.find({ isActive: true })
expect(Array.isArray(results)).toEqual(true)

collection.findById(id: string)

Finds and returns the document that has the provided id. If no document has the provided id, returns null.

const collection = listerine<UserT>(userList)
const result = collection.findById('123')

collection.findByIds(ids: string[])

Finds and returns any documents with an id found in the provided ids. If no documents match the provided ids, an empty array.

const collection = listerine<UserT>(userList)
const result = collection.findById('123')
expect(Array.isArray(results)).toEqual(true)

Query Syntax

Basic Equality

// Direct equality (implicit $equals)
list.find({ name: 'hannah' })

// Explicit equality
list.find({ name$: { $equals: 'hannah' } })

// Not equal
list.find({ name$: { $doesNotEqual: 'hannah' } })

Numeric Comparisons

// Greater than
list.find({ age$: { $isGreaterThan: 25 } })

// Less than
list.find({ age$: { $isLessThan: 30 } })

// Greater than or equal to
list.find({ age$: { $isGreaterThanOrEqualTo: 25 } })

// Less than or equal to
list.find({ age$: { $isLessThanOrEqualTo: 30 } })

// Between (inclusive)
list.find({ age$: { $isBetween:  } })

// Not between
list.find({ age$: { $isNotBetween:  } })

Array Operations

// Contains a value
list.find({ tags$: { $contains: 'admin' } })

// Contains all values
list.find({ tags$: { $containsAll: ['admin', 'dev'] } })

// Contains some values
list.find({ tags$: { $containsSome: ['admin', 'user'] } })

// Does not contain
list.find({ tags$: { $doesNotContain: 'admin' } })

// Is one of (value in array)
list.find({ role$: { $isOneOf: ['admin', 'moderator'] } })

// Is not one of
list.find({ role$: { $isNotOneOf: ['banned', 'suspended'] } })

// Is in (array is subset)
list.find({ permissions$: { $isIn: ['read', 'write', 'delete'] } })

// Is subset of
list.find({ tags$: { $isSubsetOf: ['admin', 'user', 'guest'] } })

// Is superset of
list.find({ permissions$: { $isSupersetOf: ['read'] } })

String Operations

// Contains substring
list.find({ name$: { $contains: 'Ali' } })

// Starts with
list.find({ name$: { $startsWith: 'A' } })

// Ends with
list.find({ email$: { $endsWith: '@example.com' } })

// Does not start with
list.find({ name$: { $doesNotStartWith: 'B' } })

// Does not end with
list.find({ email$: { $doesNotEndWith: '@spam.com' } })

// Length comparisons
list.find({ name$: { $isLongerThan: 5 } })
list.find({ name$: { $isShorterThan: 10 } })
list.find({ name$: { $isNotLongerThan: 15 } })
list.find({ name$: { $isNotShorterThan: 3 } })

Existence and Emptiness

// Field exists
list.find({ email$: { $exists: true } })

// Field does not exist
list.find({ email$: { $exists: false } })
list.find({ email$: { $doesNotExist: true } })

// Field is empty (null, undefined, '', [], {})
list.find({ description$: { $isEmpty: true } })

// Field is not empty
list.find({ description$: { $isNotEmpty: true } })

Logical Operators

// AND operation (default behavior)
list.find({
  age$: { $isGreaterThan: 25 },
  name$: { $startsWith: 'A' },
})

// Explicit AND
list.find({
  $and: [{ age$: { $isGreaterThan: 25 } }, { name$: { $startsWith: 'A' } }],
})

// OR operation
list.find({
  $or: [{ age$: { $isLessThan: 25 } }, { tags$: { $contains: 'admin' } }],
})

// Complex nested logic
list.find({
  $and: [
    {
      $or: [{ age$: { $isLessThan: 25 } }, { age$: { $isGreaterThan: 35 } }],
    },
    { tags$: { $contains: 'active' } },
  ],
})

Nested Object Queries

const users = [
  {
    id: '1',
    profile: {
      personal: {
        name: 'hannah',
        age: 25,
      },
      settings: {
        theme: 'dark',
      },
    },
  },
]

const list = listerine(users)

// Nested query
list.find({
  profile: {
    personal: {
      name: 'hannah',
      age$: { $isGreaterThan: 25 },
    },
  },
})

// Or...
list.find({
  'profile.personal.name': 'hannah',
  'profile.personal.age$': { $isGreaterThan: 25 },
})

Advanced Examples

User Management System

type UserT = {
  id: string
  username: string
  email: string
  age: number
  roles: string[]
  isActive: boolean
  lastLogin?: Date
  profile: {
    firstName: string
    lastName: string
    bio?: string
  }
}

// 💭 Imagine there are more users that just the one.
const users: UserT[] = [
  {
    id: '1',
    username: 'alice_admin',
    email: '[email protected]',
    age: 25,
    roles: ['admin', 'user'],
    isActive: true,
    profile: {
      firstName: 'hannah',
      lastName: 'Johnson',
      bio: 'System administrator',
    },
  }
]

const usersCollection = listerine<UserT>(memberList)

// Find active admin users
const activeAdmins = usersCollection.find({
  isActive: true,
  roles$: { $contains: 'admin' },
})

// Find users with incomplete profiles
const incompleteProfiles = usersCollection.find({
  'profile.bio$': { $doesNotExist: true }
})

// Find young active users or admins
const targetUsers = usersCollection.find({
  $or: [
    { roles$: { $contains: 'admin' } },
    {
      isActive: true,
      age$: { $isLessThan: 25 }
    },
  ],
})

E-commerce Product Search

type ProductT =  {
  id: string
  name: string
  price: number
  category: string
  tags: string[]
  inStock: boolean
  rating: number
  description: string
}

// 💭 Imagine there are more products that just the one.
const products: ProductT[] = [
  {
    id: '1',
    name: 'Wireless Headphones',
    price: 99.99,
    category: 'Electronics',
    tags: ['wireless', 'audio', 'bluetooth'],
    inStock: true,
    rating: 4.5,
    description: 'High-quality wireless headphones with noise cancellation',
  },
]

const productsCollection = listerine<ProductT>(products)

// Find affordable electronics in stock
const affordableElectronics = productsCollection.find({
  category: 'Electronics',
  price$: { $isLessThanOrEqualTo: 100 },
  inStock: true,
})

// Find highly rated products with specific features
const premiumProducts = productsCollection.find({
  rating$: { $isGreaterThanOrEqualTo: 4.0 },

  $or: [
    { tags$: { $contains: 'premium' } },
    { price$: { $isGreaterThan: 200 } }
  ],
})

// Search products by description keywords
const results = productsCollection.find({
  $or: [
    { name$: { $contains: 'wireless' } },
    { description$: { $contains: 'wireless' } },
    { tags$: { $contains: 'wireless' } }
  ],
})

TypeScript Support

listerine is built with TypeScript and provides full type safety:

type DataT = {
  id: string
  name: string
  count: number
}

const data: DataT[] = [...]
const list = listerine<DataT>(data) // Fully typed

// TypeScript will enforce correct property names and types
const results = list.find({
  name$: { $contains: 'test' }, // ✅ Valid
  count$: { $isGreaterThan: 5 }, // ✅ Valid
  // invalid$: { $contains: 'test' } // ❌ TypeScript error
})

Contributing

Contributions are welcome!
No rules or templates -- just have fun!

License

MIT License