Skip to content

Commit

Permalink
feat: polyfill Promise.withResolvers (#368)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsherret authored Feb 3, 2024
1 parent b4f133c commit c9bb94e
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 1 deletion.
Binary file modified lib/pkg/dnt_wasm_bg.wasm
Binary file not shown.
2 changes: 2 additions & 0 deletions rs-lib/src/polyfills/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ mod array_from_async;
mod error_cause;
mod import_meta;
mod object_has_own;
mod promise_with_resolvers;
mod string_replace_all;

pub trait Polyfill {
Expand Down Expand Up @@ -109,6 +110,7 @@ fn all_polyfills() -> Vec<Box<dyn Polyfill>> {
Box::new(array_find_last::ArrayFindLastPolyfill),
Box::new(array_from_async::ArrayFromAsyncPolyfill),
Box::new(import_meta::ImportMetaPolyfill),
Box::new(promise_with_resolvers::PromiseWithResolversPolyfill),
]
}

Expand Down
62 changes: 62 additions & 0 deletions rs-lib/src/polyfills/promise_with_resolvers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

use deno_ast::view::Node;

use super::Polyfill;
use super::PolyfillVisitContext;
use crate::ScriptTarget;

pub struct PromiseWithResolversPolyfill;

impl Polyfill for PromiseWithResolversPolyfill {
fn use_for_target(&self, _target: ScriptTarget) -> bool {
// (target as u32) < (ScriptTarget::ES2021 as u32)
true // just always use it for the time being
}

fn visit_node(&self, node: Node, context: &PolyfillVisitContext) -> bool {
context.has_global_property_access(node, "Promise", "withResolvers")
}

fn get_file_text(&self) -> &'static str {
include_str!("./scripts/es2021.promise-withResolvers.ts")
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::polyfills::PolyfillTester;

#[test]
pub fn finds_when_matches() {
let tester =
PolyfillTester::new(Box::new(|| Box::new(PromiseWithResolversPolyfill)));
assert_eq!(tester.matches("Promise.withResolvers"), true);
assert_eq!(
tester.matches("class Promise {} Promise.withResolvers"),
false
);
assert_eq!(tester.matches("Other.withResolvers"), false);
assert_eq!(tester.matches("Promise.withResolvers2"), false);
assert_eq!(tester.matches("const { withResolvers } = Promise;"), true);
assert_eq!(
tester.matches("const { withResolvers: test } = Promise;"),
true
);
assert_eq!(
tester.matches("const { \"withResolvers\": test } = Promise;"),
true
);
assert_eq!(tester.matches("const { withResolvers } = other;"), false);
assert_eq!(
tester.matches("class Promise {} const { withResolvers } = Promise;"),
false
);
assert_eq!(tester.matches("const { ...rest } = Promise;"), true); // unknown, so true
assert_eq!(
tester.matches("const { [computed]: test } = Promise;"),
true
); // unknown, so true
}
}
22 changes: 22 additions & 0 deletions rs-lib/src/polyfills/scripts/es2021.promise-withResolvers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
declare global {
// https://github.com/denoland/deno/blob/0bfa0cc0276e94f1a308aaad5f925eaacb6e3db2/cli/tsc/dts/lib.es2021.promise.d.ts#L53
interface PromiseConstructor {
/**
* Creates a Promise that can be resolved or rejected using provided functions.
* @returns An object containing `promise` promise object, `resolve` and `reject` functions.
*/
withResolvers<T>(): { promise: Promise<T>, resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void };
}
}

// https://github.com/tc39/proposal-promise-with-resolvers/blob/3a78801e073e99217dbeb2c43ba7212f3bdc8b83/polyfills.js#L1C1-L9C2
if (Promise.withResolvers === undefined) {
Promise.withResolvers = () => {
const out: any = {};
out.promise = new Promise((resolve_, reject_) => {
out.resolve = resolve_;
out.reject = reject_;
});
return out;
};
}
9 changes: 8 additions & 1 deletion tests/polyfill_project/mod.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

import { hasOwn } from "./mod.ts";
import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts";
import { hasOwn, withResolvers } from "./mod.ts";

Deno.test("should test the polyfill", () => {
assertEquals(hasOwn({}), false);
assertEquals(hasOwn({ prop: 5 }), true);
});

Deno.test("with resolvers", async () => {
const { promise, resolve } = withResolvers<number>();
setTimeout(() => resolve(5), 10);
const value = await promise;
assertEquals(value, 5);
});
4 changes: 4 additions & 0 deletions tests/polyfill_project/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ export function hasOwn(a: { prop?: number }) {
err.cause = new Error("test");
}
}

export function withResolvers<T>() {
return Promise.withResolvers<T>();
}

0 comments on commit c9bb94e

Please sign in to comment.