Skip to content

Commit

Permalink
Adds Promise.try (#82)
Browse files Browse the repository at this point in the history
This PR adds a polyfill for `Promise.try`.
  • Loading branch information
mhassan1 authored Dec 2, 2024
1 parent d42b580 commit b33702e
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 0 deletions.
31 changes: 31 additions & 0 deletions polyfills/Promise/try/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
aliases = [ "es2025" ]
dependencies = [
"_ESAbstract.Call",
"_ESAbstract.CreateMethodProperty",
"_ESAbstract.NewPromiseCapability",
"_ESAbstract.NormalCompletion",
"_ESAbstract.ThrowCompletion",
"_ESAbstract.Type",
"Function.prototype.name",
"Promise",
]
license = "MIT"
spec = "https://tc39.es/ecma262/#sec-promise.try"
docs = "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/try"

[browsers]
android = "*"
bb = "*"
chrome = "<128"
edge = "*"
edge_mob = "*"
firefox = "<132"
firefox_mob = "*"
ie = "*"
ie_mob = "*"
opera = "<114"
op_mob = "*"
op_mini = "*"
safari = "<18.2"
ios_saf = "<18.2"
samsung_mob = "*"
1 change: 1 addition & 0 deletions polyfills/Promise/try/detect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"Promise" in self && "try" in self.Promise;
56 changes: 56 additions & 0 deletions polyfills/Promise/try/polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* global Call, CreateMethodProperty, NewPromiseCapability, NormalCompletion, Promise, ThrowCompletion, Type */
// 27.2.4.8 Promise.try ( callback, ...args )
CreateMethodProperty(Promise, "try", function Try(callback /* , ...args */) {
var args =
arguments.length > 1 ? Array.prototype.slice.call(arguments, 1) : [];
// 1. Let C be the this value.
var C = this;
// 2. If C is not an Object, throw a TypeError exception.
if (Type(C) !== "object") {
throw new TypeError("`this` value must be an object");
}
// 3. Let promiseCapability be ? NewPromiseCapability(C).
var promiseCapability = NewPromiseCapability(C);
// 4. Let status be Completion(Call(callback, undefined, args)).
var status;
try {
status = NormalCompletion(Call(callback, undefined, args));
} catch (error) {
status = ThrowCompletion(error);
}
// 5. If status is an abrupt completion, then
if (status["[[Type]]"] === "throw") {
// a. Perform ? Call(promiseCapability.[[Reject]], undefined, « status.[[Value]] »).
Call(promiseCapability["[[Reject]]"], undefined, [status["[[Value]]"]]);
}
// 6. Else,
else {
// a. Perform ? Call(promiseCapability.[[Resolve]], undefined, « status.[[Value]] »).
Call(promiseCapability["[[Resolve]]"], undefined, [status["[[Value]]"]]);
}
// 7. Return promiseCapability.[[Promise]].
return promiseCapability["[[Promise]]"];
});

(function () {
var supportsDefiningFunctionName = (function () {
var fn = function () {};
try {
Object.defineProperty(fn, "name", {
value: "test"
});
return true;
} catch (ignore) {
return false;
}
})();

if (supportsDefiningFunctionName) {
Object.defineProperty(Promise.try, "name", {
value: "try",
writable: false,
enumerable: false,
configurable: true
});
}
})();
110 changes: 110 additions & 0 deletions polyfills/Promise/try/polyfill.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/* global Promise */
var supportsDefiningFunctionName = (function () {
var fn = function () {};
try {
Object.defineProperty(fn, "name", {
value: "test"
});
return true;
} catch (ignore) {
return false;
}
})();

it("is a function", function () {
proclaim.isFunction(Promise.try);
});

it("has correct arity", function () {
proclaim.arity(Promise.try, 1);
});

it("has correct name", function () {
if (supportsDefiningFunctionName) {
proclaim.hasName(Promise.try, "try");
} else {
proclaim.hasName(Promise.try, "Try");
}
});

it("is not enumerable", function () {
proclaim.isNotEnumerable(Promise, "try");
});

describe("try", function () {
it("returns a Promise that resolves for a callback function that returns a value", function () {
var promise = Promise.try(function () {
return "ok";
});
return promise.then(function (value) {
proclaim.equal(value, "ok");
});
});

it("returns a Promise that rejects for a callback function that throws synchronously", function () {
var promise = Promise.try(function () {
throw "not ok";
});
return promise.then(
function () {
proclaim.fail("promise did not reject");
},
function (error) {
proclaim.equal(error, "not ok");
}
);
});

it("returns a Promise that resolves for a callback function that returns a Promise that resolves", function () {
var promise = Promise.try(function () {
return Promise.resolve("ok");
});
return promise.then(function (value) {
proclaim.equal(value, "ok");
});
});

it("returns a Promise that rejects for a callback function that returns a Promise that rejects", function () {
var promise = Promise.try(function () {
return Promise.reject("not ok");
});
return promise.then(
function () {
proclaim.fail("promise did not reject");
},
function (error) {
proclaim.equal(error, "not ok");
}
);
});

it("calls the callback function with variadic arguments", function () {
var promise = Promise.try(
function (a, b) {
return a + b;
},
1,
2
);
return promise.then(function (value) {
proclaim.equal(value, 3);
});
});

it("throws a TypeError for non-constructor `this`", function () {
proclaim.throws(function () {
Promise.try.call({});
}, TypeError);
});

it("supports `this` as a Promise subclass", function () {
function _Promise(executor) {
return new Promise(executor);
}
_Promise.prototype = Promise.prototype;

var _promise = Promise.try.call(_Promise, function () {});

proclaim.ok(_promise instanceof _Promise);
});
});

0 comments on commit b33702e

Please sign in to comment.