samedi 10 juillet 2021

JavaScript Data validation design pattern - Calling library function without 'this' keyword

I'm writing a JavaScript library that would validate the data stored in flat file. It will take list of tests (reusable JavaScript code stored as text in database) and records of the datafile as array. Current code shown here is trying to convert the test scripts (JS) stored as text to JavaScript functions; attach those functions to current object and execute it. Stored test scripts (in text) make use of functions (calls them) in the JavaScript library. These functions can only be accessed if called with this keyword and reasonably so. However, There would be quite a few library functions and I don't want test test script writers to redundantly prefix library function with this.

Is there anyway I can fix this issue in current structure? Any suggestions on other design pattern or architecture that may help achieve this.

// Library of functions exposed to caller of the library
module.exports = (function (global) {
    // 'new' an object
    var editsApp = function (edits) {
        return new editsApp.init(edits);
    };

    // prototype holds methods (to save memory space)
    editsApp.prototype = {
        randomIntFromInterval: function (minX, maxX) {
            return Math.floor(Math.random() * (maxX - minX + 1) + minX);
        },

        run: function () {
            // var test = {};
            for (let i = 0; i < this.edits.length; i++) {
                // console.log(array[i]);
                this['A' + i] = this.NamedFunction(
                    'A' + i,
                    [''],
                    this.edits[i],
                    this
                )(this);
            }
            for (let i = 0; i < this.edits.length; i++) {
                // console.log(array[i]);
                this['A' + i]();
            }
        },

        NamedFunction: function (name, args, body, scope, values) {
            if (typeof args == 'string') {
                values = scope;
                scope = body;
                body = args;
                args = [];
            }

            if (!Array.isArray(scope) || !Array.isArray(values)) {
                if (typeof scope == 'object') {
                    var keys = Object.keys(scope);

                    values = keys.map(function (p) {
                        return scope[p];
                    });
                    scope = keys;
                } else {
                    values = [];
                    scope = [];
                }
            }
            return Function(
                scope,
                'function ' +
                    name +
                    '(' +
                    args.join(', ') +
                    ') {\n' +
                    body +
                    '\n}\nreturn ' +
                    name +
                    ';'
            ).apply(null, values);
        },
    };

    // the actual object is created here, allowing us to 'new' an object without calling 'new'
    editsApp.init = function (edits) {
        var self = this;

        self.edits = edits || [];
    };

    // trick borrowed from jQuery so we don't have to use the 'new' keyword
    editsApp.init.prototype = editsApp.prototype;

    // attach our editsApp to the global object, and provide a shorthand '$G' for ease our poor fingers
    global.editsApp = global.G$ = editsApp;
})(window);

// Array of test being created to run through library
export const edits = [
    `
    let c = this.randomIntFromInterval(1,10);  // WORKS 
    let d = this.randomIntFromInterval(1,10);  // WORKS
    if (c> d) {
      console.log('c is bigger than d')
    } else if (d>c) {
      console.log('d is bigger than c')
    }
        console.log('c',c );
        console.log('d',d )`,
    `
    let e = randomIntFromInterval(2,5);   // DOES NOT WORK
    let f = randomIntFromInterval(2,5);   // DOES NOT WORK
    if (e> f) {
      console.log('e is bigger than f')
    } else if (f>e) {
      console.log('f is bigger than e')
    }
        console.log('e',e );
        console.log('f',f )`,
];

// Instantiate the library, pass array of tests and execute them
var g = window.G$(edits);
g.run();

Aucun commentaire:

Enregistrer un commentaire