@onrails/maybe 0.1.1 → 0.1.3
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.
- package/README.md +14 -0
- package/dist/fluent.cjs +27 -3
- package/dist/fluent.cjs.map +1 -1
- package/dist/fluent.d.cts +2 -0
- package/dist/fluent.d.ts +2 -0
- package/dist/fluent.js +27 -3
- package/dist/fluent.js.map +1 -1
- package/dist/index.cjs +22 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +44 -9
- package/dist/index.d.ts +44 -9
- package/dist/index.js +21 -3
- package/dist/index.js.map +1 -1
- package/dist/interop.cjs.map +1 -1
- package/dist/interop.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,6 +22,20 @@ const name = match(
|
|
|
22
22
|
);
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
## Side effects
|
|
26
|
+
|
|
27
|
+
`tap` runs an effect on the `Some` value, `tapNone` on absence — both pass the
|
|
28
|
+
`Maybe` through unchanged. Mirrors `tap`/`tapErr` from `@onrails/result`. Dual-form.
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { fromNullable, tap, tapNone } from "@onrails/maybe";
|
|
32
|
+
|
|
33
|
+
const row = fromNullable(db.get(id));
|
|
34
|
+
|
|
35
|
+
tap(row, (r) => log.debug("hit", r.id)); // runs on Some, returns row
|
|
36
|
+
tapNone(row, () => metrics.miss()); // runs on None, returns row
|
|
37
|
+
```
|
|
38
|
+
|
|
25
39
|
## Result boundary
|
|
26
40
|
|
|
27
41
|
```ts
|
package/dist/fluent.cjs
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
var some = (value) => ({ _tag: "Some", value });
|
|
5
5
|
var none = () => ({ _tag: "None" });
|
|
6
6
|
var isSome = (maybe) => maybe._tag === "Some";
|
|
7
|
+
var isNone = (maybe) => maybe._tag === "None";
|
|
7
8
|
var mapImpl = (maybe, fn) => isSome(maybe) ? some(fn(maybe.value)) : none();
|
|
8
9
|
function map(...args) {
|
|
9
10
|
if (args.length === 2) return mapImpl(args[0], args[1]);
|
|
@@ -23,8 +24,25 @@ function match(...args) {
|
|
|
23
24
|
const [onSome, onNone] = args;
|
|
24
25
|
return (maybe) => matchImpl(maybe, onSome, onNone);
|
|
25
26
|
}
|
|
26
|
-
var
|
|
27
|
-
var
|
|
27
|
+
var unwrapOr = (maybe, defaultValue) => isSome(maybe) ? maybe.value : defaultValue;
|
|
28
|
+
var tapImpl = (maybe, fn) => {
|
|
29
|
+
if (isSome(maybe)) fn(maybe.value);
|
|
30
|
+
return maybe;
|
|
31
|
+
};
|
|
32
|
+
function tap(...args) {
|
|
33
|
+
if (args.length === 2) return tapImpl(args[0], args[1]);
|
|
34
|
+
const fn = args[0];
|
|
35
|
+
return (maybe) => tapImpl(maybe, fn);
|
|
36
|
+
}
|
|
37
|
+
var tapNoneImpl = (maybe, fn) => {
|
|
38
|
+
if (isNone(maybe)) fn();
|
|
39
|
+
return maybe;
|
|
40
|
+
};
|
|
41
|
+
function tapNone(...args) {
|
|
42
|
+
if (args.length === 2) return tapNoneImpl(args[0], args[1]);
|
|
43
|
+
const fn = args[0];
|
|
44
|
+
return (maybe) => tapNoneImpl(maybe, fn);
|
|
45
|
+
}
|
|
28
46
|
|
|
29
47
|
// src/fluent.ts
|
|
30
48
|
var fluent = (maybe) => Object.assign(maybe, {
|
|
@@ -34,6 +52,12 @@ var fluent = (maybe) => Object.assign(maybe, {
|
|
|
34
52
|
flatMap(fn) {
|
|
35
53
|
return fluent(flatMap(maybe, fn));
|
|
36
54
|
},
|
|
55
|
+
tap(fn) {
|
|
56
|
+
return fluent(tap(maybe, fn));
|
|
57
|
+
},
|
|
58
|
+
tapNone(fn) {
|
|
59
|
+
return fluent(tapNone(maybe, fn));
|
|
60
|
+
},
|
|
37
61
|
andThen(fn) {
|
|
38
62
|
return fluent(andThen(maybe, fn));
|
|
39
63
|
},
|
|
@@ -41,7 +65,7 @@ var fluent = (maybe) => Object.assign(maybe, {
|
|
|
41
65
|
return match(maybe, onSome, onNone);
|
|
42
66
|
},
|
|
43
67
|
getOrElse(defaultValue) {
|
|
44
|
-
return
|
|
68
|
+
return unwrapOr(maybe, defaultValue);
|
|
45
69
|
},
|
|
46
70
|
unwrapOr(defaultValue) {
|
|
47
71
|
return unwrapOr(maybe, defaultValue);
|
package/dist/fluent.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/maybe.ts","../src/fluent.ts"],"names":[],"mappings":"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","file":"fluent.cjs","sourcesContent":["import type { Maybe, None, Some } from \"./types.js\";\n\nexport type { Maybe, None, Some } from \"./types.js\";\n\n/**\n * Lifts a value into the `Some` branch.\n *\n * @example\n * ```ts\n * const m = some(1); // Maybe<number>\n * ```\n */\nexport const some = <T>(value: T): Maybe<T> => ({ _tag: \"Some\", value });\n\n/** Fantasy Land `of` — alias of {@link some}. */\nexport const of = some;\n\n/**\n * The `None` value — represents expected absence. Not a failure.\n *\n * @example\n * ```ts\n * const cached: Maybe<User> = cache.has(id) ? some(cache.get(id)) : none();\n * ```\n */\nexport const none = <T = never>(): Maybe<T> => ({ _tag: \"None\" });\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `Some`.\n *\n * @example\n * ```ts\n * if (isSome(m)) {\n * console.log(m.value); // narrowed to Some branch\n * }\n * ```\n */\nexport const isSome = <T>(maybe: Maybe<T>): maybe is Some<T> => maybe._tag === \"Some\";\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `None`.\n */\nexport const isNone = <T>(maybe: Maybe<T>): maybe is None => maybe._tag === \"None\";\n\n/**\n * Lift a nullable value into `Maybe<T>` — `null` and `undefined` become\n * `None`; anything else becomes `Some`.\n *\n * @example\n * ```ts\n * fromNullable(map.get(key)); // Maybe<V>\n * fromNullable(null); // None\n * ```\n */\nexport const fromNullable = <T>(value: T | null | undefined): Maybe<T> =>\n value == null ? none<T>() : some(value);\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Dual-form helpers — each accepts either shape:\n// data-first: `map(maybe, fn)`\n// curried: `map(fn)(maybe)`\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst mapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U> =>\n isSome(maybe) ? some(fn(maybe.value)) : none<U>();\n\n/**\n * Transform the `Some` value, passing `None` through unchanged. Dual-form.\n *\n * @example\n * ```ts\n * map(some(2), (n) => n * 3); // Some 6 — data-first\n * pipe(fromNullable(input), map((s) => s.trim())); // curried\n * ```\n */\nexport function map<T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U>;\nexport function map<T, U>(fn: (value: T) => U): (maybe: Maybe<T>) => Maybe<U>;\nexport function map(\n ...args: [Maybe<unknown>, (value: unknown) => unknown] | [(value: unknown) => unknown]\n): unknown {\n if (args.length === 2) return mapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => mapImpl(maybe, fn);\n}\n\nconst flatMapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U> =>\n isSome(maybe) ? fn(maybe.value) : none<U>();\n\n/**\n * Canonical bind for `Maybe`. Chains a `Maybe`-returning step;\n * short-circuits on `None`. Dual-form.\n *\n * @example\n * ```ts\n * flatMap(fromNullable(user), (u) =>\n * u.active ? some(u) : none(),\n * );\n * ```\n */\nexport function flatMap<T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U>;\nexport function flatMap<T, U>(fn: (value: T) => Maybe<U>): (maybe: Maybe<T>) => Maybe<U>;\nexport function flatMap(\n ...args:\n | [Maybe<unknown>, (value: unknown) => Maybe<unknown>]\n | [(value: unknown) => Maybe<unknown>]\n): unknown {\n if (args.length === 2) return flatMapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => flatMapImpl(maybe, fn);\n}\n\n/** Alias for {@link flatMap} — same dual-form shape. */\nexport const andThen = flatMap;\n\nconst matchImpl = <T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U =>\n isSome(maybe) ? onSome(maybe.value) : onNone();\n\n/**\n * Terminal collapse — fold both branches into a single value. Positional,\n * dual-form. Same shape as `Result.match` for sibling consistency.\n *\n * For files that also import `match` from `ts-pattern`, the alias\n * {@link matchMaybe} is identical.\n *\n * @example\n * ```ts\n * const greeting = match(\n * fromNullable(user),\n * (u) => `hello ${u.name}`,\n * () => \"hello guest\",\n * );\n * ```\n */\nexport function match<T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U;\nexport function match<T, U>(onSome: (value: T) => U, onNone: () => U): (maybe: Maybe<T>) => U;\nexport function match(\n ...args:\n | [Maybe<unknown>, (value: unknown) => unknown, () => unknown]\n | [(value: unknown) => unknown, () => unknown]\n): unknown {\n if (args.length === 3) return matchImpl(args[0], args[1], args[2]);\n const [onSome, onNone] = args;\n return (maybe: Maybe<unknown>) => matchImpl(maybe, onSome, onNone);\n}\n\n/** Collision-free alias — mirrors `matchResult` on `@onrails/result`. */\nexport const matchMaybe = match;\n\n/**\n * Returns the `Some` value, or `defaultValue` when the value is `None`.\n *\n * @example\n * ```ts\n * getOrElse(fromNullable(user), { name: \"guest\" });\n * ```\n */\nexport const getOrElse = <T>(maybe: Maybe<T>, defaultValue: T): T =>\n isSome(maybe) ? maybe.value : defaultValue;\n\n/** Alias — mirrors `@onrails/result` `unwrapOr`. Same as {@link getOrElse}. */\nexport const unwrapOr = getOrElse;\n\n/**\n * Unwraps the `Some` value or throws if the value is `None`. Use in tests\n * or at the boundary of an assertion; prefer `match` / `getOrElse` in\n * production code paths.\n *\n * @example\n * ```ts\n * expect(unwrap(parseUser(raw))).toEqual(expected);\n * ```\n */\nexport const unwrap = <T>(maybe: Maybe<T>): T => {\n if (isNone(maybe)) {\n throw new Error(\"Called unwrap on None\");\n }\n return maybe.value;\n};\n\n/**\n * Drop every `None` and collect the remaining `Some` values into an array.\n *\n * @example\n * ```ts\n * compact([some(1), none(), some(2)]); // [1, 2]\n * ```\n */\nexport const compact = <T>(maybes: readonly Maybe<T>[]): T[] => {\n const out: T[] = [];\n for (const m of maybes) {\n if (isSome(m)) {\n out.push(m.value);\n }\n }\n return out;\n};\n\n/**\n * `compact(items.map(fn))` — map each item to `Maybe`, drop `None`,\n * collect the rest.\n *\n * @example\n * ```ts\n * compactMap(rawRows, (row) =>\n * row.deletedAt ? none() : some(row.id),\n * );\n * // string[]\n * ```\n */\nexport const compactMap = <T, U>(items: readonly T[], fn: (item: T) => Maybe<U>): U[] =>\n compact(items.map(fn));\n\n/**\n * `flatMap(fromNullable(value), fn)` — lift a nullable then bind through\n * a `Maybe`-returning step. Convenient for chaining lookups.\n *\n * @example\n * ```ts\n * optional(rawId, (id) => fromNullable(cache.get(id)));\n * ```\n */\nexport const optional = <T, U>(value: T | null | undefined, fn: (value: T) => Maybe<U>): Maybe<U> =>\n flatMapImpl(fromNullable(value), fn);\n","import { andThen, flatMap, getOrElse, type Maybe, map, match, unwrapOr } from \"./maybe.js\";\n\nexport type FluentMaybe<T> = Maybe<T> & {\n map<U>(fn: (value: T) => U): FluentMaybe<U>;\n flatMap<U>(fn: (value: T) => Maybe<U>): FluentMaybe<U>;\n andThen<U>(fn: (value: T) => Maybe<U>): FluentMaybe<U>;\n match<U>(onSome: (value: T) => U, onNone: () => U): U;\n getOrElse(defaultValue: T): T;\n unwrapOr(defaultValue: T): T;\n};\n\nexport const fluent = <T>(maybe: Maybe<T>): FluentMaybe<T> =>\n Object.assign(maybe, {\n map<U>(fn: (value: T) => U) {\n return fluent(map(maybe, fn));\n },\n flatMap<U>(fn: (value: T) => Maybe<U>) {\n return fluent(flatMap(maybe, fn));\n },\n andThen<U>(fn: (value: T) => Maybe<U>) {\n return fluent(andThen(maybe, fn));\n },\n match<U>(onSome: (value: T) => U, onNone: () => U) {\n return match(maybe, onSome, onNone);\n },\n getOrElse(defaultValue: T) {\n return getOrElse(maybe, defaultValue);\n },\n unwrapOr(defaultValue: T) {\n return unwrapOr(maybe, defaultValue);\n },\n });\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/maybe.ts","../src/fluent.ts"],"names":[],"mappings":";;;AAYO,IAAM,OAAO,CAAI,KAAA,MAAwB,EAAE,IAAA,EAAM,QAAQ,KAAA,EAAM,CAAA;AAgB/D,IAAM,IAAA,GAAO,OAA4B,EAAE,IAAA,EAAM,MAAA,EAAO,CAAA;AAYxD,IAAM,MAAA,GAAS,CAAI,KAAA,KAAsC,KAAA,CAAM,IAAA,KAAS,MAAA;AAKxE,IAAM,MAAA,GAAS,CAAI,KAAA,KAAmC,KAAA,CAAM,IAAA,KAAS,MAAA;AAqB5E,IAAM,OAAA,GAAU,CAAO,KAAA,EAAiB,EAAA,KACtC,MAAA,CAAO,KAAK,CAAA,GAAI,IAAA,CAAK,EAAA,CAAG,KAAA,CAAM,KAAK,CAAC,IAAI,IAAA,EAAQ;AAa3C,SAAS,OACX,IAAA,EACM;AACT,EAAA,IAAI,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG,OAAO,OAAA,CAAQ,KAAK,CAAC,CAAA,EAAG,IAAA,CAAK,CAAC,CAAC,CAAA;AACtD,EAAA,MAAM,EAAA,GAAK,KAAK,CAAC,CAAA;AACjB,EAAA,OAAO,CAAC,KAAA,KAA0B,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AACrD;AAEA,IAAM,WAAA,GAAc,CAAO,KAAA,EAAiB,EAAA,KAC1C,MAAA,CAAO,KAAK,CAAA,GAAI,EAAA,CAAG,KAAA,CAAM,KAAK,CAAA,GAAI,IAAA,EAAQ;AAerC,SAAS,WACX,IAAA,EAGM;AACT,EAAA,IAAI,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG,OAAO,WAAA,CAAY,KAAK,CAAC,CAAA,EAAG,IAAA,CAAK,CAAC,CAAC,CAAA;AAC1D,EAAA,MAAM,EAAA,GAAK,KAAK,CAAC,CAAA;AACjB,EAAA,OAAO,CAAC,KAAA,KAA0B,WAAA,CAAY,KAAA,EAAO,EAAE,CAAA;AACzD;AAGO,IAAM,OAAA,GAAU,OAAA;AAEvB,IAAM,SAAA,GAAY,CAAO,KAAA,EAAiB,MAAA,EAAyB,MAAA,KACjE,MAAA,CAAO,KAAK,CAAA,GAAI,MAAA,CAAO,KAAA,CAAM,KAAK,CAAA,GAAI,MAAA,EAAO;AAoBxC,SAAS,SACX,IAAA,EAGM;AACT,EAAA,IAAI,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG,OAAO,SAAA,CAAU,IAAA,CAAK,CAAC,CAAA,EAAG,IAAA,CAAK,CAAC,CAAA,EAAG,IAAA,CAAK,CAAC,CAAC,CAAA;AACjE,EAAA,MAAM,CAAC,MAAA,EAAQ,MAAM,CAAA,GAAI,IAAA;AACzB,EAAA,OAAO,CAAC,KAAA,KAA0B,SAAA,CAAU,KAAA,EAAO,QAAQ,MAAM,CAAA;AACnE;AAgBO,IAAM,QAAA,GAAW,CAAI,KAAA,EAAiB,YAAA,KAC3C,OAAO,KAAK,CAAA,GAAI,MAAM,KAAA,GAAQ,YAAA;AAwEhC,IAAM,OAAA,GAAU,CAAI,KAAA,EAAiB,EAAA,KAAqC;AACxE,EAAA,IAAI,MAAA,CAAO,KAAK,CAAA,EAAG,EAAA,CAAG,MAAM,KAAK,CAAA;AACjC,EAAA,OAAO,KAAA;AACT,CAAA;AAcO,SAAS,OACX,IAAA,EACM;AACT,EAAA,IAAI,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG,OAAO,OAAA,CAAQ,KAAK,CAAC,CAAA,EAAG,IAAA,CAAK,CAAC,CAAC,CAAA;AACtD,EAAA,MAAM,EAAA,GAAK,KAAK,CAAC,CAAA;AACjB,EAAA,OAAO,CAAC,KAAA,KAA0B,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AACrD;AAEA,IAAM,WAAA,GAAc,CAAI,KAAA,EAAiB,EAAA,KAA6B;AACpE,EAAA,IAAI,MAAA,CAAO,KAAK,CAAA,EAAG,EAAA,EAAG;AACtB,EAAA,OAAO,KAAA;AACT,CAAA;AAcO,SAAS,WAAW,IAAA,EAA4D;AACrF,EAAA,IAAI,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG,OAAO,WAAA,CAAY,KAAK,CAAC,CAAA,EAAG,IAAA,CAAK,CAAC,CAAC,CAAA;AAC1D,EAAA,MAAM,EAAA,GAAK,KAAK,CAAC,CAAA;AACjB,EAAA,OAAO,CAAC,KAAA,KAA0B,WAAA,CAAY,KAAA,EAAO,EAAE,CAAA;AACzD;;;AC5QO,IAAM,MAAA,GAAS,CAAI,KAAA,KACxB,MAAA,CAAO,OAAO,KAAA,EAAO;AAAA,EACnB,IAAO,EAAA,EAAqB;AAC1B,IAAA,OAAO,MAAA,CAAO,GAAA,CAAI,KAAA,EAAO,EAAE,CAAC,CAAA;AAAA,EAC9B,CAAA;AAAA,EACA,QAAW,EAAA,EAA4B;AACrC,IAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,CAAA;AAAA,EAClC,CAAA;AAAA,EACA,IAAI,EAAA,EAAwB;AAC1B,IAAA,OAAO,MAAA,CAAO,GAAA,CAAI,KAAA,EAAO,EAAE,CAAC,CAAA;AAAA,EAC9B,CAAA;AAAA,EACA,QAAQ,EAAA,EAAgB;AACtB,IAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,CAAA;AAAA,EAClC,CAAA;AAAA,EACA,QAAW,EAAA,EAA4B;AACrC,IAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,CAAA;AAAA,EAClC,CAAA;AAAA,EACA,KAAA,CAAS,QAAyB,MAAA,EAAiB;AACjD,IAAA,OAAO,KAAA,CAAM,KAAA,EAAO,MAAA,EAAQ,MAAM,CAAA;AAAA,EACpC,CAAA;AAAA,EACA,UAAU,YAAA,EAAiB;AACzB,IAAA,OAAO,QAAA,CAAS,OAAO,YAAY,CAAA;AAAA,EACrC,CAAA;AAAA,EACA,SAAS,YAAA,EAAiB;AACxB,IAAA,OAAO,QAAA,CAAS,OAAO,YAAY,CAAA;AAAA,EACrC;AACF,CAAC","file":"fluent.cjs","sourcesContent":["import type { Maybe, None, Some } from \"./types.js\";\n\nexport type { Maybe, None, Some } from \"./types.js\";\n\n/**\n * Lifts a value into the `Some` branch.\n *\n * @example\n * ```ts\n * const m = some(1); // Maybe<number>\n * ```\n */\nexport const some = <T>(value: T): Maybe<T> => ({ _tag: \"Some\", value });\n\n/**\n * Fantasy Land `of` — alias of {@link some}.\n * @deprecated Use {@link some} instead.\n */\nexport const of = some;\n\n/**\n * The `None` value — represents expected absence. Not a failure.\n *\n * @example\n * ```ts\n * const cached: Maybe<User> = cache.has(id) ? some(cache.get(id)) : none();\n * ```\n */\nexport const none = <T = never>(): Maybe<T> => ({ _tag: \"None\" });\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `Some`.\n *\n * @example\n * ```ts\n * if (isSome(m)) {\n * console.log(m.value); // narrowed to Some branch\n * }\n * ```\n */\nexport const isSome = <T>(maybe: Maybe<T>): maybe is Some<T> => maybe._tag === \"Some\";\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `None`.\n */\nexport const isNone = <T>(maybe: Maybe<T>): maybe is None => maybe._tag === \"None\";\n\n/**\n * Lift a nullable value into `Maybe<T>` — `null` and `undefined` become\n * `None`; anything else becomes `Some`.\n *\n * @example\n * ```ts\n * fromNullable(map.get(key)); // Maybe<V>\n * fromNullable(null); // None\n * ```\n */\nexport const fromNullable = <T>(value: T | null | undefined): Maybe<T> =>\n value == null ? none<T>() : some(value);\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Dual-form helpers — each accepts either shape:\n// data-first: `map(maybe, fn)`\n// curried: `map(fn)(maybe)`\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst mapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U> =>\n isSome(maybe) ? some(fn(maybe.value)) : none<U>();\n\n/**\n * Transform the `Some` value, passing `None` through unchanged. Dual-form.\n *\n * @example\n * ```ts\n * map(some(2), (n) => n * 3); // Some 6 — data-first\n * pipe(fromNullable(input), map((s) => s.trim())); // curried\n * ```\n */\nexport function map<T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U>;\nexport function map<T, U>(fn: (value: T) => U): (maybe: Maybe<T>) => Maybe<U>;\nexport function map(\n ...args: [Maybe<unknown>, (value: unknown) => unknown] | [(value: unknown) => unknown]\n): unknown {\n if (args.length === 2) return mapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => mapImpl(maybe, fn);\n}\n\nconst flatMapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U> =>\n isSome(maybe) ? fn(maybe.value) : none<U>();\n\n/**\n * Canonical bind for `Maybe`. Chains a `Maybe`-returning step;\n * short-circuits on `None`. Dual-form.\n *\n * @example\n * ```ts\n * flatMap(fromNullable(user), (u) =>\n * u.active ? some(u) : none(),\n * );\n * ```\n */\nexport function flatMap<T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U>;\nexport function flatMap<T, U>(fn: (value: T) => Maybe<U>): (maybe: Maybe<T>) => Maybe<U>;\nexport function flatMap(\n ...args:\n | [Maybe<unknown>, (value: unknown) => Maybe<unknown>]\n | [(value: unknown) => Maybe<unknown>]\n): unknown {\n if (args.length === 2) return flatMapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => flatMapImpl(maybe, fn);\n}\n\n/** Alias for {@link flatMap} — same dual-form shape. */\nexport const andThen = flatMap;\n\nconst matchImpl = <T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U =>\n isSome(maybe) ? onSome(maybe.value) : onNone();\n\n/**\n * Terminal collapse — fold both branches into a single value. Positional,\n * dual-form. Same shape as `Result.match` for sibling consistency.\n *\n * For files that also import `match` from `ts-pattern`, the alias\n * {@link matchMaybe} is identical.\n *\n * @example\n * ```ts\n * const greeting = match(\n * fromNullable(user),\n * (u) => `hello ${u.name}`,\n * () => \"hello guest\",\n * );\n * ```\n */\nexport function match<T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U;\nexport function match<T, U>(onSome: (value: T) => U, onNone: () => U): (maybe: Maybe<T>) => U;\nexport function match(\n ...args:\n | [Maybe<unknown>, (value: unknown) => unknown, () => unknown]\n | [(value: unknown) => unknown, () => unknown]\n): unknown {\n if (args.length === 3) return matchImpl(args[0], args[1], args[2]);\n const [onSome, onNone] = args;\n return (maybe: Maybe<unknown>) => matchImpl(maybe, onSome, onNone);\n}\n\n/**\n * Collision-free alias — mirrors `matchResult` on `@onrails/result`.\n * @deprecated Namespace import carriers (e.g., `import * as Maybe from \"@onrails/maybe\"`) and use canonical {@link match} instead.\n */\nexport const matchMaybe = match;\n\n/**\n * Returns the `Some` value, or `defaultValue` when the value is `None`.\n *\n * @example\n * ```ts\n * unwrapOr(fromNullable(user), { name: \"guest\" });\n * ```\n */\nexport const unwrapOr = <T>(maybe: Maybe<T>, defaultValue: T): T =>\n isSome(maybe) ? maybe.value : defaultValue;\n\n/**\n * Returns the `Some` value, or `defaultValue` when the value is `None`.\n *\n * @deprecated Use canonical {@link unwrapOr} instead.\n */\nexport const getOrElse = unwrapOr;\n\n/**\n * Unwraps the `Some` value or throws if the value is `None`.\n *\n * @throws when the value is None — assertion-tier; use {@link match} / {@link unwrapOr} in business logic.\n * Allowed in `*.spec.ts` / `*.test.ts`; flagged elsewhere by the plugins.\n *\n * @example\n * ```ts\n * expect(unwrap(parseUser(raw))).toEqual(expected);\n * ```\n */\nexport const unwrap = <T>(maybe: Maybe<T>): T => {\n if (isNone(maybe)) {\n throw new Error(\"Called unwrap on None\");\n }\n return maybe.value;\n};\n\n/**\n * Drop every `None` and collect the remaining `Some` values into an array.\n *\n * @example\n * ```ts\n * compact([some(1), none(), some(2)]); // [1, 2]\n * ```\n */\nexport const compact = <T>(maybes: readonly Maybe<T>[]): T[] => {\n const out: T[] = [];\n for (const m of maybes) {\n if (isSome(m)) {\n out.push(m.value);\n }\n }\n return out;\n};\n\n/**\n * `compact(items.map(fn))` — map each item to `Maybe`, drop `None`,\n * collect the rest.\n *\n * @example\n * ```ts\n * compactMap(rawRows, (row) =>\n * row.deletedAt ? none() : some(row.id),\n * );\n * // string[]\n * ```\n */\nexport const compactMap = <T, U>(items: readonly T[], fn: (item: T) => Maybe<U>): U[] =>\n compact(items.map(fn));\n\n/**\n * `flatMap(fromNullable(value), fn)` — lift a nullable then bind through\n * a `Maybe`-returning step. Convenient for chaining lookups.\n *\n * @example\n * ```ts\n * optional(rawId, (id) => fromNullable(cache.get(id)));\n * ```\n */\nexport const optional = <T, U>(value: T | null | undefined, fn: (value: T) => Maybe<U>): Maybe<U> =>\n flatMapImpl(fromNullable(value), fn);\n\nconst tapImpl = <T>(maybe: Maybe<T>, fn: (value: T) => void): Maybe<T> => {\n if (isSome(maybe)) fn(maybe.value);\n return maybe;\n};\n\n/**\n * Run a side effect on the `Some` value, pass the `Maybe` through unchanged.\n * `None` is a no-op. Mirrors `tap` from `@onrails/result`. Dual-form.\n *\n * @example\n * ```ts\n * tap(some(2), (n) => console.log(n)); // logs 2, returns Some 2\n * pipe(fromNullable(row), tap((r) => sink.push(r))); // curried — collect on Some\n * ```\n */\nexport function tap<T>(maybe: Maybe<T>, fn: (value: T) => void): Maybe<T>;\nexport function tap<T>(fn: (value: T) => void): (maybe: Maybe<T>) => Maybe<T>;\nexport function tap(\n ...args: [Maybe<unknown>, (value: unknown) => void] | [(value: unknown) => void]\n): unknown {\n if (args.length === 2) return tapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => tapImpl(maybe, fn);\n}\n\nconst tapNoneImpl = <T>(maybe: Maybe<T>, fn: () => void): Maybe<T> => {\n if (isNone(maybe)) fn();\n return maybe;\n};\n\n/**\n * Run a side effect when the `Maybe` is `None`, pass it through unchanged.\n * `Some` is a no-op. The `None`-side mirror of {@link tap}. Dual-form.\n *\n * @example\n * ```ts\n * tapNone(none(), () => metrics.miss()); // runs effect, returns None\n * pipe(fromNullable(hit), tapNone(() => metrics.miss())); // curried\n * ```\n */\nexport function tapNone<T>(maybe: Maybe<T>, fn: () => void): Maybe<T>;\nexport function tapNone<T>(fn: () => void): (maybe: Maybe<T>) => Maybe<T>;\nexport function tapNone(...args: [Maybe<unknown>, () => void] | [() => void]): unknown {\n if (args.length === 2) return tapNoneImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => tapNoneImpl(maybe, fn);\n}\n","import { andThen, flatMap, type Maybe, map, match, tap, tapNone, unwrapOr } from \"./maybe.js\";\n\nexport type FluentMaybe<T> = Maybe<T> & {\n map<U>(fn: (value: T) => U): FluentMaybe<U>;\n flatMap<U>(fn: (value: T) => Maybe<U>): FluentMaybe<U>;\n andThen<U>(fn: (value: T) => Maybe<U>): FluentMaybe<U>;\n tap(fn: (value: T) => void): FluentMaybe<T>;\n tapNone(fn: () => void): FluentMaybe<T>;\n match<U>(onSome: (value: T) => U, onNone: () => U): U;\n getOrElse(defaultValue: T): T;\n unwrapOr(defaultValue: T): T;\n};\n\nexport const fluent = <T>(maybe: Maybe<T>): FluentMaybe<T> =>\n Object.assign(maybe, {\n map<U>(fn: (value: T) => U) {\n return fluent(map(maybe, fn));\n },\n flatMap<U>(fn: (value: T) => Maybe<U>) {\n return fluent(flatMap(maybe, fn));\n },\n tap(fn: (value: T) => void) {\n return fluent(tap(maybe, fn));\n },\n tapNone(fn: () => void) {\n return fluent(tapNone(maybe, fn));\n },\n andThen<U>(fn: (value: T) => Maybe<U>) {\n return fluent(andThen(maybe, fn));\n },\n match<U>(onSome: (value: T) => U, onNone: () => U) {\n return match(maybe, onSome, onNone);\n },\n getOrElse(defaultValue: T) {\n return unwrapOr(maybe, defaultValue);\n },\n unwrapOr(defaultValue: T) {\n return unwrapOr(maybe, defaultValue);\n },\n });\n"]}
|
package/dist/fluent.d.cts
CHANGED
|
@@ -4,6 +4,8 @@ type FluentMaybe<T> = Maybe<T> & {
|
|
|
4
4
|
map<U>(fn: (value: T) => U): FluentMaybe<U>;
|
|
5
5
|
flatMap<U>(fn: (value: T) => Maybe<U>): FluentMaybe<U>;
|
|
6
6
|
andThen<U>(fn: (value: T) => Maybe<U>): FluentMaybe<U>;
|
|
7
|
+
tap(fn: (value: T) => void): FluentMaybe<T>;
|
|
8
|
+
tapNone(fn: () => void): FluentMaybe<T>;
|
|
7
9
|
match<U>(onSome: (value: T) => U, onNone: () => U): U;
|
|
8
10
|
getOrElse(defaultValue: T): T;
|
|
9
11
|
unwrapOr(defaultValue: T): T;
|
package/dist/fluent.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ type FluentMaybe<T> = Maybe<T> & {
|
|
|
4
4
|
map<U>(fn: (value: T) => U): FluentMaybe<U>;
|
|
5
5
|
flatMap<U>(fn: (value: T) => Maybe<U>): FluentMaybe<U>;
|
|
6
6
|
andThen<U>(fn: (value: T) => Maybe<U>): FluentMaybe<U>;
|
|
7
|
+
tap(fn: (value: T) => void): FluentMaybe<T>;
|
|
8
|
+
tapNone(fn: () => void): FluentMaybe<T>;
|
|
7
9
|
match<U>(onSome: (value: T) => U, onNone: () => U): U;
|
|
8
10
|
getOrElse(defaultValue: T): T;
|
|
9
11
|
unwrapOr(defaultValue: T): T;
|
package/dist/fluent.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
var some = (value) => ({ _tag: "Some", value });
|
|
3
3
|
var none = () => ({ _tag: "None" });
|
|
4
4
|
var isSome = (maybe) => maybe._tag === "Some";
|
|
5
|
+
var isNone = (maybe) => maybe._tag === "None";
|
|
5
6
|
var mapImpl = (maybe, fn) => isSome(maybe) ? some(fn(maybe.value)) : none();
|
|
6
7
|
function map(...args) {
|
|
7
8
|
if (args.length === 2) return mapImpl(args[0], args[1]);
|
|
@@ -21,8 +22,25 @@ function match(...args) {
|
|
|
21
22
|
const [onSome, onNone] = args;
|
|
22
23
|
return (maybe) => matchImpl(maybe, onSome, onNone);
|
|
23
24
|
}
|
|
24
|
-
var
|
|
25
|
-
var
|
|
25
|
+
var unwrapOr = (maybe, defaultValue) => isSome(maybe) ? maybe.value : defaultValue;
|
|
26
|
+
var tapImpl = (maybe, fn) => {
|
|
27
|
+
if (isSome(maybe)) fn(maybe.value);
|
|
28
|
+
return maybe;
|
|
29
|
+
};
|
|
30
|
+
function tap(...args) {
|
|
31
|
+
if (args.length === 2) return tapImpl(args[0], args[1]);
|
|
32
|
+
const fn = args[0];
|
|
33
|
+
return (maybe) => tapImpl(maybe, fn);
|
|
34
|
+
}
|
|
35
|
+
var tapNoneImpl = (maybe, fn) => {
|
|
36
|
+
if (isNone(maybe)) fn();
|
|
37
|
+
return maybe;
|
|
38
|
+
};
|
|
39
|
+
function tapNone(...args) {
|
|
40
|
+
if (args.length === 2) return tapNoneImpl(args[0], args[1]);
|
|
41
|
+
const fn = args[0];
|
|
42
|
+
return (maybe) => tapNoneImpl(maybe, fn);
|
|
43
|
+
}
|
|
26
44
|
|
|
27
45
|
// src/fluent.ts
|
|
28
46
|
var fluent = (maybe) => Object.assign(maybe, {
|
|
@@ -32,6 +50,12 @@ var fluent = (maybe) => Object.assign(maybe, {
|
|
|
32
50
|
flatMap(fn) {
|
|
33
51
|
return fluent(flatMap(maybe, fn));
|
|
34
52
|
},
|
|
53
|
+
tap(fn) {
|
|
54
|
+
return fluent(tap(maybe, fn));
|
|
55
|
+
},
|
|
56
|
+
tapNone(fn) {
|
|
57
|
+
return fluent(tapNone(maybe, fn));
|
|
58
|
+
},
|
|
35
59
|
andThen(fn) {
|
|
36
60
|
return fluent(andThen(maybe, fn));
|
|
37
61
|
},
|
|
@@ -39,7 +63,7 @@ var fluent = (maybe) => Object.assign(maybe, {
|
|
|
39
63
|
return match(maybe, onSome, onNone);
|
|
40
64
|
},
|
|
41
65
|
getOrElse(defaultValue) {
|
|
42
|
-
return
|
|
66
|
+
return unwrapOr(maybe, defaultValue);
|
|
43
67
|
},
|
|
44
68
|
unwrapOr(defaultValue) {
|
|
45
69
|
return unwrapOr(maybe, defaultValue);
|
package/dist/fluent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/maybe.ts","../src/fluent.ts"],"names":[],"mappings":"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","file":"fluent.js","sourcesContent":["import type { Maybe, None, Some } from \"./types.js\";\n\nexport type { Maybe, None, Some } from \"./types.js\";\n\n/**\n * Lifts a value into the `Some` branch.\n *\n * @example\n * ```ts\n * const m = some(1); // Maybe<number>\n * ```\n */\nexport const some = <T>(value: T): Maybe<T> => ({ _tag: \"Some\", value });\n\n/** Fantasy Land `of` — alias of {@link some}. */\nexport const of = some;\n\n/**\n * The `None` value — represents expected absence. Not a failure.\n *\n * @example\n * ```ts\n * const cached: Maybe<User> = cache.has(id) ? some(cache.get(id)) : none();\n * ```\n */\nexport const none = <T = never>(): Maybe<T> => ({ _tag: \"None\" });\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `Some`.\n *\n * @example\n * ```ts\n * if (isSome(m)) {\n * console.log(m.value); // narrowed to Some branch\n * }\n * ```\n */\nexport const isSome = <T>(maybe: Maybe<T>): maybe is Some<T> => maybe._tag === \"Some\";\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `None`.\n */\nexport const isNone = <T>(maybe: Maybe<T>): maybe is None => maybe._tag === \"None\";\n\n/**\n * Lift a nullable value into `Maybe<T>` — `null` and `undefined` become\n * `None`; anything else becomes `Some`.\n *\n * @example\n * ```ts\n * fromNullable(map.get(key)); // Maybe<V>\n * fromNullable(null); // None\n * ```\n */\nexport const fromNullable = <T>(value: T | null | undefined): Maybe<T> =>\n value == null ? none<T>() : some(value);\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Dual-form helpers — each accepts either shape:\n// data-first: `map(maybe, fn)`\n// curried: `map(fn)(maybe)`\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst mapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U> =>\n isSome(maybe) ? some(fn(maybe.value)) : none<U>();\n\n/**\n * Transform the `Some` value, passing `None` through unchanged. Dual-form.\n *\n * @example\n * ```ts\n * map(some(2), (n) => n * 3); // Some 6 — data-first\n * pipe(fromNullable(input), map((s) => s.trim())); // curried\n * ```\n */\nexport function map<T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U>;\nexport function map<T, U>(fn: (value: T) => U): (maybe: Maybe<T>) => Maybe<U>;\nexport function map(\n ...args: [Maybe<unknown>, (value: unknown) => unknown] | [(value: unknown) => unknown]\n): unknown {\n if (args.length === 2) return mapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => mapImpl(maybe, fn);\n}\n\nconst flatMapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U> =>\n isSome(maybe) ? fn(maybe.value) : none<U>();\n\n/**\n * Canonical bind for `Maybe`. Chains a `Maybe`-returning step;\n * short-circuits on `None`. Dual-form.\n *\n * @example\n * ```ts\n * flatMap(fromNullable(user), (u) =>\n * u.active ? some(u) : none(),\n * );\n * ```\n */\nexport function flatMap<T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U>;\nexport function flatMap<T, U>(fn: (value: T) => Maybe<U>): (maybe: Maybe<T>) => Maybe<U>;\nexport function flatMap(\n ...args:\n | [Maybe<unknown>, (value: unknown) => Maybe<unknown>]\n | [(value: unknown) => Maybe<unknown>]\n): unknown {\n if (args.length === 2) return flatMapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => flatMapImpl(maybe, fn);\n}\n\n/** Alias for {@link flatMap} — same dual-form shape. */\nexport const andThen = flatMap;\n\nconst matchImpl = <T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U =>\n isSome(maybe) ? onSome(maybe.value) : onNone();\n\n/**\n * Terminal collapse — fold both branches into a single value. Positional,\n * dual-form. Same shape as `Result.match` for sibling consistency.\n *\n * For files that also import `match` from `ts-pattern`, the alias\n * {@link matchMaybe} is identical.\n *\n * @example\n * ```ts\n * const greeting = match(\n * fromNullable(user),\n * (u) => `hello ${u.name}`,\n * () => \"hello guest\",\n * );\n * ```\n */\nexport function match<T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U;\nexport function match<T, U>(onSome: (value: T) => U, onNone: () => U): (maybe: Maybe<T>) => U;\nexport function match(\n ...args:\n | [Maybe<unknown>, (value: unknown) => unknown, () => unknown]\n | [(value: unknown) => unknown, () => unknown]\n): unknown {\n if (args.length === 3) return matchImpl(args[0], args[1], args[2]);\n const [onSome, onNone] = args;\n return (maybe: Maybe<unknown>) => matchImpl(maybe, onSome, onNone);\n}\n\n/** Collision-free alias — mirrors `matchResult` on `@onrails/result`. */\nexport const matchMaybe = match;\n\n/**\n * Returns the `Some` value, or `defaultValue` when the value is `None`.\n *\n * @example\n * ```ts\n * getOrElse(fromNullable(user), { name: \"guest\" });\n * ```\n */\nexport const getOrElse = <T>(maybe: Maybe<T>, defaultValue: T): T =>\n isSome(maybe) ? maybe.value : defaultValue;\n\n/** Alias — mirrors `@onrails/result` `unwrapOr`. Same as {@link getOrElse}. */\nexport const unwrapOr = getOrElse;\n\n/**\n * Unwraps the `Some` value or throws if the value is `None`. Use in tests\n * or at the boundary of an assertion; prefer `match` / `getOrElse` in\n * production code paths.\n *\n * @example\n * ```ts\n * expect(unwrap(parseUser(raw))).toEqual(expected);\n * ```\n */\nexport const unwrap = <T>(maybe: Maybe<T>): T => {\n if (isNone(maybe)) {\n throw new Error(\"Called unwrap on None\");\n }\n return maybe.value;\n};\n\n/**\n * Drop every `None` and collect the remaining `Some` values into an array.\n *\n * @example\n * ```ts\n * compact([some(1), none(), some(2)]); // [1, 2]\n * ```\n */\nexport const compact = <T>(maybes: readonly Maybe<T>[]): T[] => {\n const out: T[] = [];\n for (const m of maybes) {\n if (isSome(m)) {\n out.push(m.value);\n }\n }\n return out;\n};\n\n/**\n * `compact(items.map(fn))` — map each item to `Maybe`, drop `None`,\n * collect the rest.\n *\n * @example\n * ```ts\n * compactMap(rawRows, (row) =>\n * row.deletedAt ? none() : some(row.id),\n * );\n * // string[]\n * ```\n */\nexport const compactMap = <T, U>(items: readonly T[], fn: (item: T) => Maybe<U>): U[] =>\n compact(items.map(fn));\n\n/**\n * `flatMap(fromNullable(value), fn)` — lift a nullable then bind through\n * a `Maybe`-returning step. Convenient for chaining lookups.\n *\n * @example\n * ```ts\n * optional(rawId, (id) => fromNullable(cache.get(id)));\n * ```\n */\nexport const optional = <T, U>(value: T | null | undefined, fn: (value: T) => Maybe<U>): Maybe<U> =>\n flatMapImpl(fromNullable(value), fn);\n","import { andThen, flatMap, getOrElse, type Maybe, map, match, unwrapOr } from \"./maybe.js\";\n\nexport type FluentMaybe<T> = Maybe<T> & {\n map<U>(fn: (value: T) => U): FluentMaybe<U>;\n flatMap<U>(fn: (value: T) => Maybe<U>): FluentMaybe<U>;\n andThen<U>(fn: (value: T) => Maybe<U>): FluentMaybe<U>;\n match<U>(onSome: (value: T) => U, onNone: () => U): U;\n getOrElse(defaultValue: T): T;\n unwrapOr(defaultValue: T): T;\n};\n\nexport const fluent = <T>(maybe: Maybe<T>): FluentMaybe<T> =>\n Object.assign(maybe, {\n map<U>(fn: (value: T) => U) {\n return fluent(map(maybe, fn));\n },\n flatMap<U>(fn: (value: T) => Maybe<U>) {\n return fluent(flatMap(maybe, fn));\n },\n andThen<U>(fn: (value: T) => Maybe<U>) {\n return fluent(andThen(maybe, fn));\n },\n match<U>(onSome: (value: T) => U, onNone: () => U) {\n return match(maybe, onSome, onNone);\n },\n getOrElse(defaultValue: T) {\n return getOrElse(maybe, defaultValue);\n },\n unwrapOr(defaultValue: T) {\n return unwrapOr(maybe, defaultValue);\n },\n });\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/maybe.ts","../src/fluent.ts"],"names":[],"mappings":"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","file":"fluent.js","sourcesContent":["import type { Maybe, None, Some } from \"./types.js\";\n\nexport type { Maybe, None, Some } from \"./types.js\";\n\n/**\n * Lifts a value into the `Some` branch.\n *\n * @example\n * ```ts\n * const m = some(1); // Maybe<number>\n * ```\n */\nexport const some = <T>(value: T): Maybe<T> => ({ _tag: \"Some\", value });\n\n/**\n * Fantasy Land `of` — alias of {@link some}.\n * @deprecated Use {@link some} instead.\n */\nexport const of = some;\n\n/**\n * The `None` value — represents expected absence. Not a failure.\n *\n * @example\n * ```ts\n * const cached: Maybe<User> = cache.has(id) ? some(cache.get(id)) : none();\n * ```\n */\nexport const none = <T = never>(): Maybe<T> => ({ _tag: \"None\" });\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `Some`.\n *\n * @example\n * ```ts\n * if (isSome(m)) {\n * console.log(m.value); // narrowed to Some branch\n * }\n * ```\n */\nexport const isSome = <T>(maybe: Maybe<T>): maybe is Some<T> => maybe._tag === \"Some\";\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `None`.\n */\nexport const isNone = <T>(maybe: Maybe<T>): maybe is None => maybe._tag === \"None\";\n\n/**\n * Lift a nullable value into `Maybe<T>` — `null` and `undefined` become\n * `None`; anything else becomes `Some`.\n *\n * @example\n * ```ts\n * fromNullable(map.get(key)); // Maybe<V>\n * fromNullable(null); // None\n * ```\n */\nexport const fromNullable = <T>(value: T | null | undefined): Maybe<T> =>\n value == null ? none<T>() : some(value);\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Dual-form helpers — each accepts either shape:\n// data-first: `map(maybe, fn)`\n// curried: `map(fn)(maybe)`\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst mapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U> =>\n isSome(maybe) ? some(fn(maybe.value)) : none<U>();\n\n/**\n * Transform the `Some` value, passing `None` through unchanged. Dual-form.\n *\n * @example\n * ```ts\n * map(some(2), (n) => n * 3); // Some 6 — data-first\n * pipe(fromNullable(input), map((s) => s.trim())); // curried\n * ```\n */\nexport function map<T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U>;\nexport function map<T, U>(fn: (value: T) => U): (maybe: Maybe<T>) => Maybe<U>;\nexport function map(\n ...args: [Maybe<unknown>, (value: unknown) => unknown] | [(value: unknown) => unknown]\n): unknown {\n if (args.length === 2) return mapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => mapImpl(maybe, fn);\n}\n\nconst flatMapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U> =>\n isSome(maybe) ? fn(maybe.value) : none<U>();\n\n/**\n * Canonical bind for `Maybe`. Chains a `Maybe`-returning step;\n * short-circuits on `None`. Dual-form.\n *\n * @example\n * ```ts\n * flatMap(fromNullable(user), (u) =>\n * u.active ? some(u) : none(),\n * );\n * ```\n */\nexport function flatMap<T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U>;\nexport function flatMap<T, U>(fn: (value: T) => Maybe<U>): (maybe: Maybe<T>) => Maybe<U>;\nexport function flatMap(\n ...args:\n | [Maybe<unknown>, (value: unknown) => Maybe<unknown>]\n | [(value: unknown) => Maybe<unknown>]\n): unknown {\n if (args.length === 2) return flatMapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => flatMapImpl(maybe, fn);\n}\n\n/** Alias for {@link flatMap} — same dual-form shape. */\nexport const andThen = flatMap;\n\nconst matchImpl = <T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U =>\n isSome(maybe) ? onSome(maybe.value) : onNone();\n\n/**\n * Terminal collapse — fold both branches into a single value. Positional,\n * dual-form. Same shape as `Result.match` for sibling consistency.\n *\n * For files that also import `match` from `ts-pattern`, the alias\n * {@link matchMaybe} is identical.\n *\n * @example\n * ```ts\n * const greeting = match(\n * fromNullable(user),\n * (u) => `hello ${u.name}`,\n * () => \"hello guest\",\n * );\n * ```\n */\nexport function match<T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U;\nexport function match<T, U>(onSome: (value: T) => U, onNone: () => U): (maybe: Maybe<T>) => U;\nexport function match(\n ...args:\n | [Maybe<unknown>, (value: unknown) => unknown, () => unknown]\n | [(value: unknown) => unknown, () => unknown]\n): unknown {\n if (args.length === 3) return matchImpl(args[0], args[1], args[2]);\n const [onSome, onNone] = args;\n return (maybe: Maybe<unknown>) => matchImpl(maybe, onSome, onNone);\n}\n\n/**\n * Collision-free alias — mirrors `matchResult` on `@onrails/result`.\n * @deprecated Namespace import carriers (e.g., `import * as Maybe from \"@onrails/maybe\"`) and use canonical {@link match} instead.\n */\nexport const matchMaybe = match;\n\n/**\n * Returns the `Some` value, or `defaultValue` when the value is `None`.\n *\n * @example\n * ```ts\n * unwrapOr(fromNullable(user), { name: \"guest\" });\n * ```\n */\nexport const unwrapOr = <T>(maybe: Maybe<T>, defaultValue: T): T =>\n isSome(maybe) ? maybe.value : defaultValue;\n\n/**\n * Returns the `Some` value, or `defaultValue` when the value is `None`.\n *\n * @deprecated Use canonical {@link unwrapOr} instead.\n */\nexport const getOrElse = unwrapOr;\n\n/**\n * Unwraps the `Some` value or throws if the value is `None`.\n *\n * @throws when the value is None — assertion-tier; use {@link match} / {@link unwrapOr} in business logic.\n * Allowed in `*.spec.ts` / `*.test.ts`; flagged elsewhere by the plugins.\n *\n * @example\n * ```ts\n * expect(unwrap(parseUser(raw))).toEqual(expected);\n * ```\n */\nexport const unwrap = <T>(maybe: Maybe<T>): T => {\n if (isNone(maybe)) {\n throw new Error(\"Called unwrap on None\");\n }\n return maybe.value;\n};\n\n/**\n * Drop every `None` and collect the remaining `Some` values into an array.\n *\n * @example\n * ```ts\n * compact([some(1), none(), some(2)]); // [1, 2]\n * ```\n */\nexport const compact = <T>(maybes: readonly Maybe<T>[]): T[] => {\n const out: T[] = [];\n for (const m of maybes) {\n if (isSome(m)) {\n out.push(m.value);\n }\n }\n return out;\n};\n\n/**\n * `compact(items.map(fn))` — map each item to `Maybe`, drop `None`,\n * collect the rest.\n *\n * @example\n * ```ts\n * compactMap(rawRows, (row) =>\n * row.deletedAt ? none() : some(row.id),\n * );\n * // string[]\n * ```\n */\nexport const compactMap = <T, U>(items: readonly T[], fn: (item: T) => Maybe<U>): U[] =>\n compact(items.map(fn));\n\n/**\n * `flatMap(fromNullable(value), fn)` — lift a nullable then bind through\n * a `Maybe`-returning step. Convenient for chaining lookups.\n *\n * @example\n * ```ts\n * optional(rawId, (id) => fromNullable(cache.get(id)));\n * ```\n */\nexport const optional = <T, U>(value: T | null | undefined, fn: (value: T) => Maybe<U>): Maybe<U> =>\n flatMapImpl(fromNullable(value), fn);\n\nconst tapImpl = <T>(maybe: Maybe<T>, fn: (value: T) => void): Maybe<T> => {\n if (isSome(maybe)) fn(maybe.value);\n return maybe;\n};\n\n/**\n * Run a side effect on the `Some` value, pass the `Maybe` through unchanged.\n * `None` is a no-op. Mirrors `tap` from `@onrails/result`. Dual-form.\n *\n * @example\n * ```ts\n * tap(some(2), (n) => console.log(n)); // logs 2, returns Some 2\n * pipe(fromNullable(row), tap((r) => sink.push(r))); // curried — collect on Some\n * ```\n */\nexport function tap<T>(maybe: Maybe<T>, fn: (value: T) => void): Maybe<T>;\nexport function tap<T>(fn: (value: T) => void): (maybe: Maybe<T>) => Maybe<T>;\nexport function tap(\n ...args: [Maybe<unknown>, (value: unknown) => void] | [(value: unknown) => void]\n): unknown {\n if (args.length === 2) return tapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => tapImpl(maybe, fn);\n}\n\nconst tapNoneImpl = <T>(maybe: Maybe<T>, fn: () => void): Maybe<T> => {\n if (isNone(maybe)) fn();\n return maybe;\n};\n\n/**\n * Run a side effect when the `Maybe` is `None`, pass it through unchanged.\n * `Some` is a no-op. The `None`-side mirror of {@link tap}. Dual-form.\n *\n * @example\n * ```ts\n * tapNone(none(), () => metrics.miss()); // runs effect, returns None\n * pipe(fromNullable(hit), tapNone(() => metrics.miss())); // curried\n * ```\n */\nexport function tapNone<T>(maybe: Maybe<T>, fn: () => void): Maybe<T>;\nexport function tapNone<T>(fn: () => void): (maybe: Maybe<T>) => Maybe<T>;\nexport function tapNone(...args: [Maybe<unknown>, () => void] | [() => void]): unknown {\n if (args.length === 2) return tapNoneImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => tapNoneImpl(maybe, fn);\n}\n","import { andThen, flatMap, type Maybe, map, match, tap, tapNone, unwrapOr } from \"./maybe.js\";\n\nexport type FluentMaybe<T> = Maybe<T> & {\n map<U>(fn: (value: T) => U): FluentMaybe<U>;\n flatMap<U>(fn: (value: T) => Maybe<U>): FluentMaybe<U>;\n andThen<U>(fn: (value: T) => Maybe<U>): FluentMaybe<U>;\n tap(fn: (value: T) => void): FluentMaybe<T>;\n tapNone(fn: () => void): FluentMaybe<T>;\n match<U>(onSome: (value: T) => U, onNone: () => U): U;\n getOrElse(defaultValue: T): T;\n unwrapOr(defaultValue: T): T;\n};\n\nexport const fluent = <T>(maybe: Maybe<T>): FluentMaybe<T> =>\n Object.assign(maybe, {\n map<U>(fn: (value: T) => U) {\n return fluent(map(maybe, fn));\n },\n flatMap<U>(fn: (value: T) => Maybe<U>) {\n return fluent(flatMap(maybe, fn));\n },\n tap(fn: (value: T) => void) {\n return fluent(tap(maybe, fn));\n },\n tapNone(fn: () => void) {\n return fluent(tapNone(maybe, fn));\n },\n andThen<U>(fn: (value: T) => Maybe<U>) {\n return fluent(andThen(maybe, fn));\n },\n match<U>(onSome: (value: T) => U, onNone: () => U) {\n return match(maybe, onSome, onNone);\n },\n getOrElse(defaultValue: T) {\n return unwrapOr(maybe, defaultValue);\n },\n unwrapOr(defaultValue: T) {\n return unwrapOr(maybe, defaultValue);\n },\n });\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -27,8 +27,8 @@ function match(...args) {
|
|
|
27
27
|
return (maybe) => matchImpl(maybe, onSome, onNone);
|
|
28
28
|
}
|
|
29
29
|
var matchMaybe = match;
|
|
30
|
-
var
|
|
31
|
-
var
|
|
30
|
+
var unwrapOr = (maybe, defaultValue) => isSome(maybe) ? maybe.value : defaultValue;
|
|
31
|
+
var getOrElse = unwrapOr;
|
|
32
32
|
var unwrap = (maybe) => {
|
|
33
33
|
if (isNone(maybe)) {
|
|
34
34
|
throw new Error("Called unwrap on None");
|
|
@@ -46,6 +46,24 @@ var compact = (maybes) => {
|
|
|
46
46
|
};
|
|
47
47
|
var compactMap = (items, fn) => compact(items.map(fn));
|
|
48
48
|
var optional = (value, fn) => flatMapImpl(fromNullable(value), fn);
|
|
49
|
+
var tapImpl = (maybe, fn) => {
|
|
50
|
+
if (isSome(maybe)) fn(maybe.value);
|
|
51
|
+
return maybe;
|
|
52
|
+
};
|
|
53
|
+
function tap(...args) {
|
|
54
|
+
if (args.length === 2) return tapImpl(args[0], args[1]);
|
|
55
|
+
const fn = args[0];
|
|
56
|
+
return (maybe) => tapImpl(maybe, fn);
|
|
57
|
+
}
|
|
58
|
+
var tapNoneImpl = (maybe, fn) => {
|
|
59
|
+
if (isNone(maybe)) fn();
|
|
60
|
+
return maybe;
|
|
61
|
+
};
|
|
62
|
+
function tapNone(...args) {
|
|
63
|
+
if (args.length === 2) return tapNoneImpl(args[0], args[1]);
|
|
64
|
+
const fn = args[0];
|
|
65
|
+
return (maybe) => tapNoneImpl(maybe, fn);
|
|
66
|
+
}
|
|
49
67
|
|
|
50
68
|
exports.andThen = andThen;
|
|
51
69
|
exports.compact = compact;
|
|
@@ -62,6 +80,8 @@ exports.none = none;
|
|
|
62
80
|
exports.of = of;
|
|
63
81
|
exports.optional = optional;
|
|
64
82
|
exports.some = some;
|
|
83
|
+
exports.tap = tap;
|
|
84
|
+
exports.tapNone = tapNone;
|
|
65
85
|
exports.unwrap = unwrap;
|
|
66
86
|
exports.unwrapOr = unwrapOr;
|
|
67
87
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/maybe.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["import type { Maybe, None, Some } from \"./types.js\";\n\nexport type { Maybe, None, Some } from \"./types.js\";\n\n/**\n * Lifts a value into the `Some` branch.\n *\n * @example\n * ```ts\n * const m = some(1); // Maybe<number>\n * ```\n */\nexport const some = <T>(value: T): Maybe<T> => ({ _tag: \"Some\", value });\n\n/** Fantasy Land `of` — alias of {@link some}. */\nexport const of = some;\n\n/**\n * The `None` value — represents expected absence. Not a failure.\n *\n * @example\n * ```ts\n * const cached: Maybe<User> = cache.has(id) ? some(cache.get(id)) : none();\n * ```\n */\nexport const none = <T = never>(): Maybe<T> => ({ _tag: \"None\" });\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `Some`.\n *\n * @example\n * ```ts\n * if (isSome(m)) {\n * console.log(m.value); // narrowed to Some branch\n * }\n * ```\n */\nexport const isSome = <T>(maybe: Maybe<T>): maybe is Some<T> => maybe._tag === \"Some\";\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `None`.\n */\nexport const isNone = <T>(maybe: Maybe<T>): maybe is None => maybe._tag === \"None\";\n\n/**\n * Lift a nullable value into `Maybe<T>` — `null` and `undefined` become\n * `None`; anything else becomes `Some`.\n *\n * @example\n * ```ts\n * fromNullable(map.get(key)); // Maybe<V>\n * fromNullable(null); // None\n * ```\n */\nexport const fromNullable = <T>(value: T | null | undefined): Maybe<T> =>\n value == null ? none<T>() : some(value);\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Dual-form helpers — each accepts either shape:\n// data-first: `map(maybe, fn)`\n// curried: `map(fn)(maybe)`\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst mapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U> =>\n isSome(maybe) ? some(fn(maybe.value)) : none<U>();\n\n/**\n * Transform the `Some` value, passing `None` through unchanged. Dual-form.\n *\n * @example\n * ```ts\n * map(some(2), (n) => n * 3); // Some 6 — data-first\n * pipe(fromNullable(input), map((s) => s.trim())); // curried\n * ```\n */\nexport function map<T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U>;\nexport function map<T, U>(fn: (value: T) => U): (maybe: Maybe<T>) => Maybe<U>;\nexport function map(\n ...args: [Maybe<unknown>, (value: unknown) => unknown] | [(value: unknown) => unknown]\n): unknown {\n if (args.length === 2) return mapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => mapImpl(maybe, fn);\n}\n\nconst flatMapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U> =>\n isSome(maybe) ? fn(maybe.value) : none<U>();\n\n/**\n * Canonical bind for `Maybe`. Chains a `Maybe`-returning step;\n * short-circuits on `None`. Dual-form.\n *\n * @example\n * ```ts\n * flatMap(fromNullable(user), (u) =>\n * u.active ? some(u) : none(),\n * );\n * ```\n */\nexport function flatMap<T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U>;\nexport function flatMap<T, U>(fn: (value: T) => Maybe<U>): (maybe: Maybe<T>) => Maybe<U>;\nexport function flatMap(\n ...args:\n | [Maybe<unknown>, (value: unknown) => Maybe<unknown>]\n | [(value: unknown) => Maybe<unknown>]\n): unknown {\n if (args.length === 2) return flatMapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => flatMapImpl(maybe, fn);\n}\n\n/** Alias for {@link flatMap} — same dual-form shape. */\nexport const andThen = flatMap;\n\nconst matchImpl = <T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U =>\n isSome(maybe) ? onSome(maybe.value) : onNone();\n\n/**\n * Terminal collapse — fold both branches into a single value. Positional,\n * dual-form. Same shape as `Result.match` for sibling consistency.\n *\n * For files that also import `match` from `ts-pattern`, the alias\n * {@link matchMaybe} is identical.\n *\n * @example\n * ```ts\n * const greeting = match(\n * fromNullable(user),\n * (u) => `hello ${u.name}`,\n * () => \"hello guest\",\n * );\n * ```\n */\nexport function match<T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U;\nexport function match<T, U>(onSome: (value: T) => U, onNone: () => U): (maybe: Maybe<T>) => U;\nexport function match(\n ...args:\n | [Maybe<unknown>, (value: unknown) => unknown, () => unknown]\n | [(value: unknown) => unknown, () => unknown]\n): unknown {\n if (args.length === 3) return matchImpl(args[0], args[1], args[2]);\n const [onSome, onNone] = args;\n return (maybe: Maybe<unknown>) => matchImpl(maybe, onSome, onNone);\n}\n\n/** Collision-free alias — mirrors `matchResult` on `@onrails/result`. */\nexport const matchMaybe = match;\n\n/**\n * Returns the `Some` value, or `defaultValue` when the value is `None`.\n *\n * @example\n * ```ts\n * getOrElse(fromNullable(user), { name: \"guest\" });\n * ```\n */\nexport const getOrElse = <T>(maybe: Maybe<T>, defaultValue: T): T =>\n isSome(maybe) ? maybe.value : defaultValue;\n\n/** Alias — mirrors `@onrails/result` `unwrapOr`. Same as {@link getOrElse}. */\nexport const unwrapOr = getOrElse;\n\n/**\n * Unwraps the `Some` value or throws if the value is `None`. Use in tests\n * or at the boundary of an assertion; prefer `match` / `getOrElse` in\n * production code paths.\n *\n * @example\n * ```ts\n * expect(unwrap(parseUser(raw))).toEqual(expected);\n * ```\n */\nexport const unwrap = <T>(maybe: Maybe<T>): T => {\n if (isNone(maybe)) {\n throw new Error(\"Called unwrap on None\");\n }\n return maybe.value;\n};\n\n/**\n * Drop every `None` and collect the remaining `Some` values into an array.\n *\n * @example\n * ```ts\n * compact([some(1), none(), some(2)]); // [1, 2]\n * ```\n */\nexport const compact = <T>(maybes: readonly Maybe<T>[]): T[] => {\n const out: T[] = [];\n for (const m of maybes) {\n if (isSome(m)) {\n out.push(m.value);\n }\n }\n return out;\n};\n\n/**\n * `compact(items.map(fn))` — map each item to `Maybe`, drop `None`,\n * collect the rest.\n *\n * @example\n * ```ts\n * compactMap(rawRows, (row) =>\n * row.deletedAt ? none() : some(row.id),\n * );\n * // string[]\n * ```\n */\nexport const compactMap = <T, U>(items: readonly T[], fn: (item: T) => Maybe<U>): U[] =>\n compact(items.map(fn));\n\n/**\n * `flatMap(fromNullable(value), fn)` — lift a nullable then bind through\n * a `Maybe`-returning step. Convenient for chaining lookups.\n *\n * @example\n * ```ts\n * optional(rawId, (id) => fromNullable(cache.get(id)));\n * ```\n */\nexport const optional = <T, U>(value: T | null | undefined, fn: (value: T) => Maybe<U>): Maybe<U> =>\n flatMapImpl(fromNullable(value), fn);\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/maybe.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["import type { Maybe, None, Some } from \"./types.js\";\n\nexport type { Maybe, None, Some } from \"./types.js\";\n\n/**\n * Lifts a value into the `Some` branch.\n *\n * @example\n * ```ts\n * const m = some(1); // Maybe<number>\n * ```\n */\nexport const some = <T>(value: T): Maybe<T> => ({ _tag: \"Some\", value });\n\n/**\n * Fantasy Land `of` — alias of {@link some}.\n * @deprecated Use {@link some} instead.\n */\nexport const of = some;\n\n/**\n * The `None` value — represents expected absence. Not a failure.\n *\n * @example\n * ```ts\n * const cached: Maybe<User> = cache.has(id) ? some(cache.get(id)) : none();\n * ```\n */\nexport const none = <T = never>(): Maybe<T> => ({ _tag: \"None\" });\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `Some`.\n *\n * @example\n * ```ts\n * if (isSome(m)) {\n * console.log(m.value); // narrowed to Some branch\n * }\n * ```\n */\nexport const isSome = <T>(maybe: Maybe<T>): maybe is Some<T> => maybe._tag === \"Some\";\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `None`.\n */\nexport const isNone = <T>(maybe: Maybe<T>): maybe is None => maybe._tag === \"None\";\n\n/**\n * Lift a nullable value into `Maybe<T>` — `null` and `undefined` become\n * `None`; anything else becomes `Some`.\n *\n * @example\n * ```ts\n * fromNullable(map.get(key)); // Maybe<V>\n * fromNullable(null); // None\n * ```\n */\nexport const fromNullable = <T>(value: T | null | undefined): Maybe<T> =>\n value == null ? none<T>() : some(value);\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Dual-form helpers — each accepts either shape:\n// data-first: `map(maybe, fn)`\n// curried: `map(fn)(maybe)`\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst mapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U> =>\n isSome(maybe) ? some(fn(maybe.value)) : none<U>();\n\n/**\n * Transform the `Some` value, passing `None` through unchanged. Dual-form.\n *\n * @example\n * ```ts\n * map(some(2), (n) => n * 3); // Some 6 — data-first\n * pipe(fromNullable(input), map((s) => s.trim())); // curried\n * ```\n */\nexport function map<T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U>;\nexport function map<T, U>(fn: (value: T) => U): (maybe: Maybe<T>) => Maybe<U>;\nexport function map(\n ...args: [Maybe<unknown>, (value: unknown) => unknown] | [(value: unknown) => unknown]\n): unknown {\n if (args.length === 2) return mapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => mapImpl(maybe, fn);\n}\n\nconst flatMapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U> =>\n isSome(maybe) ? fn(maybe.value) : none<U>();\n\n/**\n * Canonical bind for `Maybe`. Chains a `Maybe`-returning step;\n * short-circuits on `None`. Dual-form.\n *\n * @example\n * ```ts\n * flatMap(fromNullable(user), (u) =>\n * u.active ? some(u) : none(),\n * );\n * ```\n */\nexport function flatMap<T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U>;\nexport function flatMap<T, U>(fn: (value: T) => Maybe<U>): (maybe: Maybe<T>) => Maybe<U>;\nexport function flatMap(\n ...args:\n | [Maybe<unknown>, (value: unknown) => Maybe<unknown>]\n | [(value: unknown) => Maybe<unknown>]\n): unknown {\n if (args.length === 2) return flatMapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => flatMapImpl(maybe, fn);\n}\n\n/** Alias for {@link flatMap} — same dual-form shape. */\nexport const andThen = flatMap;\n\nconst matchImpl = <T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U =>\n isSome(maybe) ? onSome(maybe.value) : onNone();\n\n/**\n * Terminal collapse — fold both branches into a single value. Positional,\n * dual-form. Same shape as `Result.match` for sibling consistency.\n *\n * For files that also import `match` from `ts-pattern`, the alias\n * {@link matchMaybe} is identical.\n *\n * @example\n * ```ts\n * const greeting = match(\n * fromNullable(user),\n * (u) => `hello ${u.name}`,\n * () => \"hello guest\",\n * );\n * ```\n */\nexport function match<T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U;\nexport function match<T, U>(onSome: (value: T) => U, onNone: () => U): (maybe: Maybe<T>) => U;\nexport function match(\n ...args:\n | [Maybe<unknown>, (value: unknown) => unknown, () => unknown]\n | [(value: unknown) => unknown, () => unknown]\n): unknown {\n if (args.length === 3) return matchImpl(args[0], args[1], args[2]);\n const [onSome, onNone] = args;\n return (maybe: Maybe<unknown>) => matchImpl(maybe, onSome, onNone);\n}\n\n/**\n * Collision-free alias — mirrors `matchResult` on `@onrails/result`.\n * @deprecated Namespace import carriers (e.g., `import * as Maybe from \"@onrails/maybe\"`) and use canonical {@link match} instead.\n */\nexport const matchMaybe = match;\n\n/**\n * Returns the `Some` value, or `defaultValue` when the value is `None`.\n *\n * @example\n * ```ts\n * unwrapOr(fromNullable(user), { name: \"guest\" });\n * ```\n */\nexport const unwrapOr = <T>(maybe: Maybe<T>, defaultValue: T): T =>\n isSome(maybe) ? maybe.value : defaultValue;\n\n/**\n * Returns the `Some` value, or `defaultValue` when the value is `None`.\n *\n * @deprecated Use canonical {@link unwrapOr} instead.\n */\nexport const getOrElse = unwrapOr;\n\n/**\n * Unwraps the `Some` value or throws if the value is `None`.\n *\n * @throws when the value is None — assertion-tier; use {@link match} / {@link unwrapOr} in business logic.\n * Allowed in `*.spec.ts` / `*.test.ts`; flagged elsewhere by the plugins.\n *\n * @example\n * ```ts\n * expect(unwrap(parseUser(raw))).toEqual(expected);\n * ```\n */\nexport const unwrap = <T>(maybe: Maybe<T>): T => {\n if (isNone(maybe)) {\n throw new Error(\"Called unwrap on None\");\n }\n return maybe.value;\n};\n\n/**\n * Drop every `None` and collect the remaining `Some` values into an array.\n *\n * @example\n * ```ts\n * compact([some(1), none(), some(2)]); // [1, 2]\n * ```\n */\nexport const compact = <T>(maybes: readonly Maybe<T>[]): T[] => {\n const out: T[] = [];\n for (const m of maybes) {\n if (isSome(m)) {\n out.push(m.value);\n }\n }\n return out;\n};\n\n/**\n * `compact(items.map(fn))` — map each item to `Maybe`, drop `None`,\n * collect the rest.\n *\n * @example\n * ```ts\n * compactMap(rawRows, (row) =>\n * row.deletedAt ? none() : some(row.id),\n * );\n * // string[]\n * ```\n */\nexport const compactMap = <T, U>(items: readonly T[], fn: (item: T) => Maybe<U>): U[] =>\n compact(items.map(fn));\n\n/**\n * `flatMap(fromNullable(value), fn)` — lift a nullable then bind through\n * a `Maybe`-returning step. Convenient for chaining lookups.\n *\n * @example\n * ```ts\n * optional(rawId, (id) => fromNullable(cache.get(id)));\n * ```\n */\nexport const optional = <T, U>(value: T | null | undefined, fn: (value: T) => Maybe<U>): Maybe<U> =>\n flatMapImpl(fromNullable(value), fn);\n\nconst tapImpl = <T>(maybe: Maybe<T>, fn: (value: T) => void): Maybe<T> => {\n if (isSome(maybe)) fn(maybe.value);\n return maybe;\n};\n\n/**\n * Run a side effect on the `Some` value, pass the `Maybe` through unchanged.\n * `None` is a no-op. Mirrors `tap` from `@onrails/result`. Dual-form.\n *\n * @example\n * ```ts\n * tap(some(2), (n) => console.log(n)); // logs 2, returns Some 2\n * pipe(fromNullable(row), tap((r) => sink.push(r))); // curried — collect on Some\n * ```\n */\nexport function tap<T>(maybe: Maybe<T>, fn: (value: T) => void): Maybe<T>;\nexport function tap<T>(fn: (value: T) => void): (maybe: Maybe<T>) => Maybe<T>;\nexport function tap(\n ...args: [Maybe<unknown>, (value: unknown) => void] | [(value: unknown) => void]\n): unknown {\n if (args.length === 2) return tapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => tapImpl(maybe, fn);\n}\n\nconst tapNoneImpl = <T>(maybe: Maybe<T>, fn: () => void): Maybe<T> => {\n if (isNone(maybe)) fn();\n return maybe;\n};\n\n/**\n * Run a side effect when the `Maybe` is `None`, pass it through unchanged.\n * `Some` is a no-op. The `None`-side mirror of {@link tap}. Dual-form.\n *\n * @example\n * ```ts\n * tapNone(none(), () => metrics.miss()); // runs effect, returns None\n * pipe(fromNullable(hit), tapNone(() => metrics.miss())); // curried\n * ```\n */\nexport function tapNone<T>(maybe: Maybe<T>, fn: () => void): Maybe<T>;\nexport function tapNone<T>(fn: () => void): (maybe: Maybe<T>) => Maybe<T>;\nexport function tapNone(...args: [Maybe<unknown>, () => void] | [() => void]): unknown {\n if (args.length === 2) return tapNoneImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => tapNoneImpl(maybe, fn);\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -9,7 +9,10 @@ import { M as Maybe, N as None, S as Some } from './types-vkiMAo4w.cjs';
|
|
|
9
9
|
* ```
|
|
10
10
|
*/
|
|
11
11
|
declare const some: <T>(value: T) => Maybe<T>;
|
|
12
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Fantasy Land `of` — alias of {@link some}.
|
|
14
|
+
* @deprecated Use {@link some} instead.
|
|
15
|
+
*/
|
|
13
16
|
declare const of: <T>(value: T) => Maybe<T>;
|
|
14
17
|
/**
|
|
15
18
|
* The `None` value — represents expected absence. Not a failure.
|
|
@@ -90,23 +93,31 @@ declare const andThen: typeof flatMap;
|
|
|
90
93
|
*/
|
|
91
94
|
declare function match<T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U;
|
|
92
95
|
declare function match<T, U>(onSome: (value: T) => U, onNone: () => U): (maybe: Maybe<T>) => U;
|
|
93
|
-
/**
|
|
96
|
+
/**
|
|
97
|
+
* Collision-free alias — mirrors `matchResult` on `@onrails/result`.
|
|
98
|
+
* @deprecated Namespace import carriers (e.g., `import * as Maybe from "@onrails/maybe"`) and use canonical {@link match} instead.
|
|
99
|
+
*/
|
|
94
100
|
declare const matchMaybe: typeof match;
|
|
95
101
|
/**
|
|
96
102
|
* Returns the `Some` value, or `defaultValue` when the value is `None`.
|
|
97
103
|
*
|
|
98
104
|
* @example
|
|
99
105
|
* ```ts
|
|
100
|
-
*
|
|
106
|
+
* unwrapOr(fromNullable(user), { name: "guest" });
|
|
101
107
|
* ```
|
|
102
108
|
*/
|
|
103
|
-
declare const getOrElse: <T>(maybe: Maybe<T>, defaultValue: T) => T;
|
|
104
|
-
/** Alias — mirrors `@onrails/result` `unwrapOr`. Same as {@link getOrElse}. */
|
|
105
109
|
declare const unwrapOr: <T>(maybe: Maybe<T>, defaultValue: T) => T;
|
|
106
110
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
111
|
+
* Returns the `Some` value, or `defaultValue` when the value is `None`.
|
|
112
|
+
*
|
|
113
|
+
* @deprecated Use canonical {@link unwrapOr} instead.
|
|
114
|
+
*/
|
|
115
|
+
declare const getOrElse: <T>(maybe: Maybe<T>, defaultValue: T) => T;
|
|
116
|
+
/**
|
|
117
|
+
* Unwraps the `Some` value or throws if the value is `None`.
|
|
118
|
+
*
|
|
119
|
+
* @throws when the value is None — assertion-tier; use {@link match} / {@link unwrapOr} in business logic.
|
|
120
|
+
* Allowed in `*.spec.ts` / `*.test.ts`; flagged elsewhere by the plugins.
|
|
110
121
|
*
|
|
111
122
|
* @example
|
|
112
123
|
* ```ts
|
|
@@ -146,5 +157,29 @@ declare const compactMap: <T, U>(items: readonly T[], fn: (item: T) => Maybe<U>)
|
|
|
146
157
|
* ```
|
|
147
158
|
*/
|
|
148
159
|
declare const optional: <T, U>(value: T | null | undefined, fn: (value: T) => Maybe<U>) => Maybe<U>;
|
|
160
|
+
/**
|
|
161
|
+
* Run a side effect on the `Some` value, pass the `Maybe` through unchanged.
|
|
162
|
+
* `None` is a no-op. Mirrors `tap` from `@onrails/result`. Dual-form.
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```ts
|
|
166
|
+
* tap(some(2), (n) => console.log(n)); // logs 2, returns Some 2
|
|
167
|
+
* pipe(fromNullable(row), tap((r) => sink.push(r))); // curried — collect on Some
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
declare function tap<T>(maybe: Maybe<T>, fn: (value: T) => void): Maybe<T>;
|
|
171
|
+
declare function tap<T>(fn: (value: T) => void): (maybe: Maybe<T>) => Maybe<T>;
|
|
172
|
+
/**
|
|
173
|
+
* Run a side effect when the `Maybe` is `None`, pass it through unchanged.
|
|
174
|
+
* `Some` is a no-op. The `None`-side mirror of {@link tap}. Dual-form.
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```ts
|
|
178
|
+
* tapNone(none(), () => metrics.miss()); // runs effect, returns None
|
|
179
|
+
* pipe(fromNullable(hit), tapNone(() => metrics.miss())); // curried
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
declare function tapNone<T>(maybe: Maybe<T>, fn: () => void): Maybe<T>;
|
|
183
|
+
declare function tapNone<T>(fn: () => void): (maybe: Maybe<T>) => Maybe<T>;
|
|
149
184
|
|
|
150
|
-
export { Maybe, None, Some, andThen, compact, compactMap, flatMap, fromNullable, getOrElse, isNone, isSome, map, match, matchMaybe, none, of, optional, some, unwrap, unwrapOr };
|
|
185
|
+
export { Maybe, None, Some, andThen, compact, compactMap, flatMap, fromNullable, getOrElse, isNone, isSome, map, match, matchMaybe, none, of, optional, some, tap, tapNone, unwrap, unwrapOr };
|
package/dist/index.d.ts
CHANGED
|
@@ -9,7 +9,10 @@ import { M as Maybe, N as None, S as Some } from './types-vkiMAo4w.js';
|
|
|
9
9
|
* ```
|
|
10
10
|
*/
|
|
11
11
|
declare const some: <T>(value: T) => Maybe<T>;
|
|
12
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Fantasy Land `of` — alias of {@link some}.
|
|
14
|
+
* @deprecated Use {@link some} instead.
|
|
15
|
+
*/
|
|
13
16
|
declare const of: <T>(value: T) => Maybe<T>;
|
|
14
17
|
/**
|
|
15
18
|
* The `None` value — represents expected absence. Not a failure.
|
|
@@ -90,23 +93,31 @@ declare const andThen: typeof flatMap;
|
|
|
90
93
|
*/
|
|
91
94
|
declare function match<T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U;
|
|
92
95
|
declare function match<T, U>(onSome: (value: T) => U, onNone: () => U): (maybe: Maybe<T>) => U;
|
|
93
|
-
/**
|
|
96
|
+
/**
|
|
97
|
+
* Collision-free alias — mirrors `matchResult` on `@onrails/result`.
|
|
98
|
+
* @deprecated Namespace import carriers (e.g., `import * as Maybe from "@onrails/maybe"`) and use canonical {@link match} instead.
|
|
99
|
+
*/
|
|
94
100
|
declare const matchMaybe: typeof match;
|
|
95
101
|
/**
|
|
96
102
|
* Returns the `Some` value, or `defaultValue` when the value is `None`.
|
|
97
103
|
*
|
|
98
104
|
* @example
|
|
99
105
|
* ```ts
|
|
100
|
-
*
|
|
106
|
+
* unwrapOr(fromNullable(user), { name: "guest" });
|
|
101
107
|
* ```
|
|
102
108
|
*/
|
|
103
|
-
declare const getOrElse: <T>(maybe: Maybe<T>, defaultValue: T) => T;
|
|
104
|
-
/** Alias — mirrors `@onrails/result` `unwrapOr`. Same as {@link getOrElse}. */
|
|
105
109
|
declare const unwrapOr: <T>(maybe: Maybe<T>, defaultValue: T) => T;
|
|
106
110
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
111
|
+
* Returns the `Some` value, or `defaultValue` when the value is `None`.
|
|
112
|
+
*
|
|
113
|
+
* @deprecated Use canonical {@link unwrapOr} instead.
|
|
114
|
+
*/
|
|
115
|
+
declare const getOrElse: <T>(maybe: Maybe<T>, defaultValue: T) => T;
|
|
116
|
+
/**
|
|
117
|
+
* Unwraps the `Some` value or throws if the value is `None`.
|
|
118
|
+
*
|
|
119
|
+
* @throws when the value is None — assertion-tier; use {@link match} / {@link unwrapOr} in business logic.
|
|
120
|
+
* Allowed in `*.spec.ts` / `*.test.ts`; flagged elsewhere by the plugins.
|
|
110
121
|
*
|
|
111
122
|
* @example
|
|
112
123
|
* ```ts
|
|
@@ -146,5 +157,29 @@ declare const compactMap: <T, U>(items: readonly T[], fn: (item: T) => Maybe<U>)
|
|
|
146
157
|
* ```
|
|
147
158
|
*/
|
|
148
159
|
declare const optional: <T, U>(value: T | null | undefined, fn: (value: T) => Maybe<U>) => Maybe<U>;
|
|
160
|
+
/**
|
|
161
|
+
* Run a side effect on the `Some` value, pass the `Maybe` through unchanged.
|
|
162
|
+
* `None` is a no-op. Mirrors `tap` from `@onrails/result`. Dual-form.
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```ts
|
|
166
|
+
* tap(some(2), (n) => console.log(n)); // logs 2, returns Some 2
|
|
167
|
+
* pipe(fromNullable(row), tap((r) => sink.push(r))); // curried — collect on Some
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
declare function tap<T>(maybe: Maybe<T>, fn: (value: T) => void): Maybe<T>;
|
|
171
|
+
declare function tap<T>(fn: (value: T) => void): (maybe: Maybe<T>) => Maybe<T>;
|
|
172
|
+
/**
|
|
173
|
+
* Run a side effect when the `Maybe` is `None`, pass it through unchanged.
|
|
174
|
+
* `Some` is a no-op. The `None`-side mirror of {@link tap}. Dual-form.
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```ts
|
|
178
|
+
* tapNone(none(), () => metrics.miss()); // runs effect, returns None
|
|
179
|
+
* pipe(fromNullable(hit), tapNone(() => metrics.miss())); // curried
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
declare function tapNone<T>(maybe: Maybe<T>, fn: () => void): Maybe<T>;
|
|
183
|
+
declare function tapNone<T>(fn: () => void): (maybe: Maybe<T>) => Maybe<T>;
|
|
149
184
|
|
|
150
|
-
export { Maybe, None, Some, andThen, compact, compactMap, flatMap, fromNullable, getOrElse, isNone, isSome, map, match, matchMaybe, none, of, optional, some, unwrap, unwrapOr };
|
|
185
|
+
export { Maybe, None, Some, andThen, compact, compactMap, flatMap, fromNullable, getOrElse, isNone, isSome, map, match, matchMaybe, none, of, optional, some, tap, tapNone, unwrap, unwrapOr };
|
package/dist/index.js
CHANGED
|
@@ -25,8 +25,8 @@ function match(...args) {
|
|
|
25
25
|
return (maybe) => matchImpl(maybe, onSome, onNone);
|
|
26
26
|
}
|
|
27
27
|
var matchMaybe = match;
|
|
28
|
-
var
|
|
29
|
-
var
|
|
28
|
+
var unwrapOr = (maybe, defaultValue) => isSome(maybe) ? maybe.value : defaultValue;
|
|
29
|
+
var getOrElse = unwrapOr;
|
|
30
30
|
var unwrap = (maybe) => {
|
|
31
31
|
if (isNone(maybe)) {
|
|
32
32
|
throw new Error("Called unwrap on None");
|
|
@@ -44,7 +44,25 @@ var compact = (maybes) => {
|
|
|
44
44
|
};
|
|
45
45
|
var compactMap = (items, fn) => compact(items.map(fn));
|
|
46
46
|
var optional = (value, fn) => flatMapImpl(fromNullable(value), fn);
|
|
47
|
+
var tapImpl = (maybe, fn) => {
|
|
48
|
+
if (isSome(maybe)) fn(maybe.value);
|
|
49
|
+
return maybe;
|
|
50
|
+
};
|
|
51
|
+
function tap(...args) {
|
|
52
|
+
if (args.length === 2) return tapImpl(args[0], args[1]);
|
|
53
|
+
const fn = args[0];
|
|
54
|
+
return (maybe) => tapImpl(maybe, fn);
|
|
55
|
+
}
|
|
56
|
+
var tapNoneImpl = (maybe, fn) => {
|
|
57
|
+
if (isNone(maybe)) fn();
|
|
58
|
+
return maybe;
|
|
59
|
+
};
|
|
60
|
+
function tapNone(...args) {
|
|
61
|
+
if (args.length === 2) return tapNoneImpl(args[0], args[1]);
|
|
62
|
+
const fn = args[0];
|
|
63
|
+
return (maybe) => tapNoneImpl(maybe, fn);
|
|
64
|
+
}
|
|
47
65
|
|
|
48
|
-
export { andThen, compact, compactMap, flatMap, fromNullable, getOrElse, isNone, isSome, map, match, matchMaybe, none, of, optional, some, unwrap, unwrapOr };
|
|
66
|
+
export { andThen, compact, compactMap, flatMap, fromNullable, getOrElse, isNone, isSome, map, match, matchMaybe, none, of, optional, some, tap, tapNone, unwrap, unwrapOr };
|
|
49
67
|
//# sourceMappingURL=index.js.map
|
|
50
68
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/maybe.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { Maybe, None, Some } from \"./types.js\";\n\nexport type { Maybe, None, Some } from \"./types.js\";\n\n/**\n * Lifts a value into the `Some` branch.\n *\n * @example\n * ```ts\n * const m = some(1); // Maybe<number>\n * ```\n */\nexport const some = <T>(value: T): Maybe<T> => ({ _tag: \"Some\", value });\n\n/** Fantasy Land `of` — alias of {@link some}. */\nexport const of = some;\n\n/**\n * The `None` value — represents expected absence. Not a failure.\n *\n * @example\n * ```ts\n * const cached: Maybe<User> = cache.has(id) ? some(cache.get(id)) : none();\n * ```\n */\nexport const none = <T = never>(): Maybe<T> => ({ _tag: \"None\" });\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `Some`.\n *\n * @example\n * ```ts\n * if (isSome(m)) {\n * console.log(m.value); // narrowed to Some branch\n * }\n * ```\n */\nexport const isSome = <T>(maybe: Maybe<T>): maybe is Some<T> => maybe._tag === \"Some\";\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `None`.\n */\nexport const isNone = <T>(maybe: Maybe<T>): maybe is None => maybe._tag === \"None\";\n\n/**\n * Lift a nullable value into `Maybe<T>` — `null` and `undefined` become\n * `None`; anything else becomes `Some`.\n *\n * @example\n * ```ts\n * fromNullable(map.get(key)); // Maybe<V>\n * fromNullable(null); // None\n * ```\n */\nexport const fromNullable = <T>(value: T | null | undefined): Maybe<T> =>\n value == null ? none<T>() : some(value);\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Dual-form helpers — each accepts either shape:\n// data-first: `map(maybe, fn)`\n// curried: `map(fn)(maybe)`\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst mapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U> =>\n isSome(maybe) ? some(fn(maybe.value)) : none<U>();\n\n/**\n * Transform the `Some` value, passing `None` through unchanged. Dual-form.\n *\n * @example\n * ```ts\n * map(some(2), (n) => n * 3); // Some 6 — data-first\n * pipe(fromNullable(input), map((s) => s.trim())); // curried\n * ```\n */\nexport function map<T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U>;\nexport function map<T, U>(fn: (value: T) => U): (maybe: Maybe<T>) => Maybe<U>;\nexport function map(\n ...args: [Maybe<unknown>, (value: unknown) => unknown] | [(value: unknown) => unknown]\n): unknown {\n if (args.length === 2) return mapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => mapImpl(maybe, fn);\n}\n\nconst flatMapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U> =>\n isSome(maybe) ? fn(maybe.value) : none<U>();\n\n/**\n * Canonical bind for `Maybe`. Chains a `Maybe`-returning step;\n * short-circuits on `None`. Dual-form.\n *\n * @example\n * ```ts\n * flatMap(fromNullable(user), (u) =>\n * u.active ? some(u) : none(),\n * );\n * ```\n */\nexport function flatMap<T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U>;\nexport function flatMap<T, U>(fn: (value: T) => Maybe<U>): (maybe: Maybe<T>) => Maybe<U>;\nexport function flatMap(\n ...args:\n | [Maybe<unknown>, (value: unknown) => Maybe<unknown>]\n | [(value: unknown) => Maybe<unknown>]\n): unknown {\n if (args.length === 2) return flatMapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => flatMapImpl(maybe, fn);\n}\n\n/** Alias for {@link flatMap} — same dual-form shape. */\nexport const andThen = flatMap;\n\nconst matchImpl = <T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U =>\n isSome(maybe) ? onSome(maybe.value) : onNone();\n\n/**\n * Terminal collapse — fold both branches into a single value. Positional,\n * dual-form. Same shape as `Result.match` for sibling consistency.\n *\n * For files that also import `match` from `ts-pattern`, the alias\n * {@link matchMaybe} is identical.\n *\n * @example\n * ```ts\n * const greeting = match(\n * fromNullable(user),\n * (u) => `hello ${u.name}`,\n * () => \"hello guest\",\n * );\n * ```\n */\nexport function match<T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U;\nexport function match<T, U>(onSome: (value: T) => U, onNone: () => U): (maybe: Maybe<T>) => U;\nexport function match(\n ...args:\n | [Maybe<unknown>, (value: unknown) => unknown, () => unknown]\n | [(value: unknown) => unknown, () => unknown]\n): unknown {\n if (args.length === 3) return matchImpl(args[0], args[1], args[2]);\n const [onSome, onNone] = args;\n return (maybe: Maybe<unknown>) => matchImpl(maybe, onSome, onNone);\n}\n\n/** Collision-free alias — mirrors `matchResult` on `@onrails/result`. */\nexport const matchMaybe = match;\n\n/**\n * Returns the `Some` value, or `defaultValue` when the value is `None`.\n *\n * @example\n * ```ts\n * getOrElse(fromNullable(user), { name: \"guest\" });\n * ```\n */\nexport const getOrElse = <T>(maybe: Maybe<T>, defaultValue: T): T =>\n isSome(maybe) ? maybe.value : defaultValue;\n\n/** Alias — mirrors `@onrails/result` `unwrapOr`. Same as {@link getOrElse}. */\nexport const unwrapOr = getOrElse;\n\n/**\n * Unwraps the `Some` value or throws if the value is `None`. Use in tests\n * or at the boundary of an assertion; prefer `match` / `getOrElse` in\n * production code paths.\n *\n * @example\n * ```ts\n * expect(unwrap(parseUser(raw))).toEqual(expected);\n * ```\n */\nexport const unwrap = <T>(maybe: Maybe<T>): T => {\n if (isNone(maybe)) {\n throw new Error(\"Called unwrap on None\");\n }\n return maybe.value;\n};\n\n/**\n * Drop every `None` and collect the remaining `Some` values into an array.\n *\n * @example\n * ```ts\n * compact([some(1), none(), some(2)]); // [1, 2]\n * ```\n */\nexport const compact = <T>(maybes: readonly Maybe<T>[]): T[] => {\n const out: T[] = [];\n for (const m of maybes) {\n if (isSome(m)) {\n out.push(m.value);\n }\n }\n return out;\n};\n\n/**\n * `compact(items.map(fn))` — map each item to `Maybe`, drop `None`,\n * collect the rest.\n *\n * @example\n * ```ts\n * compactMap(rawRows, (row) =>\n * row.deletedAt ? none() : some(row.id),\n * );\n * // string[]\n * ```\n */\nexport const compactMap = <T, U>(items: readonly T[], fn: (item: T) => Maybe<U>): U[] =>\n compact(items.map(fn));\n\n/**\n * `flatMap(fromNullable(value), fn)` — lift a nullable then bind through\n * a `Maybe`-returning step. Convenient for chaining lookups.\n *\n * @example\n * ```ts\n * optional(rawId, (id) => fromNullable(cache.get(id)));\n * ```\n */\nexport const optional = <T, U>(value: T | null | undefined, fn: (value: T) => Maybe<U>): Maybe<U> =>\n flatMapImpl(fromNullable(value), fn);\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/maybe.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { Maybe, None, Some } from \"./types.js\";\n\nexport type { Maybe, None, Some } from \"./types.js\";\n\n/**\n * Lifts a value into the `Some` branch.\n *\n * @example\n * ```ts\n * const m = some(1); // Maybe<number>\n * ```\n */\nexport const some = <T>(value: T): Maybe<T> => ({ _tag: \"Some\", value });\n\n/**\n * Fantasy Land `of` — alias of {@link some}.\n * @deprecated Use {@link some} instead.\n */\nexport const of = some;\n\n/**\n * The `None` value — represents expected absence. Not a failure.\n *\n * @example\n * ```ts\n * const cached: Maybe<User> = cache.has(id) ? some(cache.get(id)) : none();\n * ```\n */\nexport const none = <T = never>(): Maybe<T> => ({ _tag: \"None\" });\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `Some`.\n *\n * @example\n * ```ts\n * if (isSome(m)) {\n * console.log(m.value); // narrowed to Some branch\n * }\n * ```\n */\nexport const isSome = <T>(maybe: Maybe<T>): maybe is Some<T> => maybe._tag === \"Some\";\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `None`.\n */\nexport const isNone = <T>(maybe: Maybe<T>): maybe is None => maybe._tag === \"None\";\n\n/**\n * Lift a nullable value into `Maybe<T>` — `null` and `undefined` become\n * `None`; anything else becomes `Some`.\n *\n * @example\n * ```ts\n * fromNullable(map.get(key)); // Maybe<V>\n * fromNullable(null); // None\n * ```\n */\nexport const fromNullable = <T>(value: T | null | undefined): Maybe<T> =>\n value == null ? none<T>() : some(value);\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Dual-form helpers — each accepts either shape:\n// data-first: `map(maybe, fn)`\n// curried: `map(fn)(maybe)`\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst mapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U> =>\n isSome(maybe) ? some(fn(maybe.value)) : none<U>();\n\n/**\n * Transform the `Some` value, passing `None` through unchanged. Dual-form.\n *\n * @example\n * ```ts\n * map(some(2), (n) => n * 3); // Some 6 — data-first\n * pipe(fromNullable(input), map((s) => s.trim())); // curried\n * ```\n */\nexport function map<T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U>;\nexport function map<T, U>(fn: (value: T) => U): (maybe: Maybe<T>) => Maybe<U>;\nexport function map(\n ...args: [Maybe<unknown>, (value: unknown) => unknown] | [(value: unknown) => unknown]\n): unknown {\n if (args.length === 2) return mapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => mapImpl(maybe, fn);\n}\n\nconst flatMapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U> =>\n isSome(maybe) ? fn(maybe.value) : none<U>();\n\n/**\n * Canonical bind for `Maybe`. Chains a `Maybe`-returning step;\n * short-circuits on `None`. Dual-form.\n *\n * @example\n * ```ts\n * flatMap(fromNullable(user), (u) =>\n * u.active ? some(u) : none(),\n * );\n * ```\n */\nexport function flatMap<T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U>;\nexport function flatMap<T, U>(fn: (value: T) => Maybe<U>): (maybe: Maybe<T>) => Maybe<U>;\nexport function flatMap(\n ...args:\n | [Maybe<unknown>, (value: unknown) => Maybe<unknown>]\n | [(value: unknown) => Maybe<unknown>]\n): unknown {\n if (args.length === 2) return flatMapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => flatMapImpl(maybe, fn);\n}\n\n/** Alias for {@link flatMap} — same dual-form shape. */\nexport const andThen = flatMap;\n\nconst matchImpl = <T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U =>\n isSome(maybe) ? onSome(maybe.value) : onNone();\n\n/**\n * Terminal collapse — fold both branches into a single value. Positional,\n * dual-form. Same shape as `Result.match` for sibling consistency.\n *\n * For files that also import `match` from `ts-pattern`, the alias\n * {@link matchMaybe} is identical.\n *\n * @example\n * ```ts\n * const greeting = match(\n * fromNullable(user),\n * (u) => `hello ${u.name}`,\n * () => \"hello guest\",\n * );\n * ```\n */\nexport function match<T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U;\nexport function match<T, U>(onSome: (value: T) => U, onNone: () => U): (maybe: Maybe<T>) => U;\nexport function match(\n ...args:\n | [Maybe<unknown>, (value: unknown) => unknown, () => unknown]\n | [(value: unknown) => unknown, () => unknown]\n): unknown {\n if (args.length === 3) return matchImpl(args[0], args[1], args[2]);\n const [onSome, onNone] = args;\n return (maybe: Maybe<unknown>) => matchImpl(maybe, onSome, onNone);\n}\n\n/**\n * Collision-free alias — mirrors `matchResult` on `@onrails/result`.\n * @deprecated Namespace import carriers (e.g., `import * as Maybe from \"@onrails/maybe\"`) and use canonical {@link match} instead.\n */\nexport const matchMaybe = match;\n\n/**\n * Returns the `Some` value, or `defaultValue` when the value is `None`.\n *\n * @example\n * ```ts\n * unwrapOr(fromNullable(user), { name: \"guest\" });\n * ```\n */\nexport const unwrapOr = <T>(maybe: Maybe<T>, defaultValue: T): T =>\n isSome(maybe) ? maybe.value : defaultValue;\n\n/**\n * Returns the `Some` value, or `defaultValue` when the value is `None`.\n *\n * @deprecated Use canonical {@link unwrapOr} instead.\n */\nexport const getOrElse = unwrapOr;\n\n/**\n * Unwraps the `Some` value or throws if the value is `None`.\n *\n * @throws when the value is None — assertion-tier; use {@link match} / {@link unwrapOr} in business logic.\n * Allowed in `*.spec.ts` / `*.test.ts`; flagged elsewhere by the plugins.\n *\n * @example\n * ```ts\n * expect(unwrap(parseUser(raw))).toEqual(expected);\n * ```\n */\nexport const unwrap = <T>(maybe: Maybe<T>): T => {\n if (isNone(maybe)) {\n throw new Error(\"Called unwrap on None\");\n }\n return maybe.value;\n};\n\n/**\n * Drop every `None` and collect the remaining `Some` values into an array.\n *\n * @example\n * ```ts\n * compact([some(1), none(), some(2)]); // [1, 2]\n * ```\n */\nexport const compact = <T>(maybes: readonly Maybe<T>[]): T[] => {\n const out: T[] = [];\n for (const m of maybes) {\n if (isSome(m)) {\n out.push(m.value);\n }\n }\n return out;\n};\n\n/**\n * `compact(items.map(fn))` — map each item to `Maybe`, drop `None`,\n * collect the rest.\n *\n * @example\n * ```ts\n * compactMap(rawRows, (row) =>\n * row.deletedAt ? none() : some(row.id),\n * );\n * // string[]\n * ```\n */\nexport const compactMap = <T, U>(items: readonly T[], fn: (item: T) => Maybe<U>): U[] =>\n compact(items.map(fn));\n\n/**\n * `flatMap(fromNullable(value), fn)` — lift a nullable then bind through\n * a `Maybe`-returning step. Convenient for chaining lookups.\n *\n * @example\n * ```ts\n * optional(rawId, (id) => fromNullable(cache.get(id)));\n * ```\n */\nexport const optional = <T, U>(value: T | null | undefined, fn: (value: T) => Maybe<U>): Maybe<U> =>\n flatMapImpl(fromNullable(value), fn);\n\nconst tapImpl = <T>(maybe: Maybe<T>, fn: (value: T) => void): Maybe<T> => {\n if (isSome(maybe)) fn(maybe.value);\n return maybe;\n};\n\n/**\n * Run a side effect on the `Some` value, pass the `Maybe` through unchanged.\n * `None` is a no-op. Mirrors `tap` from `@onrails/result`. Dual-form.\n *\n * @example\n * ```ts\n * tap(some(2), (n) => console.log(n)); // logs 2, returns Some 2\n * pipe(fromNullable(row), tap((r) => sink.push(r))); // curried — collect on Some\n * ```\n */\nexport function tap<T>(maybe: Maybe<T>, fn: (value: T) => void): Maybe<T>;\nexport function tap<T>(fn: (value: T) => void): (maybe: Maybe<T>) => Maybe<T>;\nexport function tap(\n ...args: [Maybe<unknown>, (value: unknown) => void] | [(value: unknown) => void]\n): unknown {\n if (args.length === 2) return tapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => tapImpl(maybe, fn);\n}\n\nconst tapNoneImpl = <T>(maybe: Maybe<T>, fn: () => void): Maybe<T> => {\n if (isNone(maybe)) fn();\n return maybe;\n};\n\n/**\n * Run a side effect when the `Maybe` is `None`, pass it through unchanged.\n * `Some` is a no-op. The `None`-side mirror of {@link tap}. Dual-form.\n *\n * @example\n * ```ts\n * tapNone(none(), () => metrics.miss()); // runs effect, returns None\n * pipe(fromNullable(hit), tapNone(() => metrics.miss())); // curried\n * ```\n */\nexport function tapNone<T>(maybe: Maybe<T>, fn: () => void): Maybe<T>;\nexport function tapNone<T>(fn: () => void): (maybe: Maybe<T>) => Maybe<T>;\nexport function tapNone(...args: [Maybe<unknown>, () => void] | [() => void]): unknown {\n if (args.length === 2) return tapNoneImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => tapNoneImpl(maybe, fn);\n}\n"]}
|
package/dist/interop.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/maybe.ts","../src/interop.ts"],"names":["ok","err","result","isOk"],"mappings":";;;;;;;AAYO,IAAM,OAAO,CAAI,KAAA,MAAwB,EAAE,IAAA,EAAM,QAAQ,KAAA,EAAM,CAAA;AAa/D,IAAM,IAAA,GAAO,OAA4B,EAAE,IAAA,EAAM,MAAA,EAAO,CAAA;AAYxD,IAAM,MAAA,GAAS,CAAI,KAAA,KAAsC,KAAA,CAAM,IAAA,KAAS,MAAA;AAiBxE,IAAM,YAAA,GAAe,CAAI,KAAA,KAC9B,KAAA,IAAS,OAAO,IAAA,EAAQ,GAAI,KAAK,KAAK,CAAA;;;ACjDjC,IAAM,SAAA,GAAY,OAAkB,EAAE,IAAA,EAAM,MAAA,EAAO;AAGnD,IAAM,QAAA,GAAW,CAAO,KAAA,EAAiB,MAAA,KAC9C,MAAA,CAAO,KAAK,CAAA,GAAIA,SAAA,CAAG,KAAA,CAAM,KAAK,CAAA,GAAIC,UAAA,CAAI,QAAQ;AAGzC,IAAM,UAAA,GAAa,CAAOC,QAAA,KAC/BC,WAAA,CAAKD,QAAM,IAAI,IAAA,CAAKA,QAAA,CAAO,KAAK,CAAA,GAAI,IAAA;AAG/B,IAAM,gBAAA,GAAmB,CAC9B,KAAA,EACA,MAAA,KACiB,SAAS,YAAA,CAAa,KAAK,GAAG,MAAM;AAGhD,IAAM,WAAA,GAAc,CAACA,QAAA,KAC1B,CAACC,YAAKD,QAAM,CAAA,IAAK,gBAAA,CAAiBA,QAAA,CAAO,KAAK;AAEhD,IAAM,gBAAA,GAAmB,CAAC,KAAA,KACxB,OAAO,KAAA,KAAU,QAAA,IACjB,KAAA,KAAU,IAAA,IACV,MAAA,IAAU,KAAA,IACT,KAAA,CAA4B,IAAA,KAAS,MAAA","file":"interop.cjs","sourcesContent":["import type { Maybe, None, Some } from \"./types.js\";\n\nexport type { Maybe, None, Some } from \"./types.js\";\n\n/**\n * Lifts a value into the `Some` branch.\n *\n * @example\n * ```ts\n * const m = some(1); // Maybe<number>\n * ```\n */\nexport const some = <T>(value: T): Maybe<T> => ({ _tag: \"Some\", value });\n\n/** Fantasy Land `of` — alias of {@link some}. */\nexport const of = some;\n\n/**\n * The `None` value — represents expected absence. Not a failure.\n *\n * @example\n * ```ts\n * const cached: Maybe<User> = cache.has(id) ? some(cache.get(id)) : none();\n * ```\n */\nexport const none = <T = never>(): Maybe<T> => ({ _tag: \"None\" });\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `Some`.\n *\n * @example\n * ```ts\n * if (isSome(m)) {\n * console.log(m.value); // narrowed to Some branch\n * }\n * ```\n */\nexport const isSome = <T>(maybe: Maybe<T>): maybe is Some<T> => maybe._tag === \"Some\";\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `None`.\n */\nexport const isNone = <T>(maybe: Maybe<T>): maybe is None => maybe._tag === \"None\";\n\n/**\n * Lift a nullable value into `Maybe<T>` — `null` and `undefined` become\n * `None`; anything else becomes `Some`.\n *\n * @example\n * ```ts\n * fromNullable(map.get(key)); // Maybe<V>\n * fromNullable(null); // None\n * ```\n */\nexport const fromNullable = <T>(value: T | null | undefined): Maybe<T> =>\n value == null ? none<T>() : some(value);\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Dual-form helpers — each accepts either shape:\n// data-first: `map(maybe, fn)`\n// curried: `map(fn)(maybe)`\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst mapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U> =>\n isSome(maybe) ? some(fn(maybe.value)) : none<U>();\n\n/**\n * Transform the `Some` value, passing `None` through unchanged. Dual-form.\n *\n * @example\n * ```ts\n * map(some(2), (n) => n * 3); // Some 6 — data-first\n * pipe(fromNullable(input), map((s) => s.trim())); // curried\n * ```\n */\nexport function map<T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U>;\nexport function map<T, U>(fn: (value: T) => U): (maybe: Maybe<T>) => Maybe<U>;\nexport function map(\n ...args: [Maybe<unknown>, (value: unknown) => unknown] | [(value: unknown) => unknown]\n): unknown {\n if (args.length === 2) return mapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => mapImpl(maybe, fn);\n}\n\nconst flatMapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U> =>\n isSome(maybe) ? fn(maybe.value) : none<U>();\n\n/**\n * Canonical bind for `Maybe`. Chains a `Maybe`-returning step;\n * short-circuits on `None`. Dual-form.\n *\n * @example\n * ```ts\n * flatMap(fromNullable(user), (u) =>\n * u.active ? some(u) : none(),\n * );\n * ```\n */\nexport function flatMap<T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U>;\nexport function flatMap<T, U>(fn: (value: T) => Maybe<U>): (maybe: Maybe<T>) => Maybe<U>;\nexport function flatMap(\n ...args:\n | [Maybe<unknown>, (value: unknown) => Maybe<unknown>]\n | [(value: unknown) => Maybe<unknown>]\n): unknown {\n if (args.length === 2) return flatMapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => flatMapImpl(maybe, fn);\n}\n\n/** Alias for {@link flatMap} — same dual-form shape. */\nexport const andThen = flatMap;\n\nconst matchImpl = <T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U =>\n isSome(maybe) ? onSome(maybe.value) : onNone();\n\n/**\n * Terminal collapse — fold both branches into a single value. Positional,\n * dual-form. Same shape as `Result.match` for sibling consistency.\n *\n * For files that also import `match` from `ts-pattern`, the alias\n * {@link matchMaybe} is identical.\n *\n * @example\n * ```ts\n * const greeting = match(\n * fromNullable(user),\n * (u) => `hello ${u.name}`,\n * () => \"hello guest\",\n * );\n * ```\n */\nexport function match<T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U;\nexport function match<T, U>(onSome: (value: T) => U, onNone: () => U): (maybe: Maybe<T>) => U;\nexport function match(\n ...args:\n | [Maybe<unknown>, (value: unknown) => unknown, () => unknown]\n | [(value: unknown) => unknown, () => unknown]\n): unknown {\n if (args.length === 3) return matchImpl(args[0], args[1], args[2]);\n const [onSome, onNone] = args;\n return (maybe: Maybe<unknown>) => matchImpl(maybe, onSome, onNone);\n}\n\n/** Collision-free alias — mirrors `matchResult` on `@onrails/result`. */\nexport const matchMaybe = match;\n\n/**\n * Returns the `Some` value, or `defaultValue` when the value is `None`.\n *\n * @example\n * ```ts\n * getOrElse(fromNullable(user), { name: \"guest\" });\n * ```\n */\nexport const getOrElse = <T>(maybe: Maybe<T>, defaultValue: T): T =>\n isSome(maybe) ? maybe.value : defaultValue;\n\n/** Alias — mirrors `@onrails/result` `unwrapOr`. Same as {@link getOrElse}. */\nexport const unwrapOr = getOrElse;\n\n/**\n * Unwraps the `Some` value or throws if the value is `None`. Use in tests\n * or at the boundary of an assertion; prefer `match` / `getOrElse` in\n * production code paths.\n *\n * @example\n * ```ts\n * expect(unwrap(parseUser(raw))).toEqual(expected);\n * ```\n */\nexport const unwrap = <T>(maybe: Maybe<T>): T => {\n if (isNone(maybe)) {\n throw new Error(\"Called unwrap on None\");\n }\n return maybe.value;\n};\n\n/**\n * Drop every `None` and collect the remaining `Some` values into an array.\n *\n * @example\n * ```ts\n * compact([some(1), none(), some(2)]); // [1, 2]\n * ```\n */\nexport const compact = <T>(maybes: readonly Maybe<T>[]): T[] => {\n const out: T[] = [];\n for (const m of maybes) {\n if (isSome(m)) {\n out.push(m.value);\n }\n }\n return out;\n};\n\n/**\n * `compact(items.map(fn))` — map each item to `Maybe`, drop `None`,\n * collect the rest.\n *\n * @example\n * ```ts\n * compactMap(rawRows, (row) =>\n * row.deletedAt ? none() : some(row.id),\n * );\n * // string[]\n * ```\n */\nexport const compactMap = <T, U>(items: readonly T[], fn: (item: T) => Maybe<U>): U[] =>\n compact(items.map(fn));\n\n/**\n * `flatMap(fromNullable(value), fn)` — lift a nullable then bind through\n * a `Maybe`-returning step. Convenient for chaining lookups.\n *\n * @example\n * ```ts\n * optional(rawId, (id) => fromNullable(cache.get(id)));\n * ```\n */\nexport const optional = <T, U>(value: T | null | undefined, fn: (value: T) => Maybe<U>): Maybe<U> =>\n flatMapImpl(fromNullable(value), fn);\n","import { err, isOk, ok, type Result } from \"@onrails/result\";\nimport { fromNullable, isSome, type Maybe, none, some } from \"./maybe.js\";\n\n/** Sentinel error tag — `Maybe<T>` bridges to `Result<T, NoneError>`. */\nexport type NoneError = { readonly _tag: \"None\" };\n\nexport const noneError = (): NoneError => ({ _tag: \"None\" });\n\n/** Lift absence into a domain error. */\nexport const toResult = <T, E>(maybe: Maybe<T>, onNone: () => E): Result<T, E> =>\n isSome(maybe) ? ok(maybe.value) : err(onNone());\n\n/** Ok values become Some; any Err becomes None (errors are not absence). */\nexport const fromResult = <T, E>(result: Result<T, E>): Maybe<T> =>\n isOk(result) ? some(result.value) : none<T>();\n\n/** Nullable edge → Maybe; explicit None error at the boundary. */\nexport const nullableToResult = <T, E>(\n value: T | null | undefined,\n onNone: () => E,\n): Result<T, E> => toResult(fromNullable(value), onNone);\n\n/** True when a Result failed specifically with {@link NoneError}. */\nexport const isNoneError = (result: Result<unknown, unknown>): result is Result<never, NoneError> =>\n !isOk(result) && isNoneErrorValue(result.error);\n\nconst isNoneErrorValue = (error: unknown): error is NoneError =>\n typeof error === \"object\" &&\n error !== null &&\n \"_tag\" in error &&\n (error as { _tag: unknown })._tag === \"None\";\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/maybe.ts","../src/interop.ts"],"names":["ok","err","result","isOk"],"mappings":";;;;;;;AAYO,IAAM,OAAO,CAAI,KAAA,MAAwB,EAAE,IAAA,EAAM,QAAQ,KAAA,EAAM,CAAA;AAgB/D,IAAM,IAAA,GAAO,OAA4B,EAAE,IAAA,EAAM,MAAA,EAAO,CAAA;AAYxD,IAAM,MAAA,GAAS,CAAI,KAAA,KAAsC,KAAA,CAAM,IAAA,KAAS,MAAA;AAiBxE,IAAM,YAAA,GAAe,CAAI,KAAA,KAC9B,KAAA,IAAS,OAAO,IAAA,EAAQ,GAAI,KAAK,KAAK,CAAA;;;ACpDjC,IAAM,SAAA,GAAY,OAAkB,EAAE,IAAA,EAAM,MAAA,EAAO;AAGnD,IAAM,QAAA,GAAW,CAAO,KAAA,EAAiB,MAAA,KAC9C,MAAA,CAAO,KAAK,CAAA,GAAIA,SAAA,CAAG,KAAA,CAAM,KAAK,CAAA,GAAIC,UAAA,CAAI,QAAQ;AAGzC,IAAM,UAAA,GAAa,CAAOC,QAAA,KAC/BC,WAAA,CAAKD,QAAM,IAAI,IAAA,CAAKA,QAAA,CAAO,KAAK,CAAA,GAAI,IAAA;AAG/B,IAAM,gBAAA,GAAmB,CAC9B,KAAA,EACA,MAAA,KACiB,SAAS,YAAA,CAAa,KAAK,GAAG,MAAM;AAGhD,IAAM,WAAA,GAAc,CAACA,QAAA,KAC1B,CAACC,YAAKD,QAAM,CAAA,IAAK,gBAAA,CAAiBA,QAAA,CAAO,KAAK;AAEhD,IAAM,gBAAA,GAAmB,CAAC,KAAA,KACxB,OAAO,KAAA,KAAU,QAAA,IACjB,KAAA,KAAU,IAAA,IACV,MAAA,IAAU,KAAA,IACT,KAAA,CAA4B,IAAA,KAAS,MAAA","file":"interop.cjs","sourcesContent":["import type { Maybe, None, Some } from \"./types.js\";\n\nexport type { Maybe, None, Some } from \"./types.js\";\n\n/**\n * Lifts a value into the `Some` branch.\n *\n * @example\n * ```ts\n * const m = some(1); // Maybe<number>\n * ```\n */\nexport const some = <T>(value: T): Maybe<T> => ({ _tag: \"Some\", value });\n\n/**\n * Fantasy Land `of` — alias of {@link some}.\n * @deprecated Use {@link some} instead.\n */\nexport const of = some;\n\n/**\n * The `None` value — represents expected absence. Not a failure.\n *\n * @example\n * ```ts\n * const cached: Maybe<User> = cache.has(id) ? some(cache.get(id)) : none();\n * ```\n */\nexport const none = <T = never>(): Maybe<T> => ({ _tag: \"None\" });\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `Some`.\n *\n * @example\n * ```ts\n * if (isSome(m)) {\n * console.log(m.value); // narrowed to Some branch\n * }\n * ```\n */\nexport const isSome = <T>(maybe: Maybe<T>): maybe is Some<T> => maybe._tag === \"Some\";\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `None`.\n */\nexport const isNone = <T>(maybe: Maybe<T>): maybe is None => maybe._tag === \"None\";\n\n/**\n * Lift a nullable value into `Maybe<T>` — `null` and `undefined` become\n * `None`; anything else becomes `Some`.\n *\n * @example\n * ```ts\n * fromNullable(map.get(key)); // Maybe<V>\n * fromNullable(null); // None\n * ```\n */\nexport const fromNullable = <T>(value: T | null | undefined): Maybe<T> =>\n value == null ? none<T>() : some(value);\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Dual-form helpers — each accepts either shape:\n// data-first: `map(maybe, fn)`\n// curried: `map(fn)(maybe)`\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst mapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U> =>\n isSome(maybe) ? some(fn(maybe.value)) : none<U>();\n\n/**\n * Transform the `Some` value, passing `None` through unchanged. Dual-form.\n *\n * @example\n * ```ts\n * map(some(2), (n) => n * 3); // Some 6 — data-first\n * pipe(fromNullable(input), map((s) => s.trim())); // curried\n * ```\n */\nexport function map<T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U>;\nexport function map<T, U>(fn: (value: T) => U): (maybe: Maybe<T>) => Maybe<U>;\nexport function map(\n ...args: [Maybe<unknown>, (value: unknown) => unknown] | [(value: unknown) => unknown]\n): unknown {\n if (args.length === 2) return mapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => mapImpl(maybe, fn);\n}\n\nconst flatMapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U> =>\n isSome(maybe) ? fn(maybe.value) : none<U>();\n\n/**\n * Canonical bind for `Maybe`. Chains a `Maybe`-returning step;\n * short-circuits on `None`. Dual-form.\n *\n * @example\n * ```ts\n * flatMap(fromNullable(user), (u) =>\n * u.active ? some(u) : none(),\n * );\n * ```\n */\nexport function flatMap<T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U>;\nexport function flatMap<T, U>(fn: (value: T) => Maybe<U>): (maybe: Maybe<T>) => Maybe<U>;\nexport function flatMap(\n ...args:\n | [Maybe<unknown>, (value: unknown) => Maybe<unknown>]\n | [(value: unknown) => Maybe<unknown>]\n): unknown {\n if (args.length === 2) return flatMapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => flatMapImpl(maybe, fn);\n}\n\n/** Alias for {@link flatMap} — same dual-form shape. */\nexport const andThen = flatMap;\n\nconst matchImpl = <T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U =>\n isSome(maybe) ? onSome(maybe.value) : onNone();\n\n/**\n * Terminal collapse — fold both branches into a single value. Positional,\n * dual-form. Same shape as `Result.match` for sibling consistency.\n *\n * For files that also import `match` from `ts-pattern`, the alias\n * {@link matchMaybe} is identical.\n *\n * @example\n * ```ts\n * const greeting = match(\n * fromNullable(user),\n * (u) => `hello ${u.name}`,\n * () => \"hello guest\",\n * );\n * ```\n */\nexport function match<T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U;\nexport function match<T, U>(onSome: (value: T) => U, onNone: () => U): (maybe: Maybe<T>) => U;\nexport function match(\n ...args:\n | [Maybe<unknown>, (value: unknown) => unknown, () => unknown]\n | [(value: unknown) => unknown, () => unknown]\n): unknown {\n if (args.length === 3) return matchImpl(args[0], args[1], args[2]);\n const [onSome, onNone] = args;\n return (maybe: Maybe<unknown>) => matchImpl(maybe, onSome, onNone);\n}\n\n/**\n * Collision-free alias — mirrors `matchResult` on `@onrails/result`.\n * @deprecated Namespace import carriers (e.g., `import * as Maybe from \"@onrails/maybe\"`) and use canonical {@link match} instead.\n */\nexport const matchMaybe = match;\n\n/**\n * Returns the `Some` value, or `defaultValue` when the value is `None`.\n *\n * @example\n * ```ts\n * unwrapOr(fromNullable(user), { name: \"guest\" });\n * ```\n */\nexport const unwrapOr = <T>(maybe: Maybe<T>, defaultValue: T): T =>\n isSome(maybe) ? maybe.value : defaultValue;\n\n/**\n * Returns the `Some` value, or `defaultValue` when the value is `None`.\n *\n * @deprecated Use canonical {@link unwrapOr} instead.\n */\nexport const getOrElse = unwrapOr;\n\n/**\n * Unwraps the `Some` value or throws if the value is `None`.\n *\n * @throws when the value is None — assertion-tier; use {@link match} / {@link unwrapOr} in business logic.\n * Allowed in `*.spec.ts` / `*.test.ts`; flagged elsewhere by the plugins.\n *\n * @example\n * ```ts\n * expect(unwrap(parseUser(raw))).toEqual(expected);\n * ```\n */\nexport const unwrap = <T>(maybe: Maybe<T>): T => {\n if (isNone(maybe)) {\n throw new Error(\"Called unwrap on None\");\n }\n return maybe.value;\n};\n\n/**\n * Drop every `None` and collect the remaining `Some` values into an array.\n *\n * @example\n * ```ts\n * compact([some(1), none(), some(2)]); // [1, 2]\n * ```\n */\nexport const compact = <T>(maybes: readonly Maybe<T>[]): T[] => {\n const out: T[] = [];\n for (const m of maybes) {\n if (isSome(m)) {\n out.push(m.value);\n }\n }\n return out;\n};\n\n/**\n * `compact(items.map(fn))` — map each item to `Maybe`, drop `None`,\n * collect the rest.\n *\n * @example\n * ```ts\n * compactMap(rawRows, (row) =>\n * row.deletedAt ? none() : some(row.id),\n * );\n * // string[]\n * ```\n */\nexport const compactMap = <T, U>(items: readonly T[], fn: (item: T) => Maybe<U>): U[] =>\n compact(items.map(fn));\n\n/**\n * `flatMap(fromNullable(value), fn)` — lift a nullable then bind through\n * a `Maybe`-returning step. Convenient for chaining lookups.\n *\n * @example\n * ```ts\n * optional(rawId, (id) => fromNullable(cache.get(id)));\n * ```\n */\nexport const optional = <T, U>(value: T | null | undefined, fn: (value: T) => Maybe<U>): Maybe<U> =>\n flatMapImpl(fromNullable(value), fn);\n\nconst tapImpl = <T>(maybe: Maybe<T>, fn: (value: T) => void): Maybe<T> => {\n if (isSome(maybe)) fn(maybe.value);\n return maybe;\n};\n\n/**\n * Run a side effect on the `Some` value, pass the `Maybe` through unchanged.\n * `None` is a no-op. Mirrors `tap` from `@onrails/result`. Dual-form.\n *\n * @example\n * ```ts\n * tap(some(2), (n) => console.log(n)); // logs 2, returns Some 2\n * pipe(fromNullable(row), tap((r) => sink.push(r))); // curried — collect on Some\n * ```\n */\nexport function tap<T>(maybe: Maybe<T>, fn: (value: T) => void): Maybe<T>;\nexport function tap<T>(fn: (value: T) => void): (maybe: Maybe<T>) => Maybe<T>;\nexport function tap(\n ...args: [Maybe<unknown>, (value: unknown) => void] | [(value: unknown) => void]\n): unknown {\n if (args.length === 2) return tapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => tapImpl(maybe, fn);\n}\n\nconst tapNoneImpl = <T>(maybe: Maybe<T>, fn: () => void): Maybe<T> => {\n if (isNone(maybe)) fn();\n return maybe;\n};\n\n/**\n * Run a side effect when the `Maybe` is `None`, pass it through unchanged.\n * `Some` is a no-op. The `None`-side mirror of {@link tap}. Dual-form.\n *\n * @example\n * ```ts\n * tapNone(none(), () => metrics.miss()); // runs effect, returns None\n * pipe(fromNullable(hit), tapNone(() => metrics.miss())); // curried\n * ```\n */\nexport function tapNone<T>(maybe: Maybe<T>, fn: () => void): Maybe<T>;\nexport function tapNone<T>(fn: () => void): (maybe: Maybe<T>) => Maybe<T>;\nexport function tapNone(...args: [Maybe<unknown>, () => void] | [() => void]): unknown {\n if (args.length === 2) return tapNoneImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => tapNoneImpl(maybe, fn);\n}\n","import { err, isOk, ok, type Result } from \"@onrails/result\";\nimport { fromNullable, isSome, type Maybe, none, some } from \"./maybe.js\";\n\n/** Sentinel error tag — `Maybe<T>` bridges to `Result<T, NoneError>`. */\nexport type NoneError = { readonly _tag: \"None\" };\n\nexport const noneError = (): NoneError => ({ _tag: \"None\" });\n\n/** Lift absence into a domain error. */\nexport const toResult = <T, E>(maybe: Maybe<T>, onNone: () => E): Result<T, E> =>\n isSome(maybe) ? ok(maybe.value) : err(onNone());\n\n/** Ok values become Some; any Err becomes None (errors are not absence). */\nexport const fromResult = <T, E>(result: Result<T, E>): Maybe<T> =>\n isOk(result) ? some(result.value) : none<T>();\n\n/** Nullable edge → Maybe; explicit None error at the boundary. */\nexport const nullableToResult = <T, E>(\n value: T | null | undefined,\n onNone: () => E,\n): Result<T, E> => toResult(fromNullable(value), onNone);\n\n/** True when a Result failed specifically with {@link NoneError}. */\nexport const isNoneError = (result: Result<unknown, unknown>): result is Result<never, NoneError> =>\n !isOk(result) && isNoneErrorValue(result.error);\n\nconst isNoneErrorValue = (error: unknown): error is NoneError =>\n typeof error === \"object\" &&\n error !== null &&\n \"_tag\" in error &&\n (error as { _tag: unknown })._tag === \"None\";\n"]}
|
package/dist/interop.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/maybe.ts","../src/interop.ts"],"names":[],"mappings":";;;;;AAYO,IAAM,OAAO,CAAI,KAAA,MAAwB,EAAE,IAAA,EAAM,QAAQ,KAAA,EAAM,CAAA;AAa/D,IAAM,IAAA,GAAO,OAA4B,EAAE,IAAA,EAAM,MAAA,EAAO,CAAA;AAYxD,IAAM,MAAA,GAAS,CAAI,KAAA,KAAsC,KAAA,CAAM,IAAA,KAAS,MAAA;AAiBxE,IAAM,YAAA,GAAe,CAAI,KAAA,KAC9B,KAAA,IAAS,OAAO,IAAA,EAAQ,GAAI,KAAK,KAAK,CAAA;;;ACjDjC,IAAM,SAAA,GAAY,OAAkB,EAAE,IAAA,EAAM,MAAA,EAAO;AAGnD,IAAM,QAAA,GAAW,CAAO,KAAA,EAAiB,MAAA,KAC9C,MAAA,CAAO,KAAK,CAAA,GAAI,EAAA,CAAG,KAAA,CAAM,KAAK,CAAA,GAAI,GAAA,CAAI,QAAQ;AAGzC,IAAM,UAAA,GAAa,CAAO,MAAA,KAC/B,IAAA,CAAK,MAAM,IAAI,IAAA,CAAK,MAAA,CAAO,KAAK,CAAA,GAAI,IAAA;AAG/B,IAAM,gBAAA,GAAmB,CAC9B,KAAA,EACA,MAAA,KACiB,SAAS,YAAA,CAAa,KAAK,GAAG,MAAM;AAGhD,IAAM,WAAA,GAAc,CAAC,MAAA,KAC1B,CAAC,KAAK,MAAM,CAAA,IAAK,gBAAA,CAAiB,MAAA,CAAO,KAAK;AAEhD,IAAM,gBAAA,GAAmB,CAAC,KAAA,KACxB,OAAO,KAAA,KAAU,QAAA,IACjB,KAAA,KAAU,IAAA,IACV,MAAA,IAAU,KAAA,IACT,KAAA,CAA4B,IAAA,KAAS,MAAA","file":"interop.js","sourcesContent":["import type { Maybe, None, Some } from \"./types.js\";\n\nexport type { Maybe, None, Some } from \"./types.js\";\n\n/**\n * Lifts a value into the `Some` branch.\n *\n * @example\n * ```ts\n * const m = some(1); // Maybe<number>\n * ```\n */\nexport const some = <T>(value: T): Maybe<T> => ({ _tag: \"Some\", value });\n\n/** Fantasy Land `of` — alias of {@link some}. */\nexport const of = some;\n\n/**\n * The `None` value — represents expected absence. Not a failure.\n *\n * @example\n * ```ts\n * const cached: Maybe<User> = cache.has(id) ? some(cache.get(id)) : none();\n * ```\n */\nexport const none = <T = never>(): Maybe<T> => ({ _tag: \"None\" });\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `Some`.\n *\n * @example\n * ```ts\n * if (isSome(m)) {\n * console.log(m.value); // narrowed to Some branch\n * }\n * ```\n */\nexport const isSome = <T>(maybe: Maybe<T>): maybe is Some<T> => maybe._tag === \"Some\";\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `None`.\n */\nexport const isNone = <T>(maybe: Maybe<T>): maybe is None => maybe._tag === \"None\";\n\n/**\n * Lift a nullable value into `Maybe<T>` — `null` and `undefined` become\n * `None`; anything else becomes `Some`.\n *\n * @example\n * ```ts\n * fromNullable(map.get(key)); // Maybe<V>\n * fromNullable(null); // None\n * ```\n */\nexport const fromNullable = <T>(value: T | null | undefined): Maybe<T> =>\n value == null ? none<T>() : some(value);\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Dual-form helpers — each accepts either shape:\n// data-first: `map(maybe, fn)`\n// curried: `map(fn)(maybe)`\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst mapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U> =>\n isSome(maybe) ? some(fn(maybe.value)) : none<U>();\n\n/**\n * Transform the `Some` value, passing `None` through unchanged. Dual-form.\n *\n * @example\n * ```ts\n * map(some(2), (n) => n * 3); // Some 6 — data-first\n * pipe(fromNullable(input), map((s) => s.trim())); // curried\n * ```\n */\nexport function map<T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U>;\nexport function map<T, U>(fn: (value: T) => U): (maybe: Maybe<T>) => Maybe<U>;\nexport function map(\n ...args: [Maybe<unknown>, (value: unknown) => unknown] | [(value: unknown) => unknown]\n): unknown {\n if (args.length === 2) return mapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => mapImpl(maybe, fn);\n}\n\nconst flatMapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U> =>\n isSome(maybe) ? fn(maybe.value) : none<U>();\n\n/**\n * Canonical bind for `Maybe`. Chains a `Maybe`-returning step;\n * short-circuits on `None`. Dual-form.\n *\n * @example\n * ```ts\n * flatMap(fromNullable(user), (u) =>\n * u.active ? some(u) : none(),\n * );\n * ```\n */\nexport function flatMap<T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U>;\nexport function flatMap<T, U>(fn: (value: T) => Maybe<U>): (maybe: Maybe<T>) => Maybe<U>;\nexport function flatMap(\n ...args:\n | [Maybe<unknown>, (value: unknown) => Maybe<unknown>]\n | [(value: unknown) => Maybe<unknown>]\n): unknown {\n if (args.length === 2) return flatMapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => flatMapImpl(maybe, fn);\n}\n\n/** Alias for {@link flatMap} — same dual-form shape. */\nexport const andThen = flatMap;\n\nconst matchImpl = <T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U =>\n isSome(maybe) ? onSome(maybe.value) : onNone();\n\n/**\n * Terminal collapse — fold both branches into a single value. Positional,\n * dual-form. Same shape as `Result.match` for sibling consistency.\n *\n * For files that also import `match` from `ts-pattern`, the alias\n * {@link matchMaybe} is identical.\n *\n * @example\n * ```ts\n * const greeting = match(\n * fromNullable(user),\n * (u) => `hello ${u.name}`,\n * () => \"hello guest\",\n * );\n * ```\n */\nexport function match<T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U;\nexport function match<T, U>(onSome: (value: T) => U, onNone: () => U): (maybe: Maybe<T>) => U;\nexport function match(\n ...args:\n | [Maybe<unknown>, (value: unknown) => unknown, () => unknown]\n | [(value: unknown) => unknown, () => unknown]\n): unknown {\n if (args.length === 3) return matchImpl(args[0], args[1], args[2]);\n const [onSome, onNone] = args;\n return (maybe: Maybe<unknown>) => matchImpl(maybe, onSome, onNone);\n}\n\n/** Collision-free alias — mirrors `matchResult` on `@onrails/result`. */\nexport const matchMaybe = match;\n\n/**\n * Returns the `Some` value, or `defaultValue` when the value is `None`.\n *\n * @example\n * ```ts\n * getOrElse(fromNullable(user), { name: \"guest\" });\n * ```\n */\nexport const getOrElse = <T>(maybe: Maybe<T>, defaultValue: T): T =>\n isSome(maybe) ? maybe.value : defaultValue;\n\n/** Alias — mirrors `@onrails/result` `unwrapOr`. Same as {@link getOrElse}. */\nexport const unwrapOr = getOrElse;\n\n/**\n * Unwraps the `Some` value or throws if the value is `None`. Use in tests\n * or at the boundary of an assertion; prefer `match` / `getOrElse` in\n * production code paths.\n *\n * @example\n * ```ts\n * expect(unwrap(parseUser(raw))).toEqual(expected);\n * ```\n */\nexport const unwrap = <T>(maybe: Maybe<T>): T => {\n if (isNone(maybe)) {\n throw new Error(\"Called unwrap on None\");\n }\n return maybe.value;\n};\n\n/**\n * Drop every `None` and collect the remaining `Some` values into an array.\n *\n * @example\n * ```ts\n * compact([some(1), none(), some(2)]); // [1, 2]\n * ```\n */\nexport const compact = <T>(maybes: readonly Maybe<T>[]): T[] => {\n const out: T[] = [];\n for (const m of maybes) {\n if (isSome(m)) {\n out.push(m.value);\n }\n }\n return out;\n};\n\n/**\n * `compact(items.map(fn))` — map each item to `Maybe`, drop `None`,\n * collect the rest.\n *\n * @example\n * ```ts\n * compactMap(rawRows, (row) =>\n * row.deletedAt ? none() : some(row.id),\n * );\n * // string[]\n * ```\n */\nexport const compactMap = <T, U>(items: readonly T[], fn: (item: T) => Maybe<U>): U[] =>\n compact(items.map(fn));\n\n/**\n * `flatMap(fromNullable(value), fn)` — lift a nullable then bind through\n * a `Maybe`-returning step. Convenient for chaining lookups.\n *\n * @example\n * ```ts\n * optional(rawId, (id) => fromNullable(cache.get(id)));\n * ```\n */\nexport const optional = <T, U>(value: T | null | undefined, fn: (value: T) => Maybe<U>): Maybe<U> =>\n flatMapImpl(fromNullable(value), fn);\n","import { err, isOk, ok, type Result } from \"@onrails/result\";\nimport { fromNullable, isSome, type Maybe, none, some } from \"./maybe.js\";\n\n/** Sentinel error tag — `Maybe<T>` bridges to `Result<T, NoneError>`. */\nexport type NoneError = { readonly _tag: \"None\" };\n\nexport const noneError = (): NoneError => ({ _tag: \"None\" });\n\n/** Lift absence into a domain error. */\nexport const toResult = <T, E>(maybe: Maybe<T>, onNone: () => E): Result<T, E> =>\n isSome(maybe) ? ok(maybe.value) : err(onNone());\n\n/** Ok values become Some; any Err becomes None (errors are not absence). */\nexport const fromResult = <T, E>(result: Result<T, E>): Maybe<T> =>\n isOk(result) ? some(result.value) : none<T>();\n\n/** Nullable edge → Maybe; explicit None error at the boundary. */\nexport const nullableToResult = <T, E>(\n value: T | null | undefined,\n onNone: () => E,\n): Result<T, E> => toResult(fromNullable(value), onNone);\n\n/** True when a Result failed specifically with {@link NoneError}. */\nexport const isNoneError = (result: Result<unknown, unknown>): result is Result<never, NoneError> =>\n !isOk(result) && isNoneErrorValue(result.error);\n\nconst isNoneErrorValue = (error: unknown): error is NoneError =>\n typeof error === \"object\" &&\n error !== null &&\n \"_tag\" in error &&\n (error as { _tag: unknown })._tag === \"None\";\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/maybe.ts","../src/interop.ts"],"names":[],"mappings":";;;;;AAYO,IAAM,OAAO,CAAI,KAAA,MAAwB,EAAE,IAAA,EAAM,QAAQ,KAAA,EAAM,CAAA;AAgB/D,IAAM,IAAA,GAAO,OAA4B,EAAE,IAAA,EAAM,MAAA,EAAO,CAAA;AAYxD,IAAM,MAAA,GAAS,CAAI,KAAA,KAAsC,KAAA,CAAM,IAAA,KAAS,MAAA;AAiBxE,IAAM,YAAA,GAAe,CAAI,KAAA,KAC9B,KAAA,IAAS,OAAO,IAAA,EAAQ,GAAI,KAAK,KAAK,CAAA;;;ACpDjC,IAAM,SAAA,GAAY,OAAkB,EAAE,IAAA,EAAM,MAAA,EAAO;AAGnD,IAAM,QAAA,GAAW,CAAO,KAAA,EAAiB,MAAA,KAC9C,MAAA,CAAO,KAAK,CAAA,GAAI,EAAA,CAAG,KAAA,CAAM,KAAK,CAAA,GAAI,GAAA,CAAI,QAAQ;AAGzC,IAAM,UAAA,GAAa,CAAO,MAAA,KAC/B,IAAA,CAAK,MAAM,IAAI,IAAA,CAAK,MAAA,CAAO,KAAK,CAAA,GAAI,IAAA;AAG/B,IAAM,gBAAA,GAAmB,CAC9B,KAAA,EACA,MAAA,KACiB,SAAS,YAAA,CAAa,KAAK,GAAG,MAAM;AAGhD,IAAM,WAAA,GAAc,CAAC,MAAA,KAC1B,CAAC,KAAK,MAAM,CAAA,IAAK,gBAAA,CAAiB,MAAA,CAAO,KAAK;AAEhD,IAAM,gBAAA,GAAmB,CAAC,KAAA,KACxB,OAAO,KAAA,KAAU,QAAA,IACjB,KAAA,KAAU,IAAA,IACV,MAAA,IAAU,KAAA,IACT,KAAA,CAA4B,IAAA,KAAS,MAAA","file":"interop.js","sourcesContent":["import type { Maybe, None, Some } from \"./types.js\";\n\nexport type { Maybe, None, Some } from \"./types.js\";\n\n/**\n * Lifts a value into the `Some` branch.\n *\n * @example\n * ```ts\n * const m = some(1); // Maybe<number>\n * ```\n */\nexport const some = <T>(value: T): Maybe<T> => ({ _tag: \"Some\", value });\n\n/**\n * Fantasy Land `of` — alias of {@link some}.\n * @deprecated Use {@link some} instead.\n */\nexport const of = some;\n\n/**\n * The `None` value — represents expected absence. Not a failure.\n *\n * @example\n * ```ts\n * const cached: Maybe<User> = cache.has(id) ? some(cache.get(id)) : none();\n * ```\n */\nexport const none = <T = never>(): Maybe<T> => ({ _tag: \"None\" });\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `Some`.\n *\n * @example\n * ```ts\n * if (isSome(m)) {\n * console.log(m.value); // narrowed to Some branch\n * }\n * ```\n */\nexport const isSome = <T>(maybe: Maybe<T>): maybe is Some<T> => maybe._tag === \"Some\";\n\n/**\n * Type-narrowing predicate: returns `true` when the value is `None`.\n */\nexport const isNone = <T>(maybe: Maybe<T>): maybe is None => maybe._tag === \"None\";\n\n/**\n * Lift a nullable value into `Maybe<T>` — `null` and `undefined` become\n * `None`; anything else becomes `Some`.\n *\n * @example\n * ```ts\n * fromNullable(map.get(key)); // Maybe<V>\n * fromNullable(null); // None\n * ```\n */\nexport const fromNullable = <T>(value: T | null | undefined): Maybe<T> =>\n value == null ? none<T>() : some(value);\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Dual-form helpers — each accepts either shape:\n// data-first: `map(maybe, fn)`\n// curried: `map(fn)(maybe)`\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst mapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U> =>\n isSome(maybe) ? some(fn(maybe.value)) : none<U>();\n\n/**\n * Transform the `Some` value, passing `None` through unchanged. Dual-form.\n *\n * @example\n * ```ts\n * map(some(2), (n) => n * 3); // Some 6 — data-first\n * pipe(fromNullable(input), map((s) => s.trim())); // curried\n * ```\n */\nexport function map<T, U>(maybe: Maybe<T>, fn: (value: T) => U): Maybe<U>;\nexport function map<T, U>(fn: (value: T) => U): (maybe: Maybe<T>) => Maybe<U>;\nexport function map(\n ...args: [Maybe<unknown>, (value: unknown) => unknown] | [(value: unknown) => unknown]\n): unknown {\n if (args.length === 2) return mapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => mapImpl(maybe, fn);\n}\n\nconst flatMapImpl = <T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U> =>\n isSome(maybe) ? fn(maybe.value) : none<U>();\n\n/**\n * Canonical bind for `Maybe`. Chains a `Maybe`-returning step;\n * short-circuits on `None`. Dual-form.\n *\n * @example\n * ```ts\n * flatMap(fromNullable(user), (u) =>\n * u.active ? some(u) : none(),\n * );\n * ```\n */\nexport function flatMap<T, U>(maybe: Maybe<T>, fn: (value: T) => Maybe<U>): Maybe<U>;\nexport function flatMap<T, U>(fn: (value: T) => Maybe<U>): (maybe: Maybe<T>) => Maybe<U>;\nexport function flatMap(\n ...args:\n | [Maybe<unknown>, (value: unknown) => Maybe<unknown>]\n | [(value: unknown) => Maybe<unknown>]\n): unknown {\n if (args.length === 2) return flatMapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => flatMapImpl(maybe, fn);\n}\n\n/** Alias for {@link flatMap} — same dual-form shape. */\nexport const andThen = flatMap;\n\nconst matchImpl = <T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U =>\n isSome(maybe) ? onSome(maybe.value) : onNone();\n\n/**\n * Terminal collapse — fold both branches into a single value. Positional,\n * dual-form. Same shape as `Result.match` for sibling consistency.\n *\n * For files that also import `match` from `ts-pattern`, the alias\n * {@link matchMaybe} is identical.\n *\n * @example\n * ```ts\n * const greeting = match(\n * fromNullable(user),\n * (u) => `hello ${u.name}`,\n * () => \"hello guest\",\n * );\n * ```\n */\nexport function match<T, U>(maybe: Maybe<T>, onSome: (value: T) => U, onNone: () => U): U;\nexport function match<T, U>(onSome: (value: T) => U, onNone: () => U): (maybe: Maybe<T>) => U;\nexport function match(\n ...args:\n | [Maybe<unknown>, (value: unknown) => unknown, () => unknown]\n | [(value: unknown) => unknown, () => unknown]\n): unknown {\n if (args.length === 3) return matchImpl(args[0], args[1], args[2]);\n const [onSome, onNone] = args;\n return (maybe: Maybe<unknown>) => matchImpl(maybe, onSome, onNone);\n}\n\n/**\n * Collision-free alias — mirrors `matchResult` on `@onrails/result`.\n * @deprecated Namespace import carriers (e.g., `import * as Maybe from \"@onrails/maybe\"`) and use canonical {@link match} instead.\n */\nexport const matchMaybe = match;\n\n/**\n * Returns the `Some` value, or `defaultValue` when the value is `None`.\n *\n * @example\n * ```ts\n * unwrapOr(fromNullable(user), { name: \"guest\" });\n * ```\n */\nexport const unwrapOr = <T>(maybe: Maybe<T>, defaultValue: T): T =>\n isSome(maybe) ? maybe.value : defaultValue;\n\n/**\n * Returns the `Some` value, or `defaultValue` when the value is `None`.\n *\n * @deprecated Use canonical {@link unwrapOr} instead.\n */\nexport const getOrElse = unwrapOr;\n\n/**\n * Unwraps the `Some` value or throws if the value is `None`.\n *\n * @throws when the value is None — assertion-tier; use {@link match} / {@link unwrapOr} in business logic.\n * Allowed in `*.spec.ts` / `*.test.ts`; flagged elsewhere by the plugins.\n *\n * @example\n * ```ts\n * expect(unwrap(parseUser(raw))).toEqual(expected);\n * ```\n */\nexport const unwrap = <T>(maybe: Maybe<T>): T => {\n if (isNone(maybe)) {\n throw new Error(\"Called unwrap on None\");\n }\n return maybe.value;\n};\n\n/**\n * Drop every `None` and collect the remaining `Some` values into an array.\n *\n * @example\n * ```ts\n * compact([some(1), none(), some(2)]); // [1, 2]\n * ```\n */\nexport const compact = <T>(maybes: readonly Maybe<T>[]): T[] => {\n const out: T[] = [];\n for (const m of maybes) {\n if (isSome(m)) {\n out.push(m.value);\n }\n }\n return out;\n};\n\n/**\n * `compact(items.map(fn))` — map each item to `Maybe`, drop `None`,\n * collect the rest.\n *\n * @example\n * ```ts\n * compactMap(rawRows, (row) =>\n * row.deletedAt ? none() : some(row.id),\n * );\n * // string[]\n * ```\n */\nexport const compactMap = <T, U>(items: readonly T[], fn: (item: T) => Maybe<U>): U[] =>\n compact(items.map(fn));\n\n/**\n * `flatMap(fromNullable(value), fn)` — lift a nullable then bind through\n * a `Maybe`-returning step. Convenient for chaining lookups.\n *\n * @example\n * ```ts\n * optional(rawId, (id) => fromNullable(cache.get(id)));\n * ```\n */\nexport const optional = <T, U>(value: T | null | undefined, fn: (value: T) => Maybe<U>): Maybe<U> =>\n flatMapImpl(fromNullable(value), fn);\n\nconst tapImpl = <T>(maybe: Maybe<T>, fn: (value: T) => void): Maybe<T> => {\n if (isSome(maybe)) fn(maybe.value);\n return maybe;\n};\n\n/**\n * Run a side effect on the `Some` value, pass the `Maybe` through unchanged.\n * `None` is a no-op. Mirrors `tap` from `@onrails/result`. Dual-form.\n *\n * @example\n * ```ts\n * tap(some(2), (n) => console.log(n)); // logs 2, returns Some 2\n * pipe(fromNullable(row), tap((r) => sink.push(r))); // curried — collect on Some\n * ```\n */\nexport function tap<T>(maybe: Maybe<T>, fn: (value: T) => void): Maybe<T>;\nexport function tap<T>(fn: (value: T) => void): (maybe: Maybe<T>) => Maybe<T>;\nexport function tap(\n ...args: [Maybe<unknown>, (value: unknown) => void] | [(value: unknown) => void]\n): unknown {\n if (args.length === 2) return tapImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => tapImpl(maybe, fn);\n}\n\nconst tapNoneImpl = <T>(maybe: Maybe<T>, fn: () => void): Maybe<T> => {\n if (isNone(maybe)) fn();\n return maybe;\n};\n\n/**\n * Run a side effect when the `Maybe` is `None`, pass it through unchanged.\n * `Some` is a no-op. The `None`-side mirror of {@link tap}. Dual-form.\n *\n * @example\n * ```ts\n * tapNone(none(), () => metrics.miss()); // runs effect, returns None\n * pipe(fromNullable(hit), tapNone(() => metrics.miss())); // curried\n * ```\n */\nexport function tapNone<T>(maybe: Maybe<T>, fn: () => void): Maybe<T>;\nexport function tapNone<T>(fn: () => void): (maybe: Maybe<T>) => Maybe<T>;\nexport function tapNone(...args: [Maybe<unknown>, () => void] | [() => void]): unknown {\n if (args.length === 2) return tapNoneImpl(args[0], args[1]);\n const fn = args[0];\n return (maybe: Maybe<unknown>) => tapNoneImpl(maybe, fn);\n}\n","import { err, isOk, ok, type Result } from \"@onrails/result\";\nimport { fromNullable, isSome, type Maybe, none, some } from \"./maybe.js\";\n\n/** Sentinel error tag — `Maybe<T>` bridges to `Result<T, NoneError>`. */\nexport type NoneError = { readonly _tag: \"None\" };\n\nexport const noneError = (): NoneError => ({ _tag: \"None\" });\n\n/** Lift absence into a domain error. */\nexport const toResult = <T, E>(maybe: Maybe<T>, onNone: () => E): Result<T, E> =>\n isSome(maybe) ? ok(maybe.value) : err(onNone());\n\n/** Ok values become Some; any Err becomes None (errors are not absence). */\nexport const fromResult = <T, E>(result: Result<T, E>): Maybe<T> =>\n isOk(result) ? some(result.value) : none<T>();\n\n/** Nullable edge → Maybe; explicit None error at the boundary. */\nexport const nullableToResult = <T, E>(\n value: T | null | undefined,\n onNone: () => E,\n): Result<T, E> => toResult(fromNullable(value), onNone);\n\n/** True when a Result failed specifically with {@link NoneError}. */\nexport const isNoneError = (result: Result<unknown, unknown>): result is Result<never, NoneError> =>\n !isOk(result) && isNoneErrorValue(result.error);\n\nconst isNoneErrorValue = (error: unknown): error is NoneError =>\n typeof error === \"object\" &&\n error !== null &&\n \"_tag\" in error &&\n (error as { _tag: unknown })._tag === \"None\";\n"]}
|