Source: lib/core/security/evaluator.js

/**
 * Provides dynamic expression and statement evaluation within a given scope.
 */
export class DynamicEvaluator {
    /**
     * Converts a scope object into binding names and values for Function constructor.
     * @param {Object} [scope={}] - The scope object.
     * @returns {{names: string[], values: any[]}}
     * @private
     */
    #toScopeBindings(scope = {}) {
        const names = [];
        const values = [];

        for (const [name, value] of Object.entries(scope)) {
            if (/^[A-Za-z_$][\w$]*$/.test(name)) {
                names.push(name);
                values.push(value);
            }
        }

        return { names, values };
    }

    /**
     * Evaluates a JavaScript expression within a scope.
     * @param {string} expression - The expression to evaluate.
     * @param {Object} [scope={}] - The scope variables.
     * @param {Object} [thisArg=scope] - The 'this' context for evaluation.
     * @returns {any} The result of evaluation.
     */
    evaluateExpression(expression, scope = {}, thisArg = scope) {
        const { names, values } = this.#toScopeBindings(scope);
        const fn = new Function(...names, `return (${expression})`);
        return fn.call(thisArg, ...values);
    }

    /**
     * Executes a JavaScript statement within a scope.
     * @param {string} source - The statement(s) to execute.
     * @param {Object} [scope={}] - The scope variables.
     * @param {Object} [thisArg=scope] - The 'this' context for execution.
     * @returns {any} The result of execution.
     */
    executeStatement(source, scope = {}, thisArg = scope) {
        const { names, values } = this.#toScopeBindings(scope);
        const fn = new Function(...names, `with(this) { ${source} }`);
        return fn.call(thisArg, ...values);
    }

    /**
     * Creates a map of executable methods from string definitions.
     * @param {Object} [methods={}] - An object containing method name and source code pairs.
     * @param {function(Object): Object} getScope - Function to retrieve the scope for a method.
     * @param {function(): Object} getThisArg - Function to retrieve the 'this' context for methods.
     * @returns {Object} A map of functions.
     */
    createMethodMap(methods = {}, getScope, getThisArg) {
        const executable = {};

        for (const [name, source] of Object.entries(methods)) {
            if (typeof source === 'function') {
                executable[name] = source.bind(getThisArg());
            } else {
                executable[name] = (...args) => this.executeStatement(
                    source,
                    { ...getScope(executable), args },
                    getThisArg()
                );
            }
        }

        return executable;
    }
}