pax_global_header00006660000000000000000000000064136215443600014516gustar00rootroot0000000000000052 comment=5ef286ffc5310e7dbe99eee1891378ffde962ae9 pify-5.0.0/000077500000000000000000000000001362154436000124675ustar00rootroot00000000000000pify-5.0.0/.editorconfig000066400000000000000000000002571362154436000151500ustar00rootroot00000000000000root = true [*] indent_style = tab end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [*.yml] indent_style = space indent_size = 2 pify-5.0.0/.gitattributes000066400000000000000000000000231362154436000153550ustar00rootroot00000000000000* text=auto eol=lf pify-5.0.0/.github/000077500000000000000000000000001362154436000140275ustar00rootroot00000000000000pify-5.0.0/.github/funding.yml000066400000000000000000000001561362154436000162060ustar00rootroot00000000000000github: sindresorhus open_collective: sindresorhus tidelift: npm/pify custom: https://sindresorhus.com/donate pify-5.0.0/.github/security.md000066400000000000000000000002631362154436000162210ustar00rootroot00000000000000# Security Policy To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. pify-5.0.0/.gitignore000066400000000000000000000000271362154436000144560ustar00rootroot00000000000000node_modules yarn.lock pify-5.0.0/.npmrc000066400000000000000000000000231362154436000136020ustar00rootroot00000000000000package-lock=false pify-5.0.0/.travis.yml000066400000000000000000000000551362154436000146000ustar00rootroot00000000000000language: node_js node_js: - '12' - '10' pify-5.0.0/index.js000066400000000000000000000053111362154436000141340ustar00rootroot00000000000000'use strict'; const processFn = (fn, options, proxy, unwrapped) => function (...arguments_) { const P = options.promiseModule; return new P((resolve, reject) => { if (options.multiArgs) { arguments_.push((...result) => { if (options.errorFirst) { if (result[0]) { reject(result); } else { result.shift(); resolve(result); } } else { resolve(result); } }); } else if (options.errorFirst) { arguments_.push((error, result) => { if (error) { reject(error); } else { resolve(result); } }); } else { arguments_.push(resolve); } const self = this === proxy ? unwrapped : this; Reflect.apply(fn, self, arguments_); }); }; const filterCache = new WeakMap(); module.exports = (input, options) => { options = { exclude: [/.+(?:Sync|Stream)$/], errorFirst: true, promiseModule: Promise, ...options }; const objectType = typeof input; if (!(input !== null && (objectType === 'object' || objectType === 'function'))) { throw new TypeError(`Expected \`input\` to be a \`Function\` or \`Object\`, got \`${input === null ? 'null' : objectType}\``); } const filter = (target, key) => { let cached = filterCache.get(target); if (!cached) { cached = {}; filterCache.set(target, cached); } if (key in cached) { return cached[key]; } const match = pattern => (typeof pattern === 'string' || typeof key === 'symbol') ? key === pattern : pattern.test(key); const desc = Reflect.getOwnPropertyDescriptor(target, key); const writableOrConfigurableOwn = (desc === undefined || desc.writable || desc.configurable); const included = options.include ? options.include.some(match) : !options.exclude.some(match); const shouldFilter = included && writableOrConfigurableOwn; cached[key] = shouldFilter; return shouldFilter; }; const cache = new WeakMap(); const proxy = new Proxy(input, { apply(target, thisArg, args) { const cached = cache.get(target); if (cached) { return Reflect.apply(cached, thisArg, args); } const pified = options.excludeMain ? target : processFn(target, options, proxy, target); cache.set(target, pified); return Reflect.apply(pified, thisArg, args); }, get(target, key) { const property = target[key]; // eslint-disable-next-line no-use-extend-native/no-use-extend-native if (!filter(target, key) || property === Function.prototype[key]) { return property; } const cached = cache.get(property); if (cached) { return cached; } if (typeof property === 'function') { const pified = processFn(property, options, proxy, target); cache.set(property, pified); return pified; } return property; } }); return proxy; }; pify-5.0.0/license000066400000000000000000000021351362154436000140350ustar00rootroot00000000000000MIT License Copyright (c) Sindre Sorhus (https://sindresorhus.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pify-5.0.0/optimization-test.js000066400000000000000000000020051362154436000165250ustar00rootroot00000000000000/* eslint-disable no-fallthrough */ 'use strict'; const assert = require('assert'); const v8 = require('v8-natives'); const pify = require('.'); function assertOptimized(fn, name) { const status = v8.getOptimizationStatus(fn); switch (status) { case 1: // `fn` is optimized console.log('pify is optimized'); return; case 2: assert(false, `${name} is not optimized (${status})`); case 3: // `fn` is always optimized return; case 4: assert(false, `${name} is never optimized (${status})`); case 6: assert(false, `${name} is maybe deoptimized (${status})`); default: assert(false, `unknown OptimizationStatus: ${status} (${name})`); } } const fn = pify({ unicorn: callback => { callback(null, 'unicorn'); } }); (async () => { try { await fn.unicorn(); v8.optimizeFunctionOnNextCall(fn.unicorn); await fn.unicorn(); assertOptimized(fn.unicorn, 'unicorn'); } catch (error) { console.error(error); process.exit(1); // eslint-disable-line unicorn/no-process-exit } })(); pify-5.0.0/package.json000066400000000000000000000015431362154436000147600ustar00rootroot00000000000000{ "name": "pify", "version": "5.0.0", "description": "Promisify a callback-style function", "license": "MIT", "repository": "sindresorhus/pify", "funding": "https://github.com/sponsors/sindresorhus", "author": { "name": "Sindre Sorhus", "email": "sindresorhus@gmail.com", "url": "https://sindresorhus.com" }, "engines": { "node": ">=10" }, "scripts": { "test": "xo && ava", "optimization-test": "node --allow-natives-syntax optimization-test.js" }, "files": [ "index.js" ], "keywords": [ "promisify", "callback", "promise", "promises", "denodify", "denodeify", "node", "then", "thenify", "convert", "transform", "wrap", "wrapper", "bind", "async", "await", "es2015", "bluebird" ], "devDependencies": { "ava": "^2.4.0", "pinkie-promise": "^2.0.0", "v8-natives": "^1.1.0", "xo": "^0.26.1" } } pify-5.0.0/readme.md000066400000000000000000000100321362154436000142420ustar00rootroot00000000000000# pify [![Build Status](https://travis-ci.org/sindresorhus/pify.svg?branch=master)](https://travis-ci.org/sindresorhus/pify) > Promisify a callback-style function ## Install ``` $ npm install pify ``` ## Usage ```js const fs = require('fs'); const pify = require('pify'); (async () => { // Promisify a single function. const data = await pify(fs.readFile)('package.json', 'utf8'); console.log(JSON.parse(data).name); //=> 'pify' // Promisify all methods in a module. const data2 = await pify(fs).readFile('package.json', 'utf8'); console.log(JSON.parse(data2).name); //=> 'pify' })(); ``` ## API ### pify(input, options?) Returns a `Promise` wrapped version of the supplied function or module. #### input Type: `Function | object` Callback-style function or module whose methods you want to promisify. #### options Type: `object` ##### multiArgs Type: `boolean`\ Default: `false` By default, the promisified function will only return the second argument from the callback, which works fine for most APIs. This option can be useful for modules like `request` that return multiple arguments. Turning this on will make it return an array of all arguments from the callback, excluding the error argument, instead of just the second argument. This also applies to rejections, where it returns an array of all the callback arguments, including the error. ```js const request = require('request'); const pify = require('pify'); const pRequest = pify(request, {multiArgs: true}); (async () => { const [httpResponse, body] = await pRequest('https://sindresorhus.com'); })(); ``` ##### include Type: `Array` Methods in a module to promisify. Remaining methods will be left untouched. ##### exclude Type: `Array`\ Default: `[/.+(?:Sync|Stream)$/]` Methods in a module **not** to promisify. Methods with names ending with `'Sync'` are excluded by default. ##### excludeMain Type: `boolean`\ Default: `false` If the given module is a function itself, it will be promisified. Enable this option if you want to promisify only methods of the module. ```js const pify = require('pify'); function fn() { return true; } fn.method = (data, callback) => { setImmediate(() => { callback(null, data); }); }; (async () => { // Promisify methods but not `fn()`. const promiseFn = pify(fn, {excludeMain: true}); if (promiseFn()) { console.log(await promiseFn.method('hi')); } })(); ``` ##### errorFirst Type: `boolean`\ Default: `true` Whether the callback has an error as the first argument. You'll want to set this to `false` if you're dealing with an API that doesn't have an error as the first argument, like `fs.exists()`, some browser APIs, Chrome Extension APIs, etc. ##### promiseModule Type: `Function` Custom promise module to use instead of the native one. ## FAQ #### How is this different from Node.js's [`util.promisify`](https://nodejs.org/api/util.html#util_util_promisify_original)? - Pify existed long before `util.promisify`. - Pify is [faster](https://github.com/sindresorhus/pify/issues/41#issuecomment-429988506). - Pify supports wrapping a whole module/object, not just a specific method. - Pify has useful options like the ability to handle multiple arguments (`multiArgs`). - Pify does not have [magic behavior](https://nodejs.org/api/util.html#util_custom_promisified_functions) for certain Node.js methods and instead focuses on predictability. ## Related - [p-event](https://github.com/sindresorhus/p-event) - Promisify an event by waiting for it to be emitted - [p-map](https://github.com/sindresorhus/p-map) - Map over promises concurrently - [More…](https://github.com/sindresorhus/promise-fun) ---
Get professional support for 'pify' with a Tidelift subscription
Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies.
pify-5.0.0/test.js000066400000000000000000000234411362154436000140100ustar00rootroot00000000000000/* eslint-disable promise/prefer-await-to-then */ import util from 'util'; import fs from 'fs'; import stream from 'stream'; import test from 'ava'; import pinkiePromise from 'pinkie-promise'; import pify from '.'; const fixture = callback => setImmediate(() => { callback(null, 'unicorn'); }); const fixture1 = callback => setImmediate(() => { callback('error', 'unicorn', 'rainbow'); }); const fixture2 = (value, callback) => setImmediate(() => { callback(null, value); }); const fixture3 = callback => setImmediate(() => { callback(null, 'unicorn', 'rainbow'); }); const fixture4 = callback => setImmediate(() => { callback(null, 'unicorn'); return 'rainbow'; }); fixture4.meow = callback => { setImmediate(() => { callback(null, 'unicorn'); }); }; const fixture5 = () => 'rainbow'; const fixtureModule = { method1: fixture, method2: fixture, method3: fixture5 }; function FixtureGrandparent() {} FixtureGrandparent.prototype.grandparentMethod1 = fixture; FixtureGrandparent.prototype.overriddenMethod1 = fixture; function FixtureParent() {} util.inherits(FixtureParent, FixtureGrandparent); FixtureParent.prototype.parentMethod1 = fixture; FixtureParent.prototype.overriddenMethod1 = fixture2; FixtureParent.prototype.overriddenValue1 = 2; function FixtureClass() { this.instanceMethod1 = fixture; this.instanceValue1 = 72; } util.inherits(FixtureClass, FixtureParent); FixtureClass.prototype.method1 = fixture; FixtureClass.prototype.method2Cb = function (callback) { setImmediate(() => { callback(null, this.instanceValue1); }); }; FixtureClass.prototype.method2Async = pify(FixtureClass.prototype.method2Cb); FixtureParent.prototype.overriddenValue1 = 4; FixtureClass.prototype.value1 = 'neo'; test('main', async t => { t.is(typeof pify(fixture)().then, 'function'); t.is(await pify(fixture)(), 'unicorn'); }); test('throw error on invalid input', t => { let error = t.throws(() => pify()); t.is(error.message, 'Expected `input` to be a `Function` or `Object`, got `undefined`'); error = t.throws(() => pify('')); t.is(error.message, 'Expected `input` to be a `Function` or `Object`, got `string`'); error = t.throws(() => pify(null)); t.is(error.message, 'Expected `input` to be a `Function` or `Object`, got `null`'); }); test('error', async t => { t.is(await pify(fixture1)().catch(error => error), 'error'); }); test('pass argument', async t => { t.is(await pify(fixture2)('rainbow'), 'rainbow'); }); test('custom Promise module', async t => { t.is(await pify(fixture, {promiseModule: pinkiePromise})(), 'unicorn'); }); test('multiArgs option', async t => { t.deepEqual(await pify(fixture3, {multiArgs: true})(), ['unicorn', 'rainbow']); }); test('multiArgs option β€” rejection', async t => { t.deepEqual(await pify(fixture1, {multiArgs: true})().catch(error => error), ['error', 'unicorn', 'rainbow']); }); test('wrap core method', async t => { t.is(JSON.parse(await pify(fs.readFile)('package.json')).name, 'pify'); }); test('module support', async t => { t.is(JSON.parse(await pify(fs).readFile('package.json')).name, 'pify'); }); test('module support - doesn\'t transform *Sync methods by default', t => { t.is(JSON.parse(pify(fs).readFileSync('package.json')).name, 'pify'); }); test('module support - doesn\'t transform *Stream methods by default', t => { t.true(pify(fs).createReadStream('package.json') instanceof stream.Readable); }); test('module support - preserves non-function members', t => { const module = { method: () => {}, nonMethod: 3 }; t.deepEqual(Object.keys(module), Object.keys(pify(module))); }); test('module support - transforms only members in options.include', t => { const pModule = pify(fixtureModule, { include: ['method1', 'method2'] }); t.is(typeof pModule.method1().then, 'function'); t.is(typeof pModule.method2().then, 'function'); t.not(typeof pModule.method3().then, 'function'); }); test('module support - doesn\'t transform members in options.exclude', t => { const pModule = pify(fixtureModule, { exclude: ['method3'] }); t.is(typeof pModule.method1().then, 'function'); t.is(typeof pModule.method2().then, 'function'); t.not(typeof pModule.method3().then, 'function'); }); test('module support - options.include over options.exclude', t => { const pModule = pify(fixtureModule, { include: ['method1', 'method2'], exclude: ['method2', 'method3'] }); t.is(typeof pModule.method1().then, 'function'); t.is(typeof pModule.method2().then, 'function'); t.not(typeof pModule.method3().then, 'function'); }); test('module support β€” function modules', t => { const pModule = pify(fixture4); t.is(typeof pModule().then, 'function'); t.is(typeof pModule.meow().then, 'function'); }); test('module support β€” function modules exclusion', t => { const pModule = pify(fixture4, { excludeMain: true }); t.is(typeof pModule.meow().then, 'function'); t.not(typeof pModule(() => {}).then, 'function'); }); test('`errorFirst` option', async t => { const fixture = (foo, callback) => { callback(foo); }; t.is(await pify(fixture, {errorFirst: false})('πŸ¦„'), 'πŸ¦„'); }); test('`errorFirst` option and `multiArgs`', async t => { const fixture = (foo, bar, callback) => { callback(foo, bar); }; t.deepEqual(await pify(fixture, { errorFirst: false, multiArgs: true })('πŸ¦„', '🌈'), ['πŸ¦„', '🌈']); }); test('class support - does not create a copy', async t => { const obj = { x: 'foo', y(callback) { setImmediate(() => { callback(null, this.x); }); } }; const pified = pify(obj); obj.x = 'bar'; t.is(await pified.y(), 'bar'); t.is(pified.x, 'bar'); }); test('class support β€” transforms inherited methods', t => { const instance = new FixtureClass(); const pInstance = pify(instance); t.is(instance.value1, pInstance.value1); t.is(typeof pInstance.instanceMethod1().then, 'function'); t.is(typeof pInstance.method1().then, 'function'); t.is(typeof pInstance.parentMethod1().then, 'function'); t.is(typeof pInstance.grandparentMethod1().then, 'function'); }); test('class support β€” preserves prototype', t => { const instance = new FixtureClass(); const pInstance = pify(instance); t.true(pInstance instanceof FixtureClass); }); test('class support β€” respects inheritance order', async t => { const instance = new FixtureClass(); const pInstance = pify(instance); t.is(instance.overriddenValue1, pInstance.overriddenValue1); t.is(await pInstance.overriddenMethod1('rainbow'), 'rainbow'); }); test('class support - transforms only members in options.include, copies all', t => { const instance = new FixtureClass(); const pInstance = pify(instance, { include: ['parentMethod1'] }); t.is(typeof pInstance.parentMethod1().then, 'function'); t.not(typeof pInstance.method1(() => {}).then, 'function'); t.not(typeof pInstance.grandparentMethod1(() => {}).then, 'function'); }); test('class support - doesn\'t transform members in options.exclude', t => { const instance = new FixtureClass(); const pInstance = pify(instance, { exclude: ['grandparentMethod1'] }); t.not(typeof pInstance.grandparentMethod1(() => {}).then, 'function'); t.is(typeof pInstance.parentMethod1().then, 'function'); }); test('class support - options.include over options.exclude', t => { const instance = new FixtureClass(); const pInstance = pify(instance, { include: ['method1', 'parentMethod1'], exclude: ['parentMethod1', 'grandparentMethod1'] }); t.is(typeof pInstance.method1().then, 'function'); t.is(typeof pInstance.parentMethod1().then, 'function'); t.not(typeof pInstance.grandparentMethod1(() => {}).then, 'function'); }); test('promisify prototype function', async t => { const instance = new FixtureClass(); t.is(await instance.method2Async(), 72); }); test('method mutation', async t => { const object = { foo(callback) { setImmediate(() => { callback(null, 'original'); }); } }; const pified = pify(object); object.foo = callback => setImmediate(() => { callback(null, 'new'); }); t.is(await pified.foo(), 'new'); }); test('symbol keys', async t => { await t.notThrowsAsync(async () => { const symbol = Symbol('symbol'); const object = { [symbol]: callback => { setImmediate(callback); } }; const pified = pify(object); await pified[symbol](); }); }); // [[Get]] for proxy objects enforces the following invariants: The value // reported for a property must be the same as the value of the corresponding // target object property if the target object property is a non-writable, // non-configurable own data property. test('non-writable non-configurable property', t => { const object = {}; Object.defineProperty(object, 'prop', { value: callback => { setImmediate(callback); }, writable: false, configurable: false }); const pified = pify(object); t.notThrows(() => { Reflect.get(pified, 'prop'); }); }); test('do not promisify Function.prototype.bind', async t => { function fn(callback) { callback(null, this); } const target = {}; t.is(await pify(fn).bind(target)(), target); }); test('do not break internal callback usage', async t => { const object = { foo(callback) { this.bar(4, callback); }, bar(...arguments_) { const callback = arguments_.pop(); callback(null, 42); } }; t.is(await pify(object).foo(), 42); }); test('Function.prototype.call', async t => { function fn(...arguments_) { const callback = arguments_.pop(); callback(null, arguments_.length); } const pified = pify(fn); t.is(await pified.call(), 0); }); test('Function.prototype.apply', async t => { function fn(...arguments_) { const callback = arguments_.pop(); callback(null, arguments_.length); } const pified = pify(fn); t.is(await pified.apply(), 0); }); test('self as member', async t => { function fn(...arguments_) { const callback = arguments_.pop(); callback(null, arguments_.length); } fn.self = fn; const pified = pify(fn); t.is(await pified.self(), 0); });