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

type-rules-engine

v0.1.0

Published

Simple, declarative and immutable rules engine for TypeScript.

Downloads

7

Readme

Highlights

  • Easy to use API.
  • Supports various ways to define rules.
  • Provides immutable fact object, powered by immer.
  • Fully tested.

Installation

reflect-metadata package is required, since type-rules-engine provides decorator based rule definition.

npm install type-rules-engine reflect-metadata
# or
yarn add type-rules-engine reflect-metadata

And be sure to reflect-metadata is imported before using type-rules-engine

import "reflect-metadata";

Last, a little tsconfig.json tweak is needed.

{
    "compilerOptions": {
        ...
        "experimentalDecorators": true,
        ...
    }
}

Usage

// 1. Define fact object
const feedCatFact = {
  says: 'meow',
  isHungry: true,
  weight: 5.5,
  feedingCount: 0,
};

// 2. Define rule - using builder API
const feedCatRule = new RuleBuilder<typeof feedCatFact>()
  .name('feed-cat-rule')
  .description('Hungry cats meowing for food')
  .priority(1)
  .when(({ getFact }) => getFact().says === 'meow' && getFact().isHungry)
  .then(({ setFact }) => {
    setFact(fact => {
      fact.feedingCount++;
      fact.isHungry = false;
    });
  })
  .then(({ setFact }) => {
    setFact(fact => {
      fact.says = 'purr';
      fact.weight += 0.1;
    });
  })
  .build();

// or using class and decorators
@Rule({ 
  name: 'feed-cat-rule', 
  description: 'Hungry cats meowing for food',
  priority: 1,
})
class FeedCatRule extends RuleDraft<typeof feedCatFact> {
  @When()
  isCatHungry() {
    const { says, isHungry } = this.getFact();
    return says === 'meow' && isHungry;
  }
  
  @Then({ order: 1 })
  feedCat() {
    this.setFact(fact => {
      fact.feedingCount++;
      fact.isHungry = false;
    });
  }

  @Then({ order: 2 })
  gainWeight() {
    this.setFact(fact => {
      fact.says = 'purr';
      fact.weight += 0.1;
    });
  }
}
const feedCarRule = new FeedCatRule()

// 3. Fire rules engine
const result = await new RulesEngine().fact(feedCatFact).rules([feedCatRule]).fire();
expect(result.triggeredRules).toEqual(['feed-cat-rule']);
expect(result.fact).toEqual({
  says: 'purr',
  isHungry: false,
  weight: 5.6,
  feedingCount: 1,
});

more usages can be found here.

API Reference

We've already covered most APIs in above part, and I believe that it's self-explanatory enough. I'll mention here only about advanced configs and edge cases.

RulesEngine

RulesEngine provides useful options like stop evaluating rules at some point or log result for debugging purpose.

RulesEngineConfig:

| Property | Default | Description | |-----------------------------------------|:-------:|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| | skipOnFirstNonTriggeredRule?: boolean | false | Stops execution when condition() fails, if set to true. | | skipOnFirstAppliedRule?: boolean | false | Stops execution when action() runs successfully, if set to true. | | skipOnFirstFailedRule?: boolean | false | Stops execution when action() throws error, if set to true. | | throwOnError?: boolean | false | Throws when error occurred in condition() or action(), if set to true. By default, it does not throw error inside rule execution except RulesEngineError. | | debug?: boolean | false | Print evaluation result using console.log, if set to true. |

Immutability

We're in JavaScript world, and we all love immutability. Unlike most rules engines, type-rules-engine keeps fact objects immutable, powered by immer.

const fact = { status: 'initialized' };
const rule = new RuleBuilder<typeof fact>()
  .when(() => true)
  .then(({ getFact, setFact }) => {
    // ☠️ Updating fact directly is not allowed.
    getFact().status = 'updated'
    
    // 👌 Instead, use `setFact`.
    setFact(fact => {
      fact.status = 'updated';
    });
  })
  .build();

const result = await new RulesEngine().fact(fact).rules([rule]).fire();

// Updates inside rules engine never affect original fact object.
expect(fact.status).toEqual('initialized');
expect(result.fact.status).toEqual('updated');

Note that setFact is just a wrapper around immer's produce method. See this page for more descriptions.

Road map

Features that are planned:

  • Custom logger support. Replace default console.log on debug mode.
  • Rule composition. Something like this
  • Support for expression language. (Still looking for nice language implementation)

Inspirations

easy-rules which is written in Java inspired a lot of concepts and core API designs of this library.

Contributing

  1. Fork this repository
  2. Create new feature branch
  3. Write your codes and commit
  4. Make all tests and linter rules pass
  5. Push and make pull request