@konker.dev/neverthrow-r 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Type-level vocabulary for the package: the `ResultR` / `ResultAsyncR` shapes
3
+ * that add a *requirements* channel on top of `neverthrow`'s `Result` /
4
+ * `ResultAsync`, plus the helper types (`Scope`, `ExtendedScope`, `Simplify`)
5
+ * used by do-notation and intersection flattening.
6
+ *
7
+ * @remarks
8
+ * Most users only need {@link ResultR} and {@link ResultAsyncR}. The remaining
9
+ * exports are surfaced because the do-notation helpers (`bindR`, `bindAsyncR`)
10
+ * expose them in their return types, so consumers may encounter them in
11
+ * inferred types.
12
+ *
13
+ * Every operator across the package — sync, async, bridges, do — preserves the
14
+ * R/T/E shape and **intersects** the `R` channel across composed steps
15
+ * (`R1 & R2`), so requirements accumulate as a chain is built.
16
+ *
17
+ * @example
18
+ * Lift a value, transform it, accumulate requirements, then provide them:
19
+ *
20
+ * ```ts
21
+ * import { okR } from '@konker.dev/neverthrow-r/constructors';
22
+ * import { andThen, map } from '@konker.dev/neverthrow-r/sync';
23
+ * import { pipe } from '@konker.dev/neverthrow-r/pipe';
24
+ * import { provide } from '@konker.dev/neverthrow-r/provide';
25
+ * import type { ResultR } from '@konker.dev/neverthrow-r/types';
26
+ *
27
+ * type WithMultiplier = { multiplier: number };
28
+ *
29
+ * const scaled = (n: number): ResultR<WithMultiplier, number, never> =>
30
+ * (r) => okR<number>(n * r.multiplier)(undefined);
31
+ *
32
+ * const program = pipe(
33
+ * okR<number>(2),
34
+ * map((n) => n + 1),
35
+ * andThen(scaled),
36
+ * );
37
+ *
38
+ * provide(program, { multiplier: 10 }); // Ok(30)
39
+ * ```
40
+ *
41
+ * @module
42
+ */
43
+ import type { Result, ResultAsync } from 'neverthrow';
44
+ /**
45
+ * A `Result<T, E>` that requires an environment `R` to produce.
46
+ *
47
+ * @remarks
48
+ * `ResultR<R, T, E>` is structurally `(r: R) => Result<T, E>`. The `R` channel
49
+ * is the third dimension this package adds on top of `neverthrow`: it makes
50
+ * dependencies (database handles, config, clocks, …) explicit in the type
51
+ * rather than implicit in the closure.
52
+ *
53
+ * Use `unknown` for `R` when no environment is required (most often via the
54
+ * default on constructors like {@link okR}).
55
+ *
56
+ * Composition operators in {@link sync} and {@link do} intersect `R` across
57
+ * steps, so `R1 & R2 & R3` falls out of `andThen`-style chains automatically.
58
+ *
59
+ * @typeParam R - The requirements (environment) the value depends on.
60
+ * @typeParam T - The success type.
61
+ * @typeParam E - The error type.
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * import type { ResultR } from '@konker.dev/neverthrow-r/types';
66
+ * import { ok } from 'neverthrow';
67
+ *
68
+ * type Deps = { now: () => Date };
69
+ *
70
+ * const currentYear: ResultR<Deps, number, never> =
71
+ * (r) => ok(r.now().getFullYear());
72
+ * ```
73
+ *
74
+ * @see {@link ResultAsyncR} for the async sibling.
75
+ * @see {@link provide} for supplying the environment.
76
+ */
77
+ export type ResultR<R, T, E> = (r: R) => Result<T, E>;
78
+ /**
79
+ * A `ResultAsync<T, E>` that requires an environment `R` to produce.
80
+ *
81
+ * @remarks
82
+ * The async sibling of {@link ResultR}. Structurally `(r: R) => ResultAsync<T, E>`.
83
+ * Combine sync and async values in one pipeline via the {@link bridges} module.
84
+ *
85
+ * @typeParam R - The requirements (environment) the value depends on.
86
+ * @typeParam T - The success type.
87
+ * @typeParam E - The error type.
88
+ *
89
+ * @example
90
+ * ```ts
91
+ * import type { ResultAsyncR } from '@konker.dev/neverthrow-r/types';
92
+ * import { okAsync } from 'neverthrow';
93
+ *
94
+ * type Deps = { fetch: (url: string) => Promise<unknown> };
95
+ *
96
+ * const fetchJson: (url: string) => ResultAsyncR<Deps, unknown, never> =
97
+ * (url) => (r) => okAsync(undefined).map(() => r.fetch(url));
98
+ * ```
99
+ *
100
+ * @see {@link ResultR} for the sync version.
101
+ */
102
+ export type ResultAsyncR<R, T, E> = (r: R) => ResultAsync<T, E>;
103
+ /**
104
+ * Flattens an intersection type into a single record so it renders nicely in
105
+ * inferred type displays and tooltips.
106
+ *
107
+ * @remarks
108
+ * Used internally where a chain has accumulated `R1 & R2 & R3 & …` and a
109
+ * cleaner display is desired (e.g. {@link provideSome}'s return type). Has no
110
+ * runtime effect.
111
+ *
112
+ * @typeParam T - The type to flatten.
113
+ *
114
+ * @example
115
+ * ```ts
116
+ * import type { Simplify } from '@konker.dev/neverthrow-r/types';
117
+ *
118
+ * type A = { a: number };
119
+ * type B = { b: string };
120
+ * type Combined = Simplify<A & B>; // { a: number; b: string }
121
+ * ```
122
+ */
123
+ export type Simplify<T> = {
124
+ [K in keyof T]: T[K];
125
+ } & {};
126
+ /**
127
+ * A record-shaped scope keyed by string field names, used by do-notation to
128
+ * accumulate intermediate values across a chain of `bindR` / `bindAsyncR`
129
+ * steps.
130
+ *
131
+ * @typeParam Keys - The union of string keys currently in the scope.
132
+ *
133
+ * @example
134
+ * ```ts
135
+ * import type { Scope } from '@konker.dev/neverthrow-r/types';
136
+ *
137
+ * type S = Scope<'user' | 'config'>;
138
+ * // { user: unknown; config: unknown }
139
+ * ```
140
+ *
141
+ * @see {@link ExtendedScope} for the type-level "add a field" operation.
142
+ */
143
+ export type Scope<Keys extends string> = Record<Keys, unknown>;
144
+ /**
145
+ * Adds a typed field `N: A` to an existing scope `S`, preserving the existing
146
+ * fields' types. Distributive over unions in `S`.
147
+ *
148
+ * @remarks
149
+ * This is the type-level operation behind {@link bindR}: it computes the
150
+ * record shape *after* a new field has been bound, with the new field's type
151
+ * `A` slotted in and existing fields untouched.
152
+ *
153
+ * @typeParam S - The existing scope record.
154
+ * @typeParam N - The string-literal name of the field being added.
155
+ * @typeParam A - The type of the newly bound value.
156
+ *
157
+ * @example
158
+ * ```ts
159
+ * import type { ExtendedScope } from '@konker.dev/neverthrow-r/types';
160
+ *
161
+ * type S0 = { user: { id: number } };
162
+ * type S1 = ExtendedScope<S0, 'role', 'admin' | 'guest'>;
163
+ * // { user: { id: number }; role: 'admin' | 'guest' }
164
+ * ```
165
+ *
166
+ * @see {@link bindR}
167
+ */
168
+ export type ExtendedScope<S extends object, N extends string, A> = S extends unknown ? {
169
+ [K in keyof S | N]: K extends N ? A : K extends keyof S ? S[K] : never;
170
+ } : never;
171
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,MAAM,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAEhE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG,EAAE,CAAC;AAExD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,KAAK,CAAC,IAAI,SAAS,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EAAE,CAAC,IAAI,CAAC,SAAS,OAAO,GAChF;KACG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK;CACvE,GACD,KAAK,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Type-level vocabulary for the package: the `ResultR` / `ResultAsyncR` shapes
3
+ * that add a *requirements* channel on top of `neverthrow`'s `Result` /
4
+ * `ResultAsync`, plus the helper types (`Scope`, `ExtendedScope`, `Simplify`)
5
+ * used by do-notation and intersection flattening.
6
+ *
7
+ * @remarks
8
+ * Most users only need {@link ResultR} and {@link ResultAsyncR}. The remaining
9
+ * exports are surfaced because the do-notation helpers (`bindR`, `bindAsyncR`)
10
+ * expose them in their return types, so consumers may encounter them in
11
+ * inferred types.
12
+ *
13
+ * Every operator across the package — sync, async, bridges, do — preserves the
14
+ * R/T/E shape and **intersects** the `R` channel across composed steps
15
+ * (`R1 & R2`), so requirements accumulate as a chain is built.
16
+ *
17
+ * @example
18
+ * Lift a value, transform it, accumulate requirements, then provide them:
19
+ *
20
+ * ```ts
21
+ * import { okR } from '@konker.dev/neverthrow-r/constructors';
22
+ * import { andThen, map } from '@konker.dev/neverthrow-r/sync';
23
+ * import { pipe } from '@konker.dev/neverthrow-r/pipe';
24
+ * import { provide } from '@konker.dev/neverthrow-r/provide';
25
+ * import type { ResultR } from '@konker.dev/neverthrow-r/types';
26
+ *
27
+ * type WithMultiplier = { multiplier: number };
28
+ *
29
+ * const scaled = (n: number): ResultR<WithMultiplier, number, never> =>
30
+ * (r) => okR<number>(n * r.multiplier)(undefined);
31
+ *
32
+ * const program = pipe(
33
+ * okR<number>(2),
34
+ * map((n) => n + 1),
35
+ * andThen(scaled),
36
+ * );
37
+ *
38
+ * provide(program, { multiplier: 10 }); // Ok(30)
39
+ * ```
40
+ *
41
+ * @module
42
+ */
43
+ export {};
44
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG"}
package/package.json ADDED
@@ -0,0 +1,117 @@
1
+ {
2
+ "name": "@konker.dev/neverthrow-r",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "author": "Konrad Markus <mail@konker.dev>",
6
+ "license": "ISC",
7
+ "description": "Extension for neverthrow to add a requirements/dependencies channel",
8
+ "homepage": "https://konker.dev/",
9
+ "keywords": [
10
+ "node",
11
+ "neverthrow",
12
+ "dependency",
13
+ "typescript",
14
+ "functional-programming"
15
+ ],
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/konker/konker.dev/packages/neverthrow-r"
19
+ },
20
+ "exports": {
21
+ "./package.json": "./package.json",
22
+ ".": {
23
+ "types": "./dist/index.d.ts",
24
+ "import": "./dist/index.js"
25
+ },
26
+ "./async": {
27
+ "types": "./dist/async.d.ts",
28
+ "import": "./dist/async.js"
29
+ },
30
+ "./bridges": {
31
+ "types": "./dist/bridges.d.ts",
32
+ "import": "./dist/bridges.js"
33
+ },
34
+ "./constructors": {
35
+ "types": "./dist/constructors.d.ts",
36
+ "import": "./dist/constructors.js"
37
+ },
38
+ "./do": {
39
+ "types": "./dist/do.d.ts",
40
+ "import": "./dist/do.js"
41
+ },
42
+ "./pipe": {
43
+ "types": "./dist/pipe.d.ts",
44
+ "import": "./dist/pipe.js"
45
+ },
46
+ "./provide": {
47
+ "types": "./dist/provide.d.ts",
48
+ "import": "./dist/provide.js"
49
+ },
50
+ "./sync": {
51
+ "types": "./dist/sync.d.ts",
52
+ "import": "./dist/sync.js"
53
+ },
54
+ "./types": {
55
+ "types": "./dist/types.d.ts",
56
+ "import": "./dist/types.js"
57
+ }
58
+ },
59
+ "files": [
60
+ "dist/**/*",
61
+ "!dist/**/*.test.*"
62
+ ],
63
+ "main": "dist/index.js",
64
+ "devDependencies": {
65
+ "@arethetypeswrong/cli": "^0.18.2",
66
+ "@effect/language-service": "^0.86.1",
67
+ "@eslint/compat": "^2.0.1",
68
+ "@eslint/js": "^9.39.2",
69
+ "@konker.dev/common-config": "^0.8.0",
70
+ "@types/node": "^25.8.0",
71
+ "@vitest/coverage-istanbul": "^4.1.6",
72
+ "aws-sdk-client-mock": "^4.1.0",
73
+ "aws-sdk-client-mock-vitest": "^7.0.1",
74
+ "eslint": "^9.39.2",
75
+ "eslint-plugin-fp": "^2.3.0",
76
+ "eslint-plugin-prettier": "^5.5.5",
77
+ "eslint-plugin-simple-import-sort": "^12.1.1",
78
+ "eslint-plugin-sort-destructure-keys": "^2.0.0",
79
+ "leasot": "^14.4.0",
80
+ "madge": "^8.0.0",
81
+ "prettier": "^3.8.3",
82
+ "tsx": "^4.22.1",
83
+ "type-coverage": "^2.29.7",
84
+ "typedoc": "^0.28.15",
85
+ "typedoc-plugin-markdown": "^4.4.0",
86
+ "typescript": "^5.9.3",
87
+ "typescript-eslint": "^8.52.0",
88
+ "vitest": "^4.1.6"
89
+ },
90
+ "dependencies": {
91
+ "neverthrow": "^8.2.0"
92
+ },
93
+ "scripts": {
94
+ "test": "vitest run --coverage",
95
+ "clean": "rm -rf dist && rm -f tsconfig.tsbuildinfo",
96
+ "typecheck": "tsc --noEmit",
97
+ "build": "pnpm run clean && tsc",
98
+ "type-coverage-check": "type-coverage --detail --at-least 97",
99
+ "circular-check": "madge --extensions ts --circular --no-color --no-spinner --warning src",
100
+ "eslint-check": "eslint --max-warnings=0 '**/*.{ts,js,json}'",
101
+ "eslint-fix": "npx eslint --fix||true",
102
+ "generated-exports-check": "npx --package=@konker.dev/common-config generate-exports-verify `pwd`",
103
+ "docs-generate": "typedoc",
104
+ "generated-docs-check": "pnpm run docs-generate && git diff --exit-code docs/reference",
105
+ "examples-check": "node scripts/check-examples.mjs",
106
+ "exports-check": "NPM_CONFIG_CACHE=.npm-cache attw --pack . --ignore-rules=cjs-resolves-to-esm --profile=esm-only",
107
+ "fixme-check": "leasot --exit-nicely --skip-unsupported src",
108
+ "prettier-check": "npx prettier --check --ignore-path .gitignore --ignore-path .prettierignore '**/*.{css,html,js,ts,json,md,yaml,yml}'",
109
+ "prettier-fix": "pnpm run prettier-check --write",
110
+ "lint-check": "pnpm run eslint-check && pnpm run prettier-check && pnpm run circular-check && pnpm run fixme-check",
111
+ "lint-fix": "pnpm run eslint-fix && pnpm run prettier-fix",
112
+ "pre-push": "pnpm run lint-check && pnpm run typecheck",
113
+ "codecov": "npx --package=@konker.dev/common-config codecov-upload `pwd` '@konker.dev/neverthrow-r'",
114
+ "ci": "pnpm run lint-check && pnpm run typecheck && pnpm run type-coverage-check && pnpm run test && pnpm run build && pnpm run generated-exports-check && pnpm run generated-docs-check && pnpm run examples-check && pnpm run exports-check && pnpm run fixme-check",
115
+ "cd": "pnpm run build && npx --package=@konker.dev/common-config npm-publish-if-version-not-exists `pwd`"
116
+ }
117
+ }