nalloc 0.0.1

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 (58) hide show
  1. package/README.md +282 -0
  2. package/build/devtools.cjs +79 -0
  3. package/build/devtools.cjs.map +1 -0
  4. package/build/devtools.d.ts +82 -0
  5. package/build/devtools.js +43 -0
  6. package/build/devtools.js.map +1 -0
  7. package/build/index.cjs +76 -0
  8. package/build/index.cjs.map +1 -0
  9. package/build/index.d.ts +4 -0
  10. package/build/index.js +5 -0
  11. package/build/index.js.map +1 -0
  12. package/build/option.cjs +279 -0
  13. package/build/option.cjs.map +1 -0
  14. package/build/option.d.ts +356 -0
  15. package/build/option.js +157 -0
  16. package/build/option.js.map +1 -0
  17. package/build/result.cjs +381 -0
  18. package/build/result.cjs.map +1 -0
  19. package/build/result.d.ts +442 -0
  20. package/build/result.js +229 -0
  21. package/build/result.js.map +1 -0
  22. package/build/safe.cjs +88 -0
  23. package/build/safe.cjs.map +1 -0
  24. package/build/safe.d.ts +29 -0
  25. package/build/safe.js +18 -0
  26. package/build/safe.js.map +1 -0
  27. package/build/testing.cjs +111 -0
  28. package/build/testing.cjs.map +1 -0
  29. package/build/testing.d.ts +85 -0
  30. package/build/testing.js +81 -0
  31. package/build/testing.js.map +1 -0
  32. package/build/types.cjs +78 -0
  33. package/build/types.cjs.map +1 -0
  34. package/build/types.d.ts +137 -0
  35. package/build/types.js +36 -0
  36. package/build/types.js.map +1 -0
  37. package/build/unsafe.cjs +82 -0
  38. package/build/unsafe.cjs.map +1 -0
  39. package/build/unsafe.d.ts +27 -0
  40. package/build/unsafe.js +11 -0
  41. package/build/unsafe.js.map +1 -0
  42. package/package.json +93 -0
  43. package/src/__tests__/index.ts +13 -0
  44. package/src/__tests__/option.ts +610 -0
  45. package/src/__tests__/option.types.ts +120 -0
  46. package/src/__tests__/result.ts +721 -0
  47. package/src/__tests__/result.types.ts +249 -0
  48. package/src/__tests__/safe.ts +24 -0
  49. package/src/__tests__/tooling.ts +86 -0
  50. package/src/__tests__/unsafe.ts +24 -0
  51. package/src/devtools.ts +97 -0
  52. package/src/index.ts +18 -0
  53. package/src/option.ts +510 -0
  54. package/src/result.ts +676 -0
  55. package/src/safe.ts +58 -0
  56. package/src/testing.ts +159 -0
  57. package/src/types.ts +201 -0
  58. package/src/unsafe.ts +47 -0
package/src/safe.ts ADDED
@@ -0,0 +1,58 @@
1
+ import { some as someUnsafe, ok as okUnsafe, err, none, isErr } from './types.js';
2
+ import type {
3
+ Some,
4
+ None,
5
+ Ok,
6
+ Err,
7
+ Option as OptionType,
8
+ OptionValue,
9
+ IsOption,
10
+ InferSome,
11
+ Result as ResultType,
12
+ ResultValue,
13
+ ResultErrorType,
14
+ IsResult,
15
+ InferErr,
16
+ ValueType,
17
+ } from './types.js';
18
+
19
+ export type { Some, None, Ok, Err, OptionType, OptionValue, IsOption, InferSome, ResultType, ResultValue, ResultErrorType, IsResult, InferErr };
20
+
21
+ export { none, err };
22
+ export * as Option from './option.js';
23
+ export * as Result from './result.js';
24
+
25
+ /**
26
+ * Creates a Some value with runtime validation.
27
+ * Throws if the value is null or undefined.
28
+ * @param value - The value to wrap (must be non-nullable)
29
+ * @returns The value typed as Some
30
+ * @throws {TypeError} If value is null or undefined
31
+ * @example
32
+ * some(42) // Some(42)
33
+ * some(null) // throws TypeError
34
+ * some(undefined) // throws TypeError
35
+ */
36
+ export function some<T>(value: T): Some<ValueType<T>> {
37
+ if (value === null || value === undefined) {
38
+ throw new TypeError('some() requires a non-nullable value');
39
+ }
40
+ return someUnsafe(value as ValueType<T>);
41
+ }
42
+
43
+ /**
44
+ * Creates an Ok value with runtime validation.
45
+ * Throws if the value is an Err (prevents accidental double-wrapping).
46
+ * @param value - The success value
47
+ * @returns The value typed as Ok
48
+ * @throws {TypeError} If value is an Err
49
+ * @example
50
+ * ok(42) // Ok(42)
51
+ * ok(err('fail')) // throws TypeError
52
+ */
53
+ export function ok<T>(value: T): Ok<T> {
54
+ if (isErr(value)) {
55
+ throw new TypeError('ok() cannot wrap an Err value');
56
+ }
57
+ return okUnsafe(value);
58
+ }
package/src/testing.ts ADDED
@@ -0,0 +1,159 @@
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
+ }
package/src/types.ts ADDED
@@ -0,0 +1,201 @@
1
+ /** Values that represent None (absence of a value). */
2
+ export type NoneValueType = null | undefined | void;
3
+
4
+ /** Widens literal types to their base types for better type inference. */
5
+ export type Widen<T> = T extends string
6
+ ? string
7
+ : T extends number
8
+ ? number
9
+ : T extends boolean
10
+ ? boolean
11
+ : T extends bigint
12
+ ? bigint
13
+ : T extends symbol
14
+ ? symbol
15
+ : T;
16
+
17
+ /** Widens never to unknown, otherwise preserves the type. */
18
+ export type WidenNever<T> = [T] extends [never] ? unknown : T;
19
+
20
+ /** Excludes None values from a type, leaving only valid Some values. */
21
+ export type ValueType<T> = Exclude<T, NoneValueType>;
22
+
23
+ export declare const SOME_BRAND: unique symbol;
24
+
25
+ /** Represents a value that is present. The value itself is the Some - no wrapper object. */
26
+ export type Some<T> = ValueType<T> & { readonly [SOME_BRAND]: true };
27
+
28
+ /** Represents the absence of a value (null or undefined). */
29
+ export type None = NoneValueType & { readonly [SOME_BRAND]: false };
30
+
31
+ /** Constant representing None. Use this instead of null/undefined for clarity. */
32
+ export const NONE = undefined as None;
33
+
34
+ /** A value that may or may not be present. Some(T) is the value itself; None is null/undefined. */
35
+ export type Option<T> = Some<ValueType<T>> | None;
36
+
37
+ /** Extracts the value type from an Option type. */
38
+ export type OptionValue<TOption> = TOption extends Option<infer TValue> ? TValue : never;
39
+
40
+ /** Type predicate: true if T is an Option type. */
41
+ export type IsOption<T> = T extends Option<any> ? true : false;
42
+
43
+ /** Infers the Some type from a value, preserving the inner type. */
44
+ export type InferSome<T> = T extends Some<infer TValue> ? Some<ValueType<TValue>> : never;
45
+
46
+ /**
47
+ * Checks if an Option contains a value (is Some).
48
+ * @param opt - The Option to check
49
+ * @returns true if the Option is Some, false if None
50
+ * @example
51
+ * isSome(42) // true
52
+ * isSome(null) // false
53
+ * isSome(undefined) // false
54
+ */
55
+ export function isSome<T>(opt: Some<T>): true;
56
+ export function isSome(opt: None): false;
57
+ export function isSome<T>(opt: unknown): opt is Some<T>;
58
+ export function isSome(opt: unknown): boolean {
59
+ return opt !== null && opt !== undefined;
60
+ }
61
+
62
+ /**
63
+ * Checks if an Option is None (absent).
64
+ * @param opt - The Option to check
65
+ * @returns true if the Option is None, false if Some
66
+ * @example
67
+ * isNone(null) // true
68
+ * isNone(undefined) // true
69
+ * isNone(42) // false
70
+ */
71
+ export function isNone<T>(opt: Some<T>): false;
72
+ export function isNone(opt: None): true;
73
+ export function isNone(opt: unknown): opt is None;
74
+ export function isNone(opt: unknown): boolean {
75
+ return opt === null || opt === undefined;
76
+ }
77
+
78
+ /**
79
+ * Creates an Option from a nullable value. Returns None for null/undefined, Some otherwise.
80
+ * @param value - The value to wrap
81
+ * @returns Some(value) if value is non-null, None otherwise
82
+ * @example
83
+ * optionOf(42) // Some(42)
84
+ * optionOf(null) // None
85
+ * optionOf(undefined) // None
86
+ */
87
+ export function optionOf(value: null): None;
88
+ export function optionOf(value: undefined): None;
89
+ export function optionOf<T>(value: T): T extends NoneValueType ? None : Some<T>;
90
+ export function optionOf<T>(value: T): Option<T> {
91
+ return isNone(value as Option<T>) ? NONE : (value as Some<T>);
92
+ }
93
+
94
+ /**
95
+ * Creates a Some value. Does not validate - use safe.some() for validation.
96
+ * @param value - The value to wrap (must be non-null)
97
+ * @returns The value typed as Some
98
+ * @example
99
+ * some(42) // Some(42)
100
+ */
101
+ export function some<T>(value: ValueType<T>): Some<ValueType<T>> {
102
+ return value as Some<ValueType<T>>;
103
+ }
104
+
105
+ /** Constant representing None. Alias for NONE. */
106
+ export const none: None = NONE;
107
+
108
+ declare const OK_BRAND: unique symbol;
109
+
110
+ /** Represents a successful Result value. The value itself is the Ok - no wrapper object. */
111
+ export type Ok<T> = T & { readonly [OK_BRAND]: true };
112
+
113
+ const ERR_BRAND = Symbol.for('nalloc.ResultError');
114
+
115
+ interface ResultErrorShape<E> {
116
+ readonly error: E;
117
+ readonly [ERR_BRAND]: true;
118
+ }
119
+
120
+ function ResultErrorCtor<E>(this: ResultErrorShape<E>, error: E): void {
121
+ (this as { error: E }).error = error;
122
+ }
123
+ (ResultErrorCtor.prototype as { [ERR_BRAND]: true })[ERR_BRAND] = true;
124
+
125
+ /** The error wrapper type used internally. */
126
+ export type ResultError<E> = ResultErrorShape<E>;
127
+
128
+ function hasErrBrand(value: unknown): value is ResultError<unknown> {
129
+ return (value as Record<symbol, unknown>)?.[ERR_BRAND] === true;
130
+ }
131
+
132
+ /** Represents a failed Result containing an error. */
133
+ export type Err<E> = ResultError<E>;
134
+
135
+ /** A value that is either successful (Ok) or failed (Err). Ok is the value itself; Err wraps the error. */
136
+ export type Result<T, E> = Ok<T> | Err<E>;
137
+
138
+ /** Extracts the success value type from a Result type. */
139
+ export type ResultValue<TResult> = TResult extends Result<infer TValue, any> ? TValue : never;
140
+
141
+ /** Extracts the error type from a Result type. */
142
+ export type ResultErrorType<TResult> = TResult extends Result<any, infer TError> ? TError : never;
143
+
144
+ /** Type predicate: true if T is a Result type. */
145
+ export type IsResult<T> = T extends Result<any, any> ? true : false;
146
+
147
+ /** Infers the Err type from a value, preserving the error type. */
148
+ export type InferErr<T> = T extends Err<infer TError> ? Err<TError> : never;
149
+
150
+ /**
151
+ * Checks if a Result is Ok (successful).
152
+ * @param result - The Result to check
153
+ * @returns true if the Result is Ok, false if Err
154
+ * @example
155
+ * isOk(42) // true (Ok value)
156
+ * isOk(err('fail')) // false
157
+ */
158
+ export function isOk<T>(result: Ok<T>): true;
159
+ export function isOk<E>(result: Err<E>): false;
160
+ export function isOk<T, E>(result: Result<T, E>): result is Ok<T>;
161
+ export function isOk<T, E>(result: Result<T, E>): boolean {
162
+ return !hasErrBrand(result);
163
+ }
164
+
165
+ /**
166
+ * Checks if a Result is Err (failed).
167
+ * @param result - The Result to check
168
+ * @returns true if the Result is Err, false if Ok
169
+ * @example
170
+ * isErr(err('fail')) // true
171
+ * isErr(42) // false (Ok value)
172
+ */
173
+ export function isErr<E>(result: Err<E>): true;
174
+ export function isErr(result: Ok<any>): false;
175
+ export function isErr<T, E>(result: Result<T, E>): result is Err<E>;
176
+ export function isErr<T, E>(result: Result<T, E>): boolean {
177
+ return hasErrBrand(result);
178
+ }
179
+
180
+ /**
181
+ * Creates an Ok value. Does not validate - use safe.ok() for validation.
182
+ * @param value - The success value
183
+ * @returns The value typed as Ok
184
+ * @example
185
+ * ok(42) // Ok(42)
186
+ */
187
+ export function ok<T>(value: T): Ok<T> {
188
+ return value as Ok<T>;
189
+ }
190
+
191
+ /**
192
+ * Creates an Err value wrapping an error.
193
+ * @param error - The error value
194
+ * @returns An Err containing the error
195
+ * @example
196
+ * err('something went wrong') // Err('something went wrong')
197
+ * err(new Error('failed')) // Err(Error)
198
+ */
199
+ export function err<E>(error: E): Err<E> {
200
+ return new (ResultErrorCtor as unknown as new (error: E) => Err<E>)(error);
201
+ }
package/src/unsafe.ts ADDED
@@ -0,0 +1,47 @@
1
+ import type { Some, Ok } from './types.js';
2
+ export { none, err } from './types.js';
3
+ export type {
4
+ Some,
5
+ None,
6
+ Ok,
7
+ Err,
8
+ Option as OptionType,
9
+ OptionValue,
10
+ IsOption,
11
+ InferSome,
12
+ Result as ResultType,
13
+ ResultValue,
14
+ ResultErrorType,
15
+ IsResult,
16
+ InferErr,
17
+ } from './types.js';
18
+ export * as Option from './option.js';
19
+ export * as Result from './result.js';
20
+
21
+ /**
22
+ * Creates a Some value without runtime validation.
23
+ * Use when you are certain the value is non-nullable.
24
+ * For validated creation, use safe.some() instead.
25
+ * @param value - The value to wrap (assumed non-nullable)
26
+ * @returns The value typed as Some
27
+ * @example
28
+ * some(42) // Some(42)
29
+ * some(null) // Some(null) - no validation, may cause issues
30
+ */
31
+ export function some<T>(value: T): Some<T> {
32
+ return value as unknown as Some<T>;
33
+ }
34
+
35
+ /**
36
+ * Creates an Ok value without runtime validation.
37
+ * Use when you are certain the value is not an Err.
38
+ * For validated creation, use safe.ok() instead.
39
+ * @param value - The success value (assumed not an Err)
40
+ * @returns The value typed as Ok
41
+ * @example
42
+ * ok(42) // Ok(42)
43
+ * ok(err('fail')) // Ok(Err) - no validation, may cause issues
44
+ */
45
+ export function ok<T>(value: T): Ok<T> {
46
+ return value as Ok<T>;
47
+ }