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

@f-o-t/condition-evaluator

v2.0.7

Published

A flexible, type-safe condition evaluator for building rule engines. Uses Zod for schema validation with types inferred from schemas.

Readme

@f-o-t/condition-evaluator

A flexible, type-safe condition evaluator for building rule engines. Uses Zod for schema validation with types inferred from schemas.

Installation

bun add @f-o-t/condition-evaluator

Quick Start

import {
   evaluateCondition,
   evaluateConditionGroup,
   type Condition,
   type ConditionGroup,
   type EvaluationContext,
} from "@f-o-t/condition-evaluator";

const condition: Condition = {
   id: "1",
   type: "string",
   field: "name",
   operator: "eq",
   value: "John",
};

const context: EvaluationContext = {
   data: { name: "John", age: 25 },
};

const result = evaluateCondition(condition, context);
console.log(result.passed); // true

Features

  • Type-safe: All types inferred from Zod schemas
  • Multiple condition types: string, number, boolean, date, array, custom
  • Plugin System: Create custom operators with createOperator() and createEvaluator()
  • Weighted Scoring: Support for weighted conditions with threshold-based evaluation
  • Dynamic References: Compare fields against other fields using valueRef
  • Diagnostics: Human-readable reasons, diff analysis, and dependency extraction
  • Nested field access: Access nested properties with dot notation (user.profile.name)
  • Condition groups: Combine conditions with AND/OR logic
  • Zod validation: All inputs validated at runtime

API Reference

Evaluation Functions

evaluateCondition(condition, context)

Evaluates a single condition against a context.

const result = evaluateCondition(
   {
      id: "1",
      type: "number",
      field: "amount",
      operator: "gt",
      value: 100,
   },
   { data: { amount: 150 } },
);

console.log(result.passed); // true
console.log(result.actualValue); // 150

evaluateConditionGroup(group, context)

Evaluates a group of conditions with AND/OR logic.

const result = evaluateConditionGroup(
   {
      id: "g1",
      operator: "AND",
      conditions: [
         { id: "1", type: "string", field: "status", operator: "eq", value: "active" },
         { id: "2", type: "number", field: "score", operator: "gte", value: 80 },
      ],
   },
   { data: { status: "active", score: 95 } },
);

console.log(result.passed); // true

evaluateConditions(groups, context)

Evaluates multiple condition groups (all must pass).

const { passed, results } = evaluateConditions(
   [group1, group2],
   { data: { ... } }
);

evaluate(conditionOrGroup, context)

Universal function that handles both single conditions and groups.

Condition Types & Operators

String Operators

| Operator | Description | Value Type | | -------------- | ------------------------------ | ---------- | | eq | Equals | string | | neq | Not equals | string | | contains | Contains substring | string | | not_contains | Does not contain substring | string | | starts_with | Starts with | string | | ends_with | Ends with | string | | matches | Matches regex pattern | string | | is_empty | Is empty/null/undefined | - | | is_not_empty | Is not empty | - | | in | Value is in list | string[] | | not_in | Value is not in list | string[] |

Options: caseSensitive, trim

Number Operators

| Operator | Description | Value Type | | ------------- | ---------------------- | -------------------- | | eq | Equals | number | | neq | Not equals | number | | gt | Greater than | number | | gte | Greater than or equal | number | | lt | Less than | number | | lte | Less than or equal | number | | between | Between two values | [number, number] | | not_between | Not between two values | [number, number] |

Boolean Operators

| Operator | Description | Value Type | | ---------- | ----------- | ----------- | | eq | Equals | boolean | | neq | Not equals | boolean | | is_true | Is true | - | | is_false | Is false | - |

Date Operators

| Operator | Description | Value Type | | -------------- | ------------------------ | ---------------------------- | | eq | Equals | string \| Date \| number | | neq | Not equals | string \| Date \| number | | before | Before date | string \| Date \| number | | after | After date | string \| Date \| number | | between | Between two dates | [DateValue, DateValue] | | not_between | Not between two dates | [DateValue, DateValue] | | is_weekend | Is Saturday or Sunday | - | | is_weekday | Is Monday-Friday | - | | day_of_week | Matches day(s) of week | number \| number[] (0-6) | | day_of_month | Matches day(s) of month | number \| number[] (1-31) |

Array Operators

| Operator | Description | Value Type | | -------------- | ------------------------ | ----------- | | contains | Contains item | unknown | | not_contains | Does not contain item | unknown | | contains_all | Contains all items | unknown[] | | contains_any | Contains any item | unknown[] | | is_empty | Array is empty | - | | is_not_empty | Array is not empty | - | | length_eq | Length equals | number | | length_gt | Length greater than | number | | length_lt | Length less than | number |

Condition Options

All conditions support a negate option to invert the result:

{
   id: "1",
   type: "string",
   field: "status",
   operator: "eq",
   value: "active",
   options: { negate: true } // Will pass if status is NOT "active"
}

Nested Groups

Groups can be nested for complex logic:

const group: ConditionGroup = {
   id: "root",
   operator: "AND",
   conditions: [
      { id: "1", type: "string", field: "status", operator: "eq", value: "active" },
      {
         id: "nested",
         operator: "OR",
         conditions: [
            { id: "2", type: "number", field: "score", operator: "gt", value: 90 },
            { id: "3", type: "string", field: "role", operator: "eq", value: "admin" },
         ],
      },
   ],
};

Schemas

All Zod schemas are exported for custom validation:

import {
   StringCondition,
   NumberCondition,
   Condition,
   ConditionGroup,
   EvaluationContext,
} from "@f-o-t/condition-evaluator";

// Validate a condition
const result = Condition.safeParse(myCondition);
if (!result.success) {
   console.error(result.error);
}

Individual Operator Functions

Low-level operator functions are also exported:

import {
   evaluateString,
   evaluateNumber,
   evaluateBoolean,
   evaluateDate,
   evaluateArray,
} from "@f-o-t/condition-evaluator";

// Direct evaluation without full condition structure
const passed = evaluateString("contains", "hello world", "world");

Types

type EvaluationContext = {
   data: Record<string, unknown>;
   metadata?: Record<string, unknown>;
};

type EvaluationResult = {
   conditionId: string;
   passed: boolean;
   field: string;
   operator: string;
   actualValue: unknown;
   expectedValue?: unknown;
   error?: string;
};

type GroupEvaluationResult = {
   groupId: string;
   operator: "AND" | "OR";
   passed: boolean;
   results: (EvaluationResult | GroupEvaluationResult)[];
};

Plugin System

Create custom operators for domain-specific logic:

import { createOperator, createEvaluator } from "@f-o-t/condition-evaluator";
import { z } from "zod";

// Define a custom operator
const isPalindrome = createOperator({
   name: "is_palindrome",
   valueSchema: z.undefined(),
   evaluate: (actual) => {
      if (typeof actual !== "string") return false;
      const cleaned = actual.toLowerCase().replace(/[^a-z0-9]/g, "");
      return cleaned === cleaned.split("").reverse().join("");
   },
   reason: (passed, actual) =>
      passed ? `"${actual}" is a palindrome` : `"${actual}" is not a palindrome`,
});

// Create evaluator with custom operators
const customEvaluator = createEvaluator({
   operators: { is_palindrome: isPalindrome },
});

// Use with custom condition type
const result = customEvaluator.evaluateCondition(
   {
      id: "1",
      type: "custom",
      field: "word",
      operator: "is_palindrome",
   },
   { data: { word: "racecar" } },
);

Weighted Scoring

Use weighted conditions for fuzzy matching:

const result = evaluateConditionGroup(
   {
      id: "g1",
      operator: "AND",
      scoringMode: "weighted",
      threshold: 0.7, // 70% score required to pass
      conditions: [
         { id: "1", type: "string", field: "name", operator: "eq", value: "John", weight: 2 },
         { id: "2", type: "number", field: "age", operator: "gte", value: 18, weight: 1 },
      ],
   },
   { data: { name: "John", age: 16 } },
);

console.log(result.totalScore); // 2 (name matched)
console.log(result.maxPossibleScore); // 3 (total weights)
console.log(result.scorePercentage); // 0.666...

Dynamic References

Compare fields against other fields:

const condition: Condition = {
   id: "1",
   type: "number",
   field: "currentPrice",
   operator: "lt",
   valueRef: "maxBudget", // Compare against another field
};

evaluateCondition(condition, { data: { currentPrice: 50, maxBudget: 100 } });
// Passes because 50 < 100

Dependency Extraction

Analyze condition dependencies for static analysis:

import { extractDependencies } from "@f-o-t/condition-evaluator";

const deps = extractDependencies(conditionGroup);
console.log(deps.fields); // ["user.name", "order.total"]
console.log(deps.references); // ["limits.maxOrder"]
console.log(deps.maxDepth); // 2

License

MIT