Skip to content

Commit

Permalink
feat: add util.promisify
Browse files Browse the repository at this point in the history
  • Loading branch information
SukkaW committed Jan 26, 2024
1 parent 66bbb7f commit 44f1358
Show file tree
Hide file tree
Showing 15 changed files with 196 additions and 2 deletions.
1 change: 1 addition & 0 deletions DOWNLOAD_STATS.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,6 @@
| `@nolyfill/typed-array-length` | [![npm](https://img.shields.io/npm/dt/@nolyfill/typed-array-length.svg?style=flat-square&logo=npm&logoColor=white&label=total%20downloads&color=333)](https://www.npmjs.com/package/@nolyfill/typed-array-length) |
| `@nolyfill/typedarray` | [![npm](https://img.shields.io/npm/dt/@nolyfill/typedarray.svg?style=flat-square&logo=npm&logoColor=white&label=total%20downloads&color=333)](https://www.npmjs.com/package/@nolyfill/typedarray) |
| `@nolyfill/unbox-primitive` | [![npm](https://img.shields.io/npm/dt/@nolyfill/unbox-primitive.svg?style=flat-square&logo=npm&logoColor=white&label=total%20downloads&color=333)](https://www.npmjs.com/package/@nolyfill/unbox-primitive) |
| `@nolyfill/util.promisify` | [![npm](https://img.shields.io/npm/dt/@nolyfill/util.promisify.svg?style=flat-square&logo=npm&logoColor=white&label=total%20downloads&color=333)](https://www.npmjs.com/package/@nolyfill/util.promisify) |
| `@nolyfill/which-boxed-primitive` | [![npm](https://img.shields.io/npm/dt/@nolyfill/which-boxed-primitive.svg?style=flat-square&logo=npm&logoColor=white&label=total%20downloads&color=333)](https://www.npmjs.com/package/@nolyfill/which-boxed-primitive) |
| `@nolyfill/which-typed-array` | [![npm](https://img.shields.io/npm/dt/@nolyfill/which-typed-array.svg?style=flat-square&logo=npm&logoColor=white&label=total%20downloads&color=333)](https://www.npmjs.com/package/@nolyfill/which-typed-array) |
3 changes: 2 additions & 1 deletion create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ const autoGeneratedPackagesList = [
['es-aggregate-error'],
['promise.any', { '@nolyfill/es-aggregate-error': 'workspace:*' }, '>=12.4.0'],
['promise.allsettled'],
['array.prototype.toreversed']
['array.prototype.toreversed'],
['util.promisify', { '@nolyfill/safe-array-concat': 'workspace:*' }, '>=12.4.0']
] as const;

const singleFilePackagesList = [
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@
"typed-array-length": "workspace:@nolyfill/typed-array-length@*",
"typedarray": "workspace:@nolyfill/typedarray@*",
"unbox-primitive": "workspace:@nolyfill/unbox-primitive@*",
"util.promisify": "workspace:@nolyfill/util.promisify@*",
"which-boxed-primitive": "workspace:@nolyfill/which-boxed-primitive@*",
"which-typed-array": "workspace:@nolyfill/which-typed-array@*"
},
Expand Down Expand Up @@ -234,6 +235,7 @@
"typed-array-length": "npm:@nolyfill/typed-array-length@latest",
"typedarray": "npm:@nolyfill/typedarray@latest",
"unbox-primitive": "npm:@nolyfill/unbox-primitive@latest",
"util.promisify": "npm:@nolyfill/util.promisify@latest",
"which-boxed-primitive": "npm:@nolyfill/which-boxed-primitive@latest",
"which-typed-array": "npm:@nolyfill/which-typed-array@latest"
}
Expand Down
1 change: 1 addition & 0 deletions packages/data/es-shim-like/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"license": "MIT",
"dependencies": {
"@nolyfill/es-aggregate-error": "workspace:*",
"@nolyfill/safe-array-concat": "workspace:*",
"@nolyfill/shared": "workspace:*"
}
}
135 changes: 135 additions & 0 deletions packages/data/es-shim-like/src/util.promisify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
'use strict';

import type { CustomPromisify } from 'util';

import { defineEsShim } from '@nolyfill/shared';
import safeConcat from '@nolyfill/safe-array-concat';

const kCustomPromisifiedSymbol = Symbol.for('nodejs.util.promisify.custom');
const kCustomPromisifyArgsSymbol = Symbol('customPromisifyArgs');

// eslint-disable-next-line @typescript-eslint/ban-types -- overload signature
function promisify<TCustom extends Function>(fn: CustomPromisify<TCustom>): TCustom;

function promisify<TResult>(
fn: (callback: (err: any, result: TResult) => void) => void,
): () => Promise<TResult>;
function promisify(fn: (callback: (err?: any) => void) => void): () => Promise<void>;

function promisify<T1, TResult>(
fn: (arg1: T1, callback: (err: any, result: TResult) => void) => void,
): (arg1: T1) => Promise<TResult>;
function promisify<T1>(fn: (arg1: T1, callback: (err?: any) => void) => void): (arg1: T1) => Promise<void>;

function promisify<T1, T2, TResult>(
fn: (arg1: T1, arg2: T2, callback: (err: any, result: TResult) => void) => void,
): (arg1: T1, arg2: T2) => Promise<TResult>;
function promisify<T1, T2>(
fn: (arg1: T1, arg2: T2, callback: (err?: any) => void) => void,
): (arg1: T1, arg2: T2) => Promise<void>;

function promisify<T1, T2, T3, TResult>(
fn: (arg1: T1, arg2: T2, arg3: T3, callback: (err: any, result: TResult) => void) => void,
): (arg1: T1, arg2: T2, arg3: T3) => Promise<TResult>;
function promisify<T1, T2, T3>(
fn: (arg1: T1, arg2: T2, arg3: T3, callback: (err?: any) => void) => void,
): (arg1: T1, arg2: T2, arg3: T3) => Promise<void>;

function promisify<T1, T2, T3, T4, TResult>(
fn: (arg1: T1, arg2: T2, arg3: T3, arg4: T4, callback: (err: any, result: TResult) => void) => void,
): (arg1: T1, arg2: T2, arg3: T3, arg4: T4) => Promise<TResult>;
function promisify<T1, T2, T3, T4>(
fn: (arg1: T1, arg2: T2, arg3: T3, arg4: T4, callback: (err?: any) => void) => void,
): (arg1: T1, arg2: T2, arg3: T3, arg4: T4) => Promise<void>;

function promisify<T1, T2, T3, T4, T5, TResult>(
fn: (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, callback: (err: any, result: TResult) => void) => void,
): (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5) => Promise<TResult>;
function promisify<T1, T2, T3, T4, T5>(
fn: (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, callback: (err?: any) => void) => void,
): (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5) => Promise<void>;

// eslint-disable-next-line @typescript-eslint/ban-types -- overload signature
function promisify(orig: Function): Function {
if (typeof orig !== 'function') {
const error = new TypeError('The "original" argument must be of type function') as NodeJS.ErrnoException;
error.code = 'ERR_INVALID_ARG_TYPE';
error.toString = function value() {
return `${this.name}[${this.code}]: ${this.message}`;
};
throw error;
}

if (kCustomPromisifiedSymbol in orig && orig[kCustomPromisifiedSymbol]) {
const customFunction = orig[kCustomPromisifiedSymbol];
if (typeof customFunction !== 'function') {
const customError = TypeError('The [util.promisify.custom] property must be of type function.') as NodeJS.ErrnoException;
customError.code = 'ERR_INVALID_ARG_TYPE';
customError.toString = function value() {
return `${this.name}[${this.code}]: ${this.message}`;
};
throw customError;
}
Object.defineProperty(customFunction, kCustomPromisifiedSymbol, {
configurable: true,
enumerable: false,
value: customFunction,
writable: false
});
return customFunction;
}

// Names to create an object from in case the callback receives multiple
// arguments, e.g. ['stdout', 'stderr'] for child_process.exec.
const argumentNames = kCustomPromisifyArgsSymbol in orig && (orig[kCustomPromisifyArgsSymbol] as ArrayLike<unknown> | undefined);

const promisified = function fn(this: any, ...args: any[]) {
// eslint-disable-next-line @typescript-eslint/no-this-alias -- wrap fn
const self = this;
return new Promise((resolve, reject) => {
orig.apply(self, safeConcat(args, (err: any) => {
const values = args.length > 1 ? args.slice(1) : [];
if (err) {
reject(err);
} else if (argumentNames && typeof argumentNames !== 'undefined' && values.length > 1) {
const obj: Record<string, unknown> = {};
Array.prototype.forEach.call(argumentNames, (name: string, index: number) => {
obj[name] = values[index];
});
resolve(obj);
} else {
resolve(values[0]);
}
}));
});
};

Object.setPrototypeOf(promisified, Object.getPrototypeOf(orig));

Object.defineProperty(promisified, kCustomPromisifiedSymbol, {
configurable: true,
enumerable: false,
value: promisified,
writable: false
});
const descriptors = Object.getOwnPropertyDescriptors(orig);
Array.prototype.forEach.call(descriptors, (k, v) => {
try {
Object.defineProperty(promisified, k, v);
} catch {
// handle nonconfigurable function properties
}
});
return promisified;
}

promisify.custom = kCustomPromisifiedSymbol;

export default defineEsShim(promisify, true);
/**
* @deprecated
* Not exposed by native `util.promisify` or supported by browserify's `util.promisify`.
*
* Use `util.promisify.custom` instead.
*/
export const customPromisifyArgs = kCustomPromisifyArgsSymbol;
2 changes: 2 additions & 0 deletions packages/generated/util.promisify/auto.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
'use strict';
/* noop */
7 changes: 7 additions & 0 deletions packages/generated/util.promisify/entry.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions packages/generated/util.promisify/implementation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
'use strict';
module.exports = require('./entry.js').implementation;
2 changes: 2 additions & 0 deletions packages/generated/util.promisify/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
'use strict';
module.exports = require('./entry.js').index();
22 changes: 22 additions & 0 deletions packages/generated/util.promisify/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "@nolyfill/util.promisify",
"version": "1.0.28",
"repository": {
"type": "git",
"url": "https://github.com/SukkaW/nolyfill",
"directory": "packages/generated/util.promisify"
},
"main": "./index.js",
"license": "MIT",
"files": [
"*.js"
],
"scripts": {},
"dependencies": {
"@nolyfill/safe-array-concat": "workspace:*",
"@nolyfill/shared": "workspace:*"
},
"engines": {
"node": ">=12.4.0"
}
}
2 changes: 2 additions & 0 deletions packages/generated/util.promisify/polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
'use strict';
module.exports = require('./entry.js').polyfill;
2 changes: 2 additions & 0 deletions packages/generated/util.promisify/shim.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
'use strict';
module.exports = require('./entry.js').shim;
1 change: 1 addition & 0 deletions packages/tools/cli/src/all-packages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export const allPackages = [
"typed-array-length",
"typedarray",
"unbox-primitive",
"util.promisify",
"which-boxed-primitive",
"which-typed-array"
];
13 changes: 13 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion turbo.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
},
"//#codegen": {
"inputs": [
"create.ts"
"create.ts",
"packages/data/**"
]
},
"build": {
Expand Down

0 comments on commit 44f1358

Please sign in to comment.