AnnouncementsMatrixEventsFunnyVideosMusicAncapsTechnologyEconomicsPrivacyGIFSCringeAnarchyFilmPicsThemesIdeas4MatrixAskMatrixHelpTop Subs
2

I've been doing something with my Node environment that I am 140% certain is frowned upon. But it's sooooo good.

I got sick of all the things missing from the node repl. Things that really should be built-ins, but aren't. I've put this into a file called preload.js. It assigns all kinds of things to global. I know that's super illegal. And assigns things to various class prototypes. Superdooper illegal.

My standard JS arrays now can do things a lot like pytorch, and I don't apologize for it.

My standard math library now does math. All the math you would want.

My fs modules not can read lines of a file into an array. Because this is goofy. fs.readFileSync(path,'utf8').split('\n').slice(0,-1);

Even worse is this:

(await fsp.readFile(path,'utf8')).split('\n').slice(0,-1);

in the case you want a promise version. No. You should not have to import a module to do basic stuff.

Also fsp is available everywhere. No more calling fs.promises or the other common behavior of just assigning that to fs and then your module has to remember which one that is using. That's not very symantic if a variable that's practically a reserved name can have different access patterns in one file vs another. And you shouldn't need extra steps to what should now be standard.

But last. And I have zero miles using it. But I know it's going to be good. I just added my favorite thing. I added exportFunc. Oh my gosh. The repl is now a dev environment. It's the easiest function to write.

global.exportFunc = (func,path="index.js")=>{    
 return fsp.appendFile(path,`\n${func}\n`);     
};

Do you know what this does for testability and error reduction when functions are implemented in the repl first?

You can test function in the text editor because your text editor is actually a repl. This might be a vim killer for me. The only thing I'm debating is adding an export statement by default. Then you can even close your repl, open your text editor, and re-open the repl and every function you coded in the previous session doesn't need to be re-implemented to get to the same place.

I do understand why all of this is considered illegal. NodeJS code tends to get migrated to other systems and you need the code to be environment agnostic beyond what can be specified in a package.json. I get it. I even agreed. I just agree with the idea that there are strong arguments for both. It's not weird for people to customize their Bash environment. That's just another language running on the system. Yet people manage to write, share, and copy other people's bash code all the time with zero problems despite us all having custom aliases and the like.

The insufficiency of javascripts standard library just broke the camel's back. I want to do data manipulation in the repl and I want it to be sane to do. Even importing something is too much. I want it to be instant.

In Bash you don't have to set up your environment specific to the task you are doing in the moment. It's ready to role. "I'm doing X, so let's set up Y,W,Z so we can do X." No. Your system should be ready to do X. At the very least that's what a repl or shell should be. If you are someone who does data manipulation your repl should be ready to do data manipuation. That means importing and exporting files with ease and having your most used functions at the ready.

A few more sane things added that should have always existed.

fs.writeJSON
fs.writeJSONSync
fs.writeJSONProm
fs.promises.writeJSON
global.range

Do you know how annoying doing range in Javascript is.

The implementation function is oddly long enough to make you cry.

global.range=function (a,b,c) {
 var start,end,step;
 if(arguments.length<1) throw 'We need an argument'
 if(arguments.length==1) {
  start=0;
  end=a;
  step=1;
 }
 else {
  start=a;
  end=b;
  step=c||1;
 }
 var out=[];
 for(var i=start;i<end;i+=step) {
  out.push(i);
 }
 return out;
};

No one should have to write that on the fly anytime they need a range. When you don't need so many options it ends up half as bad. Half as bad is way too much to get [0,1,2,3,4] in javascript.

Array(5).fill(0).map((i,idx)=>idx).

At that point it defeats the point of range because it is neither easy or semantic. Why javascript doesn't have a built in range function when it's a multi-paradigm (read functional) language with a preference for the use of higher order functions? How can I map filter reduce if you won't let me generate a base state quickly? How can python be setup to do MFR better than javascript?

global.exec
global.execp

Let's get as close to the shell as possible. execp is especially reasonable here.

Now the really basic stuff that should exist.


Math.sec = t=>1/Math.sin(t);
Math.csc = t=>1/Math.cos(t);
Math.cot = t=>1/Math.tan(t);
Math.nroot = (a,b)=>Math.pow(a,1/b);
Math.ln = Math.log;
global.ln = Math.log;
Math.TAU = Math.PI*2;
Math.pi = Math.PI;
Math.tau = Math.TAU;
Math.e = Math.E
Math.deg2rad = a=>a*Math.TAU*360;
Math.rad2deg = a=>a*360/Math.TAU;

Speaking of making the repl more shell like let's make the basics top level.

global.mv = fs.promises.rename
global.cp = fs.promises.copyFile
global.ls = (path='.')=>fs.readdirSync(path);
global.cd = process.chdir;
String.prototype.cut = function(delim,nfield) {
 return this.split(delim)[nfield]||'';
};
Array.prototype.cut =function(delim,nfield) {
 return this.map(i=>i.cut(delim,nfield));
};
global.wget = async path=>{
 var resp = await fetch(path);
 return resp.text();
};
global.fetchJSON = async path=>{
 var resp = await fetch(path);
 return resp.json();
}

A lot of these aren't implemented the cleanest possible but the point is to make the repl dirty and effective.

Array.prototype.grep = function(needle,options={}) {
 if(options.c) {
  return this.filter(i=i.includes(needle)).length;
 }
 if(options.C) {
  var context=options.C;
  var indexes = [];
  var out=[];
  var lastincluded=-1;
  var self=this;
  this.forEach((line,i)=>{
   if(line.includes(needle)) {
    for(var j=Math.max(0,lastincluded+1,i-context);j<Math.min(self.length,1+i+context);++j) {
     //indexes.push(j);
     out.push(self[j]);
     lastincluded=j;
    }
   }
  });
  return out;
 }
 return this.filter(i=>i.includes(needle));
}

I realize I could have properly used regex there. But this is a dynamic file. It would use regex when I need some regex.

More obvious math shit

Math.vector = require('/home/k/node/jstransformers/vectors');
Math.dotprod = Math.vector.dotprod;
Math.mean = Math.vector.mean;
Math.avg = Math.mean
Math.sum = Math.vector.sum;

global.max=max;
function max(list) {
 var best=-Infinity;
 for(var i of list) {
  if(i>best) best=i;
 }
 return best;
}
global.min=min;
function min(list) {
 var best=Infinity;
 for(var i of list) {
  if(i<best) best=i;
 }
 return best;
}

Array.prototype.min = function() {
 return min(this);
}

Array.prototype.max = function() {
 return max(this);
};

Also Array.prototype.maxIndex and Array.prototype.maxIndexes. That one is optimized and a little long so I'll omit that.

Some of this is just standard to exist in any language. There is more I could add. I only shared about a quarter of it. Just the highlights. None of the machine learning stuff.

Maybe if the javascript community wants to frown on making a custom environment by assigning to global they should include some basics that any other language has. Making someone Math.max.apply(null,list) is absurd. It should just be max(list). Also the hidden 256 limit of the standard solution is dangerous.

Comment preview