ugly-adapter

get promises out of standard callback APIs

Usage no npm install needed!

<script type="module">
  import uglyAdapter from 'https://cdn.skypack.dev/ugly-adapter';
</script>

README

Universal Callback => Promise Adapter

With Koa and ES7 async functions gaining prominence, the JavaScript world is poised to transition to promises. That means we need a sane way to promisify callback-based APIs. Rather than importing lots of different promisification wrappers for each API, this lib provides a single way to promisify every API.

Install

npm install ugly-adapter

Use

import adapt from 'ugly-adapter';
...
var data = await adapt(fs.readFile, './data.txt', 'utf8');

This lib also exposes methods to make partial application easier. Which is useful if you want to re-use an adapted version of a function.

var read = adapt.part(fs.readFile);
var data1 = await read('./data1', 'utf8');
var data2 = await read('./data2', 'utf8');

API

Call a bare function: adapt()

Useful when you don't think a function cares about this.

// signature
var promise = adapt(<function>, ...args)

// fs.readFile(path, enc, callback) example
adapt(fs.readFile, './data.txt', 'utf8').then(...)

Call a method on an object: adapt.method()

Useful when you think a function definitely cares about this.

// signature
var promise = adapt.method(<object>, <string>, ...args)

// user.authenticate(opts, callback) example
var user = new User()
adapt.method(user, 'authenticate', {
  userName: userName,
  password: password
}).then(...)

Partially apply a bare function: adapt.part()

// signature
var fn = adapt.part(<function>, ...args)

// example
var stat = adapt.part(fs.stat, './data.txt', 'utf8')
stat().then(...)

Partially apply a method on an object: adapt.method.part()

// signature
var fn = adapt.method.part(<object>, <string>, ...args)

// example
var user = new User()
var authenticate = adapt.method.part(user, 'authenticate')
authenticate({
  userName: userName,
  password: password
}).then(...)

A note about partial application. You can basically move the )( around willy-nilly.

// these behave identically
var promise = adapt.part(a,b,c)()
var promise = adapt.part(a,b)(c)
var promise = adapt.part(a)(b,c)
var promise = adapt.part()(a,b,c)

Promify a library: adapt.promify(lib)

You can promisify entire library modules, such as fs. It will return an object with all the same properties and functions. The functions have the same signature—sans callback—and return promises.

var adapt = require('ugly-adapter')
  , callbackFs = require('fs')
  , fs = adapt.promify(callbackFs);

fs.stat(...).then(...);

The above promifies every function in the fs module. If you only want to promify a subset of functions, declare them in a whitelist.

var adapt = require('ugly-adapter')
  , callbackFs = require('fs')
  , fs = adapt.promify(callbackFs, 'stat', 'readFile');

fs.stat(...).then(...);
fs.readFile(...).then(...);
fs.link(...).then(...); // error, wasn't in the whitelist!

Async/Await Example

Now that we can convert callbacks to promises, we can write async functions everywhere.

async function jsonReadFile(path, encoding) {
  let data = await adapt(fs.readFile, encoding);
  data = JSON.parse(data);
  return data;
}

Any Promise

Ugly adapter uses any-promise promises. This is something you can safely ignore and everything works normally. However, if you want to polyfill/replace your environment's Promise for whatever reason, this allows you swap in whatever conforming Promise you want and this library will use it.