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 🙏

© 2026 – Pkg Stats / Ryan Hefner

tinyfilter

v1.0.2

Published

`tinyfilter` is a extremely tiny filtering language.

Readme

tinyfilter

tinyfilter is a extremely tiny filtering language.

It's like expr-lang but safe for untrusted human input.

It was built for backbeat's table folder language.

Add it to your repo with:

cargo add tinyfilter

and for javascript

npm add tinyfilter
# or whatever package manager the kids use nowadays

Why?

I need a tiny, easily embeddable filter language for backbeat that is safe against untrusted user input.

It also needs a tiny surface area, as the spec for this is technically part of the backbeat spec.

It's unsafe to evaluate untrusted expr-lang inputs. For example, evaluating 1..9007199254740992 will let you instantly crash the host, and expr-lang has far too much of an implementation surface for something I want to be portable.

Usage

In Rust:

fn main() {
	let mut cx = tinyfilter::Context::default();

    cx.insert("age", 24.0);
    cx.insert("name", "zk");
    cx.insert("hasID", false);

	match tinyfilter::evaluate("age >= 18 and hasID", &cx) {
		Ok(true) => println!("filter matched"),
		Ok(false) => println!("filter didn't match"),
		Err(err) => println!("the user's filter was invalid: {err}"),
	}
}

In Typescript:

import { evaluate } from "tinyfilter";

let result = evaluate("age >= 18 and hasID", {
	age: 24,
	name: "zk",
	hasID: false,
});

Full Reference

Syntax

Filters generally look like this:

hasID and age > 18

A filter must resolve to either true or false. An expression that doesn't resolve to a boolean will error.

There is no let or any way to create intermediate bindings.

You can do conditionals with if/else, if you want to use some extra lines.

if age < 18 {
	false
} else {
	hasID
}

Types

There are:

  • str, which is UTF8 text. You can write a string literal with "asdf".
  • num, which is a 64 bit floating point number. You can define integers e.g. 123 or decimals 123.456. You can also put _ to separate integers up e.g. 1_000_000.
  • bool, which is true or false. You can write true or false to specify a boolean.
  • map, which are key value pairs. You can index into a map with map.value or map["value with funny name"]. There is no map literal syntax.
  • nil, which is produced from indexing into a map that doesn't have a value for that key.

There are no arrays/lists, and there is no syntax for a map literal. (by design, use expr-lang if you need powerful stuff)

Operators

a + b

Add two numbers together. There is no string concatenation.

  • 5 + 5 == 10
  • 1.7 + 5 == 6.7
  • "a" + "b" (error)
  • 5 + true (error)

a - b

Subtract two numbers.

  • 5 - 5 == 0
  • 1.7 - 5 == -3.3

a * b

Multiply two numbers.

  • 2 * 1.5 == 3

a / b

Divide two numbers. Use floor(a / b) for integer division.

  • 5 / 2 == 2.5
  • 5 / 0 (error)

a % b

Return the remainder of dividing a by b.

  • 10 % 3 == 1
  • 10 % 3.1 == 0.7
  • -5.5 % 2 == -1.5

a ** b

Return a to the power of b.

  • 5 ** 3 == 125
  • 5 ** 2.5 == 55.90169943749474
  • 5 ** -1 == 1/5

a == b

Return whether a is equal to b. Errors if either side of argument is a map.

  • (5 == 5) == true
  • (5 == 4) == false
  • (5 == "5") == false
  • ("foo" == "foo") == true

a != b

Return whether a is not equal to b. Errors if either side of argument is a map

  • (5 != 4) == true
  • (5 != 5) == false
  • (5 != "5") == true

a < b, a <= b, a > b, a >= b

Return whether a is less than (<), less than or equal to (<=), greater than (>), greater than or equal to (>=) b.

  • 5 > 4 == true
  • 5 > 5 == false
  • 5 >= 5 == true
  • 5.5 < 6 == true
  • 5.5 < 1 == false
  • 5.5 <= 5.5 == true

not a

Return the boolean opposite of a.

  • not true == false
  • not false == true
  • not 12 (error)

a and b

Return true if a and b are true.

  • true and true == true
  • true and false == false
  • 1 and true (error)

a or b

Return true if a or b are true.

  • true or false == true
  • false or false == false
  • 1 or true (error)

a otherwise b

Returns b if a is null.

  • tags.difficulty otherwise 0 == 0 (assume that tags.difficulty is nil)
  • tags.isAwesome otherwise false == true (assume that tags.isAwesome is true)
  • "a" otherwise "b" (error)

exists a

Returns true if a is not nil.

  • exists tags.difficulty == false
  • exists tags.isAwesome == true
  • not exists tags.difficulty == true

Functions

num(arg)

Takes a string and converts it into a number. Floats get truncated.

  • num("14") == 14
  • num("14.123") == 14.123
  • num("a") (error)
  • num("1e10") (error)

type(arg)

Takes anything and returns a string indicating what type it is.

  • type(5) == "num"
  • type(5.5) == "num"
  • type("hi") == "str"
  • type(nil) == "nil"
  • type(true) == "bool"

startsWith(str, str)

Returns whether the first string starts with the second string.

  • startsWith("md5/70924d6fa4b2d745185fa4660703a5c0", "md5/") == true
  • startsWith("md5/70924d6fa4b2d745185fa4660703a5c0", "sha256/") == false

contains(str, str)

Returns whether the first string contains the second string.

  • contains("Blue Rain", "Rain") == true
  • contains("Blue Rain", "Black") == false

endsWith(str, str)

Returns whether the first string ends with the second string.

  • endsWith("epic0", "0") == true
  • endsWith("epic0", "1") == false

abs(num)

Return the absolute value of a number.

  • abs(-5.1) == 5.1

ceil(num)

Returns the number rounded up.

  • ceil(5.1) == 6

floor(num)

Returns the number rounded down.

  • floor(5.9) == 5

round(num)

Round the number to the nearest whole number.

  • round(5.1) == 5
  • round(5.9) == 6
  • round(5.5) == 6

min(num, num)

Return the smallest of two numbers.

  • min(9, 5.5) == 5.5

max(num, num)

Return the largest of two numbers.

  • max(9, 5.5) == 9