taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 64313ff428e4e7e31885ef5a599c6acabd783d66
parent f71a7b766a62273a3710433f0017d142e8a48313
Author: Florian Dold <florian@dold.me>
Date:   Tue, 18 Feb 2025 18:11:57 +0100

taler-util: separate result type

We should not overload the sum type used for API responses for other
results.

Diffstat:
Apackages/taler-util/src/result.ts | 41+++++++++++++++++++++++++++++++++++++++++
Mpackages/taler-util/src/taleruri.ts | 56++++++++++++++++++++++++++++----------------------------
2 files changed, 69 insertions(+), 28 deletions(-)

diff --git a/packages/taler-util/src/result.ts b/packages/taler-util/src/result.ts @@ -0,0 +1,41 @@ +/* + This file is part of GNU Taler + (C) 2025 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +import { TalerErrorCode } from "./taler-error-codes.js"; + +/** + * Result of a generic operation that can fail. + */ +export type Result<T, Err> = ResultOk<T> | ResultError<Err>; + +export interface ResultOk<T> { + readonly tag: "ok"; + readonly value: T; +} + +export interface ResultError<Err> { + readonly tag: "error"; + readonly error: Err; +} + +export const Result = { + of<T>(value: T): Result<T, any> { + return { tag: "ok", value }; + }, + error<Err extends TalerErrorCode>(error: Err): ResultError<Err> { + return { tag: "error", error }; + }, +}; diff --git a/packages/taler-util/src/taleruri.ts b/packages/taler-util/src/taleruri.ts @@ -25,7 +25,7 @@ */ import { Codec, Context, DecodingError, renderContext } from "./codec.js"; import { canonicalizeBaseUrl } from "./helpers.js"; -import { opFixedSuccess, opKnownTalerFailure } from "./operation.js"; +import { Result } from "./result.js"; import { TalerErrorCode } from "./taler-error-codes.js"; import { AmountString } from "./types-taler-common.js"; import { URL, URLSearchParams } from "./url.js"; @@ -139,20 +139,18 @@ export interface AddExchangeUri { */ export function parseWithdrawUriWithError(s: string) { const pi = parseProtoInfoWithError(s, "withdraw"); - if (pi.type === "fail") { + if (pi.tag === "error") { return pi; } - const c = pi.body.rest.split("?", 2); + const c = pi.value.rest.split("?", 2); const path = c[0]; const q = new URLSearchParams(c[1] ?? ""); const parts = path.split("/"); if (parts.length < 2) { - return opKnownTalerFailure(TalerErrorCode.WALLET_TALER_URI_MALFORMED, { - code: TalerErrorCode.WALLET_TALER_URI_MALFORMED, - }); + return Result.error(TalerErrorCode.WALLET_TALER_URI_MALFORMED); } const host = parts[0].toLowerCase(); @@ -170,12 +168,12 @@ export function parseWithdrawUriWithError(s: string) { const result: WithdrawUriResult = { type: TalerUriAction.Withdraw, bankIntegrationApiBaseUrl: canonicalizeBaseUrl( - `${pi.body.innerProto}://${p}/`, + `${pi.value.innerProto}://${p}/`, ), withdrawalOperationId: withdrawId, externalConfirmation: q.get("external-confirmation") == "1", }; - return opFixedSuccess(result); + return Result.of(result); } /** @@ -184,8 +182,8 @@ export function parseWithdrawUriWithError(s: string) { */ export function parseWithdrawUri(s: string): WithdrawUriResult | undefined { const r = parseWithdrawUriWithError(s); - if (r.type === "fail") return undefined; - return r.body; + if (r.tag === "error") return undefined; + return r.value; } /** @@ -194,15 +192,13 @@ export function parseWithdrawUri(s: string): WithdrawUriResult | undefined { */ export function parseAddExchangeUriWithError(s: string) { const pi = parseProtoInfoWithError(s, "add-exchange"); - if (pi.type === "fail") { + if (pi.tag === "error") { return pi; } - const parts = pi.body.rest.split("/"); + const parts = pi.value.rest.split("/"); if (parts.length < 2) { - return opKnownTalerFailure(TalerErrorCode.WALLET_TALER_URI_MALFORMED, { - code: TalerErrorCode.WALLET_TALER_URI_MALFORMED, - }); + return Result.error(TalerErrorCode.WALLET_TALER_URI_MALFORMED); } const host = parts[0].toLowerCase(); @@ -218,9 +214,9 @@ export function parseAddExchangeUriWithError(s: string) { const result: AddExchangeUri = { type: TalerUriAction.AddExchange, - exchangeBaseUrl: canonicalizeBaseUrl(`${pi.body.innerProto}://${p}/`), + exchangeBaseUrl: canonicalizeBaseUrl(`${pi.value.innerProto}://${p}/`), }; - return opFixedSuccess(result); + return Result.of(result); } /** @@ -229,8 +225,8 @@ export function parseAddExchangeUriWithError(s: string) { */ export function parseAddExchangeUri(s: string): AddExchangeUri | undefined { const r = parseAddExchangeUriWithError(s); - if (r.type === "fail") return undefined; - return r.body; + if (r.tag === "error") return undefined; + return r.value; } /** @@ -289,31 +285,35 @@ function parseProtoInfo( } } -function parseProtoInfoWithError(s: string, action: string) { +interface ProtoInfo { + innerProto: string; + rest: string; +} + +function parseProtoInfoWithError( + s: string, + action: string, +): Result<ProtoInfo, TalerErrorCode.WALLET_TALER_URI_MALFORMED> { if ( !s.toLowerCase().startsWith("taler://") && !s.toLowerCase().startsWith("taler+http://") ) { - return opKnownTalerFailure(TalerErrorCode.WALLET_TALER_URI_MALFORMED, { - code: TalerErrorCode.WALLET_TALER_URI_MALFORMED, - }); + return Result.error(TalerErrorCode.WALLET_TALER_URI_MALFORMED); } const pfxPlain = `taler://${action}/`; const pfxHttp = `taler+http://${action}/`; if (s.toLowerCase().startsWith(pfxPlain)) { - return opFixedSuccess({ + return Result.of({ innerProto: "https", rest: s.substring(pfxPlain.length), }); } else if (s.toLowerCase().startsWith(pfxHttp)) { - return opFixedSuccess({ + return Result.of({ innerProto: "http", rest: s.substring(pfxHttp.length), }); } else { - return opKnownTalerFailure(TalerErrorCode.WALLET_TALER_URI_MALFORMED, { - code: TalerErrorCode.WALLET_TALER_URI_MALFORMED, - }); + return Result.error(TalerErrorCode.WALLET_TALER_URI_MALFORMED); } }