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

binderize

v0.0.1

Published

Allow normal functions to work with Function Bind Syntax

Downloads

4

Readme

Binderize - Experimenting with function bind syntax

Interested in using the new function bind syntax but none of your functions are compatible? Binderize them!

Converting the lodash chain example

import { bindFirst } from 'binderize';
import _ from 'lodash';

const { sortBy, map, head } = _.mapValues(_, bindFirst);

var users = [
  { 'user': 'barney',  'age': 36 },
  { 'user': 'fred',    'age': 40 },
  { 'user': 'pebbles', 'age': 1 }
];

var youngest = users
  ::sortBy('age')
  ::map(o => o.user + ' is ' + o.age)
  ::head();
// → 'pebbles is 1'

The same example with Ramda

import { bindLast } from 'binderize';
import R from 'ramda';

const { sortBy, map, head } = R.map(bindLast, R);

var users = [
  { 'user': 'barney',  'age': 36 },
  { 'user': 'fred',    'age': 40 },
  { 'user': 'pebbles', 'age': 1 }
];

var youngest = users
  ::sortBy(o => o.age)
  ::map(o => o.user + ' is ' + o.age)
  ::head();
// → 'pebbles is 1'

Now you can use your favorite libraries and functions with this new syntax.

Binder API

Each binder takes a function and allows it to accept one of its arguments as its this context, instead of regularly passed argument. The rule of thumb is to use the binder that corresponds to the argument you want to be on the left of the bind (::).

bind

Converts a single argument function that accepts that argument as its this context.

const head = bind(list => list[0]);

[1, 2, 3]::head(); // 1

bindFirst

Converts a function to one where the this context is passed as the first argument to the wrapped function.

const append = bindFirst((list, a) => [...list, a]);

[1, 2, 3]::append(4); // [1, 2, 3, 4]

bindLast

Converts a function to one where the this context is passed as the last argument to the wrapped function.

const append = bindFirst((a, list) => [...list, a]);

[1, 2, 3]::append(4); // [1, 2, 3, 4]

bindN

Converts a function to one where the this context is passed as the Nth argument to the wrapped function.

const greet = bindN(1, (greeting, name, ending) => `${greeting} ${name}, ${ending}`);

"Adam"::greet("Hello", "how are you?"); // "Hello Adam, how are you?";

Modifiers - (Experimental)

Modifiers can be used to enable functions to work in more contexts than they were originally defined. You get a higher level of functionality with the same sugary function bind syntax. These modifiers can also be stacked to lift to combine these contexts. Import these from binderize/modifiers.

import { ... } from 'binderize/modifiers'

These are experimental, and I am not sure how useful they will be. Any ideas are welcome!

maybe

Allows a function to not be called when the payload is null or undefined to avoid exceptions

const upcase = x => x.toUpperCase();
const maybeUpcase = maybe::bind(upcase);

null::maybeUpcase() // null / Does not throw an error
"test"::maybeUpdate() // "TEST"

on

Allows a function to run with a certain field of an object as the payload.

const increment = x => x + 1;
const growOlder = on('age')::bind(increment);

const user = { name: 'Adam', age: 28 };
user::growOlder() // { name: 'Adam', age: 29 };

promise

Allows the function to treat the result of a promise as its payload.

const log = ::console.log;
const logPromise = promise::bind(log);

Promise.resolve(1)::logPromise(); // logs 1 when the promise resolves

map

Maps the function over the payload.

const increment = x => x + 1;
const incrementAll = map::bind(increment);

[1, 2, 3]::incrementAll() // [2, 3, 4]

Stacking / Chaining

As mentioned these can be changed. Imaging pulling a list of users back from an API, incrementing a nullable age variable (or leaving them null), then sending them back to the API. You can use a stack of modifiers to lift a simple function like increment into the context you want it work in.

const increment = x => x + 1;
// When the promise resolves (promise)
// for each value (map)
// on the age field (on)
// maybe (maybe) increment the value
const incrementUsers = promise::map::on('age')::maybe::bind(increment);

getUsersAsPromise()::incrementAllAges().then(saveUsers);

If our API returns this list of users:

[
  {
    "id": 1,
    "age": 10
  },
  {
    "id": 2,
    "age": null
  }
]

This updated list will be passed to the saveUsers function above:

[
  {
    "id": 1,
    "age": 11
  },
  {
    "id": 2,
    "age": null
  }
]

Stacking can also be used in other creative ways and even combined with the different apply functions in binderize (apply, applyFirst, applyLast, applyN) to create some other useful functionality.

safeThen implicitly handles null / undefined values in promises.

const safeThen = promise::maybe(apply);

Promise.resolve(null)::safeThen(x => x.toUpperCase()).then(x => console.log(x)); // logs null - Does not error
Promise.resolve("test")::safeThen(x => x.toUpperCase()).then(x => console.log(x)); // logs "TEST"

License

MIT