ionic-team / rollup-plugin-node-polyfills

MIT License
139 stars 59 forks source link

util polyfill does not include callbackify, promisify and other utilities #38

Open giuseppeg opened 2 years ago

giuseppeg commented 2 years ago

Hi there

Firstly, thanks for your work on this project! 🙂

It seems that the util polyfill is outdated and doesn't include callbackify. It would be awesome if you could add it or depend on node-util directly.

FWIW @remorses @ryanflorence I ended up discovering this because I use remix-run which uses @esbuild-plugins/node-modules-polyfill. Specifically web3.js uses callbackify somewhere in their codebase.

Here's the diff.

diff --git a/node_modules/rollup-plugin-node-polyfills/polyfills/util.js b/node_modules/rollup-plugin-node-polyfills/polyfills/util.js
index 2194380..a00ee54 100644
--- a/node_modules/rollup-plugin-node-polyfills/polyfills/util.js
+++ b/node_modules/rollup-plugin-node-polyfills/polyfills/util.js
@@ -18,6 +18,17 @@
 // 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.
+
+var getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors ||
+  function getOwnPropertyDescriptors(obj) {
+    var keys = Object.keys(obj);
+    var descriptors = {};
+    for (var i = 0; i < keys.length; i++) {
+      descriptors[keys[i]] = Object.getOwnPropertyDescriptor(obj, keys[i]);
+    }
+    return descriptors;
+  };
+
 import process from 'process';
 var formatRegExp = /%[sdj%]/g;
 export function format(f) {
@@ -572,6 +583,54 @@ function hasOwnProperty(obj, prop) {
   return Object.prototype.hasOwnProperty.call(obj, prop);
 }

+function callbackifyOnRejected(reason, cb) {
+  // `!reason` guard inspired by bluebird (Ref: https://goo.gl/t5IS6M).
+  // Because `null` is a special error value in callbacks which means "no error
+  // occurred", we error-wrap so the callback consumer can distinguish between
+  // "the promise rejected with null" or "the promise fulfilled with undefined".
+  if (!reason) {
+    var newReason = new Error('Promise was rejected with a falsy value');
+    newReason.reason = reason;
+    reason = newReason;
+  }
+  return cb(reason);
+}
+
+export function callbackify(original) {
+  if (typeof original !== 'function') {
+    throw new TypeError('The "original" argument must be of type Function');
+  }
+
+  // We DO NOT return the promise as it gives the user a false sense that
+  // the promise is actually somehow related to the callback's execution
+  // and that the callback throwing will reject the promise.
+  function callbackified() {
+    var args = [];
+    for (var i = 0; i < arguments.length; i++) {
+      args.push(arguments[i]);
+    }
+
+    var maybeCb = args.pop();
+    if (typeof maybeCb !== 'function') {
+      throw new TypeError('The last argument must be of type Function');
+    }
+    var self = this;
+    var cb = function() {
+      return maybeCb.apply(self, arguments);
+    };
+    // In true node style we process the callback on `nextTick` with all the
+    // implications (stack, `uncaughtException`, `async_hooks`)
+    original.apply(this, args)
+      .then(function(ret) { process.nextTick(cb.bind(null, null, ret)) },
+            function(rej) { process.nextTick(callbackifyOnRejected.bind(null, rej, cb)) });
+  }
+
+  Object.setPrototypeOf(callbackified, Object.getPrototypeOf(original));
+  Object.defineProperties(callbackified,
+                          getOwnPropertyDescriptors(original));
+  return callbackified;
+}
+
 export default {
   inherits: inherits,
   _extend: _extend,
@@ -594,5 +653,6 @@ export default {
   inspect: inspect,
   deprecate: deprecate,
   format: format,
-  debuglog: debuglog
+  debuglog: debuglog,
+  callbackify: callbackify,
 }

This issue body was partially generated by patch-package.

shenjo commented 2 years ago

also miss promisify image

MichaelDeBoey commented 1 year ago

@giuseppeg @IvanKushchenko @shenjo I've created https://github.com/remorses/esbuild-plugins/pull/19 to update @esbuild-plugins/node-modules-polyfill (which is what we use in the Remix repo) to use @FredKSchott's rollup-plugin-polyfill-node instead.

Can you check out my PR & test out if that one's working for you?