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

@inaut/math-functions

v1.3.1

Published

Executes code-lines with function calls like Excel

Downloads

21

Readme

1. Mathematic functions

Executes a string-expression.
Script-engine is used to read the expression, build a tree of nodes, validates and calculates the result by executing the nodes.

By default, expression are stored for later reuse. A script-environment, the context of the subject, has to be defined.

1.1. Supported datatypes

Following datatypes are supported:

  • boolean
  • string
  • number
  • arrays

1.1.1. Boolean

Following boolean values are possible:

  • false
  • true

1.1.2. String

A string starts and ends with ' (single-quote). A backslash can be used to escape the single-quote (\'). Examples of strings:

  • 'Hello World!'
  • 'Hello \'World\'!' => 'Hello 'World'!'

1.1.3. Number

Number starts and ends with numbers and dot. Only one dot is allowed. All numbers are interpreted as floating point number in real-format. If the number starts with 0x or 0b, the values are interpreted in hexa-decimal (e.g. 0xFFFF) or binary (0b1010). Example of numbers:

  • 12.3
  • .123 => 0.123
    1. => 123.0
  • -12.3
  • -.123 => -0.123 ==> if there is an operator or backet before the minus, or the minus is the first character in the string
  • 0xAF12 => 44818
  • 0b1001 => 9

1.1.4. Array

Array is a list of items. An array starts with [-bracket and ends with ]. Comma ,is used as delimiter between the items. Only arrays of one datatype are supported. An item can be from datatype

  • boolean
  • string
  • number
  • function

1.1.5. Functions

Functions are returning a value based on the provided argument(s) and their algorithmus. If the provided arguments are invalid, an object instance of ExpressionError will be returned. Function IF_ERROR() can be used to get a substitute value instead the error-value back.

For a list of available function, please check api-documentation directory doc {@link BaseFunction}.

1.2. Order of execution

Operations are executed according their priority. Operations with higher priority are executed before lower once. Operations with the same priority are executed from the left to the right. The priority follows the standard of javascript. Arguments of functions, operations are functions as well, are executed from the left to the right. The node tree is executed from the leave-nodes, down to the root-node. Higher priority operations are moving deeper into the tree than nodes with low priority.

2. Installation and Usage

2.1. Installation

For installation, call

npm install active-content --save

2.2. Usage

Setup ScriptEngine

import { ScriptEngine } from 'active-content';


// get singleton of the engine
const engine = ScriptEngine.GET(); //or new ScriptEngine(), if only local use is needed;
// set environment
engine.setEnvironment({requestData: (selector, args) => {
    switch(selector) {
        case `GET_VALUE`:


    }
}})
//import here your own functions
import("./file-path-to-function");

Execute an expression

// somewhere later
// create and execute expression
const expr = "IF(... , ..., ...)";
const result = ScriptEngine.GET().executeBoolean(expr, "myObject.propertyName"); // or: engine.executeBoolean(), egine.executeNumber(), engine.executeString(), execute()
...

2.3. Setup Environment

You have to setup an environment-object and apply this object to the script-engine via the method setEnvironment() or at each call of any execution-Method.

A function can request data of your environmet (context of the subject you are executiong the expression) through the requestData-Method. The argument selector defines the data a function requests, args are optional arguments for detailed specification of the data. The method returns the data requested or throws an Error.

An instance of class {@link DefaultEnvironment} can be set.

| selector | args | call by function | return | description | |---|:---:|:---:|:---:|:---:| | GET_VALUE | group: group the property belongs (data, notify,..); name: Name of the Property | GET_VALUE() | stringbooleannumber | Returns the value of the requested property | GET_VALUE_STATE | group: group the property belongs (data, notify,..); name: Name of the Property | GET_VALUE_STATE() | boolean | Returns the read-status of the property (true: value is valid) | GET_VALUE_TS | group: string = group the property belongs (data, notify,..); name: string = Name of the Property | GET_VALUE_TS() | number | Returns the timestamp of the property as unix-timestamp in sec | GET_DATE_TIME | useLocalTime: boolean | GET_DATE_TIME() | Date | Should return the actual date-time. Is omitted (throws an error) the date-time from the system will be taken (call of new Date()); | SET_VALUE | group: string = group the property belongs (data, notify,..); name: string = Name of the Propertyvalue: any = value to set | SET_VALUE() | void | Set the value of the variable.

2.4. Add your own function

Workarround until another solution is found (reason: extend class BaseFunction for lib is not working):

2.4.1. BasicFunction-Class

Create a file named BasicFunctin.ts and insert following content.

import { IBaseFunction, ExpressionError } from '@inaut/math-functions';


export abstract class BaseFunction implements IBaseFunction{
    private name: string;
    /**
     * Returns the name of the function
     */
    public getName() {
        return this.name;
    }

    public toString() {
        return 'CodeFunction ' + this.getName();
    }
    private operation: string | undefined;
    /**
     * Returns true if this function is also available as operation (using operator)
     */
    public isOperator() {
        return !!this.operation;
    }

    private priority: number | undefined;
    /**
     * Returns the priority of this function.
     * Only needed for operators.
     */
    public getPriority() {
        if (this.priority === undefined) {
            throw new Error(this.toString() + ' is an operation, but priority is not defined!');
        }
        return this.priority;
    }
    /**
     * Returns true if the priority of this function is higher than the provided priority
     */
    public hasHigherPriorityThan(priority: number) {
        const myPriority = this.getPriority();
        return myPriority !== undefined ? myPriority > priority : false;
    }

    /**
     * Returns the operator-character of this function.
     * Throws an error if this function is not useable as operation.
     */
    public getOperator() {
        if (this.operation) {
            return this.operation;
        } else {
            throw new Error('Function ' + this.getName() + ' has no operator!');
        }
    }
    private description = "";
    /**
     * Returns the description of this function.
     * An empty string if a description is not available.
     */
    public getDescription() {
        if (this.description === undefined) {
            this.description = "";
        }
        return this.description;
    };
    
    private storing = false;
    /**
     * Returns true if this function is storing values between the calls. So, an instance needs to be created for each occurrence.
     */
    public isStoring() {
        return this.storing;
    }
    private asyncron = false;
    /**
     * Returns true if this function must be called asyncron and returns the value not immediately.
     */
    public isAsyncron() {
        return this.asyncron;
    }

    /**
     * Creates a new operator-function
     * @param name Name of the function used in script. Use capital letters\ (e.g. `MY_FUNCTION`)
     * @param priority Priority of this operation according javascript-standard. Higher value => higher priority. Operation with higher priority are called first. (https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Operators/Operator_Precedence)
     * @param operator Character(s) used for this operator function\ (e.g. `>=`, `==`, `!=`).
     * @param description Description about the function
     * @param storesValues If true, function contains data to be hold until next call. Default is false.
     */
    protected constructor(name: string, priority: number, operator: string, description?: string, storesValues?: boolean);
    /**
     * Creates a new function
     * @param name Name of the function used in script. Use capital letters\ (e.g. `MY_FUNCTION`)
     * @param description Description about the function
     * @param storesValues If true, function contains data to be hold until next call. Default is false.
     * @param isAsyncron If true, function must be executed asyncron. Default is false. Therefore override method {@link BaseFunction.executeAsync}. If false, override {@link BaseFunction.execute}
     */ 
    protected constructor(name: string, description?: string, storesValues?: boolean, isAsyncron?: boolean );
    protected constructor(name: string, priorityOrDescription?: number | string, operationOrDescriptionOrStores?: string | boolean, descriptionOrAsync?: string | boolean, stores?: boolean) {
        if (!name) {
            throw new Error('Argument `name` is missing!');
        }
        this.name = name;
        if (priorityOrDescription !== undefined && typeof priorityOrDescription === 'number') {
            // first method signature
            this.priority = priorityOrDescription;
            // operator
            if (typeof operationOrDescriptionOrStores === 'string') {
                this.operation = operationOrDescriptionOrStores;
            } else {
                if (operationOrDescriptionOrStores === undefined) {
                    throw new Error('Argument `operation` is missing!');
                } else {
                    throw new Error('Argument `operation` is not from type `string`!');
                }
            }
            // description
            if (typeof descriptionOrAsync === 'string') {
                this.description = descriptionOrAsync;
            }
            if (stores !== undefined) {
                this.storing = stores;
            }

        } else {
            // second method signature
            // description
            if (priorityOrDescription && typeof priorityOrDescription === 'string') {
                this.description = priorityOrDescription;
            }
            if (operationOrDescriptionOrStores !== undefined && typeof operationOrDescriptionOrStores === 'boolean') {
                this.storing = operationOrDescriptionOrStores;
            }
            if (typeof descriptionOrAsync === 'boolean') {
                this.asyncron = descriptionOrAsync;
            }
        }
    }

    public abstract execute(preexecutedArguments: any[], environment: any, node: Node, execPath?: string): any;

    public executeAsync(preexecutedArguments: any[], environment: any, node: Node, execPath?: string): Promise<any> {
        return new Promise<any>((resolve, reject) => {
            resolve(this.execute(preexecutedArguments, environment, node));
        });
    }

    /**
     * Returns true, if the argument (node-children) should be executed before `execute` of this function is called.
     * By default, returns true for all arguments. Override in function if certain arguments are executed for getting ther value inside the `execute`-method.
     * @param index Zero-based index of the argument
     * @param node The node, none executed (result is not availabe at that time)
     */
    public isPreexecutedArgument(index: number, node: Node): boolean {
        return true;
    }

    /**
     * Returns true if args is an ExpressionError-object or an array which contains an ExpressionError-object.
     */
    protected hasArgumentError(args: any | any[]) {
        if (args && Array.isArray(args)) {
            return args.some(arg => this.isExpressionError(arg));
        } else if (args && typeof args === 'object') {
            return this.isExpressionError(args);
        } else {
            return false;
        }
    }

    /**
     * Returns the first argument with error inside args, if args is an array. Or args itself, if args is an object of ExpressionError (or derived).
     */
    protected getArgumentError(args: any | any[] ): ExpressionError | undefined {
        if (args && Array.isArray(args)) {
            return args.find(arg => this.isExpressionError(arg));
        } else if (args && typeof args === 'object') {
            return this.isExpressionError(args) ? args : undefined;
        } else {
            return undefined;
        }
    }

    protected isExpressionError(objectToCheck: any) {
        if (objectToCheck && typeof objectToCheck === 'object') {
            const errObject = objectToCheck as ExpressionError;
            return errObject.getPosition && errObject.getPosition() !== undefined && errObject.message !== undefined;
        } else {
            return false;
        }
    }


    public abstract clone(): BaseFunction;

}

2.4.2. Create your own function

Create a typescript-file.

import { ScriptEnvironment, Node, ArgumentWrongTypeError, FunctionError, ArgumentMissingError } from '@inaut/math-functions';
import { BaseFunction } from './base-function';

/**
*   Convert degree to radiant
*   
*   ```
*   TO_RAD(degree:number) => number;
*   ```
*
**/
// tslint:disable-next-line:class-name
export class Function_TO_RAD extends BaseFunction {

    @CodeFunction()
    public static META() {
        return new Function_TO_RAD();
    }

    private constructor() {
        super('TO_RAD', 'Convert degree to radiant');
    }

    public execute(preexcArguments: any[], environment: ScriptEnvironment, node: Node, execPath: string) {
        if (this.hasArgumentError(preexcArguments)) {
            return this.getArgumentError(preexcArguments);
        }
        try {
            if (!Array.isArray(preexcArguments) || preexcArguments.length === 0) {
                throw new ArgumentMissingError(node, this, 'degree', 0);
            }
            if (typeof preexcArguments[0] !== 'number') {
                throw new ArgumentWrongTypeError(node, this, 'degree', 0, 'number', typeof preexcArguments[0]);
            }
            const deg = preexcArguments[0];
            return deg * Math.PI / 180.0;
        } catch (err) {
            return err;
        }
    }

    public clone() {
        return new Function_TO_RAD();
    }
}

2.4.3. Register Function

Register function at your script-engine with call of setFunction()-method.

Example:

import { ScriptEngine } from "@inaut/math-functions";
import { Function_TO_RAD } from './function-to-rad';

ScriptEngine.GET().setFunction(Function_TO_RAD.META());

2.5. Open issues

2.5.1. Asyncron function support minor

Support of asyncron call of function and nodes on the path to a asyncron function.

3. Version history

3.1. v1.3.0 (2022-07-01)

  • Added string functions

    • SPLIT {@link Function_SPLIT}
    • REPLACE {@link Function_REPLACE}
    • TRIM {@link Function_TRIM}
    • TRIM_START {@link Function_TRIM_START}
    • TRIM_END {@link Function_TRIM_END}
    • CONCATE {@link Function_CONCATE}
    • JOIN {@link Function_JOIN}
    • GET_CHAR {@link Function_GET_CHAR}
    • GET_STRING {@link Function_GET_STRING}
    • IN_STRING {@link Function_IN_STRING}
    • POS_IN_STRING {@link Function_POS_IN_STRING}
    • LEN {@link Function_IN_STRING}: Returns string or array-length
  • Fix searching for function. Make sure the correct function is taken and not a function starting with the same string.

3.2. v1.3.1 (2022-07-06)

  • Added functions
    • GET_ARRAY_SPLICE {@link Function_GET_ARRAY_SPLICE}
    • TO_LOWER_CASE {@link Function_TO_LOWER_CASE}
    • TO_UPPER_CASE {@link Function_TO_UPPER_CASE}