import { primordials } from "ext:core/mod.js";
const {
ArrayPrototypePop,
Error,
FunctionPrototypeBind,
ReflectApply,
ObjectDefineProperties,
ObjectGetOwnPropertyDescriptors,
ObjectSetPrototypeOf,
ObjectValues,
PromisePrototypeThen,
} = primordials;
import { nextTick } from "ext:deno_node/_next_tick.ts";
import { validateFunction } from "ext:deno_node/internal/validators.mjs";
class NodeFalsyValueRejectionError extends Error {
code = "ERR_FALSY_VALUE_REJECTION";
constructor(reason) {
super("Promise was rejected with falsy value");
this.reason = reason;
}
}
function callbackify(original) {
validateFunction(original, "original");
function callbackified(...args) {
const maybeCb = ArrayPrototypePop(args);
validateFunction(maybeCb, "last argument");
const cb = FunctionPrototypeBind(maybeCb, this);
PromisePrototypeThen(
ReflectApply(original, this, args),
(ret) => nextTick(cb, null, ret),
(rej) => {
rej = rej || new NodeFalsyValueRejectionError(rej);
return nextTick(cb, rej);
},
);
}
const descriptors = ObjectGetOwnPropertyDescriptors(original);
if (typeof descriptors.length.value === "number") {
descriptors.length.value++;
}
if (typeof descriptors.name.value === "string") {
descriptors.name.value += "Callbackified";
}
const propertiesValues = ObjectValues(descriptors);
for (let i = 0; i < propertiesValues.length; i++) {
ObjectSetPrototypeOf(propertiesValues[i], null);
}
ObjectDefineProperties(callbackified, descriptors);
return callbackified;
}
export { callbackify };