Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

makepromise

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

makepromise - npm Package Compare versions

Comparing version 2.0.0 to 3.0.0

.alamoderc.json

78

build/index.js

@@ -1,68 +0,52 @@

"use strict";
let erotic = require('erotic'); if (erotic && erotic.__esModule) erotic = erotic.default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = makePromise;
var _erotic = _interopRequireDefault(require("erotic"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function checkArgumentIndex(length, i) {
if (i > length - 2) {
throw new Error('Function does not accept that many arguments');
throw new Error('Function does not accept that many arguments.')
}
}
/**
* Create a promise from a function.
* @param {function} fn Function to call
* @param {any[]|any} [args] Array of arguments to use in call, or one argument, or none
* @param {any} [resolveValue] Override function's return value with this
* @returns {Promise<any>} A promise resolved on callback invocation w/out error,
* and rejected on callback called w/ error.
* Get a promise from a function which otherwise accepts a callback.
* @param {function} fn A function to promisify.
* @param {any[]|any} [args] An array of arguments to use in the call, or a single argument.
* @param {any} [resolveValue] A value to override the value with which the promise will be resolved.
* @returns {Promise<any>} A promise resolved on callback invocation without an error and rejected on callback called with an error.
*/
async function makePromise(fn, args, resolveValue) {
const er = (0, _erotic.default)();
async function makePromise(fn, args, resolveValue) {
const er = erotic(true)
if (typeof fn !== 'function') {
throw new Error('function must be passed');
throw new Error('Function must be passed.')
}
const {
length: fnLength
} = fn;
const { length: fnLength } = fn
if (!fnLength) {
throw new Error('Function does not accept any arguments');
throw new Error('Function does not accept any arguments.')
}
const res = await new Promise((resolve, reject) => {
const res = await new Promise((resolve, reject)=> {
const cb = (err, res) => {
if (err) {
const error = er(err);
return reject(error);
const error = er(err)
return reject(error)
}
return resolve(resolveValue || res)
}
return resolve(resolveValue || res);
};
let allArgs = [cb]
let allArgs = [cb];
if (Array.isArray(args)) {
args.forEach((arg, i) => {
checkArgumentIndex(fnLength, i);
});
allArgs = [...args, cb];
} else if (Array.from(arguments).length > 1) {
// args passed as a single argument, not array
checkArgumentIndex(fnLength, 0);
allArgs = [args, cb];
checkArgumentIndex(fnLength, i)
})
allArgs = [...args, cb]
} else if (Array.from(arguments).length > 1) { // args passed as a single argument, not array
checkArgumentIndex(fnLength, 0)
allArgs = [args, cb]
}
fn.apply(fn.this, allArgs)
})
return res
}
fn.apply(fn.this, allArgs);
});
return res;
}
module.exports = makePromise
//# sourceMappingURL=index.js.map

@@ -0,1 +1,10 @@

## 31 August 2018
### 3.0.0
- [package] Remove `ES5` folder.
- [build] Build w/ [`alamode`](https://alamode.cc).
- [doc] Document with `documentary`, add bound methods example.
- [feature] Transparent `erotic` error stack.
## 12 May 2018

@@ -2,0 +11,0 @@

{
"name": "makepromise",
"version": "2.0.0",
"description": "Make a native Promise from a function with a callback",
"version": "3.0.0",
"description": "Make a Promise from a function with a callback and preserve its error stack.",
"main": "build",
"scripts": {
"teb": "LIB_MAIN=../../es5 zoroaster --babel",
"t": "zoroaster --babel",
"test": "zoroaster test/spec --babel",
"test-build": "LIB_MAIN=../../build zoroaster test/spec --babel",
"test-es5-bin": "LIB_MAIN=../../es5 zoroaster test/spec --babel",
"test-es5": "zoroaster es5/test/spec",
"build": "babel src --out-dir build",
"e": "node examples/run"
"t": "zoroaster -a",
"test": "zoroaster test/spec -a",
"test-build": "ALAMODE_ENV=test-build zoroaster test/spec -a",
"build": "yarn-s b doc",
"b": "alamode src -o build",
"doc": "NODE_DEBUG=doc doc documentary -o README.md",
"e": "node example"
},

@@ -22,6 +21,13 @@ "repository": {

"promise",
"async",
"await",
"ecmascript",
"es6",
"ecma",
"promisify",
"node",
"callback",
"cb"
"cb",
"error",
"stack"
],

@@ -35,15 +41,12 @@ "author": "Anton <anton@adc.sh>",

"devDependencies": {
"@babel/cli": "7.0.0-beta.46",
"@babel/core": "7.0.0-beta.46",
"@babel/plugin-syntax-object-rest-spread": "7.0.0-beta.46",
"@babel/plugin-transform-modules-commonjs": "7.0.0-beta.46",
"@babel/register": "7.0.0-beta.46",
"catchment": "2.0.1",
"lockfile": "1.0.4",
"alamode": "1.3.0",
"catchment": "3.0.0",
"documentary": "1.10.0",
"wrote": "1.4.0",
"zoroaster": "1.1.0"
"yarn-s": "1.1.0",
"zoroaster": "2.4.0"
},
"dependencies": {
"erotic": "1.0.1"
"erotic": "1.2.1"
}
}
# makepromise
[![npm version](https://badge.fury.io/js/makepromise.svg)](https://badge.fury.io/js/makepromise)
[![npm version](https://badge.fury.io/js/makepromise.svg)](https://npmjs.org/package/makepromise)
Make native `Promise` from a function with a callback.
`makepromise` can be used to get a _Promise_ from a function with a callback. It will also make sure that the error stack starts at the line where the `makepromise` was called.
## `makePromise(fn:Function(...args, cb:Function(err:Error, res:any))) => Promise<any>`
```
yarn add -E makepromise
```
Create a promise from a function which accepts a callback as the last argument,
and where the callback will be called with 2 arguments: `(error, result)`.
## Table Of Contents
For example, you can unlink a file (here, a temp file is created with
[`wrote` package][1]):
- [Table Of Contents](#table-of-contents)
- [API](#api)
* [`async makePromise(fn: function(...args, cb), args: (*[]|*))`](#async-makepromisefn-functionargs-cbargs--void)
* [`async makePromise(fn: function(...args, cb), args: (*[]|*), resolveValue: *)`](#async-makepromisefn-functionargs-cbargs-resolvevalue--void)
* [Binding Methods](#binding-methods)
- [Error Stack](#error-stack)
- [TODO](#todo)
- [Copyright](#copyright)
## API
The package exports a default `makepromise` function.
```js
import { unlink } from 'fs'
import { createWritable } from 'wrote'
import makePromise from 'makepromise'
```
### `async makePromise(`<br/>&nbsp;&nbsp;`fn: function(...args, cb),`<br/>&nbsp;&nbsp;`args: (*[]|*),`<br/>`): void`
let file
Create a promise from a function which accepts a callback as the last argument, and where the callback will be called with 2 arguments: `error` and `result`. The arguments must be passed either as an array, or a single value.
The example below shows how to use `makePromise` with an array of arguments (promisified `truncate`) and a single argument (promisified `unlink`). The context of the example is 2 methods from a lib to create a temp file, and read data from a file.
```js
import { truncate, unlink, existsSync } from 'fs'
import makePromise from 'makepromise'
import { createTempFile, readFile } from './lib'
(async () => {
// create a temp file and open a writable stream
const ws = await createWritable()
const { path: file } = ws // /var/folders/s0/tmp/T/wrote-69822.data
// here, just close the stream without makepromise, because it's a different
// kind of constructor, ie. resolve-reject and not error callback handlers
await new Promise((resolve, reject) => {
ws.once('close', resolve)
ws.once('error', reject)
ws.close()
})
await makePromise(unlink, file)
try {
// 0. SETUP: create a temp file.
const path = await createTempFile('hello-world')
const data = readFile(path)
console.log('Created temp file %s', path)
console.log('Exists: %s', existsSync(path))
console.log('Content: "%s"', data)
// 1. TRUNCATE to 5 characters.
await makePromise(truncate, [path, 5])
const data2 = await readFile(path)
console.log('Content: "%s"', data2)
// 2. ERASE the temp file.
await makePromise(unlink, path)
console.log('Exists: %s', existsSync(path))
} catch (err) {
console.log(err)
}
})()
```
In addition, errors will be updated to include the stack trace of when
`makePromise` was called, rather than have node internal error stack, or no
stack at all:
```
Created temp file example/temp.data
Exists: true
Content: "hello-world"
Content: "hello"
Exists: false
```
### `async makePromise(`<br/>&nbsp;&nbsp;`fn: function(...args, cb),`<br/>&nbsp;&nbsp;`args: (*[]|*),`<br/>&nbsp;&nbsp;`resolveValue: *,`<br/>`): void`
When `resolveValue` is passed as the last argument to the `makePromise` function, the returned promise will be forced to resolve with it.
```js
import { unlink } from 'fs'
import makePromise from 'makepromise'
import { createTempFile } from './lib'
(async () => {
try {
await makePromise(fs.unlink, 'error-test-file')
} catch ({ stack }){
console.log(stack)
/*
Error: ENOENT: no such file or directory, unlink 'error-test-file'
at cb (makepromise/src/index.js:28:31)
at makePromise (makepromise/src/index.js:18:16)
at Object.<anonymous> (makepromise/examples/error-stack.js:4:1)
*/ // without this feature:
/*
Error: ENOENT: no such file or directory, unlink 'error-test-file'
*/
// 0. SETUP: create a temp file.
const path = await createTempFile()
// 1. UNLINK and return the path to the temp file.
const erasedPath = await makePromise(unlink, path, path)
console.log('Erased: %s', erasedPath)
} catch (err) {
console.log(err)
}

@@ -62,51 +93,97 @@ })()

## `makePromise(fn:Function(...args, cb:Function(err:Error, res:any), resolveValue:any)) => Promise<any>`
```
Erased: example/temp.data
```
Pass `resolveValue` as second argument to make promise be resolved with it.
### Binding Methods
Sometimes, it is important to bind methods of instances to their contexts, otherwise they will loose access to `this`.
For example. when closing a _Writable_ stream, its `close` method must be bound to its instance.
```js
import { unlink } from 'fs'
import { createWritable } from 'wrote'
import { createWriteStream, unlink } from 'fs'
import makePromise from 'makepromise'
import { createTempFile, readFile } from './lib'
(async () => {
// create a temp file and open a writable stream
const ws = await createWritable()
await closeWritable(ws)
const { path: file } = ws
console.log(file) // /var/folders/s0/tmp/T/wrote-69822.data
// pass 3rd argument as the return value
const resolvedFile = await makePromise(unlink, file, file)
console.log(resolvedFile === file) // true
try {
// 0. SETUP: create a temp file.
const path = await createTempFile()
// 1. CREATE a write stream, and end it with data.
const ws = createWriteStream(path)
await makePromise(ws.end.bind(ws), 'example-data')
// 2. CHECK that data has been written.
const data = await readFile(path)
console.log('Read file: "%s"', data)
// 3. TEAR-DOWN: remove file.
await makePromise(unlink, path)
} catch (err) {
console.log(err)
}
})()
```
## More examples
```
Read file: "example-data"
```
Check `test/spec/integration` for the following tests:
## Error Stack
* How to [unlock a file with](https://github.com/artdecocode/makepromise/blob/master/test/spec/integration.js#L12)
[`lockfile` package][2]
* [How to write to a writable stream](https://github.com/artdecocode/makepromise/blob/master/test/spec/integration.js#L29)
* How to [unlink a file with `fs.unlink`](https://github.com/artdecocode/makepromise/blob/master/test/spec/integration.js#L38)
* How to [read stat with `fs.stat`](https://github.com/artdecocode/makepromise/blob/master/test/spec/integration.js#L58)
* How to catch errors after [call `fs.stat` with non-existent file](https://github.com/artdecocode/makepromise/blob/master/test/spec/integration.js#L66))
This modules will make sure that errors are updated to include the stack trace of when `makePromise` was called, rather than have the Node's internal error stack or no stack at all.
## ES5
```js
import { unlink } from 'fs'
import makePromise from 'makepromise'
> DO NOT USE THIS. USE NEWER NODE.JS
The package uses some newer language features. For your convenience, it's been
transpiled to be compatible with Node 4. You can use the following snippet.
(async () => {
try {
await makePromise(unlink, 'error-test-file')
} catch ({ stack }) {
console.log(stack)
}
})()
```
```
Error: ENOENT: no such file or directory, unlink 'error-test-file'
at /Users/zavr/adc/makepromise/example/error-stack.js:6:11
at Object.<anonymous> (/Users/zavr/adc/makepromise/example/error-stack.js:10:3)
at Module._compile (/Users/zavr/adc/makepromise/node_modules/pirates/lib/index.js:83:24)
at Object.newLoader [as .js] (/Users/zavr/adc/makepromise/node_modules/pirates/lib/index.js:88:7)
```
Without this functionality, the error stack would not appear.
```js
const makePromise = require('makepromise/es5')
import { unlink } from 'fs'
(async () => {
try {
await new Promise((r, j) => {
unlink('error-test-file', (err) => {
if (err) return j(err)
return r()
})
})
} catch ({ stack }) {
console.log(stack)
}
})()
```
---
```
Error: ENOENT: no such file or directory, unlink 'error-test-file'
```
## TODO
Licence: MIT
- [ ] fix missing `v2.0.0` commit.
*(c) [Art Deco Code](https://artdeco.bz) 2018*
## Copyright
[1]: https://www.npmjs.com/package/wrote
[2]: https://www.npmjs.com/package/lockfile
(c) [Art Deco][1] 2018
[1]: https://artdeco.bz

@@ -5,3 +5,3 @@ import erotic from 'erotic'

if (i > length - 2) {
throw new Error('Function does not accept that many arguments')
throw new Error('Function does not accept that many arguments.')
}

@@ -11,17 +11,16 @@ }

/**
* Create a promise from a function.
* @param {function} fn Function to call
* @param {any[]|any} [args] Array of arguments to use in call, or one argument, or none
* @param {any} [resolveValue] Override function's return value with this
* @returns {Promise<any>} A promise resolved on callback invocation w/out error,
* and rejected on callback called w/ error.
* Get a promise from a function which otherwise accepts a callback.
* @param {function} fn A function to promisify.
* @param {any[]|any} [args] An array of arguments to use in the call, or a single argument.
* @param {any} [resolveValue] A value to override the value with which the promise will be resolved.
* @returns {Promise<any>} A promise resolved on callback invocation without an error and rejected on callback called with an error.
*/
export default async function makePromise(fn, args, resolveValue) {
const er = erotic()
const er = erotic(true)
if (typeof fn !== 'function') {
throw new Error('function must be passed')
throw new Error('Function must be passed.')
}
const { length: fnLength } = fn
if (!fnLength) {
throw new Error('Function does not accept any arguments')
throw new Error('Function does not accept any arguments.')
}

@@ -52,3 +51,2 @@

return res
}
}

@@ -1,35 +0,52 @@

import { createWritable, erase } from 'wrote'
import { createWritable, erase, read } from 'wrote'
export default async function context() {
const t = this
Object.assign(t, {
async getWs() {
const ws = await createWritable()
t._ws = ws
return ws
},
async _destroy() {
if (t._ws) {
try {
await erase(t._ws)
} catch (err) { /* ignore error if deleted already */ }
}
},
})
Object.defineProperties(this, {
testArg: {
value: 'test-arg',
},
nullErrFn: {
get: () => (arg, cb) => {
if (typeof arg === 'function') { // assume no argument is expected
return arg(null)
}
return cb(null, arg)
},
},
errFn: {
get: () => (err, cb) => cb(err, null),
},
})
}
export default class Context {
async _destroy() {
if (this._ws) {
try {
await erase(this._ws)
} catch (err) { /* ignore error if deleted already */ }
}
}
get readFile() {
return read
}
get testArg() {
return 'test-arg'
}
get simple() {
return cb => cb(null)
}
get withArg() {
return (arg, cb) => cb(null, arg)
}
/**
* Make a function which will call the callback with an error.
* @param {Error} err Error which will be passed to the callback.
*/
makeErrFn(err) {
return cb => cb(err)
}
async getWs() {
const ws = await createWritable()
this._ws = ws
return ws
}
async closeWs(ws) {
await new Promise((resolve, reject) => {
ws.once('close', resolve)
ws.once('error', reject)
ws.close()
})
}
/**
* Returns an array of arguments passed to a function, without the callback.
* @param {*[]} args Arguments passed to a function, including a callback.
*/
parseArguments(args) {
const argArray = Array.from(args)
const realArgs = argArray.splice(0, argArray.length - 1)
return realArgs
}
}

@@ -1,3 +0,4 @@

/* global makePromise */
import { equal, deepEqual } from 'assert'
import { equal, deepEqual, throws } from 'zoroaster/assert'
import makePromise from '../../src'
import Context from '../context'

@@ -7,67 +8,64 @@ const argCheck = {

const fn = () => {}
try {
await makePromise(fn)
throw new Error('should have thrown an error')
} catch ({ message }) {
equal(message, 'Function does not accept any arguments')
}
await throws({
fn: makePromise,
args: [fn],
message: 'Function does not accept any arguments.',
})
},
async 'passing arguments when none allowed'() {
const fn = cb => cb()
try {
await makePromise(fn, 'hello-world')
throw new Error('should have thrown an error')
} catch ({ message }) {
equal(message, 'Function does not accept that many arguments')
}
await throws({
fn: makePromise,
args: [fn, 'hello-world'],
message: 'Function does not accept that many arguments.',
})
},
async 'passing more arguments when allowed'() {
const fn = (test, cb) => { cb(null, test) }
try {
await makePromise(fn, ['hello world', 'extra argument'])
throw new Error('should have thrown an error')
} catch ({ message, stack }) {
equal(message, 'Function does not accept that many arguments')
}
const fn = (test, cb) => cb(null, test)
await throws({
fn: makePromise,
args: [fn, ['hello world', 'extra argument']],
message: 'Function does not accept that many arguments.',
})
},
}
export const argumentCheckTestSuite = {
'returns a rejected promise when': argCheck,
async 'should call function with correct arguments'() {
/** @type {Object.<string, (c: Context)>} */
const T = {
context: Context,
'throws when': argCheck,
async 'calls function with correct arguments'({ parseArguments }) {
const testArgs = ['test-arg-1', undefined, 'test-arg-2']
let args
const fn = function TestFn(testArgA, testArgB, testArgC, cb) {
args = arguments
args = parseArguments(arguments)
cb(null)
}
await makePromise(fn, testArgs)
const argArray = Array.from(args)
const realArgs = argArray.splice(0, argArray.length - 1)
deepEqual(realArgs, testArgs)
deepEqual(args, testArgs)
},
async 'should call function with correct argument'() {
async 'calls function with correct argument'({ parseArguments }) {
const testArg = 'test-arg-1'
let args
const fn = function TestFn(testArgA, cb) {
args = arguments
args = parseArguments(arguments)
cb(null)
}
await makePromise(fn, testArg)
const argArray = Array.from(args)
equal(argArray.length, 2)
equal(argArray[0], testArg)
equal(args.length, 1)
equal(args[0], testArg)
},
async 'should call function with correct undefined argument'() {
async 'calls function with correct undefined argument'({ parseArguments }) {
const testArg = undefined
let args
const fn = function TestFn(testArgA, cb) {
args = arguments
args = parseArguments(arguments)
cb(null)
}
await makePromise(fn, testArg)
const argArray = Array.from(args)
equal(argArray.length, 2)
equal(argArray[0], testArg)
equal(args.length, 1)
equal(args[0], testArg)
},
}
export default T

@@ -1,10 +0,13 @@

/* global makePromise */
import context from '../context'
import { ok } from 'zoroaster/assert'
import makePromise from '../../src'
import Context from '../context'
/** @type {Object.<string, (c: Context)>} */
const T = {
context,
async 'should resolve with function result'({ getWs }) {
context: Context,
async 'resolves with function result'({ getWs }) {
const ws = await getWs()
const boundFn = ws.close.bind(ws)
await makePromise(boundFn)
ok(ws.closed)
},

@@ -11,0 +14,0 @@ }

@@ -1,28 +0,11 @@

/* global makePromise */
import { equal, ok } from 'assert'
import { equal, ok, throws } from 'zoroaster/assert'
import { stat, unlink, Stats } from 'fs'
import { unlock } from 'lockfile'
import { erase, read } from 'wrote'
import context from '../context'
import { erase } from 'wrote'
import makePromise from '../../src'
import Context from '../context'
/** @type {Object.<string, (c: Context)>} */
const T = {
context,
async 'should be able to unlock a file'({ getWs }) {
const ws = await getWs()
ok(ws.writable)
await makePromise(stat, ws.path)
await makePromise(unlock, ws.path)
ok(!ws.closed) // stream not closed
ok(!ws._writableState.ended)
try {
await makePromise(stat, ws.path)
throw new Error('should have been rejected')
} catch ({ code }) {
ok(code, 'ENOENT')
}
await makePromise(ws.end.bind(ws))
ok(ws.closed)
ok(ws._writableState.ended)
},
async 'should write to a file stream'({ getWs }) {
context: Context,
async 'writes to a file stream'({ getWs, readFile }) {
const testData = 'some-test-data'

@@ -33,21 +16,16 @@ const ws = await getWs()

// read file
const actual = await read(ws.path)
const actual = await readFile(ws.path)
equal(actual, testData)
},
async 'should unlink a file'({ getWs }) {
async 'unlinks a file'({ getWs, closeWs, readFile }) {
const ws = await getWs()
await new Promise((resolve, reject) => {
ws.once('close', resolve)
ws.once('error', reject)
ws.close()
await closeWs(ws)
await makePromise(unlink, ws.path)
await throws({
fn: readFile,
args: [ws.path],
code: 'ENOENT',
})
await makePromise(unlink, ws.path)
try {
await read(ws.path)
throw new Error('should have thrown')
} catch ({ code }) {
equal(code, 'ENOENT')
}
},
async 'should end stream'({ getWs }) {
async 'ends stream'({ getWs }) {
const ws = await getWs()

@@ -57,22 +35,23 @@ await makePromise(ws.end.bind(ws))

},
async 'should read stats'({ getWs }) {
async 'reads stats'({ getWs }) {
const ws = await getWs()
ok(!ws._writableState.ended)
/**
* @type {Stats}
*/
const res = await makePromise(stat, ws.path)
ok(res instanceof Stats)
await erase(ws) // move to context
ok(res.isFile())
},
async 'should not read stats of non-existent file'({ getWs }) {
async 'throws when readings stats of non-existent file'({ getWs }) {
const ws = await getWs()
await erase(ws)
try {
await makePromise(stat, ws.path)
throw new Error('should have been rejected')
} catch ({ code }) {
equal(code, 'ENOENT')
}
await throws({
fn: makePromise,
args: [stat, ws.path],
code: 'ENOENT',
})
},
}
export default T
export default T
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc