Improving the code of a JavaScript compiler through refactoring

I recently delved into the intricacies of a JavaScript package compiler and decided to revamp its fundamental structure. Each time a string is compiled, it gets appended to the SrcTable array and then outputted. However, for the output to be obtained, the SrcTable must be declared global. This poses a question as the example that serves as the foundation for my code has this variable declared locally. I am keen on understanding: 1. Why is it not possible to declare the variable locally here? 2. What alterations are necessary to enable it to function as local?

The srcTable resides within the preprocessors.compiler variable.

function resolveRequest(request) {
  var match = request.match(/^\s*import\s+(.*)$/),
    imports = {};

  if (match) {
    match[1].replace(/\s*([\w.\-$]+)(?:\s+as\s+([\w.\-$]+))?,?/g, function(_, from, as) {
      imports = {
        from: from,
        as: as || from
      };
    });
  }
  return imports;
}

var preprocessors = {
  import: "var importExpr = /^(\\s*)(import\\s+[^=+*\"'\\r\\n;\\/]+|from\\s+[^=+\"'\\r\\n;\\/ ]+\\s+import\\s+[^=+\"'\\r\\n;\\/]+)(;|\\/|$)/gm;" +
    "function replace(raw, p1, p2, p3) {" +
    "  return p1 + 'jsio(\"' + p2 + '\")' + p3;" +
    "};" +
    "exports = function(src) {" +
    "  return src.replace(importExpr, replace);" +
    "};",
  compiler: "srcTable = [];" + // inquiring if this array can be made local
    "        exports = function (src) {" +
    "          var jsioNormal = " + /^(.*)jsio\s*\(\s*(['"].+?['"])\s*(,\s*\{[^}]+\})?\)/gm + "\n;" +
    "          var match = jsioNormal.exec(src);\n" +
    "          if(match) {" +
    "            var request = eval(match[2]);\n" +
    "            jsio(request, ['import', 'compiler']);\n" +
    "          } \n" +
    "          srcTable.push(src);"+
    "          return '';\n" +
    "        };" +
    "        exports.compile = function(request) {" +
    "          jsio(request, ['import', 'compiler']);" +
    "        };" + 
    "        exports.generateSrc = function (callback) {"+
    "          callback(srcTable);"+
    "        };"
};

function _require(previousCtx, request, p) {
  var p = p || ['import'];
  var request = resolveRequest(request);
  var src = eval(request.from);

  p.forEach(function(name, index) {
    var args = name == 'import' ? [] : null;
    var preprocessor = jsio('import preprocessors.' + name, args);

    src = preprocessor(src);
  });

  var code = "(function (__) { with (__) {" + src + "}});";
  var fn = eval(code);
  var context = makeContext();
  fn(context);
  previousCtx[request.as] = context.exports;
  return context.exports;
}

function makeContext() {
  return {
    jsio: function(request, p) {
      return _require(this, request, p);
    },
    exports: {}
  };
}

var jsio = makeContext().jsio;

var example = {
  app: "import example.calculator as calculator;" +
    "   calculator.add(2, 3);",

  calculator: "import example.print as print;" +
    "          exports = {" +
    "            add: function (a, b) {" +
    "              print(a+b);" +
    "            }" +
    "          }",

  print: "exports = function(res) {" +
    "       console.log(res);" +
    "     }"
};

var compiler = jsio('import preprocessors.compiler;');
compiler.compile('import example.app;');
compiler.generateSrc(function(src) {
  console.log(src);
});

Answer №1

During the compilation of code with the JavaScript with context, it is important to cache the function evaluating the code. This prevents the recreation of instances every time the same code is compiled. Therefore, the solution is as follows:

function resolveRequest(request) {
  var match = request.match(/^\s*import\s+(.*)$/),
    imports = {};

  if (match) {
    match[1].replace(/\s*([\w.\-$]+)(?:\s+as\s+([\w.\-$]+))?,?/g, function(_, from, as) {
      imports = {
        from: from,
        as: as || from
      };
    });
  }
  return imports;
}

var preprocessors = {
  import: "var importExpr = /^(\\s*)(import\\s+[^=+*\"'\\r\\n;\\/]+|from\\s+[^=+\"'\\r\\n;\\/ ]+\\s+import\\s+[^=+\"'\\r\\n;\\/]+)(;|\\/|$)/gm;" +
    "function replace(raw, p1, p2, p3) {" +
    "  return p1 + 'jsio(\"' + p2 + '\")' + p3;" +
    "};" +
    "exports = function(src) {" +
    "  return src.replace(importExpr, replace);" +
    "};",
  compiler: "var srcTable = [];\n" +
    "        exports = function (src) {\n" +
    "          var jsioNormal = " + /^(.*)jsio\s*\(\s*(['"].+?['"])\s*(,\s*\{[^}]+\})?\)/gm + "\n;" +
    "          var match = jsioNormal.exec(src);\n" +
    "          if(match) {\n" +
    "            var request = eval(match[2]);\n" +
    "            jsio(request, ['import', 'compiler']);\n" +
    "          } \n" +
    "          srcTable.push(src);\n" +
    "          return '';\n" +
    "        };\n" +
    "        exports.compile = function(request) {\n" +
    "          jsio(request, ['import', 'compiler']);\n" +
    "        };\n" +
    "        exports.generateSrc = function (callback) {\n" +
    "          callback(srcTable);\n" +
    "        };\n"
};

var _cache_context = [];

function _require(previousCtx, request, p) {
  var p = p || ['import'];
  var request = resolveRequest(request);
  var src = loadModule(request).src;

  p.forEach(function(name, index) {
    var args = name == 'import' ? [] : null;
    var preprocessor = jsio('import preprocessors.' + name, args);
    src = preprocessor(src);
  });

  if (src) {
    if (!_cache_context[request.from]) {
      var code = "(function (__) { with (__) {\n" + src + "\n}});";
      var fn = eval(code);
      var context = makeContext();
      fn(context);
      _cache_context[request.from] = context.exports;
    }
    previousCtx[request.as] = _cache_context[request.from];
    return previousCtx[request.as];
  }
}

function loadModule(request){
 var src = eval(request.from);

 return {
   src: src,
   path: request.from
 } 
}

function makeContext() {
  return {
    jsio: function(request, p) {
      return _require(this, request, p);
    },
    exports: {}
  };
}

var jsio = makeContext().jsio;

var example = {
  app: "import example.calculator as calculator;" +
    "   calculator.add(2, 3);",

  calculator: "import example.print as print;" +
    "          exports = {" +
    "            add: function (a, b) {" +
    "              print(a+b);" +
    "            }" +
    "          }",

  print: "exports = function(res) {" +
    "       console.log(res);" +
    "     }"
};

var compiler = jsio('import preprocessors.compiler;');
compiler.compile('import example.app;');
compiler.generateSrc(function(src) {
  console.log(src);
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How does the 'this' variable function when it comes to models in embedded documents?

Being relatively new to node.js and sails, I find it quite easy to work with and enjoy it :) Currently, I am using the sails Framework version 0.10rc3 with MongoDB and sails-mongo. I understand that the contributors of waterline do not particularly like e ...

Press a button to link a click event handler to another button

function example() {console.log('example');} $('#button1').click(function(){ $('#button2').onclick = example(); }); <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> ...

Passing parameters to an Angular 2 component

When it comes to passing a string parameter to my component, I need the flexibility to adjust the parameters of services based on the passed value. Here's how I handle it: In my index.html, I simply call my component and pass the required parameter. ...

Issue with Intel XDK: the document.location.href is directing to an incorrect page

Hello Community of Developers, I have been experimenting with different methods but still haven't found a solution. In my project using Intel XDK, whenever I attempt to change the page using location.location.href = "#EndGame" or similar codes in Java ...

Is there a way to retrieve the widths of several <span> elements at once?

Having a few <span> elements generated dynamically, I need to find out their combined width. Wrapping them in a <div> and using alert($("#spanWrap").width()); resulted in the container's width instead of that of the <span> elements. ...

Sending data from child components to parent components in Angular

I'm facing an issue with retrieving data from a child array named store within user data returned by an API. When trying to access this child array in my view, it keeps returning undefined. Code export class TokoPage implements OnInit { store= nu ...

When transitioning to a different page, Angular is creating a duplicate of $scope

My webpage features a section where I showcase all the individuals stored in the database, referred to as the All Persons Page. Within this page, there are two primary options: Add New Person Delete Person (Any selected individual) An issue arises when ...

In Laravel, Inertia.js will automatically close a modal if there are no validation errors present

Here is the method I am currently using: methods: { submit() { this.$inertia.post('/projects', this.form); this.openModal = false; }, }, Unfortunately, this method closes the modal even if there are validation erro ...

Occasionally, AJAX requests may not always be in the correct sequence

I'm struggling with the POST and GET requests. Everything seems to be in order on my server side until I send the data, but then things get jumbled up on the client side. For instance, the data should be received in reverse order as shown below: Data ...

What is the best way to extract the frameset from a frame window?

Here is a code snippet to consider: function conceal(frameElem) { var frameSet = frameElem.frameSet; //<-- this doesn't seem to be working $(frameSet).attr('cols', '0,*'); } //conceal the parent frame conceal(window.pa ...

Having trouble passing a jQuery variable containing a string value to PHP through the jQuery AJAX function?

Below is the jQuery function code snippet: function processMessage() { if (textValue != "") { messageString='<div class="alert-box round"><p class="text-left">' + username + ':' + textValue + '</p>< ...

What could be causing my AngularJS directive to malfunction in Edge browser?

I have encountered an issue where this code works fine in all major browsers, but Edge only shows the valid value in the DOM inspector. The page still displays the old value. Why is this happening? (function (angular, module) { 'use strict'; ...

Tips for avoiding the push method from replacing my items within an array?

Currently, I am diving into Typescript and VueJS, where I encountered an issue with pushing elements to my array. It seems to constantly override the 'name' property. Let me share the code snippet causing this problem: const itemsSelectedOptions ...

What is the reason behind div elements shifting when hovering over a particular element?

Currently, I have floated all my div elements (icons) to the left and margin-lefted them to create space in between. I've displayed them inline as well. However, when I hover over one element (icon), the rest of the elements move. Can you please help ...

Data is not loaded until after the HTML for the Nuxt page has been

My issue is that I have a dynamic page where product details are loaded, but the html code loads before the data. This results in errors when trying to use static elements like images because the "product" object does not exist. To address this problem, I ...

Securing child paths in Vue.js

Having trouble protecting child routes from parent routes, facing some issues export default new Router({ routes: [ //frontend routes { {path: 'auth', component: Auth, children: authroutes, beforeEnter: (to, from, n ...

I encountered a RangeError with code [ERR_HTTP_INVALID_STATUS_CODE] due to an invalid status code being undefined

I have encountered a specific error while running my note-taking app. The error seems to be related to the following piece of code - app.use((err,req,res,next)=>{ res.status(err.status).json({ error : { message : err.message ...

Is it possible to verify the data within a VueJS model? It seems that none of the Vue validators are effective

Hello there, It's common knowledge that using Vue-validator with most UI components can be challenging when it comes to validation. I've been utilizing Vue Material Components by @mjanys, which is a fantastic library. The author has included met ...

Tips for creating a substitute for a standard prototype in JavaScript

Having trouble with a JavaScript interpreter that has a buggy Array.prototype.sort. I want to replace it, at least for testing purposes. I have a function called mySort(array, comparator), but how can I make it work like array.sort(comparator)? I also ne ...

Using JQuery Slider to call a function without the need for an ID, instead utilizing the object directly

Currently, I am working on implementing a Slider using JQuery, and I have encountered an issue in my code. The function is set to run when the page loads, creating a slider with the Id specified in the div element: $(function() { $( "#slider& ...