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:
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);
}
}