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

fortree

v0.5.0

Published

A descriptive, data-based, and data-driven decisions language

Downloads

15

Readme

Fortree

A descriptive, no-code, plain-text, data-driven query language.

Why use Fortree

Whilst building an application in a highly-restricted Node.js environment, I came into a need to query an evolving dataset. I wanted to be able to specify new queries on-the-fly, and needed the flexibility of performing complex computation when necessary. I couldn't access a database instance, which meant no SQL, and to eval is to give up the keys to your kingdom. Additionally, I needed the freedom to update the language with new constructs over time, without needing to update anything other than the dependencies. Lastly, I wanted the languaged used to be expressive and friendly to my non-technical peers.

Fortree is a decisions "language" that is written in Human JSON. Since it is data, it can be changed without the need to rebuild or redeploy. It has access to a limited context provided to the interpreter, and can perform manipulations on that data to enable advanced compositions for complex decisions. The design of Fortree satisfies four key goals:

  • Descriptive
    Everything is expressed in simple English, no symbols
  • Consistent
    With few exceptions, every statement takes the form:-
{
  expr: string
  params: [ ... ]
}
  • Powerful
    The language is capable of expressing complex decision making logic
  • Secure
    There's no eval, and no shenanigans — Fortree doesn't do anything you wouldn't

Getting Started

Installation is a doddle:

# or, your package manager of choice
npm install fortree

Once installed, using Fortree is straightforward. You have two options.

If your rules are written in Human JSON, the preferred syntax, you should call parseAndEvaluate on your unparsed HJson string.

import { Fortree } from 'fortree'

const fortree = new Fortree()
const hjson = `{
  expr: number
  value: 3
}`
fortree.parseAndEvaluate(hjson) // returns 3

Alternatively, you can write your rules as JSON and parse them separately. If you prefer to do things that way, you should call evaluate instead.

import { Fortree } from 'fortree'

const fortree = new Fortree()
const json = JSON.parse(`{ "expr": "number", "value": 5 }`)
fortree.evaluate(json) // returns 3

Should your application need to load and execute your ruleset often, pre-caching a parsed copy of your ruleset will improve performance.

Examples

Arithmetic

# (10 + 2) * 5
{
  expr: multiply
  params:
  [
    {
      expr: add
      params:
      [
        {
          expr: number
          value: 10
        }
        {
          expr: number
          value: 2
        }
      ]
    }
    {
      expr: number
      value: 5
    }
  ]
}

A random round of FizzBuzz

# context = { digit: Math.round(Math.random() * 100) }
{
  expr: if
  params:
  [
    {
      expr: equals
      params:
      [
        {
          expr: modulo
          params:
          [
            {
              expr: variable
              name: digit
            }
            {
              expr: number
              value: 15
            }
          ]
        }
        {
          expr: number
          value: 15
        }
      ]
    }
    {
      expr: string
      value: fizzbuzz
    }
    {
      expr: if
      params:
      [
        {
          expr: equals
          params:
          [
            {
              expr: modulo
              params:
              [
                {
                  expr: variable
                  name: digit
                }
                {
                  expr: number
                  value: 3
                }
              ]
            }
            {
              expr: number
              value: 3
            }
          ]
        }
        {
          expr: string
          value: fizz
        }
        {
          expr: if
          params:
          [
            {
              expr: equals
              params:
              [
                {
                  expr: modulo
                  params:
                  [
                    {
                      expr: variable
                      name: digit
                    }
                    {
                      expr: number
                      value: 5
                    }
                  ]
                }
                {
                  expr: number
                  value: 5
                }
              ]
            }
            {
              expr: string
              value: buzz
            }
            {
              expr: variable
              name: digit
            }
          ]
        }
      ]
    }
  ]
}

Further Reading

See SPECIFICATION for an exhaustive outline of the language.