128 lines
4.1 KiB
TypeScript
128 lines
4.1 KiB
TypeScript
import { bench, describe } from 'vitest';
|
|
import { STANDARD } from '../helpers/bench-options.js';
|
|
import {
|
|
ok,
|
|
err,
|
|
Result,
|
|
ntOk,
|
|
ntErr,
|
|
ntFromThrowable,
|
|
TsOk,
|
|
TsErr,
|
|
OxOk,
|
|
OxErr,
|
|
E,
|
|
pipe,
|
|
TmResult,
|
|
} from '../helpers/imports.js';
|
|
|
|
const validJson = '{"name":"Alice","age":30,"email":"alice@example.com"}';
|
|
const invalidJson = 'not json {{{';
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// JSON parsing — valid input
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe('Scenario: JSON parse + extract field — valid input', () => {
|
|
bench('native-monad', () => {
|
|
Result.from(() => JSON.parse(validJson), () => 'parse error')
|
|
.map(obj => obj.name as string)
|
|
.flatMap(name => (name.length > 0 ? ok(name) : err('empty name')));
|
|
}, STANDARD);
|
|
|
|
bench('neverthrow', () => {
|
|
ntFromThrowable(() => JSON.parse(validJson), () => 'parse error')()
|
|
.map(obj => obj.name as string)
|
|
.andThen(name => (name.length > 0 ? ntOk(name) : ntErr('empty name')));
|
|
}, STANDARD);
|
|
|
|
bench('ts-results-es', () => {
|
|
let r;
|
|
try { r = TsOk(JSON.parse(validJson)); }
|
|
catch { r = TsErr('parse error'); }
|
|
r.map((obj: any) => obj.name as string)
|
|
.andThen((name: string) => (name.length > 0 ? TsOk(name) : TsErr('empty name')));
|
|
}, STANDARD);
|
|
|
|
bench('oxide.ts', () => {
|
|
let r;
|
|
try { r = OxOk(JSON.parse(validJson)); }
|
|
catch { r = OxErr('parse error'); }
|
|
r.map((obj: any) => obj.name as string)
|
|
.andThen((name: string) => (name.length > 0 ? OxOk(name) : OxErr('parse error')));
|
|
}, STANDARD);
|
|
|
|
bench('fp-ts', () => {
|
|
pipe(
|
|
E.tryCatch(() => JSON.parse(validJson), () => 'parse error'),
|
|
E.map(obj => obj.name as string),
|
|
E.flatMap(name => (name.length > 0 ? E.right(name) : E.left('empty name'))),
|
|
);
|
|
}, STANDARD);
|
|
|
|
bench('true-myth', () => {
|
|
TmResult.tryOr('parse error', () => JSON.parse(validJson))
|
|
.map(obj => obj.name as string)
|
|
.andThen(name => (name.length > 0 ? TmResult.ok(name) : TmResult.err('empty name')));
|
|
}, STANDARD);
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// JSON parsing — invalid input
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe('Scenario: JSON parse + extract field — invalid input', () => {
|
|
bench('native-monad', () => {
|
|
Result.from(() => JSON.parse(invalidJson), () => 'parse error')
|
|
.map(obj => obj.name as string)
|
|
.flatMap(name => (name.length > 0 ? ok(name) : err('empty name')));
|
|
}, STANDARD);
|
|
|
|
bench('neverthrow', () => {
|
|
ntFromThrowable(() => JSON.parse(invalidJson), () => 'parse error')()
|
|
.map(obj => obj.name as string)
|
|
.andThen(name => (name.length > 0 ? ntOk(name) : ntErr('empty name')));
|
|
}, STANDARD);
|
|
|
|
bench('fp-ts', () => {
|
|
pipe(
|
|
E.tryCatch(() => JSON.parse(invalidJson), () => 'parse error'),
|
|
E.map(obj => obj.name as string),
|
|
E.flatMap(name => (name.length > 0 ? E.right(name) : E.left('empty name'))),
|
|
);
|
|
}, STANDARD);
|
|
|
|
bench('true-myth', () => {
|
|
TmResult.tryOr('parse error', () => JSON.parse(invalidJson))
|
|
.map(obj => obj.name as string)
|
|
.andThen(name => (name.length > 0 ? TmResult.ok(name) : TmResult.err('empty name')));
|
|
}, STANDARD);
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Number parsing — valid
|
|
// ---------------------------------------------------------------------------
|
|
|
|
describe('Scenario: number parsing — valid', () => {
|
|
const input = '42.5';
|
|
|
|
bench('native-monad', () => {
|
|
Result.from(() => {
|
|
const n = Number(input);
|
|
if (Number.isNaN(n)) throw new Error('NaN');
|
|
return n;
|
|
}).flatMap(n => (n > 0 ? ok(n) : err('not positive')));
|
|
}, STANDARD);
|
|
|
|
bench('fp-ts', () => {
|
|
pipe(
|
|
E.tryCatch(() => {
|
|
const n = Number(input);
|
|
if (Number.isNaN(n)) throw new Error('NaN');
|
|
return n;
|
|
}, () => 'parse error'),
|
|
E.flatMap(n => (n > 0 ? E.right(n) : E.left('not positive'))),
|
|
);
|
|
}, STANDARD);
|
|
});
|