From d25b9228ad59f57c5eb95ef7f16e5a2f635f5d0a Mon Sep 17 00:00:00 2001 From: freitzzz <1160907@isep.ipp.pt> Date: Mon, 20 May 2024 08:03:13 +0100 Subject: [PATCH 1/2] chore(deps): add @web-pacotes/foundation-types --- package-lock.json | 12 ++++++++++-- package.json | 3 +++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index bf0dcaf..ca20c08 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,13 +1,16 @@ { "name": "@web-pacotes/networking", - "version": "0.0.7", + "version": "0.0.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@web-pacotes/networking", - "version": "0.0.7", + "version": "0.0.8", "license": "MIT", + "dependencies": { + "@web-pacotes/foundation-types": "^0.0.4" + }, "devDependencies": { "@changesets/cli": "^2.26.1", "@freitzzz/gh-pagez": "^5.0.1", @@ -2788,6 +2791,11 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@web-pacotes/foundation-types": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@web-pacotes/foundation-types/-/foundation-types-0.0.4.tgz", + "integrity": "sha512-F0KkVmRubjiFBKyIA8g4ip/IiRCk+6TN5vP7m78K7U0XPPrMC1MZEZ7A478Lg+7/iXMTsIOJUIrh8POwe9bAHA==" + }, "node_modules/acorn": { "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", diff --git a/package.json b/package.json index b0a4dfc..240323f 100644 --- a/package.json +++ b/package.json @@ -69,5 +69,8 @@ "ts-jest": "^29.1.0", "tsup": "^6.7.0", "typescript": "^5.0.4" + }, + "dependencies": { + "@web-pacotes/foundation-types": "^0.0.4" } } \ No newline at end of file From 43798f3e826e61978a49fdac99c134ea19cd2404 Mon Sep 17 00:00:00 2001 From: freitzzz <1160907@isep.ipp.pt> Date: Mon, 20 May 2024 08:03:52 +0100 Subject: [PATCH 2/2] refactor: replace internal monads with those provided in @web-pacotes/foundation-types --- src/clients/networking_client.ts | 14 ++--- src/clients/proxy_networking_client.ts | 2 +- src/models/body.ts | 12 ++--- src/type-utils/either.test.ts | 66 ----------------------- src/type-utils/either.ts | 75 -------------------------- src/type-utils/index.ts | 3 -- src/type-utils/lazy.test.ts | 49 ----------------- src/type-utils/lazy.ts | 38 ------------- src/type-utils/option.ts | 4 -- 9 files changed, 12 insertions(+), 251 deletions(-) delete mode 100644 src/type-utils/either.test.ts delete mode 100644 src/type-utils/either.ts delete mode 100644 src/type-utils/lazy.test.ts delete mode 100644 src/type-utils/lazy.ts delete mode 100644 src/type-utils/option.ts diff --git a/src/clients/networking_client.ts b/src/clients/networking_client.ts index c89a022..83cfa2e 100644 --- a/src/clients/networking_client.ts +++ b/src/clients/networking_client.ts @@ -15,7 +15,7 @@ import { resolveUrl } from '../models'; import { FetchClient } from '../models'; -import { Either, fold, left, right } from '../type-utils'; +import { Either, fold, Left, Right } from '@web-pacotes/foundation-types'; /** * An alias for {@link NetworkingClient} positional parameters. @@ -235,26 +235,26 @@ export class NetworkingClient { }); if (eager ?? true) { - result = right( + result = Right( await HttpResponse.fromEagerFetchResponse(fetchResponse) ); } else { - result = right(HttpResponse.fromFetchResponse(fetchResponse)); + result = Right(HttpResponse.fromFetchResponse(fetchResponse)); } } catch (err) { if (err === undefined) { - result = left(new NoInternetConnectionError()); + result = Left(new NoInternetConnectionError()); } else if (!(err instanceof Error)) { - result = left(new UnknownError({ cause: `${err}` })); + result = Left(new UnknownError({ cause: `${err}` })); } else if (err.name === 'TimeoutError') { - result = left( + result = Left( new TimeoutError({ cause: err.message, timeoutMS: this.timeoutMS }) ); } else { - result = left(new UnknownError({ cause: JSON.stringify(err) })); + result = Left(new UnknownError({ cause: JSON.stringify(err) })); } } diff --git a/src/clients/proxy_networking_client.ts b/src/clients/proxy_networking_client.ts index e8eb033..b5e4ca7 100644 --- a/src/clients/proxy_networking_client.ts +++ b/src/clients/proxy_networking_client.ts @@ -1,5 +1,5 @@ import { HttpRequest, HttpRequestError, HttpResponse } from '../models'; -import { Either } from '../type-utils'; +import type { Either } from '@web-pacotes/foundation-types'; import { NetworkingClient, NetworkingClientPositionalParameters diff --git a/src/models/body.ts b/src/models/body.ts index 712a2ce..d2aa9b9 100644 --- a/src/models/body.ts +++ b/src/models/body.ts @@ -1,4 +1,4 @@ -import { Lazy } from '../type-utils'; +import { Lazy, compute, computed } from "@web-pacotes/foundation-types"; export type Text = string; export type Binary = Blob; @@ -28,7 +28,7 @@ export function empty(): HttpBody { * @returns a lazy {@link HttpBody} that does not resolve until computed. */ export function of(value: () => T): HttpBody { - return Lazy.sync(value); + return Lazy(value); } /** @@ -38,8 +38,8 @@ export function of(value: () => T): HttpBody { * @returns a value of {@link T} type, extracted from the {@link HttpBody} type. */ export function extract(body: HttpBody): T { - if (isLazyBody(body)) { - return body.get(); + if (!computed(body)) { + return compute(body); } return body; @@ -63,10 +63,6 @@ export function convert(body: HttpBody): FetchBody { } } -function isLazyBody(body: HttpBody): body is LazyHttpBody { - return body instanceof Lazy; -} - function isBinary(data: Anything): data is Blob { return data instanceof Blob; } diff --git a/src/type-utils/either.test.ts b/src/type-utils/either.test.ts deleted file mode 100644 index 40e0513..0000000 --- a/src/type-utils/either.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { expect, describe, test } from '@jest/globals'; -import { fold, isLeft, isRight, left, right } from './either'; - -describe('either', function () { - describe('isLeft', function () { - test('returns true if monad is error', function () { - const monad = left('error'); - - const check = isLeft(monad); - - expect(check).toBeTruthy(); - }); - - test('returns false if monad is success', function () { - const monad = right('success'); - - const check = isLeft(monad); - - expect(check).toBeFalsy(); - }); - }); - - describe('isRight', function () { - test('returns true if monad is success', function () { - const monad = right('success'); - - const check = isRight(monad); - - expect(check).toBeTruthy(); - }); - - test('returns false if monad is error', function () { - const monad = left('error'); - - const check = isRight(monad); - - expect(check).toBeFalsy(); - }); - }); - - describe('fold', function () { - test('folds error value if monad is error', function () { - const monad = left('error'); - - const value = fold( - monad, - (l) => l, - (r) => r - ); - - expect(value).toBe('error'); - }); - - test('folds success value if monad is success', function () { - const monad = right('success'); - - const value = fold( - monad, - (l) => l, - (r) => r - ); - - expect(value).toBe('success'); - }); - }); -}); diff --git a/src/type-utils/either.ts b/src/type-utils/either.ts deleted file mode 100644 index e133bfe..0000000 --- a/src/type-utils/either.ts +++ /dev/null @@ -1,75 +0,0 @@ -type Left = { - readonly tag: 'left'; - readonly value: L; -}; - -type Right = { - readonly tag: 'right'; - readonly value: R; -}; - -/** - * Types a poor man Either Monad. As per convention, the {@link L} type represents an error, while the {@link R} type the success result. - */ -export type Either = Left | Right; - -/** - * Creates an {@link Either} that represents an error. - */ -export function left(l: L): Either { - return >{ - tag: 'left', - value: l - }; -} - -/** - * Creates an {@link Either} that represents a success result. - */ -export function right(r: R): Either { - return >{ - tag: 'right', - value: r - }; -} - -/** - * Folds the value of either monad by computing the left callback, if an error, or right callback if a success result. - * - * @param monad - the either monad being folded - * @param ifLeft - callback that folds an error in a common type - * @param ifRight - callback that folds a success result in a common type - * @returns the folded value based on the computed callbacks. - */ -export function fold( - monad: Either, - ifLeft: (l: L) => F, - ifRight: (r: R) => F -): F { - switch (monad.tag) { - case 'left': - return ifLeft(monad.value); - case 'right': - return ifRight(monad.value); - } -} - -/** - * Provides a type guard to check if the monad is an error. - * - * @param monad - the either monad to check if its an error - * @returns true if error, false otherwise - */ -export function isLeft(monad: Either): monad is Left { - return monad.tag === 'left'; -} - -/** - * Provides a type guard to check if the monad is a success result. - * - * @param monad - the either monad to check if its a success - * @returns true if success, false otherwise - */ -export function isRight(monad: Either): monad is Right { - return !isLeft(monad); -} diff --git a/src/type-utils/index.ts b/src/type-utils/index.ts index 57b2e3a..f298acd 100644 --- a/src/type-utils/index.ts +++ b/src/type-utils/index.ts @@ -1,4 +1 @@ -export * from './either'; -export * from './lazy'; -export * from './option'; export * from './range'; diff --git a/src/type-utils/lazy.test.ts b/src/type-utils/lazy.test.ts deleted file mode 100644 index 9cc66e9..0000000 --- a/src/type-utils/lazy.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { expect, describe, test } from '@jest/globals'; -import { Lazy } from './lazy'; - -describe('lazy', function () { - describe('sync', function () { - test('first call computes the value', function () { - let value = 3; - - const lazyCallback = () => (value = value + 3); - const lazy = Lazy.sync(lazyCallback); - - const computed = lazy.get(); - - expect(computed).toBe(6); - }); - - test('second and subsequent calls do not compute the value', function () { - let value = 3; - - const lazyCallback = () => (value = value + 3); - const lazy = Lazy.sync(lazyCallback); - - for (let i = 0; i < 10; i++) { - lazy.get(); - } - - const computed = lazy.get(); - - expect(computed).toBe(6); - }); - }); - - describe('async', function () { - test('second and subsequent calls return a resolved promise', async function () { - let value = 3; - - const lazyCallback = async () => (value = value + 3); - const lazy = Lazy.async(lazyCallback); - - for (let i = 0; i < 10; i++) { - await lazy.get(); - } - - const computed = await lazy.get(); - - expect(computed).toBe(6); - }); - }); -}); diff --git a/src/type-utils/lazy.ts b/src/type-utils/lazy.ts deleted file mode 100644 index f5d83b5..0000000 --- a/src/type-utils/lazy.ts +++ /dev/null @@ -1,38 +0,0 @@ -type LazyValueCallback = () => T; - -/** - * Types a value that is not computed at the time it's created. - */ -export class Lazy { - private value: T | LazyValueCallback; - - protected constructor(lazy: LazyValueCallback) { - this.value = lazy; - } - - static sync(lazy: LazyValueCallback) { - return new Lazy(lazy); - } - - static async(lazy: LazyValueCallback>) { - return new AsyncLazy(lazy); - } - - /** - * Gets the lazy computed value. If it's not available yet, computes it by calling the callback. - * - * @returns the lazy loaded value - */ - get(): T { - if (typeof this.value === 'function') { - this.value = (this.value as LazyValueCallback)(); - } - - return this.value; - } -} - -/** - * Types a value that is lazy loaded but requires an async call to compute it. - */ -export class AsyncLazy extends Lazy> {} diff --git a/src/type-utils/option.ts b/src/type-utils/option.ts deleted file mode 100644 index 55a560a..0000000 --- a/src/type-utils/option.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Types a optional type at the compile check level. - */ -export type Option = T | undefined;