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

esch

v2.1.0

Published

A light-weight, powerful functional library

Downloads

11

Readme

Esch

Build Status

Functional programming is powerful when not bogged down with preconcieved notions. Esch aims to be to the functional pattern what Mithril.js is to front-end frameworks. Tiny and powerful with just enough magic to make your life easier. Definitely not your Swiss army knife, but your 6" fixed blade knife that a survivalist would use.

Methods

Esch(data, ops...) Esch(ops...)

returns an Esch chain, and you can pass in as many functions as you want or even compose another Esch instance

Esch.bind(data)

returns an Esch chain bound to a data-type, it would be the same as Esch(data)

Esch(data)( fn1 )( fn2 )()

invoking the Esch instance with any argument other than a function or array of functions says you want to compute the stack from Left -> Right

Esch(data)( fn1, fn2, fn3).apply.left()

Esch(data)( fn1, fn2, fn3).unravel()

convenience methods for invoking and Esch stack from Left -> Right

Esch(data)( fn1, fn2, fn3).apply.right()

A convenience method for invoking and Esch stack from Right -> Left

Esch()( fn1, promisedFn1, fn3)(data).then(handleDone).catch(handleError)

If Esch detects a promise in your operational stack, it upgrades the remaining functions to promised versions, and returns a promise that you can then can attack your usual promise handlers to.

Internals

I highly encourage you to read through the src/index.coffee to see what is going on internally (it's only 92 lines).

It is very important to remember the the outer most context is the context that Esch is applied to

However, let's destructure what's going on a bit with this example:

const Esch = require('esch');

## some contrived utils
let utils = {}

utils.mapAdd = function (n){
  return function(list){
    return list.map(function(num){
      return num + n
    });
  }
}

utils.mapMultiply = function (n){
  return function(list){
    return list.map(function(num){
      return num * n
    });
  }
}

utils.mapSubtract = function (n){
  return function(list){
    return list.map(function(num){
      return num - n
    });
  }
}

utils.reduce = function(list){
  return list.map(function(memo, n){
    return memo + n
  });
}

var stack = Esch(); // returns an Esch.chainable bound to an empty object value

var reduction = stack( utils.mapAdd(4)      ) // by passing in a Function we tell Esch we are still adding to the stack
                     ( utils.mapMultiply(3) )
                     ( utils.mapSubtract(1) )
                     ( utils.reduce         )
                     ( [1,2,3,4]            ); // By passing in something that isn't a function, we tell Esch to unravel our stack
                                               // The default application is left -> right || top -> bottom 

console.log(reduction); // 74

Here we are doing a very simple map reduce to our initial values.
When invoking Esch() we are telling Esch we want a new stack of operations, and passing the context value [1,2,3,4] through the manipulation pipeline. There are a couple of different ways to achieve this same result, including merging contexts to create dynamic pipelines.

var tree = Esch(); // returns an Esch.chainable

var data = tree.bind([1,2,3,4]); // change the beginning context of our Esch.chainable stack

var amsr = tree(
  utils.mapAdd(4),
  utils.mapMultiply(3),
  utils.mapSubtract(1),
);

l2r = data(amsr)(utils.reduce).apply.left();  // tell Esch we want a Left -> Right  application

/* 
  Nesting
  Internally Esch flattens these nested stack calls into a singular event chain\
*/

// tell Esch we want a Right -> Left application of our mapping functions
// then apply a Left -> Right reduction on the result
// ** JUST BECAUSE YOU CAN DOESN'T MEAN YOU SHOULD
var r2l = Esch(data(amsr)(amsr(amsr)).apply.right())(utils.reduce)(); 

console.log(r2l);
                              

But wait... There is more!

Esch internally handles Promises as well...

var Promise = require('bluebird');

utils.fetch = function (route) {
  return new Promise(function(resolve, reject){
    return request(route, function(err, callback){
      if (err) return reject(err);
      return resolve(callback);
    });
  });
};

var stack = Esch();

var manipulate = stack( utils.fetch('/numbers') )
                      ( utils.mapAdd(4)         );

manipulate().then(function(result){
  console.log(result);
});

What happens in this case is that Esch attempts to unravel the entire stack until it hits an operation that returns a Promise, it then forward maps the remainder of the stack to promises to ensure that the entirety of the stack will yield to the manipulation preceeding it.

The new promised operations forward its result to the next operation once resolved, and finally returns a promise that you use to then on the stack's completion.

Think of it like this, where each step it a set of operations (since you can nest them recursively deep)

Stack:

Level 1 (fn1, fn2, fn3)                                            * Promised Stack *
-------                                                           ------------------
      |                              * fn4 is PROMISED *          |
      | Level 2 (fn4, fn5)           fn5, fn6, ... fnN  upgraded  |
      ---------                      ------------------------------
              |                      |
              |                      |
              |  Level 3 (fn6.. FnN) |
              -----------------------

Once Esch determines the execution order, the entire stack is flattened and processed.

TODOS

  • Add the ability to apply a Stream to a stack, so that as each object is emitted it is passed to the stack