From 1623fc7de417161192a537695e78f903aae39c86 Mon Sep 17 00:00:00 2001 From: Muthu Kumar Date: Mon, 27 Feb 2023 17:17:54 +0530 Subject: [PATCH] feat: rewrite to Deno/TS --- .circleci/config.yml | 36 ------------ .vscode/launch.json | 14 ----- .vscode/settings.json | 4 ++ LICENSE | 21 +++++++ build.sh | 12 ---- es5/index.js | 142 --------------------------------------------- es5/index.min.js | 1 - es6/index.js | 1 - index.js | 104 --------------------------------- index.ts | 44 ++++++++++++++ package-lock.json | 112 ----------------------------------- package.json | 37 ------------ package.json.old | 30 ++++++++++ spec/PromiseObject.spec.js | 76 ------------------------ spec/support/jasmine.json | 11 ---- test.ts | 48 +++++++++++++++ 16 files changed, 147 insertions(+), 546 deletions(-) delete mode 100644 .circleci/config.yml delete mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 LICENSE delete mode 100755 build.sh delete mode 100644 es5/index.js delete mode 100644 es5/index.min.js delete mode 100644 es6/index.js delete mode 100644 index.js create mode 100644 index.ts delete mode 100644 package-lock.json delete mode 100644 package.json create mode 100644 package.json.old delete mode 100644 spec/PromiseObject.spec.js delete mode 100644 spec/support/jasmine.json create mode 100644 test.ts diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 698644d..0000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,36 +0,0 @@ -# Javascript Node CircleCI 2.0 configuration file -# -# Check https://circleci.com/docs/2.0/language-javascript/ for more details -# -version: 2 -jobs: - build: - docker: - # specify the version you desire here - - image: circleci/node:10.3 - - working_directory: ~/repo - - steps: - - checkout - - # Download and cache dependencies - - restore_cache: - keys: - - v1-dependencies-{{ checksum "package.json" }} - # fallback to using the latest cache if no exact match is found - - v1-dependencies- - - - run: npm install - - - run: npm install --only=dev - - - save_cache: - paths: - - node_modules - key: v1-dependencies-{{ checksum "package.json" }} - - # run tests! - - run: npm test - - diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index e8f6960..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "node", - "request": "launch", - "name": "Launch Program", - "program": "${workspaceFolder}/test.js" - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..28867f2 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "deno.enable": true, + "deno.lint": false +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..65a8f98 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Feathers Studio + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 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. diff --git a/build.sh b/build.sh deleted file mode 100755 index ff86b3c..0000000 --- a/build.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -mkdir -p ./es5 -echo "Browserifying..." -npx browserify ./es6/index.js -s promiseObject > ./es5/index.temp.js -echo "Babelifying..." -npx babel ./es5/index.temp.js --presets=env --plugins=babel-plugin-transform-object-rest-spread -o ./es5/index.js -echo "Minifying output..." -npx uglifyjs ./es5/index.js > ./es5/index.min.js -echo "Cleaning up..." -rm ./es5/index.temp.js -echo "Done!" diff --git a/es5/index.js b/es5/index.js deleted file mode 100644 index 8f703ea..0000000 --- a/es5/index.js +++ /dev/null @@ -1,142 +0,0 @@ -"use strict"; - -var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - -function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } - -function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } - -(function (f) { - if ((typeof exports === "undefined" ? "undefined" : _typeof(exports)) === "object" && typeof module !== "undefined") { - module.exports = f(); - } else if (typeof define === "function" && define.amd) { - define([], f); - } else { - var g;if (typeof window !== "undefined") { - g = window; - } else if (typeof global !== "undefined") { - g = global; - } else if (typeof self !== "undefined") { - g = self; - } else { - g = this; - }g.promiseObject = f(); - } -})(function () { - var define, module, exports;return function () { - function r(e, n, t) { - function o(i, f) { - if (!n[i]) { - if (!e[i]) { - var c = "function" == typeof require && require;if (!f && c) return c(i, !0);if (u) return u(i, !0);var a = new Error("Cannot find module '" + i + "'");throw a.code = "MODULE_NOT_FOUND", a; - }var p = n[i] = { exports: {} };e[i][0].call(p.exports, function (r) { - var n = e[i][1][r];return o(n || r); - }, p, p.exports, r, e, n, t); - }return n[i].exports; - }for (var u = "function" == typeof require && require, i = 0; i < t.length; i++) { - o(t[i]); - }return o; - }return r; - }()({ 1: [function (require, module, exports) { - module.exports = require('../index.js'); - }, { "../index.js": 2 }], 2: [function (require, module, exports) { - "use strict"; - - /** - * Returns true if x is an object, false otherwise. - * @param {any} x - * @returns {Boolean} - */ - - var isObject = function isObject(x) { - return x && (typeof x === "undefined" ? "undefined" : _typeof(x)) === 'object' && x.constructor === Object; - }; - - /* A well known Symbol. */ - var $SELF = typeof Symbol !== 'undefined' ? Symbol('SELF') : '[~~//-- SELF --//~~]'; - - /** - * Replaces values that match the query parameter - * with a reference to the parent parameter. - * @param {Object} object Object to make cyclic. - * @param {any} query Query to match against. - * @returns {Object} - */ - var makeCyclic = function makeCyclic(object, query) { - var start = function start(obj) { - return Object.keys(obj).reduce(function (acc, key) { - var value = obj[key]; - if (value === query) { - obj[key] = object; - return [].concat(_toConsumableArray(acc), [key]); - }; - if (isObject(value)) return [].concat(_toConsumableArray(acc), _toConsumableArray(start(value, query)));else return acc; - }, []); - }; - return start(object); - }; - - /** - * Promise.map polyfill. - * @param {Array.} arr Array of Promises. - * @param {Function} functor Function to call resolved values. - */ - var PromiseMap = function PromiseMap(arr, functor) { - return Promise.all(arr.map(function (x) { - return Promise.resolve(x).then(functor); - })); - }; - - /** - * Resolve a flat object's promises. - * @param {Object} - * @returns {Object} - */ - var ResolveObject = function ResolveObject(obj) { - return Promise.all(Object.keys(obj).map(function (key) { - return Promise.resolve(obj[key]).then(function (val) { - return obj[key] = val; - }); - })).then(function (_) { - return obj; - }); - }; - - /** - * Recursively resolves deep objects with nested promises. - * @param {Object} object Object or value to resolve. - * @returns {Object} Resolved object. - */ - var PromiseObject = function PromiseObject(object) { - var shouldReplaceSelf = false; - var ResolveDeepObject = function ResolveDeepObject(obj) { - return Promise.resolve(obj).then(function (resolvedObject) { - if (Array.isArray(resolvedObject)) { - // Promise and map every item to recursively deep resolve. - return PromiseMap(resolvedObject, function (obj) { - return ResolveDeepObject(obj); - }); - } else if (isObject(resolvedObject)) { - return ResolveObject(Object.keys(resolvedObject).reduce(function (acc, key) { - if (resolvedObject[key] === object) { - shouldReplaceSelf = true; - return _extends({}, acc, _defineProperty({}, key, $SELF)); - } - return _extends({}, acc, _defineProperty({}, key, ResolveDeepObject(resolvedObject[key]))); - }, {})); - } - return resolvedObject; - }); - }; - return ResolveDeepObject(object).then(function (obj) { - // Replace $SELF with reference to obj - if (shouldReplaceSelf) makeCyclic(obj, $SELF); - return obj; - }); - }; - - module.exports = PromiseObject; - }, {}] }, {}, [1])(1); -}); diff --git a/es5/index.min.js b/es5/index.min.js deleted file mode 100644 index b1b2fd6..0000000 --- a/es5/index.min.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";var _extends=Object.assign||function(target){for(var i=1;i x && - typeof x === 'object' && - x.constructor === Object; - -/* A well known Symbol. */ -const $SELF = typeof Symbol !== 'undefined' ? - Symbol('SELF') : - '[~~//-- SELF --//~~]'; - -/** - * Replaces values that match the query parameter - * with a reference to the parent parameter. - * @param {Object} object Object to make cyclic. - * @param {any} query Query to match against. - * @returns {Object} - */ -const makeCyclic = (object, query) => { - const start = obj => Object.keys(obj).reduce((acc, key) => { - const value = obj[key]; - if (value === query) { - obj[key] = object; - return [...acc, key] - }; - if (isObject(value)) return [...acc, ...start(value, query)]; - else return acc; - }, []); - return start(object); -}; - -/** - * Promise.map polyfill. - * @param {Array.} arr Array of Promises. - * @param {Function} functor Function to call resolved values. - */ -const PromiseMap = (arr, functor) => - Promise.all(arr.map(x => Promise.resolve(x).then(functor))); - -/** - * Resolve a flat object's promises. - * @param {Object} - * @returns {Object} - */ -const ResolveObject = obj => - Promise.all( - Object - .keys(obj) - .map(key => - Promise - .resolve(obj[key]) - .then(val => obj[key] = val)) - ) - .then(_ => obj); - -/** - * Recursively resolves deep objects with nested promises. - * @param {Object} object Object or value to resolve. - * @returns {Object} Resolved object. - */ -const PromiseObject = object => { - let shouldReplaceSelf = false; - const ResolveDeepObject = obj => - Promise - .resolve(obj) - .then(resolvedObject => { - if (Array.isArray(resolvedObject)) { - // Promise and map every item to recursively deep resolve. - return PromiseMap(resolvedObject, obj => ResolveDeepObject(obj)); - } else if (isObject(resolvedObject)) { - return ResolveObject( - Object - .keys(resolvedObject) - .reduce((acc, key) => { - if (resolvedObject[key] === object) { - shouldReplaceSelf = true; - return { - ...acc, - [key]: $SELF, // Replace with resolved object. - } - } - return { - ...acc, - [key]: ResolveDeepObject(resolvedObject[key]), - } - }, {})); - - } - return resolvedObject; - }); - return ResolveDeepObject(object) - .then(obj => { - // Replace $SELF with reference to obj - if(shouldReplaceSelf) makeCyclic(obj, $SELF); - return obj; - }); -}; - -module.exports = PromiseObject; \ No newline at end of file diff --git a/index.ts b/index.ts new file mode 100644 index 0000000..a7ec493 --- /dev/null +++ b/index.ts @@ -0,0 +1,44 @@ +type ResolveObject = T extends object + ? T extends Promise + ? ResolveObject + : { [k in keyof T]: ResolveObject } + : T; + +/** Recursively resolves deep objects with nested promises. */ +export async function promiseObject(obj: T): Promise> { + const seen = new Map(); + + async function resolver(obj: T): Promise> { + // null / undefined + if (obj == null) return obj as ResolveObject; + + // other primitive + if (typeof obj !== "object") return obj as ResolveObject; + + if (seen.has(obj)) return seen.get(obj) as ResolveObject; + + // PromiseLike + if ("then" in obj && typeof obj.then === "function") { + const resolved = resolver(await obj); + seen.set(obj, resolved); + return resolved as ResolveObject; + } + + // Array + if (Array.isArray(obj)) { + const resolved = await Promise.all(obj.map(each => Promise.resolve(each).then(resolver))); + seen.set(obj, resolved); + return resolved as ResolveObject; + } + + // object + const ret = {} as ResolveObject; + seen.set(obj, ret); + // @ts-ignore + for (const [key, value] of Object.entries(obj)) ret[key] = await resolver(value); + seen.set(obj, ret); + return ret; + } + + return resolver(obj); +} diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index ad9f9b0..0000000 --- a/package-lock.json +++ /dev/null @@ -1,112 +0,0 @@ -{ - "name": "@codefeathers/promise.object", - "version": "0.9.1", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "balanced-match": { - "version": "1.0.0", - "resolved": "http://localhost:4873/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "http://localhost:4873/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "http://localhost:4873/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "http://localhost:4873/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "glob": { - "version": "7.1.2", - "resolved": "http://localhost:4873/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "http://localhost:4873/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "http://localhost:4873/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "jasmine": { - "version": "3.1.0", - "resolved": "http://localhost:4873/jasmine/-/jasmine-3.1.0.tgz", - "integrity": "sha1-K9Wf1+xuwOistk4J9Fpo7SrRlSo=", - "dev": true, - "requires": { - "glob": "^7.0.6", - "jasmine-core": "~3.1.0" - } - }, - "jasmine-core": { - "version": "3.1.0", - "resolved": "http://localhost:4873/jasmine-core/-/jasmine-core-3.1.0.tgz", - "integrity": "sha1-pHheE11d9lAk38kiSVPfWFvSdmw=", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "http://localhost:4873/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "once": { - "version": "1.4.0", - "resolved": "http://localhost:4873/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "http://localhost:4873/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "wrappy": { - "version": "1.0.2", - "resolved": "http://localhost:4873/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index d06937b..0000000 --- a/package.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "@codefeathers/promise.object", - "version": "0.9.5", - "description": "Deep resolve promises in objects.", - "main": "es5/index.min.js", - "scripts": { - "test": "jasmine", - "build": "./build.sh" - }, - "keywords": [ - "Promise", - "A+", - "objects", - "deep resolve" - ], - "author": "Muthu Kumar <@MKRhere> (https://mkr.pw)", - "contributors": [ - "Thomas Rory Gummerson <@TRGWII> (https://rory.no)" - ], - "repository": { - "type": "git", - "url": "git+https://github.com/codefeathers/Promise.object.git" - }, - "bugs": { - "url": "https://github.com/codefeathers/Promise.object/issues" - }, - "homepage": "https://github.com/codefeathers/Promise.object#readme", - "license": "MIT", - "devDependencies": { - "babel-cli": "^6.26.0", - "babel-plugin-transform-object-rest-spread": "^6.26.0", - "babel-preset-env": "^1.7.0", - "browserify": "^16.2.2", - "jasmine": "^3.1.0", - "uglify-js": "^3.4.0" - } -} diff --git a/package.json.old b/package.json.old new file mode 100644 index 0000000..d760f2c --- /dev/null +++ b/package.json.old @@ -0,0 +1,30 @@ +{ + "name": "@codefeathers/promise.object", + "version": "0.9.5", + "description": "Deep resolve promises in objects.", + "main": "es5/index.min.js", + "scripts": { + "test": "jasmine", + "build": "./build.sh" + }, + "keywords": [ + "Promise", + "A+", + "objects", + "deep resolve" + ], + "author": "Muthu Kumar <@MKRhere> (https://mkr.pw)", + "contributors": [ + "Thomas Rory Gummerson <@TRGWII> (https://rory.no)" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/codefeathers/Promise.object.git" + }, + "bugs": { + "url": "https://github.com/codefeathers/Promise.object/issues" + }, + "homepage": "https://github.com/codefeathers/Promise.object#readme", + "license": "MIT", + "devDependencies": {} +} diff --git a/spec/PromiseObject.spec.js b/spec/PromiseObject.spec.js deleted file mode 100644 index 7c5cb88..0000000 --- a/spec/PromiseObject.spec.js +++ /dev/null @@ -1,76 +0,0 @@ -'use strict'; - -Promise.object = require('../es5/index.min.js'); - -// Simple object -const testObject1 = { - foo: Promise.resolve(1), - bar: { - foobar: Promise.resolve(2), - }, -}; - -const resolvedObject1 = { - foo: 1, - bar: { - foobar: 2 - }, -}; - -// Nested promises with circular reference -const testObject2 = { - foo: Promise.resolve(1), - bar: { - foobar: Promise.resolve(2) - }, - baz: [ 1, "two", Promise.resolve(3) ], -}; - -testObject2.link1 = testObject2; -testObject2.link2 = { link3: testObject2 }; - -const resolvedObject2 = { - foo: 1, - bar: { - foobar: 2, - }, - baz: [ 1, "two", 3 ], -}; - -resolvedObject2.link1 = resolvedObject2; -resolvedObject2.link2 = { link3: resolvedObject2 }; - -// Deeply nested promises -const testObject3 = Promise.resolve({ - foo: Promise.resolve({ - bar: Promise.resolve( - Promise.resolve(5) - ), - }), -}); - -const resolvedObject3 = { - foo: { - bar: 5, - }, -}; - -/* global describe it expect */ -describe("Promise.object", () => { - - it("Should return resolvedObject1", () => { - return Promise.object(testObject1) - .then(obj => expect(obj).toEqual(resolvedObject1)); - }) - - it("Should return resolvedObject2", () => { - return Promise.object(testObject2) - .then(obj => expect(obj).toEqual(resolvedObject2)); - }) - - it("Should return resolvedObject3", () => { - return Promise.object(testObject3) - .then(obj => expect(obj).toEqual(resolvedObject3)); - }) - -}) \ No newline at end of file diff --git a/spec/support/jasmine.json b/spec/support/jasmine.json deleted file mode 100644 index 370fc44..0000000 --- a/spec/support/jasmine.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "spec_dir": "spec", - "spec_files": [ - "**/*[sS]pec.js" - ], - "helpers": [ - "helpers/**/*.js" - ], - "stopSpecOnExpectationFailure": false, - "random": true -} diff --git a/test.ts b/test.ts new file mode 100644 index 0000000..2c9e5a6 --- /dev/null +++ b/test.ts @@ -0,0 +1,48 @@ +import { assertEquals } from "https://deno.land/std@0.178.0/testing/asserts.ts"; +import { promiseObject } from "./index.ts"; + +// Simple object +const simple = { + test: { foo: Promise.resolve(1), bar: { foobar: Promise.resolve(2) } }, + resolved: { foo: 1, bar: { foobar: 2 } }, +}; + +// Nested promises with circular reference +const nested = { + test: (() => { + let o = { + foo: Promise.resolve(1), + bar: { foobar: Promise.resolve(2) }, + baz: [1, "two", Promise.resolve(3)], + }; + + return Object.assign(o, { link1: o, link2: { link3: o } }); + })(), + resolved: (() => { + const o = { + foo: 1, + bar: { foobar: 2 }, + baz: [1, "two", 3], + }; + + return Object.assign(o, { link1: o, link2: { link3: o } }); + })(), +}; + +// Deeply nested promises +const deeplyNested = { + test: Promise.resolve({ foo: Promise.resolve({ bar: Promise.resolve(Promise.resolve(5)) }) }), + resolved: { foo: { bar: 5 } }, +}; + +Deno.test("Should resolve simple object", async () => { + assertEquals(await promiseObject(simple.test), simple.resolved); +}); + +Deno.test("Should resolve cyclic objects", async () => { + assertEquals(await promiseObject(nested.test), nested.resolved); +}); + +Deno.test("Should resolve deeply cyclic objects", async () => { + assertEquals(await promiseObject(deeplyNested.test), deeplyNested.resolved); +});