@consolidados/results 0.4.0 → 0.5.0
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 +65 -0
- package/dist/helpers/match.cjs +23 -41
- package/dist/helpers/match.cjs.map +1 -1
- package/dist/helpers/match.d.cts +1 -1
- package/dist/helpers/match.d.ts +1 -1
- package/dist/helpers/match.js +23 -41
- package/dist/helpers/match.js.map +1 -1
- package/dist/index.cjs +36 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +36 -41
- package/dist/index.js.map +1 -1
- package/dist/option/index.cjs +13 -0
- package/dist/option/index.cjs.map +1 -1
- package/dist/option/index.d.cts +1 -1
- package/dist/option/index.d.ts +1 -1
- package/dist/option/index.js +13 -0
- package/dist/option/index.js.map +1 -1
- package/dist/option/option.cjs +13 -0
- package/dist/option/option.cjs.map +1 -1
- package/dist/option/option.d.cts +2 -2
- package/dist/option/option.d.ts +2 -2
- package/dist/option/option.js +13 -0
- package/dist/option/option.js.map +1 -1
- package/dist/{option-B_KKIecf.d.cts → option-CYCiGxtw.d.cts} +13 -0
- package/dist/{option-B_KKIecf.d.ts → option-CYCiGxtw.d.ts} +13 -0
- package/dist/result/index.cjs +7 -0
- package/dist/result/index.cjs.map +1 -1
- package/dist/result/index.d.cts +1 -1
- package/dist/result/index.d.ts +1 -1
- package/dist/result/index.js +7 -0
- package/dist/result/index.js.map +1 -1
- package/dist/result/result.cjs +7 -0
- package/dist/result/result.cjs.map +1 -1
- package/dist/result/result.d.cts +2 -2
- package/dist/result/result.d.ts +2 -2
- package/dist/result/result.js +7 -0
- package/dist/result/result.js.map +1 -1
- package/dist/types/globals.d.cts +1 -1
- package/dist/types/globals.d.ts +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -48,6 +48,71 @@ const result = Ok(42);
|
|
|
48
48
|
const option = Some("hello");
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
+
### Monorepo / workspace setup
|
|
52
|
+
|
|
53
|
+
In a monorepo (Turborepo, Nx, pnpm workspaces, etc.) you usually don't want
|
|
54
|
+
to repeat the global wiring in every `tsconfig.json` and every entrypoint.
|
|
55
|
+
Wrap it once in a shared types package and have the other workspaces depend
|
|
56
|
+
on that.
|
|
57
|
+
|
|
58
|
+
**1. Create a shared package, e.g. `packages/types`:**
|
|
59
|
+
|
|
60
|
+
`packages/types/src/globals.ts` — runtime side-effect (registers
|
|
61
|
+
`Ok`, `Err`, `Some`, `None`, `match` on `globalThis`):
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import "@consolidados/results";
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`packages/types/src/globals-types.d.ts` — ambient TypeScript types so
|
|
68
|
+
`Result<T, E>` and `Option<T>` work without per-file imports:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import type { Option as _Option, Result as _Result } from "@consolidados/results";
|
|
72
|
+
|
|
73
|
+
declare global {
|
|
74
|
+
type Result<T, E> = _Result<T, E>;
|
|
75
|
+
type Option<T> = _Option<T>;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export {};
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`packages/types/package.json` — expose both as subpath exports:
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"name": "@your-org/types",
|
|
86
|
+
"dependencies": { "@consolidados/results": "^0.5.0" },
|
|
87
|
+
"exports": {
|
|
88
|
+
"./globals": "./src/globals.ts",
|
|
89
|
+
"./globals-types": "./src/globals-types.d.ts"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**2. In each consuming workspace:**
|
|
95
|
+
|
|
96
|
+
`services/<name>/tsconfig.json`:
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"compilerOptions": {
|
|
101
|
+
"types": ["node", "@your-org/types/globals-types"]
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`services/<name>/src/main.ts` (first import of the entrypoint):
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import "@your-org/types/globals";
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Now every file in that workspace can use `Ok`, `Err`, `Some`, `None`, `match`,
|
|
113
|
+
`Result<T, E>`, and `Option<T>` without any import — and the wiring lives in
|
|
114
|
+
one place.
|
|
115
|
+
|
|
51
116
|
## Quick Start
|
|
52
117
|
|
|
53
118
|
### Result - Handle Success/Failure
|
package/dist/helpers/match.cjs
CHANGED
|
@@ -1,59 +1,41 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
// src/helpers/match.ts
|
|
4
|
+
var TAG = Symbol.for("@consolidados/results.tag");
|
|
4
5
|
function match(matcher, cases, discriminant) {
|
|
5
|
-
|
|
6
|
+
const t = typeof matcher;
|
|
7
|
+
if (t === "string" || t === "number" || t === "symbol") {
|
|
6
8
|
const handler = cases[matcher];
|
|
7
|
-
if (handler)
|
|
9
|
+
if (handler) return handler();
|
|
10
|
+
if (cases.default) return cases.default();
|
|
11
|
+
throw new Error(`No case found for value: ${String(matcher)}`);
|
|
12
|
+
}
|
|
13
|
+
if (matcher !== null && t === "object") {
|
|
14
|
+
const tag = matcher[TAG];
|
|
15
|
+
if (tag !== void 0) {
|
|
16
|
+
const handler = cases[tag];
|
|
17
|
+
if (!handler) throw new Error(`Missing case for ${tag}`);
|
|
18
|
+
if (tag === "Ok" || tag === "Some") return handler(matcher.unwrap());
|
|
19
|
+
if (tag === "Err") return handler(matcher.unwrapErr());
|
|
8
20
|
return handler();
|
|
9
21
|
}
|
|
10
|
-
if (
|
|
11
|
-
|
|
22
|
+
if (discriminant) {
|
|
23
|
+
const dv = matcher[discriminant];
|
|
24
|
+
const handler = cases[dv];
|
|
25
|
+
if (handler) return handler(matcher);
|
|
26
|
+
if (cases.default) return cases.default(matcher);
|
|
27
|
+
throw new Error(`No case found for discriminant value: ${String(dv)}`);
|
|
12
28
|
}
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
if (typeof matcher === "object" && matcher !== null && !discriminant) {
|
|
16
|
-
for (const key in cases) {
|
|
29
|
+
for (const key in matcher) {
|
|
17
30
|
if (key === "default") continue;
|
|
18
|
-
if (key in
|
|
31
|
+
if (key in cases) {
|
|
19
32
|
const handler = cases[key];
|
|
20
33
|
if (handler) {
|
|
21
34
|
return typeof handler === "function" ? handler(matcher[key]) : handler();
|
|
22
35
|
}
|
|
23
36
|
}
|
|
24
37
|
}
|
|
25
|
-
if (cases.default)
|
|
26
|
-
return cases.default();
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
if (discriminant && typeof matcher === "object" && matcher !== null) {
|
|
30
|
-
const discriminantValue = matcher[discriminant];
|
|
31
|
-
const handler = cases[discriminantValue];
|
|
32
|
-
if (handler) {
|
|
33
|
-
return handler(matcher);
|
|
34
|
-
}
|
|
35
|
-
if (cases.default) {
|
|
36
|
-
return cases.default(matcher);
|
|
37
|
-
}
|
|
38
|
-
throw new Error(
|
|
39
|
-
`No case found for discriminant value: ${String(discriminantValue)}`
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
if (typeof matcher === "object" && matcher !== null && "isOk" in matcher && matcher.isOk()) {
|
|
43
|
-
if (!cases.Ok) throw new Error("Missing case for Ok");
|
|
44
|
-
return cases.Ok(matcher.unwrap());
|
|
45
|
-
}
|
|
46
|
-
if (typeof matcher === "object" && matcher !== null && "isErr" in matcher && matcher.isErr()) {
|
|
47
|
-
if (!cases.Err) throw new Error("Missing case for Err");
|
|
48
|
-
return cases.Err(matcher.unwrapErr());
|
|
49
|
-
}
|
|
50
|
-
if (typeof matcher === "object" && matcher !== null && "isSome" in matcher && matcher.isSome()) {
|
|
51
|
-
if (!cases.Some) throw new Error("Missing case for Some");
|
|
52
|
-
return cases.Some(matcher.unwrap());
|
|
53
|
-
}
|
|
54
|
-
if (typeof matcher === "object" && matcher !== null && "isNone" in matcher && matcher.isNone()) {
|
|
55
|
-
if (!cases.None) throw new Error("Missing case for None");
|
|
56
|
-
return cases.None();
|
|
38
|
+
if (cases.default) return cases.default();
|
|
57
39
|
}
|
|
58
40
|
throw new Error("Invalid matcher or missing case");
|
|
59
41
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/helpers/match.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"sources":["../../src/helpers/match.ts"],"names":[],"mappings":";;;AAKA,IAAM,GAAA,GAAM,MAAO,CAAA,GAAA,CAAI,2BAA2B,CAAA;AA+F3C,SAAS,KAAA,CACd,OACA,EAAA,KAAA,EACA,YACG,EAAA;AAEH,EAAA,MAAM,IAAI,OAAO,OAAA;AACjB,EAAA,IAAI,CAAM,KAAA,QAAA,IAAY,CAAM,KAAA,QAAA,IAAY,MAAM,QAAU,EAAA;AACtD,IAAM,MAAA,OAAA,GAAU,MAAM,OAAO,CAAA;AAC7B,IAAI,IAAA,OAAA,SAAgB,OAAQ,EAAA;AAC5B,IAAA,IAAI,KAAM,CAAA,OAAA,EAAgB,OAAA,KAAA,CAAM,OAAQ,EAAA;AACxC,IAAA,MAAM,IAAI,KAAM,CAAA,CAAA,yBAAA,EAA4B,MAAO,CAAA,OAAO,CAAC,CAAE,CAAA,CAAA;AAAA;AAG/D,EAAI,IAAA,OAAA,KAAY,IAAQ,IAAA,CAAA,KAAM,QAAU,EAAA;AAKtC,IAAM,MAAA,GAAA,GAAM,QAAQ,GAAG,CAAA;AACvB,IAAA,IAAI,QAAQ,MAAW,EAAA;AACrB,MAAM,MAAA,OAAA,GAAU,MAAM,GAAG,CAAA;AACzB,MAAA,IAAI,CAAC,OAAS,EAAA,MAAM,IAAI,KAAM,CAAA,CAAA,iBAAA,EAAoB,GAAG,CAAE,CAAA,CAAA;AACvD,MAAI,IAAA,GAAA,KAAQ,QAAQ,GAAQ,KAAA,MAAA,SAAe,OAAQ,CAAA,OAAA,CAAQ,QAAQ,CAAA;AACnE,MAAA,IAAI,QAAQ,KAAO,EAAA,OAAO,OAAQ,CAAA,OAAA,CAAQ,WAAgB,CAAA;AAE1D,MAAA,OAAO,OAAQ,EAAA;AAAA;AAIjB,IAAA,IAAI,YAAc,EAAA;AAChB,MAAM,MAAA,EAAA,GAAK,QAAQ,YAAY,CAAA;AAC/B,MAAM,MAAA,OAAA,GAAU,MAAM,EAAE,CAAA;AACxB,MAAI,IAAA,OAAA,EAAgB,OAAA,OAAA,CAAQ,OAAO,CAAA;AACnC,MAAA,IAAI,KAAM,CAAA,OAAA,EAAgB,OAAA,KAAA,CAAM,QAAQ,OAAO,CAAA;AAC/C,MAAA,MAAM,IAAI,KAAM,CAAA,CAAA,sCAAA,EAAyC,MAAO,CAAA,EAAE,CAAC,CAAE,CAAA,CAAA;AAAA;AAOvE,IAAA,KAAA,MAAW,OAAO,OAAS,EAAA;AACzB,MAAA,IAAI,QAAQ,SAAW,EAAA;AACvB,MAAA,IAAI,OAAO,KAAO,EAAA;AAChB,QAAM,MAAA,OAAA,GAAU,MAAM,GAAG,CAAA;AACzB,QAAA,IAAI,OAAS,EAAA;AACX,UAAO,OAAA,OAAO,YAAY,UACtB,GAAA,OAAA,CAAQ,QAAQ,GAAG,CAAC,IACpB,OAAQ,EAAA;AAAA;AACd;AACF;AAEF,IAAA,IAAI,KAAM,CAAA,OAAA,EAAgB,OAAA,KAAA,CAAM,OAAQ,EAAA;AAAA;AAG1C,EAAM,MAAA,IAAI,MAAM,iCAAiC,CAAA;AACnD;AAGC,UAAA,CAAmB,KAAQ,GAAA,KAAA","file":"match.cjs","sourcesContent":["import type { Option } from \"../option\";\nimport type { Result } from \"../result\";\n\n// Hidden discriminant tag — set by Ok/Err/Some/None instances for O(1) dispatch.\n// Same Symbol as the one declared in the variant classes via Symbol.for.\nconst TAG = Symbol.for(\"@consolidados/results.tag\");\n\n// Utility types for mixed primitive + object unions\ntype PrimitiveMembers<T> = Extract<T, PropertyKey>;\ntype ObjectKeys<T> = T extends object ? keyof T : never;\ntype ObjectPropertyType<T, K extends PropertyKey> = T extends object\n ? K extends keyof T\n ? T[K]\n : never\n : never;\n\n// Helper to determine if a key K is a primitive member or object key\ntype HandlerFor<T, K extends PropertyKey, R> = K extends PrimitiveMembers<T>\n ? () => R\n : K extends ObjectKeys<T>\n ? (value: ObjectPropertyType<T, K>) => R\n : never;\n\n// Build cases type with a single mapped type\ntype MatchCases<T, R, HasDefault extends boolean = false> = (HasDefault extends true\n ? Partial<{\n [K in PrimitiveMembers<T> | ObjectKeys<T>]: HandlerFor<T, K, R>;\n }>\n : {\n [K in PrimitiveMembers<T> | ObjectKeys<T>]: HandlerFor<T, K, R>;\n }) &\n (HasDefault extends true ? { default: () => R } : {});\n\n// Overload for Result type\nexport function match<T, E, ROk, RErr>(\n matcher: Result<T, E>,\n cases: {\n Ok: (value: T) => ROk;\n Err: (error: E) => RErr;\n },\n): ROk | RErr;\n\n// Overload for Option type\nexport function match<T, RSome, RNone>(\n matcher: Option<T>,\n cases: {\n Some: (value: T) => RSome;\n None: () => RNone;\n },\n): RSome | RNone;\n\n// Overload for mixed primitive + object unions WITH default (cases optional)\nexport function match<T extends PropertyKey | object, R>(\n matcher: T,\n cases: MatchCases<T, R, true>,\n): R;\n\n// Overload for mixed primitive + object unions WITHOUT default (exhaustive)\nexport function match<T extends PropertyKey | object, R>(\n matcher: T,\n cases: MatchCases<T, R, false>,\n): R;\n\n// Overload for discriminated unions with default case\nexport function match<\n T extends { [K in D]: string | number | symbol },\n D extends keyof T,\n R,\n>(\n matcher: T,\n cases: { [K in T[D]]?: (value: Extract<T, { [P in D]: K }>) => R } & {\n default: (value: T) => R;\n },\n discriminant: D,\n): R;\n\n// Overload for discriminated unions without default case (exhaustive)\nexport function match<\n T extends { [K in D]: string | number | symbol },\n D extends keyof T,\n R,\n>(\n matcher: T,\n cases: { [K in T[D]]: (value: Extract<T, { [P in D]: K }>) => R },\n discriminant: D,\n): R;\n\n// Overload for primitives with default case\nexport function match<T extends PropertyKey, R>(\n matcher: T,\n cases: Partial<Record<T, () => R>> & { default: () => R },\n): R;\n\n// Overload for primitives without default case (exhaustive)\nexport function match<T extends PropertyKey, R>(\n matcher: T,\n cases: Record<T, () => R>,\n): R;\n\n// Implementation\nexport function match<T, E, R>(\n matcher: Result<T, E> | Option<T> | any,\n cases: any,\n discriminant?: keyof any,\n): R {\n // 1) Primitives (string/number/symbol) — direct key lookup, O(1).\n const t = typeof matcher;\n if (t === \"string\" || t === \"number\" || t === \"symbol\") {\n const handler = cases[matcher];\n if (handler) return handler();\n if (cases.default) return cases.default();\n throw new Error(`No case found for value: ${String(matcher)}`);\n }\n\n if (matcher !== null && t === \"object\") {\n // 2) Tagged variant (Ok/Err/Some/None) — single Symbol read + single lookup.\n // The Symbol property is invisible to `for...in`, `Object.keys`, and\n // `JSON.stringify`, so mixed unions with plain-object variants are\n // unaffected.\n const tag = matcher[TAG];\n if (tag !== undefined) {\n const handler = cases[tag];\n if (!handler) throw new Error(`Missing case for ${tag}`);\n if (tag === \"Ok\" || tag === \"Some\") return handler(matcher.unwrap());\n if (tag === \"Err\") return handler(matcher.unwrapErr() as E);\n // tag === \"None\"\n return handler();\n }\n\n // 3) Discriminated union via explicit `discriminant` arg — O(1).\n if (discriminant) {\n const dv = matcher[discriminant];\n const handler = cases[dv];\n if (handler) return handler(matcher);\n if (cases.default) return cases.default(matcher);\n throw new Error(`No case found for discriminant value: ${String(dv)}`);\n }\n\n // 4) Mixed primitive + object union — iterate matcher's own enumerable\n // keys (usually 1 for tagged variant objects like `{ Other: [...] }`)\n // and look up by key in cases. This flips the loop from O(cases)\n // to O(matcher-keys), which is effectively O(1) for tagged variants.\n for (const key in matcher) {\n if (key === \"default\") continue;\n if (key in cases) {\n const handler = cases[key];\n if (handler) {\n return typeof handler === \"function\"\n ? handler(matcher[key])\n : handler();\n }\n }\n }\n if (cases.default) return cases.default();\n }\n\n throw new Error(\"Invalid matcher or missing case\");\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: <explanation>\n(globalThis as any).match = match;\n"]}
|
package/dist/helpers/match.d.cts
CHANGED
package/dist/helpers/match.d.ts
CHANGED
package/dist/helpers/match.js
CHANGED
|
@@ -1,57 +1,39 @@
|
|
|
1
1
|
// src/helpers/match.ts
|
|
2
|
+
var TAG = Symbol.for("@consolidados/results.tag");
|
|
2
3
|
function match(matcher, cases, discriminant) {
|
|
3
|
-
|
|
4
|
+
const t = typeof matcher;
|
|
5
|
+
if (t === "string" || t === "number" || t === "symbol") {
|
|
4
6
|
const handler = cases[matcher];
|
|
5
|
-
if (handler)
|
|
7
|
+
if (handler) return handler();
|
|
8
|
+
if (cases.default) return cases.default();
|
|
9
|
+
throw new Error(`No case found for value: ${String(matcher)}`);
|
|
10
|
+
}
|
|
11
|
+
if (matcher !== null && t === "object") {
|
|
12
|
+
const tag = matcher[TAG];
|
|
13
|
+
if (tag !== void 0) {
|
|
14
|
+
const handler = cases[tag];
|
|
15
|
+
if (!handler) throw new Error(`Missing case for ${tag}`);
|
|
16
|
+
if (tag === "Ok" || tag === "Some") return handler(matcher.unwrap());
|
|
17
|
+
if (tag === "Err") return handler(matcher.unwrapErr());
|
|
6
18
|
return handler();
|
|
7
19
|
}
|
|
8
|
-
if (
|
|
9
|
-
|
|
20
|
+
if (discriminant) {
|
|
21
|
+
const dv = matcher[discriminant];
|
|
22
|
+
const handler = cases[dv];
|
|
23
|
+
if (handler) return handler(matcher);
|
|
24
|
+
if (cases.default) return cases.default(matcher);
|
|
25
|
+
throw new Error(`No case found for discriminant value: ${String(dv)}`);
|
|
10
26
|
}
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
if (typeof matcher === "object" && matcher !== null && !discriminant) {
|
|
14
|
-
for (const key in cases) {
|
|
27
|
+
for (const key in matcher) {
|
|
15
28
|
if (key === "default") continue;
|
|
16
|
-
if (key in
|
|
29
|
+
if (key in cases) {
|
|
17
30
|
const handler = cases[key];
|
|
18
31
|
if (handler) {
|
|
19
32
|
return typeof handler === "function" ? handler(matcher[key]) : handler();
|
|
20
33
|
}
|
|
21
34
|
}
|
|
22
35
|
}
|
|
23
|
-
if (cases.default)
|
|
24
|
-
return cases.default();
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
if (discriminant && typeof matcher === "object" && matcher !== null) {
|
|
28
|
-
const discriminantValue = matcher[discriminant];
|
|
29
|
-
const handler = cases[discriminantValue];
|
|
30
|
-
if (handler) {
|
|
31
|
-
return handler(matcher);
|
|
32
|
-
}
|
|
33
|
-
if (cases.default) {
|
|
34
|
-
return cases.default(matcher);
|
|
35
|
-
}
|
|
36
|
-
throw new Error(
|
|
37
|
-
`No case found for discriminant value: ${String(discriminantValue)}`
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
if (typeof matcher === "object" && matcher !== null && "isOk" in matcher && matcher.isOk()) {
|
|
41
|
-
if (!cases.Ok) throw new Error("Missing case for Ok");
|
|
42
|
-
return cases.Ok(matcher.unwrap());
|
|
43
|
-
}
|
|
44
|
-
if (typeof matcher === "object" && matcher !== null && "isErr" in matcher && matcher.isErr()) {
|
|
45
|
-
if (!cases.Err) throw new Error("Missing case for Err");
|
|
46
|
-
return cases.Err(matcher.unwrapErr());
|
|
47
|
-
}
|
|
48
|
-
if (typeof matcher === "object" && matcher !== null && "isSome" in matcher && matcher.isSome()) {
|
|
49
|
-
if (!cases.Some) throw new Error("Missing case for Some");
|
|
50
|
-
return cases.Some(matcher.unwrap());
|
|
51
|
-
}
|
|
52
|
-
if (typeof matcher === "object" && matcher !== null && "isNone" in matcher && matcher.isNone()) {
|
|
53
|
-
if (!cases.None) throw new Error("Missing case for None");
|
|
54
|
-
return cases.None();
|
|
36
|
+
if (cases.default) return cases.default();
|
|
55
37
|
}
|
|
56
38
|
throw new Error("Invalid matcher or missing case");
|
|
57
39
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/helpers/match.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../../src/helpers/match.ts"],"names":[],"mappings":";AAKA,IAAM,GAAA,GAAM,MAAO,CAAA,GAAA,CAAI,2BAA2B,CAAA;AA+F3C,SAAS,KAAA,CACd,OACA,EAAA,KAAA,EACA,YACG,EAAA;AAEH,EAAA,MAAM,IAAI,OAAO,OAAA;AACjB,EAAA,IAAI,CAAM,KAAA,QAAA,IAAY,CAAM,KAAA,QAAA,IAAY,MAAM,QAAU,EAAA;AACtD,IAAM,MAAA,OAAA,GAAU,MAAM,OAAO,CAAA;AAC7B,IAAI,IAAA,OAAA,SAAgB,OAAQ,EAAA;AAC5B,IAAA,IAAI,KAAM,CAAA,OAAA,EAAgB,OAAA,KAAA,CAAM,OAAQ,EAAA;AACxC,IAAA,MAAM,IAAI,KAAM,CAAA,CAAA,yBAAA,EAA4B,MAAO,CAAA,OAAO,CAAC,CAAE,CAAA,CAAA;AAAA;AAG/D,EAAI,IAAA,OAAA,KAAY,IAAQ,IAAA,CAAA,KAAM,QAAU,EAAA;AAKtC,IAAM,MAAA,GAAA,GAAM,QAAQ,GAAG,CAAA;AACvB,IAAA,IAAI,QAAQ,MAAW,EAAA;AACrB,MAAM,MAAA,OAAA,GAAU,MAAM,GAAG,CAAA;AACzB,MAAA,IAAI,CAAC,OAAS,EAAA,MAAM,IAAI,KAAM,CAAA,CAAA,iBAAA,EAAoB,GAAG,CAAE,CAAA,CAAA;AACvD,MAAI,IAAA,GAAA,KAAQ,QAAQ,GAAQ,KAAA,MAAA,SAAe,OAAQ,CAAA,OAAA,CAAQ,QAAQ,CAAA;AACnE,MAAA,IAAI,QAAQ,KAAO,EAAA,OAAO,OAAQ,CAAA,OAAA,CAAQ,WAAgB,CAAA;AAE1D,MAAA,OAAO,OAAQ,EAAA;AAAA;AAIjB,IAAA,IAAI,YAAc,EAAA;AAChB,MAAM,MAAA,EAAA,GAAK,QAAQ,YAAY,CAAA;AAC/B,MAAM,MAAA,OAAA,GAAU,MAAM,EAAE,CAAA;AACxB,MAAI,IAAA,OAAA,EAAgB,OAAA,OAAA,CAAQ,OAAO,CAAA;AACnC,MAAA,IAAI,KAAM,CAAA,OAAA,EAAgB,OAAA,KAAA,CAAM,QAAQ,OAAO,CAAA;AAC/C,MAAA,MAAM,IAAI,KAAM,CAAA,CAAA,sCAAA,EAAyC,MAAO,CAAA,EAAE,CAAC,CAAE,CAAA,CAAA;AAAA;AAOvE,IAAA,KAAA,MAAW,OAAO,OAAS,EAAA;AACzB,MAAA,IAAI,QAAQ,SAAW,EAAA;AACvB,MAAA,IAAI,OAAO,KAAO,EAAA;AAChB,QAAM,MAAA,OAAA,GAAU,MAAM,GAAG,CAAA;AACzB,QAAA,IAAI,OAAS,EAAA;AACX,UAAO,OAAA,OAAO,YAAY,UACtB,GAAA,OAAA,CAAQ,QAAQ,GAAG,CAAC,IACpB,OAAQ,EAAA;AAAA;AACd;AACF;AAEF,IAAA,IAAI,KAAM,CAAA,OAAA,EAAgB,OAAA,KAAA,CAAM,OAAQ,EAAA;AAAA;AAG1C,EAAM,MAAA,IAAI,MAAM,iCAAiC,CAAA;AACnD;AAGC,UAAA,CAAmB,KAAQ,GAAA,KAAA","file":"match.js","sourcesContent":["import type { Option } from \"../option\";\nimport type { Result } from \"../result\";\n\n// Hidden discriminant tag — set by Ok/Err/Some/None instances for O(1) dispatch.\n// Same Symbol as the one declared in the variant classes via Symbol.for.\nconst TAG = Symbol.for(\"@consolidados/results.tag\");\n\n// Utility types for mixed primitive + object unions\ntype PrimitiveMembers<T> = Extract<T, PropertyKey>;\ntype ObjectKeys<T> = T extends object ? keyof T : never;\ntype ObjectPropertyType<T, K extends PropertyKey> = T extends object\n ? K extends keyof T\n ? T[K]\n : never\n : never;\n\n// Helper to determine if a key K is a primitive member or object key\ntype HandlerFor<T, K extends PropertyKey, R> = K extends PrimitiveMembers<T>\n ? () => R\n : K extends ObjectKeys<T>\n ? (value: ObjectPropertyType<T, K>) => R\n : never;\n\n// Build cases type with a single mapped type\ntype MatchCases<T, R, HasDefault extends boolean = false> = (HasDefault extends true\n ? Partial<{\n [K in PrimitiveMembers<T> | ObjectKeys<T>]: HandlerFor<T, K, R>;\n }>\n : {\n [K in PrimitiveMembers<T> | ObjectKeys<T>]: HandlerFor<T, K, R>;\n }) &\n (HasDefault extends true ? { default: () => R } : {});\n\n// Overload for Result type\nexport function match<T, E, ROk, RErr>(\n matcher: Result<T, E>,\n cases: {\n Ok: (value: T) => ROk;\n Err: (error: E) => RErr;\n },\n): ROk | RErr;\n\n// Overload for Option type\nexport function match<T, RSome, RNone>(\n matcher: Option<T>,\n cases: {\n Some: (value: T) => RSome;\n None: () => RNone;\n },\n): RSome | RNone;\n\n// Overload for mixed primitive + object unions WITH default (cases optional)\nexport function match<T extends PropertyKey | object, R>(\n matcher: T,\n cases: MatchCases<T, R, true>,\n): R;\n\n// Overload for mixed primitive + object unions WITHOUT default (exhaustive)\nexport function match<T extends PropertyKey | object, R>(\n matcher: T,\n cases: MatchCases<T, R, false>,\n): R;\n\n// Overload for discriminated unions with default case\nexport function match<\n T extends { [K in D]: string | number | symbol },\n D extends keyof T,\n R,\n>(\n matcher: T,\n cases: { [K in T[D]]?: (value: Extract<T, { [P in D]: K }>) => R } & {\n default: (value: T) => R;\n },\n discriminant: D,\n): R;\n\n// Overload for discriminated unions without default case (exhaustive)\nexport function match<\n T extends { [K in D]: string | number | symbol },\n D extends keyof T,\n R,\n>(\n matcher: T,\n cases: { [K in T[D]]: (value: Extract<T, { [P in D]: K }>) => R },\n discriminant: D,\n): R;\n\n// Overload for primitives with default case\nexport function match<T extends PropertyKey, R>(\n matcher: T,\n cases: Partial<Record<T, () => R>> & { default: () => R },\n): R;\n\n// Overload for primitives without default case (exhaustive)\nexport function match<T extends PropertyKey, R>(\n matcher: T,\n cases: Record<T, () => R>,\n): R;\n\n// Implementation\nexport function match<T, E, R>(\n matcher: Result<T, E> | Option<T> | any,\n cases: any,\n discriminant?: keyof any,\n): R {\n // 1) Primitives (string/number/symbol) — direct key lookup, O(1).\n const t = typeof matcher;\n if (t === \"string\" || t === \"number\" || t === \"symbol\") {\n const handler = cases[matcher];\n if (handler) return handler();\n if (cases.default) return cases.default();\n throw new Error(`No case found for value: ${String(matcher)}`);\n }\n\n if (matcher !== null && t === \"object\") {\n // 2) Tagged variant (Ok/Err/Some/None) — single Symbol read + single lookup.\n // The Symbol property is invisible to `for...in`, `Object.keys`, and\n // `JSON.stringify`, so mixed unions with plain-object variants are\n // unaffected.\n const tag = matcher[TAG];\n if (tag !== undefined) {\n const handler = cases[tag];\n if (!handler) throw new Error(`Missing case for ${tag}`);\n if (tag === \"Ok\" || tag === \"Some\") return handler(matcher.unwrap());\n if (tag === \"Err\") return handler(matcher.unwrapErr() as E);\n // tag === \"None\"\n return handler();\n }\n\n // 3) Discriminated union via explicit `discriminant` arg — O(1).\n if (discriminant) {\n const dv = matcher[discriminant];\n const handler = cases[dv];\n if (handler) return handler(matcher);\n if (cases.default) return cases.default(matcher);\n throw new Error(`No case found for discriminant value: ${String(dv)}`);\n }\n\n // 4) Mixed primitive + object union — iterate matcher's own enumerable\n // keys (usually 1 for tagged variant objects like `{ Other: [...] }`)\n // and look up by key in cases. This flips the loop from O(cases)\n // to O(matcher-keys), which is effectively O(1) for tagged variants.\n for (const key in matcher) {\n if (key === \"default\") continue;\n if (key in cases) {\n const handler = cases[key];\n if (handler) {\n return typeof handler === \"function\"\n ? handler(matcher[key])\n : handler();\n }\n }\n }\n if (cases.default) return cases.default();\n }\n\n throw new Error(\"Invalid matcher or missing case\");\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: <explanation>\n(globalThis as any).match = match;\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -1,66 +1,51 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
// src/helpers/match.ts
|
|
4
|
+
var TAG = Symbol.for("@consolidados/results.tag");
|
|
4
5
|
function match(matcher, cases, discriminant) {
|
|
5
|
-
|
|
6
|
+
const t = typeof matcher;
|
|
7
|
+
if (t === "string" || t === "number" || t === "symbol") {
|
|
6
8
|
const handler = cases[matcher];
|
|
7
|
-
if (handler)
|
|
9
|
+
if (handler) return handler();
|
|
10
|
+
if (cases.default) return cases.default();
|
|
11
|
+
throw new Error(`No case found for value: ${String(matcher)}`);
|
|
12
|
+
}
|
|
13
|
+
if (matcher !== null && t === "object") {
|
|
14
|
+
const tag = matcher[TAG];
|
|
15
|
+
if (tag !== void 0) {
|
|
16
|
+
const handler = cases[tag];
|
|
17
|
+
if (!handler) throw new Error(`Missing case for ${tag}`);
|
|
18
|
+
if (tag === "Ok" || tag === "Some") return handler(matcher.unwrap());
|
|
19
|
+
if (tag === "Err") return handler(matcher.unwrapErr());
|
|
8
20
|
return handler();
|
|
9
21
|
}
|
|
10
|
-
if (
|
|
11
|
-
|
|
22
|
+
if (discriminant) {
|
|
23
|
+
const dv = matcher[discriminant];
|
|
24
|
+
const handler = cases[dv];
|
|
25
|
+
if (handler) return handler(matcher);
|
|
26
|
+
if (cases.default) return cases.default(matcher);
|
|
27
|
+
throw new Error(`No case found for discriminant value: ${String(dv)}`);
|
|
12
28
|
}
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
if (typeof matcher === "object" && matcher !== null && !discriminant) {
|
|
16
|
-
for (const key in cases) {
|
|
29
|
+
for (const key in matcher) {
|
|
17
30
|
if (key === "default") continue;
|
|
18
|
-
if (key in
|
|
31
|
+
if (key in cases) {
|
|
19
32
|
const handler = cases[key];
|
|
20
33
|
if (handler) {
|
|
21
34
|
return typeof handler === "function" ? handler(matcher[key]) : handler();
|
|
22
35
|
}
|
|
23
36
|
}
|
|
24
37
|
}
|
|
25
|
-
if (cases.default)
|
|
26
|
-
return cases.default();
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
if (discriminant && typeof matcher === "object" && matcher !== null) {
|
|
30
|
-
const discriminantValue = matcher[discriminant];
|
|
31
|
-
const handler = cases[discriminantValue];
|
|
32
|
-
if (handler) {
|
|
33
|
-
return handler(matcher);
|
|
34
|
-
}
|
|
35
|
-
if (cases.default) {
|
|
36
|
-
return cases.default(matcher);
|
|
37
|
-
}
|
|
38
|
-
throw new Error(
|
|
39
|
-
`No case found for discriminant value: ${String(discriminantValue)}`
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
if (typeof matcher === "object" && matcher !== null && "isOk" in matcher && matcher.isOk()) {
|
|
43
|
-
if (!cases.Ok) throw new Error("Missing case for Ok");
|
|
44
|
-
return cases.Ok(matcher.unwrap());
|
|
45
|
-
}
|
|
46
|
-
if (typeof matcher === "object" && matcher !== null && "isErr" in matcher && matcher.isErr()) {
|
|
47
|
-
if (!cases.Err) throw new Error("Missing case for Err");
|
|
48
|
-
return cases.Err(matcher.unwrapErr());
|
|
49
|
-
}
|
|
50
|
-
if (typeof matcher === "object" && matcher !== null && "isSome" in matcher && matcher.isSome()) {
|
|
51
|
-
if (!cases.Some) throw new Error("Missing case for Some");
|
|
52
|
-
return cases.Some(matcher.unwrap());
|
|
53
|
-
}
|
|
54
|
-
if (typeof matcher === "object" && matcher !== null && "isNone" in matcher && matcher.isNone()) {
|
|
55
|
-
if (!cases.None) throw new Error("Missing case for None");
|
|
56
|
-
return cases.None();
|
|
38
|
+
if (cases.default) return cases.default();
|
|
57
39
|
}
|
|
58
40
|
throw new Error("Invalid matcher or missing case");
|
|
59
41
|
}
|
|
60
42
|
globalThis.match = match;
|
|
61
43
|
|
|
62
44
|
// src/result/__internal__/return-types/err.ts
|
|
45
|
+
var TAG2 = Symbol.for("@consolidados/results.tag");
|
|
63
46
|
var Err = class _Err {
|
|
47
|
+
/** Hidden tag — read by `match()` for O(1) dispatch. */
|
|
48
|
+
[TAG2] = "Err";
|
|
64
49
|
error;
|
|
65
50
|
/**
|
|
66
51
|
* Creates a new `Err` instance with the given error value.
|
|
@@ -171,6 +156,7 @@ var Err = class _Err {
|
|
|
171
156
|
};
|
|
172
157
|
|
|
173
158
|
// src/result/__internal__/return-types/ok.ts
|
|
159
|
+
var TAG3 = Symbol.for("@consolidados/results.tag");
|
|
174
160
|
var Ok = class _Ok {
|
|
175
161
|
/**
|
|
176
162
|
* Creates a new `Ok` instance with the given value.
|
|
@@ -179,6 +165,9 @@ var Ok = class _Ok {
|
|
|
179
165
|
constructor(_value) {
|
|
180
166
|
this._value = _value;
|
|
181
167
|
}
|
|
168
|
+
/** Hidden tag — read by `match()` for O(1) dispatch. Symbol-keyed so it
|
|
169
|
+
* doesn't appear in `for...in`, `Object.keys`, or `JSON.stringify`. */
|
|
170
|
+
[TAG3] = "Ok";
|
|
182
171
|
/**
|
|
183
172
|
* Checks if this result is an `Ok`.
|
|
184
173
|
* @returns `true` because this is an `Ok`.
|
|
@@ -290,6 +279,7 @@ globalThis.Ok = Ok2;
|
|
|
290
279
|
globalThis.Err = Err2;
|
|
291
280
|
|
|
292
281
|
// src/option/__internal__/return-types/some.ts
|
|
282
|
+
var TAG4 = Symbol.for("@consolidados/results.tag");
|
|
293
283
|
var Some2 = class _Some {
|
|
294
284
|
/**
|
|
295
285
|
* Creates a new `Some` option with the given value.
|
|
@@ -298,6 +288,8 @@ var Some2 = class _Some {
|
|
|
298
288
|
constructor(_value) {
|
|
299
289
|
this._value = _value;
|
|
300
290
|
}
|
|
291
|
+
/** Hidden tag — read by `match()` for O(1) dispatch. */
|
|
292
|
+
[TAG4] = "Some";
|
|
301
293
|
/**
|
|
302
294
|
* Checks if this option is a `Some`.
|
|
303
295
|
* @returns `true` if this option is a `Some`, otherwise `false`.
|
|
@@ -382,7 +374,10 @@ var Some2 = class _Some {
|
|
|
382
374
|
};
|
|
383
375
|
|
|
384
376
|
// src/option/__internal__/return-types/none.ts
|
|
377
|
+
var TAG5 = Symbol.for("@consolidados/results.tag");
|
|
385
378
|
var None3 = class {
|
|
379
|
+
/** Hidden tag — read by `match()` for O(1) dispatch. */
|
|
380
|
+
[TAG5] = "None";
|
|
386
381
|
/**
|
|
387
382
|
* Checks if this option is a `Some`.
|
|
388
383
|
* @returns `false` because this is a `None`.
|