1.0.27 • Published 2 months ago

@adifkz/exp-p v1.0.27

Weekly downloads
-
License
ISC
Repository
github
Last release
2 months ago

Expression Parser for JavaScript/TypeScript

License

The Expression Parser library, also known as "@adifkz/exp-p," is a powerful tool for parsing and evaluating mathematical and logical expressions. It provides a flexible and extensible solution for integrating expression parsing capabilities into your projects. This documentation will guide you through the usage, customization options, and API of the library. You can find the library on npm under the package name "@adifkz/exp-p" and the source code on GitHub at https://github.com/adyfk/exp-p.

Features

  • Evaluate mathematical expressions with operators like +, -, *, /, %, ^, etc.
  • Evaluate logical expressions with operators like AND, OR, NOT, etc.
  • Support for parentheses to control the order of operations.
  • Define and use variables in your expressions.
  • Define custom functions to extend the functionality of the parser.
  • Evaluate string literals.
  • Evaluate array literals and perform operations on arrays.
  • Evaluate object literals and access properties dynamically.

Installation

You can install ExpressionParser using npm:

npm install @adifkz/exp-p

Usage

To use ExpressionParser in your JavaScript code, you need to import the ExpressionParser class and create an instance of it:

import { createParser } from '@adifkz/exp-p';

const parser = createParser();

Evaluating Expressions

Once you have created an instance of ExpressionParser, you can use the evaluate method to evaluate expressions. The evaluate method takes two parameters: the expression to evaluate and an optional context object that contains variables and functions used in the expression.

const parser = createParser();

const result = parser.evaluate('2 + 3 * 4'); // 14

Variable Mapping

You can define variables and use them in your expressions by providing a context object to the evaluate method.

const parser = createParser();

// Define variables
const variables = {
  x: 5,
  y: 10,
};

// Evaluate expression with variables
const result = parser.evaluate("x + y", variables);
console.log(result); // Output: 15

Function Extension

The Expression Parser allows you to extend its functionality by adding custom functions. Here's an example of defining a custom function:

const parser = createParser();

// Define custom function
const functions = {
  square: (_, value: number) => value * value,
};

parser.setFunctions(functions)
// Evaluate expression with custom function
const result = parser.evaluate("square(5)");
console.log(result); // Output: 25

Examples

import moment from 'moment'
import { createParser, FunctionMap } from '../'

describe('example', () => {
  it('basic operator', () => {
    const parser = createParser({
    })
    expect(parser.evaluate('(2 + 3) * 4 - 4')).toBe(16)
    expect(parser.evaluate('-4 + 5')).toBe(1)
    expect(parser.evaluate('4 <= (5 + 2)')).toBe(true)
    expect(parser.evaluate('4 > 5')).toBe(false)
    expect(parser.evaluate('5 ^ 2 + 2')).toBe(27)
    expect(parser.evaluate('5 + 4 * 4')).toBe(21)
    expect(parser.evaluate('5 % 3')).toBe(2)
    expect(parser.evaluate('5.5 * 3')).toBe(16.5)
    expect(parser.evaluate('5 == 5')).toBe(true)
  });
  it('function', () => {
    // Usage example
    const variables = { x: 5 };
    const functions: FunctionMap = {
      add: (_, a: number, b: number) => a + b,
      length: (_, str: string) => str.length,
      length_all: (_, str1: string, str2: string, str3: string) => [str1.length, str2.length, str3.length],
    };
    const parser = createParser({ variables });
    parser.setFunctions(functions)
    expect(parser.evaluate('add(1 + 1, 5) + x')).toBe(12)
    expect(parser.evaluate('length("ADI") + 5', variables)).toBe(8)
    expect(parser.evaluate('length_all("ADI", "FA", "TK")', variables)).toEqual([3, 2, 2])
  });
  it('string', () => {
    const parser = createParser();
    expect(parser.evaluate('"ADI"')).toBe("ADI")
    expect(parser.evaluate('\'ADI\'')).toBe("ADI")
    expect(parser.evaluate('regex("ddd212sdf","\\d\\w\\d")')).toBe(true)
    expect(parser.evaluate('regex("ddd212sdf","\\d\\w\\d","y")')).toBe(false)
  })
  it('boolean', () => {
    const parser = createParser();
    expect(parser.evaluate('true and false')).toBe(false)
    expect(parser.evaluate('true or false')).toBe(true)
    expect(parser.evaluate('!true')).toBe(false)
    expect(parser.evaluate('!!true')).toBe(true)
  })
  it('array', () => {
    const parser = createParser();
    expect(parser.evaluate("[1, 2, 3, 4]")).toEqual([1, 2, 3, 4])
    expect(parser.evaluate("[\"2\", 5]")).toEqual(["2", 5])
    expect(parser.evaluate("[2 + 5, 5]")).toEqual([7, 5])
    expect(parser.evaluate("[5, x]", { x: 2 })).toEqual([5, 2])
  })
  it('array method', () => {
    const parser = createParser();
    const products = [
      { name: 'Product 1', price: 150, quantity: 2 },
      { name: 'Product 2', price: 80, quantity: 0 },
      { name: 'Product 3', price: 200, quantity: 5 },
      { name: 'Product 4', price: 120, quantity: 1 }
    ];
    expect(
      parser.evaluate('filter(products, "_item_.price > 100 and _item_.quantity > 0")', {
        products
      })
    ).toEqual([
      { name: 'Product 1', price: 150, quantity: 2 },
      { name: 'Product 3', price: 200, quantity: 5 },
      { name: 'Product 4', price: 120, quantity: 1 }
    ])

    expect(
      parser.evaluate('map(products, "_item_.name")', {
        products
      })
    ).toEqual([
      'Product 1',
      'Product 2',
      'Product 3',
      'Product 4',
    ])

    expect(
      parser.evaluate('find(products, "_item_.price > 0")', {
        products
      })
    ).toEqual({
      "name": "Product 1",
      "price": 150,
      "quantity": 2
    })

    expect(
      parser.evaluate('some(products, "_item_.price == 200")', {
        products
      })
    ).toBe(true)

    expect(
      parser.evaluate('reduce(products, "_curr_ + _item_.price", 0)', {
        products
      })
    ).toBe(550)
  })
  it('object', () => {
    const parser = createParser();
    expect(parser.evaluate("{ name: 'ADI', age: 20 }")).toEqual({
      name: "ADI",
      age: 20
    })
    expect(parser.evaluate("{ name: 'ADI', age: 5 + 2 }")).toEqual({
      name: "ADI",
      age: 7
    })
    expect(parser.evaluate("object.name", { object: { name: 'ADI' } })).toEqual('ADI')
    expect(parser.evaluate("object.name", { object: { name: 'ADI' } })).toEqual('ADI')
    expect(parser.evaluate("object.0.name", { object: [{ name: 'ADI' }] })).toEqual('ADI')
    expect(parser.evaluate("object.0.object.0.name", { object: [{ name: 'ADI', object: [{ name: "ADI" }] }] })).toEqual('ADI')
  })
  it('date', () => {
    const parser = createParser();

    // expect(parser.evaluate(`date()`)).toBe(moment().toISOString())
    expect(parser.evaluate(`date("2020-01-01")`)).toBe('2019-12-31T17:00:00.000Z')
    expect(parser.evaluate(`date_day(date("2020-01-01"))`)).toBe(1)
    expect(parser.evaluate(`date_month(date("2020-01-01"))`)).toBe(1)
    expect(parser.evaluate(`date_year(date("2020-01-01"))`)).toBe(2020)
    expect(parser.evaluate(`date_format("DD-MM-YYYY", "2020-01-01")`)).toBe("01-01-2020")
    expect(parser.evaluate(`date_in_format("YYYY-MM-DD", "2020-01-01")`)).toBe('2019-12-31T17:00:00.000Z')
    expect(parser.evaluate(`date_in_millis(${moment("2020/01/01", 'YYYY/MM/DD').valueOf()})`)).toBe('2019-12-31T17:00:00.000Z')
    expect(parser.evaluate(`date_millis("2020-01-01")`)).toBe(1577811600000)
    expect(parser.evaluate(`date_format("DD-MM-YYYY", date_plus(1, "day", "2020-01-05"))`)).toBe("06-01-2020")
    expect(parser.evaluate(`date_format("DD-MM-YYYY", date_plus(-1, "day", "2020-01-05"))`)).toBe("04-01-2020")
    expect(parser.evaluate(`date_format("DD-MM-YYYY", date_minus(1, "day", "2020-01-05"))`)).toBe("04-01-2020")
    expect(parser.evaluate(`date_format("DD-MM-YYYY", date_minus(-1, "day", "2020-01-05"))`)).toBe("06-01-2020")
  })
});
1.0.27

2 months ago

1.0.26

3 months ago

1.0.25

3 months ago

1.0.24

5 months ago

1.0.23

5 months ago

1.0.22

5 months ago

1.0.21

5 months ago

1.0.19

7 months ago

1.0.18

7 months ago

1.0.20

7 months ago

1.0.17

10 months ago

1.0.16

10 months ago

1.0.15

11 months ago

1.0.14

11 months ago

1.0.13

11 months ago

1.0.12

11 months ago

1.0.11

11 months ago

1.0.10

11 months ago

1.0.9

11 months ago

1.0.8

11 months ago

1.0.7

11 months ago

1.0.6

11 months ago

1.0.5

11 months ago

1.0.4

11 months ago

1.0.3

11 months ago

1.0.2

11 months ago

1.0.1

11 months ago

1.0.0

11 months ago

0.0.0-development

11 months ago