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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@icrules/core

v0.2.3-alpha.0

Published

Intuitive Compact Rules: A small and extensible rules engine with a compact JSON footprint.

Downloads

8

Readme

ICRules

Intuitive Compact Rules

An extensible JavaScript rules engine with serialized compact JSON container with a React based rules editor to generate rules.

Quick Start

# Install
npm i @icrules/core

Rules include a quantifier and a list of rules that are evaluated individually against the facts.

Here is sample of what constructing a rule manually against a small set of facts would look like...

import { processRules } from '@icrules/core';

const facts = { 
  market: 'en-US', 
  color: 'blue', 
  diameter: 10 
};

const rules = { 
  any: [
    ['market', 'eq', 'en-US'], 
    ['diameter', 'gt', 5]
  ] 
};

const result = processRules(facts, rules);

// result.pass is true if market is en-US and diameter is greater than 5
console.log(result.pass) 

Rule Schema

The rules schema utilizes a compact human readable JSON compatible JavaScript model.

A Rule Group has a index key quantifier of all or any and references a Rule or RuleGroup

A simple rule looks like this given facts are { grass: 'green' }

{ all: [['grass', 'eq', 'green']] }
  ^    ^  ^        ^     ^
  |    |  |        |     term => term that is evaluated against subject
  |    |  |        operator ===> evaluates condition
  |    |  subject           ===> reference facts field
  |    group                ===> allows us to combine multiple rules using the quantifier           
  quantifier                ===> evaluates rule list as "all" ([].every) or "any" ([].some)

More complex rules can be constructed with nested rule groups.

// In the below rule the user must have selected language as "en" and 
// either must be signed-in or have a guestid 
const rule = { 
  all: [
    ['language', 'eq', 'en'],
    { 
      any: [
        ['signedin', 'eq', true], 
        ['guestid', 'eq', true]
      ]
    }
  ] 
}

Note the JSON construct tends to be compact and easy to read using this schema.

Using this scheme allows us to construct more complex rules. It's as simple as providing a list of rules for each quantifier to evaluate against the facts. Each quantifier references an array of rules or rule groups.

ICRules API

processRules()

import { processRules, Facts, Rules, Plugin } from '@icrules/core';

const facts: Facts = {
  market: 'en-US', 
  signedIn: false
}

const rules: Rules = {
  all: [
    ['market', 'eq', 'en-US'],
    ['signedIn', 'eq', true],
  ]
}

const plugins = [] as Plugin[];
const results: ProcessResult = processRules(facts, rules, plugins);

if(results.pass){
  // do the thing that needs done
}

processVerbose()

ICRules() instance

Extensibility

There is a plugin model that allows us to extend the results of the rules being processed. That plugin model is used internally to create a verbosePlugin result.

import { processRules } from '@icrules/core';

// sample facts
const facts = {
  language: 'en',
  signedin: false,
  guestid: true
}

// sample rule
const rule = { 
  all: [
    ['language', 'eq', 'en'],
    { 
      any: [
        ['signedin', 'eq', true], 
        ['guestid', 'eq', true]
      ]
    }
  ] 
};

// the verbose plugin is fairly basic in that it simply returns the 
// values sent in on each level with zero logic, filters and processing
const verbosePlugin = ({ pass, rule, group }) => ({ pass, rule, group });
const processResult = processRules(facts, rule, [verbosePlugin]);

The plugin or plugins are processed for each rule and group evaluated.

With no plugin, processResult value would simply be { pass: true }.

With the verbose plugin it will return each rule evaluated { rule } and if it passed or failed { pass } along with each group evaluated { group }. We can use this information to evaluate which rules are passing/failing to debug the facts/rules used. This is what the editor uses to inform the user what rules and groups are passing in real time against facts while creating rules.

The results from the verbose plugin look like this...

{
  "pass": true,
  "rule": {
    "all": [
      ["language", "eq","en"],
      {
        "any": [
          ["signedin", "eq", true ],
          ["guestid",  "eq", true ]
        ]
      }
    ]
  },
  "group": { // group gives us insights into all rules evaluated
    "all": [
      {
        "pass": true,
        "rule": ["language", "eq", "en"]
      },
      {
        "pass": true, 
        "rule": {
          "any": [
            ["signedin", "eq", true],
            ["guestid",  "eq", true]
          ]
        },
        "group": {
          "any": [
            {
              "pass": false, // <-- this is the only evalutation that failed
              "rule": ["signedin", "eq", true]
            },
            {
              "pass": true,
              "rule": ["guestid", "eq", true]
            }
          ],
          "pass": true // <-- this group passed 
        }
      }
    ],
    "pass": true // <-- this parent or root group passed 
  }
}

Here are the Rule and RuleGroup types might help one understand the schema construct a bit better.

export type Subject = string;
export type Term = any;
export type Rule = [Subject, Operator, Term];
export type Quantifiers = 'all' | 'any';
export type Operator = 'eq' | 'neq' | 'gt' | 'lt' | 'gte' | 'lte' | 'has' | 'nhas' | 'in' | 'nit';
export type Rules = (Rule | RuleGroup)[];
export type RuleGroup = { all?: Rules, any?: Rules };

Using the Operators

The editor uses these labels to each operator which better explain the general usage of operators

|operator|label|JS| |---|---|---| eq | equals | === neq | not equals | !== lt | less than | < lte | less or equal | <= gt | greater than | > gte | greater or equal | >= has | contains | fact.includes nhas | not contains | !fact.includes in | in term | term.includes nit | not in term | !term.includes

Examples

Plugin support