nalloc 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +124 -38
  2. package/build/index.cjs +12 -68
  3. package/build/index.cjs.map +1 -1
  4. package/build/index.d.ts +1 -4
  5. package/build/index.js +1 -3
  6. package/build/index.js.map +1 -1
  7. package/build/iter.cjs +105 -0
  8. package/build/iter.cjs.map +1 -0
  9. package/build/iter.d.ts +61 -0
  10. package/build/iter.js +78 -0
  11. package/build/iter.js.map +1 -0
  12. package/build/option.cjs +19 -5
  13. package/build/option.cjs.map +1 -1
  14. package/build/option.d.ts +22 -1
  15. package/build/option.js +14 -6
  16. package/build/option.js.map +1 -1
  17. package/build/result.cjs +125 -54
  18. package/build/result.cjs.map +1 -1
  19. package/build/result.d.ts +83 -53
  20. package/build/result.js +100 -38
  21. package/build/result.js.map +1 -1
  22. package/build/safe.cjs +34 -15
  23. package/build/safe.cjs.map +1 -1
  24. package/build/safe.d.ts +4 -27
  25. package/build/safe.js +3 -14
  26. package/build/safe.js.map +1 -1
  27. package/build/types.cjs +38 -7
  28. package/build/types.cjs.map +1 -1
  29. package/build/types.d.ts +26 -4
  30. package/build/types.js +23 -7
  31. package/build/types.js.map +1 -1
  32. package/build/unsafe.cjs +14 -61
  33. package/build/unsafe.cjs.map +1 -1
  34. package/build/unsafe.d.ts +2 -27
  35. package/build/unsafe.js +2 -9
  36. package/build/unsafe.js.map +1 -1
  37. package/package.json +13 -16
  38. package/src/__tests__/index.ts +42 -0
  39. package/src/__tests__/iter.ts +218 -0
  40. package/src/__tests__/option.ts +48 -19
  41. package/src/__tests__/result.ts +286 -91
  42. package/src/__tests__/result.types.ts +3 -22
  43. package/src/__tests__/safe.ts +9 -15
  44. package/src/__tests__/unsafe.ts +11 -12
  45. package/src/index.ts +1 -18
  46. package/src/iter.ts +129 -0
  47. package/src/option.ts +36 -7
  48. package/src/result.ts +216 -113
  49. package/src/safe.ts +5 -42
  50. package/src/types.ts +52 -14
  51. package/src/unsafe.ts +2 -47
  52. package/build/devtools.cjs +0 -79
  53. package/build/devtools.cjs.map +0 -1
  54. package/build/devtools.d.ts +0 -82
  55. package/build/devtools.js +0 -43
  56. package/build/devtools.js.map +0 -1
  57. package/build/testing.cjs +0 -111
  58. package/build/testing.cjs.map +0 -1
  59. package/build/testing.d.ts +0 -85
  60. package/build/testing.js +0 -81
  61. package/build/testing.js.map +0 -1
  62. package/src/__tests__/tooling.ts +0 -86
  63. package/src/devtools.ts +0 -97
  64. package/src/testing.ts +0 -159
package/build/testing.js DELETED
@@ -1,81 +0,0 @@
1
- import { isOk, isErr, isSome, isNone } from "./types.js";
2
- import { formatOption, formatResult } from "./devtools.js";
3
- export function expectOk(result, message) {
4
- if (isOk(result)) {
5
- return result;
6
- }
7
- const fallback = message ?? `Expected Ok(...) but received ${formatResult(result)}`;
8
- throw new Error(fallback);
9
- }
10
- export function expectErr(result, message) {
11
- if (isErr(result)) {
12
- return result.error;
13
- }
14
- const fallback = message ?? `Expected Err(...) but received ${formatResult(result)}`;
15
- throw new Error(fallback);
16
- }
17
- export function expectSome(opt, message) {
18
- if (isSome(opt)) {
19
- return opt;
20
- }
21
- const fallback = message ?? `Expected Some(...) but received ${formatOption(opt)}`;
22
- throw new Error(fallback);
23
- }
24
- export function expectNone(opt, message) {
25
- if (isNone(opt)) {
26
- return;
27
- }
28
- const fallback = message ?? `Expected None but received ${formatOption(opt)}`;
29
- throw new Error(fallback);
30
- }
31
- const resultMatchers = {
32
- toBeOk (received) {
33
- const pass = isOk(received);
34
- return {
35
- pass,
36
- message: ()=>pass ? 'Result is Ok as expected.' : `Expected Ok(...) but received ${formatResult(received)}`
37
- };
38
- },
39
- toBeErr (received) {
40
- const pass = isErr(received);
41
- return {
42
- pass,
43
- message: ()=>pass ? 'Result is Err as expected.' : `Expected Err(...) but received ${formatResult(received)}`
44
- };
45
- },
46
- toContainErr (received, expected) {
47
- const pass = isErr(received) && received.error === expected;
48
- return {
49
- pass,
50
- message: ()=>{
51
- if (pass) return `Err matched expected value ${String(expected)}.`;
52
- return `Expected Err(${String(expected)}) but received ${formatResult(received)}`;
53
- }
54
- };
55
- }
56
- };
57
- const optionMatchers = {
58
- toBeSome (received) {
59
- const pass = isSome(received);
60
- return {
61
- pass,
62
- message: ()=>pass ? 'Option is Some as expected.' : `Expected Some(...) but received ${formatOption(received)}`
63
- };
64
- },
65
- toBeNone (received) {
66
- const pass = isNone(received);
67
- return {
68
- pass,
69
- message: ()=>pass ? 'Option is None as expected.' : `Expected None but received ${formatOption(received)}`
70
- };
71
- }
72
- };
73
- export const matchers = {
74
- ...resultMatchers,
75
- ...optionMatchers
76
- };
77
- export function extendExpect(expectLike) {
78
- expectLike.extend(matchers);
79
- }
80
-
81
- //# sourceMappingURL=testing.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/testing.ts"],"sourcesContent":["import { isOk, isErr, isSome, isNone, Result, Err, Option } from './types.js';\nimport { formatOption, formatResult } from './devtools.js';\n\n/** Result shape returned by custom matchers. */\ntype MatcherResult = { pass: boolean; message(): string };\n\n/**\n * Asserts that a Result is Ok and returns the value.\n * Throws if the Result is Err.\n * @param result - The Result to check\n * @param message - Optional custom error message\n * @returns The Ok value\n * @throws {Error} If the Result is Err\n * @example\n * expectOk(ok(42)) // returns 42\n * expectOk(err('fail')) // throws Error\n */\nexport function expectOk<T, E>(result: Result<T, E>, message?: string): T {\n if (isOk(result)) {\n return result;\n }\n\n const fallback = message ?? `Expected Ok(...) but received ${formatResult(result)}`;\n throw new Error(fallback);\n}\n\n/**\n * Asserts that a Result is Err and returns the error.\n * Throws if the Result is Ok.\n * @param result - The Result to check\n * @param message - Optional custom error message\n * @returns The error value\n * @throws {Error} If the Result is Ok\n * @example\n * expectErr(err('fail')) // returns 'fail'\n * expectErr(ok(42)) // throws Error\n */\nexport function expectErr<T, E>(result: Result<T, E>, message?: string): E {\n if (isErr(result)) {\n return (result as Err<E>).error;\n }\n\n const fallback = message ?? `Expected Err(...) but received ${formatResult(result)}`;\n throw new Error(fallback);\n}\n\n/**\n * Asserts that an Option is Some and returns the value.\n * Throws if the Option is None.\n * @param opt - The Option to check\n * @param message - Optional custom error message\n * @returns The Some value\n * @throws {Error} If the Option is None\n * @example\n * expectSome(42) // returns 42\n * expectSome(null) // throws Error\n */\nexport function expectSome<T>(opt: Option<T>, message?: string): T {\n if (isSome(opt)) {\n return opt;\n }\n const fallback = message ?? `Expected Some(...) but received ${formatOption(opt)}`;\n throw new Error(fallback);\n}\n\n/**\n * Asserts that an Option is None.\n * Throws if the Option is Some.\n * @param opt - The Option to check\n * @param message - Optional custom error message\n * @throws {Error} If the Option is Some\n * @example\n * expectNone(null) // succeeds\n * expectNone(42) // throws Error\n */\nexport function expectNone<T>(opt: Option<T>, message?: string): void {\n if (isNone(opt)) {\n return;\n }\n const fallback = message ?? `Expected None but received ${formatOption(opt)}`;\n throw new Error(fallback);\n}\n\nconst resultMatchers = {\n toBeOk(this: unknown, received: Result<unknown, unknown>): MatcherResult {\n const pass = isOk(received);\n return {\n pass,\n message: () => (pass ? 'Result is Ok as expected.' : `Expected Ok(...) but received ${formatResult(received)}`),\n };\n },\n toBeErr(this: unknown, received: Result<unknown, unknown>): MatcherResult {\n const pass = isErr(received);\n return {\n pass,\n message: () => (pass ? 'Result is Err as expected.' : `Expected Err(...) but received ${formatResult(received)}`),\n };\n },\n toContainErr(this: unknown, received: Result<unknown, unknown>, expected: unknown): MatcherResult {\n const pass = isErr(received) && (received as Err<unknown>).error === expected;\n return {\n pass,\n message: () => {\n if (pass) return `Err matched expected value ${String(expected)}.`;\n return `Expected Err(${String(expected)}) but received ${formatResult(received)}`;\n },\n };\n },\n};\n\nconst optionMatchers = {\n toBeSome(this: unknown, received: Option<unknown>): MatcherResult {\n const pass = isSome(received);\n return {\n pass,\n message: () => (pass ? 'Option is Some as expected.' : `Expected Some(...) but received ${formatOption(received)}`),\n };\n },\n toBeNone(this: unknown, received: Option<unknown>): MatcherResult {\n const pass = isNone(received);\n return {\n pass,\n message: () => (pass ? 'Option is None as expected.' : `Expected None but received ${formatOption(received)}`),\n };\n },\n};\n\n/**\n * Custom matchers for Jest/Vitest.\n * Includes toBeOk, toBeErr, toContainErr, toBeSome, toBeNone.\n * Use with expect.extend(matchers) or extendExpect(expect).\n */\nexport const matchers = {\n ...resultMatchers,\n ...optionMatchers,\n};\n\n/** Interface for test frameworks with an extend method (Jest, Vitest). */\nexport type ExpectLike = {\n extend(matchers: Record<string, (...args: any[]) => MatcherResult>): void;\n};\n\n/**\n * Extends a test framework's expect with Option and Result matchers.\n * @param expectLike - The expect object to extend (Jest/Vitest)\n * @example\n * import { expect } from 'vitest';\n * import { extendExpect } from 'nalloc/testing';\n * extendExpect(expect);\n *\n * // Now you can use:\n * expect(result).toBeOk();\n * expect(result).toBeErr();\n * expect(option).toBeSome();\n * expect(option).toBeNone();\n */\nexport function extendExpect(expectLike: ExpectLike): void {\n expectLike.extend(matchers);\n}\n"],"names":["isOk","isErr","isSome","isNone","formatOption","formatResult","expectOk","result","message","fallback","Error","expectErr","error","expectSome","opt","expectNone","resultMatchers","toBeOk","received","pass","toBeErr","toContainErr","expected","String","optionMatchers","toBeSome","toBeNone","matchers","extendExpect","expectLike","extend"],"mappings":"AAAA,SAASA,IAAI,EAAEC,KAAK,EAAEC,MAAM,EAAEC,MAAM,QAA6B,aAAa;AAC9E,SAASC,YAAY,EAAEC,YAAY,QAAQ,gBAAgB;AAgB3D,OAAO,SAASC,SAAeC,MAAoB,EAAEC,OAAgB;IACnE,IAAIR,KAAKO,SAAS;QAChB,OAAOA;IACT;IAEA,MAAME,WAAWD,WAAW,CAAC,8BAA8B,EAAEH,aAAaE,SAAS;IACnF,MAAM,IAAIG,MAAMD;AAClB;AAaA,OAAO,SAASE,UAAgBJ,MAAoB,EAAEC,OAAgB;IACpE,IAAIP,MAAMM,SAAS;QACjB,OAAO,AAACA,OAAkBK,KAAK;IACjC;IAEA,MAAMH,WAAWD,WAAW,CAAC,+BAA+B,EAAEH,aAAaE,SAAS;IACpF,MAAM,IAAIG,MAAMD;AAClB;AAaA,OAAO,SAASI,WAAcC,GAAc,EAAEN,OAAgB;IAC5D,IAAIN,OAAOY,MAAM;QACf,OAAOA;IACT;IACA,MAAML,WAAWD,WAAW,CAAC,gCAAgC,EAAEJ,aAAaU,MAAM;IAClF,MAAM,IAAIJ,MAAMD;AAClB;AAYA,OAAO,SAASM,WAAcD,GAAc,EAAEN,OAAgB;IAC5D,IAAIL,OAAOW,MAAM;QACf;IACF;IACA,MAAML,WAAWD,WAAW,CAAC,2BAA2B,EAAEJ,aAAaU,MAAM;IAC7E,MAAM,IAAIJ,MAAMD;AAClB;AAEA,MAAMO,iBAAiB;IACrBC,QAAsBC,QAAkC;QACtD,MAAMC,OAAOnB,KAAKkB;QAClB,OAAO;YACLC;YACAX,SAAS,IAAOW,OAAO,8BAA8B,CAAC,8BAA8B,EAAEd,aAAaa,WAAW;QAChH;IACF;IACAE,SAAuBF,QAAkC;QACvD,MAAMC,OAAOlB,MAAMiB;QACnB,OAAO;YACLC;YACAX,SAAS,IAAOW,OAAO,+BAA+B,CAAC,+BAA+B,EAAEd,aAAaa,WAAW;QAClH;IACF;IACAG,cAA4BH,QAAkC,EAAEI,QAAiB;QAC/E,MAAMH,OAAOlB,MAAMiB,aAAa,AAACA,SAA0BN,KAAK,KAAKU;QACrE,OAAO;YACLH;YACAX,SAAS;gBACP,IAAIW,MAAM,OAAO,CAAC,2BAA2B,EAAEI,OAAOD,UAAU,CAAC,CAAC;gBAClE,OAAO,CAAC,aAAa,EAAEC,OAAOD,UAAU,eAAe,EAAEjB,aAAaa,WAAW;YACnF;QACF;IACF;AACF;AAEA,MAAMM,iBAAiB;IACrBC,UAAwBP,QAAyB;QAC/C,MAAMC,OAAOjB,OAAOgB;QACpB,OAAO;YACLC;YACAX,SAAS,IAAOW,OAAO,gCAAgC,CAAC,gCAAgC,EAAEf,aAAac,WAAW;QACpH;IACF;IACAQ,UAAwBR,QAAyB;QAC/C,MAAMC,OAAOhB,OAAOe;QACpB,OAAO;YACLC;YACAX,SAAS,IAAOW,OAAO,gCAAgC,CAAC,2BAA2B,EAAEf,aAAac,WAAW;QAC/G;IACF;AACF;AAOA,OAAO,MAAMS,WAAW;IACtB,GAAGX,cAAc;IACjB,GAAGQ,cAAc;AACnB,EAAE;AAqBF,OAAO,SAASI,aAAaC,UAAsB;IACjDA,WAAWC,MAAM,CAACH;AACpB"}
@@ -1,86 +0,0 @@
1
- import { beforeAll, describe, expect, it } from 'vitest';
2
- import { ok, err, none, some } from '../types.js';
3
- import {
4
- expectOk,
5
- expectErr,
6
- expectSome,
7
- expectNone,
8
- extendExpect,
9
- } from '../testing.js';
10
- import {
11
- formatOption,
12
- formatResult,
13
- inspectOption,
14
- inspectResult,
15
- logOption,
16
- logResult,
17
- toJSONOption,
18
- toJSONResult,
19
- } from '../devtools.js';
20
-
21
- describe('testing utilities', () => {
22
- beforeAll(() => {
23
- extendExpect(expect as any);
24
- });
25
-
26
- it('expectOk returns Ok payload or throws', () => {
27
- const value = expectOk(ok(5));
28
- expect(value).toBe(5);
29
- expect(() => expectOk(err('nope'))).toThrow(/Err/);
30
- });
31
-
32
- it('expectErr returns error payload or throws', () => {
33
- const error = expectErr(err('boom'));
34
- expect(error).toBe('boom');
35
- expect(() => expectErr(ok(1))).toThrow(/Ok/);
36
- });
37
-
38
- it('expectSome / expectNone validate Option', () => {
39
- const value = expectSome(some(3));
40
- expect(value).toBe(3);
41
- expect(() => expectSome(none)).toThrow(/None/);
42
- expect(() => expectNone(some(2))).toThrow(/Some/);
43
- });
44
-
45
- it('adds matchers to expect', () => {
46
- expect(ok(1)).toBeOk();
47
- expect(err('oops')).toBeErr();
48
- expect(some(4)).toBeSome();
49
- expect(none).toBeNone();
50
- });
51
- });
52
-
53
- describe('devtools utilities', () => {
54
- it('formats option', () => {
55
- expect(formatOption(some('x'))).toBe('Some(x)');
56
- expect(formatOption(none)).toBe('None');
57
- });
58
-
59
- it('formats result', () => {
60
- expect(formatResult(ok(7))).toBe('Ok(7)');
61
- expect(formatResult(err('fail'))).toBe('Err(fail)');
62
- });
63
-
64
- it('inspects option/result', () => {
65
- expect(inspectOption(some('x'))).toEqual({ kind: 'some', value: 'x' });
66
- expect(inspectOption(none)).toEqual({ kind: 'none' });
67
- expect(inspectResult(ok('y'))).toEqual({ status: 'ok', value: 'y' });
68
- expect(inspectResult(err('fail'))).toEqual({ status: 'err', error: 'fail' });
69
- });
70
-
71
- it('logs option/result via logger', () => {
72
- const calls: unknown[][] = [];
73
- const logger = (...args: unknown[]) => calls.push(args);
74
- logOption(some(1), logger);
75
- logResult(err('fail'), logger);
76
- expect(calls[0]).toEqual(['Some(1)']);
77
- expect(calls[1]).toEqual(['Err', 'fail']);
78
- });
79
-
80
- it('serialises option/result to JSON friendly data', () => {
81
- expect(toJSONOption(some(2))).toEqual({ kind: 'some', value: 2 });
82
- expect(toJSONOption(none)).toEqual({ kind: 'none' });
83
- expect(toJSONResult(ok(3))).toEqual({ status: 'ok', value: 3 });
84
- expect(toJSONResult(err('fail'))).toEqual({ status: 'err', error: 'fail' });
85
- });
86
- });
package/src/devtools.ts DELETED
@@ -1,97 +0,0 @@
1
- import { Option, Result, isSome, isOk } from './types.js';
2
-
3
- /** Logger function signature for custom logging. */
4
- type Logger = (message: string, ...args: unknown[]) => void;
5
-
6
- /**
7
- * Formats an Option as a human-readable string.
8
- * @param opt - The Option to format
9
- * @returns "Some(value)" or "None"
10
- * @example
11
- * formatOption(42) // "Some(42)"
12
- * formatOption(null) // "None"
13
- * formatOption(undefined) // "None"
14
- */
15
- export function formatOption<T>(opt: Option<T>): string {
16
- return isSome(opt) ? `Some(${String(opt)})` : 'None';
17
- }
18
-
19
- /**
20
- * Formats a Result as a human-readable string.
21
- * For Err containing an Error, displays the error message.
22
- * @param result - The Result to format
23
- * @returns "Ok(value)" or "Err(error)"
24
- * @example
25
- * formatResult(42) // "Ok(42)"
26
- * formatResult(err('fail')) // "Err(fail)"
27
- * formatResult(err(new Error('oops'))) // "Err(oops)"
28
- */
29
- export function formatResult<T, E>(result: Result<T, E>): string {
30
- if (isOk(result)) {
31
- return `Ok(${String(result)})`;
32
- }
33
- const error = (result as { error: E }).error;
34
- return `Err(${error instanceof Error ? error.message : String(error)})`;
35
- }
36
-
37
- /**
38
- * Inspects an Option, returning a tagged object for debugging or serialization.
39
- * @param opt - The Option to inspect
40
- * @returns `{ kind: 'some', value: T }` or `{ kind: 'none' }`
41
- * @example
42
- * inspectOption(42) // { kind: 'some', value: 42 }
43
- * inspectOption(null) // { kind: 'none' }
44
- */
45
- export function inspectOption<T>(opt: Option<T>) {
46
- return isSome(opt) ? { kind: 'some' as const, value: opt } : { kind: 'none' as const };
47
- }
48
-
49
- /**
50
- * Inspects a Result, returning a tagged object for debugging or serialization.
51
- * @param result - The Result to inspect
52
- * @returns `{ status: 'ok', value: T }` or `{ status: 'err', error: E }`
53
- * @example
54
- * inspectResult(42) // { status: 'ok', value: 42 }
55
- * inspectResult(err('fail')) // { status: 'err', error: 'fail' }
56
- */
57
- export function inspectResult<T, E>(result: Result<T, E>) {
58
- return isOk(result) ? { status: 'ok' as const, value: result } : { status: 'err' as const, error: (result as { error: E }).error };
59
- }
60
-
61
- /**
62
- * Logs an Option using the provided logger (defaults to console.log).
63
- * @param opt - The Option to log
64
- * @param logger - The logging function to use
65
- * @example
66
- * logOption(42) // logs "Some(42)"
67
- * logOption(null) // logs "None"
68
- * logOption(42, console.warn) // logs "Some(42)" as warning
69
- */
70
- export function logOption<T>(opt: Option<T>, logger: Logger = console.log): void {
71
- logger(formatOption(opt));
72
- }
73
-
74
- /**
75
- * Logs a Result using the provided logger (defaults to console.log).
76
- * Logs "Ok" with the value or "Err" with the error.
77
- * @param result - The Result to log
78
- * @param logger - The logging function to use
79
- * @example
80
- * logResult(42) // logs "Ok", 42
81
- * logResult(err('fail')) // logs "Err", "fail"
82
- * logResult(42, console.warn) // logs "Ok", 42 as warning
83
- */
84
- export function logResult<T, E>(result: Result<T, E>, logger: Logger = console.log): void {
85
- const tagged = inspectResult(result);
86
- if (tagged.status === 'ok') {
87
- logger(`Ok`, tagged.value);
88
- return;
89
- }
90
- logger(`Err`, tagged.error);
91
- }
92
-
93
- /** Alias for inspectOption. Returns a JSON-serializable representation. */
94
- export const toJSONOption = inspectOption;
95
-
96
- /** Alias for inspectResult. Returns a JSON-serializable representation. */
97
- export const toJSONResult = inspectResult;
package/src/testing.ts DELETED
@@ -1,159 +0,0 @@
1
- import { isOk, isErr, isSome, isNone, Result, Err, Option } from './types.js';
2
- import { formatOption, formatResult } from './devtools.js';
3
-
4
- /** Result shape returned by custom matchers. */
5
- type MatcherResult = { pass: boolean; message(): string };
6
-
7
- /**
8
- * Asserts that a Result is Ok and returns the value.
9
- * Throws if the Result is Err.
10
- * @param result - The Result to check
11
- * @param message - Optional custom error message
12
- * @returns The Ok value
13
- * @throws {Error} If the Result is Err
14
- * @example
15
- * expectOk(ok(42)) // returns 42
16
- * expectOk(err('fail')) // throws Error
17
- */
18
- export function expectOk<T, E>(result: Result<T, E>, message?: string): T {
19
- if (isOk(result)) {
20
- return result;
21
- }
22
-
23
- const fallback = message ?? `Expected Ok(...) but received ${formatResult(result)}`;
24
- throw new Error(fallback);
25
- }
26
-
27
- /**
28
- * Asserts that a Result is Err and returns the error.
29
- * Throws if the Result is Ok.
30
- * @param result - The Result to check
31
- * @param message - Optional custom error message
32
- * @returns The error value
33
- * @throws {Error} If the Result is Ok
34
- * @example
35
- * expectErr(err('fail')) // returns 'fail'
36
- * expectErr(ok(42)) // throws Error
37
- */
38
- export function expectErr<T, E>(result: Result<T, E>, message?: string): E {
39
- if (isErr(result)) {
40
- return (result as Err<E>).error;
41
- }
42
-
43
- const fallback = message ?? `Expected Err(...) but received ${formatResult(result)}`;
44
- throw new Error(fallback);
45
- }
46
-
47
- /**
48
- * Asserts that an Option is Some and returns the value.
49
- * Throws if the Option is None.
50
- * @param opt - The Option to check
51
- * @param message - Optional custom error message
52
- * @returns The Some value
53
- * @throws {Error} If the Option is None
54
- * @example
55
- * expectSome(42) // returns 42
56
- * expectSome(null) // throws Error
57
- */
58
- export function expectSome<T>(opt: Option<T>, message?: string): T {
59
- if (isSome(opt)) {
60
- return opt;
61
- }
62
- const fallback = message ?? `Expected Some(...) but received ${formatOption(opt)}`;
63
- throw new Error(fallback);
64
- }
65
-
66
- /**
67
- * Asserts that an Option is None.
68
- * Throws if the Option is Some.
69
- * @param opt - The Option to check
70
- * @param message - Optional custom error message
71
- * @throws {Error} If the Option is Some
72
- * @example
73
- * expectNone(null) // succeeds
74
- * expectNone(42) // throws Error
75
- */
76
- export function expectNone<T>(opt: Option<T>, message?: string): void {
77
- if (isNone(opt)) {
78
- return;
79
- }
80
- const fallback = message ?? `Expected None but received ${formatOption(opt)}`;
81
- throw new Error(fallback);
82
- }
83
-
84
- const resultMatchers = {
85
- toBeOk(this: unknown, received: Result<unknown, unknown>): MatcherResult {
86
- const pass = isOk(received);
87
- return {
88
- pass,
89
- message: () => (pass ? 'Result is Ok as expected.' : `Expected Ok(...) but received ${formatResult(received)}`),
90
- };
91
- },
92
- toBeErr(this: unknown, received: Result<unknown, unknown>): MatcherResult {
93
- const pass = isErr(received);
94
- return {
95
- pass,
96
- message: () => (pass ? 'Result is Err as expected.' : `Expected Err(...) but received ${formatResult(received)}`),
97
- };
98
- },
99
- toContainErr(this: unknown, received: Result<unknown, unknown>, expected: unknown): MatcherResult {
100
- const pass = isErr(received) && (received as Err<unknown>).error === expected;
101
- return {
102
- pass,
103
- message: () => {
104
- if (pass) return `Err matched expected value ${String(expected)}.`;
105
- return `Expected Err(${String(expected)}) but received ${formatResult(received)}`;
106
- },
107
- };
108
- },
109
- };
110
-
111
- const optionMatchers = {
112
- toBeSome(this: unknown, received: Option<unknown>): MatcherResult {
113
- const pass = isSome(received);
114
- return {
115
- pass,
116
- message: () => (pass ? 'Option is Some as expected.' : `Expected Some(...) but received ${formatOption(received)}`),
117
- };
118
- },
119
- toBeNone(this: unknown, received: Option<unknown>): MatcherResult {
120
- const pass = isNone(received);
121
- return {
122
- pass,
123
- message: () => (pass ? 'Option is None as expected.' : `Expected None but received ${formatOption(received)}`),
124
- };
125
- },
126
- };
127
-
128
- /**
129
- * Custom matchers for Jest/Vitest.
130
- * Includes toBeOk, toBeErr, toContainErr, toBeSome, toBeNone.
131
- * Use with expect.extend(matchers) or extendExpect(expect).
132
- */
133
- export const matchers = {
134
- ...resultMatchers,
135
- ...optionMatchers,
136
- };
137
-
138
- /** Interface for test frameworks with an extend method (Jest, Vitest). */
139
- export type ExpectLike = {
140
- extend(matchers: Record<string, (...args: any[]) => MatcherResult>): void;
141
- };
142
-
143
- /**
144
- * Extends a test framework's expect with Option and Result matchers.
145
- * @param expectLike - The expect object to extend (Jest/Vitest)
146
- * @example
147
- * import { expect } from 'vitest';
148
- * import { extendExpect } from 'nalloc/testing';
149
- * extendExpect(expect);
150
- *
151
- * // Now you can use:
152
- * expect(result).toBeOk();
153
- * expect(result).toBeErr();
154
- * expect(option).toBeSome();
155
- * expect(option).toBeNone();
156
- */
157
- export function extendExpect(expectLike: ExpectLike): void {
158
- expectLike.extend(matchers);
159
- }