@@ -25,6 +25,7 @@ const uv = process.binding('uv');
2525const Buffer = require ( 'buffer' ) . Buffer ;
2626const internalUtil = require ( 'internal/util' ) ;
2727const binding = process . binding ( 'util' ) ;
28+ const errors = require ( 'internal/errors' ) ;
2829
2930const isError = internalUtil . isError ;
3031
@@ -1055,3 +1056,53 @@ process.versions[exports.inspect.custom] =
10551056 ( depth ) => exports . format ( JSON . parse ( JSON . stringify ( process . versions ) ) ) ;
10561057
10571058exports . promisify = internalUtil . promisify ;
1059+
1060+ function callbackifyOnRejected ( reason , cb ) {
1061+ // `!reason` guard inspired by bluebird (Ref: https://goo.gl/t5IS6M).
1062+ // Because `null` is a special error value in callbacks which means "no error
1063+ // occurred", we error-wrap so the callback consumer can distinguish between
1064+ // "the promise rejected with null" or "the promise fulfilled with undefined".
1065+ if ( ! reason ) {
1066+ const newReason = new errors . Error ( 'FALSY_VALUE_REJECTION' ) ;
1067+ newReason . reason = reason ;
1068+ reason = newReason ;
1069+ Error . captureStackTrace ( reason , callbackifyOnRejected ) ;
1070+ }
1071+ return cb ( reason ) ;
1072+ }
1073+
1074+
1075+ function callbackify ( original ) {
1076+ if ( typeof original !== 'function' ) {
1077+ throw new errors . TypeError (
1078+ 'ERR_INVALID_ARG_TYPE' ,
1079+ 'original' ,
1080+ 'function' ) ;
1081+ }
1082+
1083+ // We DO NOT return the promise as it gives the user a false sense that
1084+ // the promise is actually somehow related to the callback's execution
1085+ // and that the callback throwing will reject the promise.
1086+ function callbackified ( ...args ) {
1087+ const maybeCb = args . pop ( ) ;
1088+ if ( typeof maybeCb !== 'function' ) {
1089+ throw new errors . TypeError (
1090+ 'ERR_INVALID_ARG_TYPE' ,
1091+ 'last argument' ,
1092+ 'function' ) ;
1093+ }
1094+ const cb = ( ...args ) => { Reflect . apply ( maybeCb , this , args ) ; } ;
1095+ // In true node style we process the callback on `nextTick` with all the
1096+ // implications (stack, `uncaughtException`, `async_hooks`)
1097+ Reflect . apply ( original , this , args )
1098+ . then ( ( ret ) => process . nextTick ( cb , null , ret ) ,
1099+ ( rej ) => process . nextTick ( callbackifyOnRejected , rej , cb ) ) ;
1100+ }
1101+
1102+ Object . setPrototypeOf ( callbackified , Object . getPrototypeOf ( original ) ) ;
1103+ Object . defineProperties ( callbackified ,
1104+ Object . getOwnPropertyDescriptors ( original ) ) ;
1105+ return callbackified ;
1106+ }
1107+
1108+ exports . callbackify = callbackify ;
0 commit comments