initial commit

This commit is contained in:
2026-03-30 08:34:35 +02:00
commit 49d8ea67ba
103 changed files with 22387 additions and 0 deletions

View File

@@ -0,0 +1,127 @@
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);
});