@terrygonguet/utils 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,20 +1,35 @@
1
1
  {
2
2
  "name": "@terrygonguet/utils",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "dev": "vite",
7
7
  "build": "tsc && vite build",
8
- "preview": "vite preview"
8
+ "test": "vitest test --ui --watch --update",
9
+ "coverage": "vitest run --coverage"
9
10
  },
10
11
  "devDependencies": {
12
+ "@vitest/ui": "^0.32.0",
13
+ "prettier": "^2.8.8",
11
14
  "typescript": "^5.0.2",
12
- "vite": "^4.3.9"
15
+ "vite": "^4.3.9",
16
+ "vitest": "^0.32.0"
13
17
  },
14
18
  "exports": {
15
19
  ".": {
16
- "types": "./dist/main.js",
17
- "import": "./types/main.d.ts"
20
+ "types": "./types/main.js",
21
+ "import": "./dist/main.d.ts"
22
+ },
23
+ "./async": {
24
+ "types": "./types/async.js",
25
+ "import": "./dist/async.d.ts"
26
+ },
27
+ "./functional": {
28
+ "types": "./types/functional/index.d.ts",
29
+ "import": "./dist/functional.js"
18
30
  }
31
+ },
32
+ "dependencies": {
33
+ "just-compose": "^2.3.0"
19
34
  }
20
35
  }
@@ -0,0 +1,9 @@
1
+ import { describe } from "vitest"
2
+ import { wait } from "./async.ts"
3
+
4
+ describe("wait", it => {
5
+ it("Waits", async ({ expect }) => {
6
+ // TODO: figure out how to test that
7
+ await expect(wait(25)).resolves
8
+ })
9
+ })
package/src/async.ts ADDED
@@ -0,0 +1,3 @@
1
+ export function wait(ms: number): Promise<void> {
2
+ return new Promise(resolve => setTimeout(resolve, ms))
3
+ }
@@ -0,0 +1,11 @@
1
+ import { describe } from "vitest"
2
+ import { identity } from "./index.ts"
3
+
4
+ describe.concurrent("identity()", it => {
5
+ it("does nothing", ({ expect }) => {
6
+ expect(identity(5)).to.equal(5)
7
+ expect(identity("test")).to.equal("test")
8
+ const object = { prop: "value" }
9
+ expect(identity(object)).to.equal(object)
10
+ })
11
+ })
@@ -0,0 +1,7 @@
1
+ export * from "./maybe.ts"
2
+ export * from "./result.ts"
3
+ export { default as compose } from "just-compose"
4
+
5
+ export function identity<T>(value: T) {
6
+ return value
7
+ }
@@ -0,0 +1,85 @@
1
+ import { describe } from "vitest"
2
+ import { Some, None, Maybe } from "./maybe.ts"
3
+
4
+ describe.concurrent("Maybe", it => {
5
+ /** @type {Maybe<number>} */
6
+ const some = Some(5)
7
+ /** @type {Maybe<number>} */
8
+ const none = None
9
+
10
+ it("isSome()", ({ expect }) => {
11
+ expect(some.isSome()).to.be.true
12
+ expect(none.isSome()).to.be.false
13
+ })
14
+
15
+ it("isNone()", ({ expect }) => {
16
+ expect(some.isNone()).to.be.false
17
+ expect(none.isNone()).to.be.true
18
+ })
19
+
20
+ it("orDefault()", ({ expect }) => {
21
+ expect(some.orDefault(15)).to.equal(5)
22
+ expect(none.orDefault(15)).to.equal(15)
23
+ })
24
+
25
+ it("map()", ({ expect }) => {
26
+ const mappedSome = some.map(n => n * 2)
27
+ expect(mappedSome.isSome()).to.be.true
28
+ expect(mappedSome.value).to.equal(10)
29
+ const mappedNone = none.map(n => n * 2)
30
+ expect(mappedNone.isNone()).to.be.true
31
+ })
32
+
33
+ it("flatMap()", ({ expect }) => {
34
+ const some1 = some.flatMap(n => Some(n * 2))
35
+ expect(some1.isSome()).to.be.true
36
+ expect(some1.value).to.equal(10)
37
+ const none1 = some.flatMap(n => None)
38
+ expect(none1.isNone()).to.be.true
39
+ const some2 = none.flatMap(n => Some(n * 2))
40
+ expect(some2.isSome()).to.be.false
41
+ const none2 = some.flatMap(n => None)
42
+ expect(none2.isNone()).to.be.true
43
+ })
44
+
45
+ it("toJSON()", ({ expect }) => {
46
+ expect(some.toJSON()).toMatchInlineSnapshot()
47
+ expect(none.toJSON()).toMatchInlineSnapshot()
48
+ })
49
+
50
+ describe.concurrent("Maybe.JSONReviver()", it => {
51
+ const $_kind = "@terrygonguet/utils/functional/maybe"
52
+ const $_variant_Some = "@terrygonguet/utils/functional/maybe/Some"
53
+ const $_variant_None = "@terrygonguet/utils/functional/maybe/None"
54
+
55
+ it("does nothing to normal objects", ({ expect }) => {
56
+ const json1 = `{"prop":"value"}`
57
+ const obj1 = JSON.parse(json1, Maybe.JSONReviver)
58
+ expect(obj1).to.deep.equal({ prop: "value" })
59
+ })
60
+
61
+ it("revives a Some", ({ expect }) => {
62
+ const json2 = `{"prop":"value","some":{"$_kind":"${$_kind}","$_variant":"${$_variant_Some}","value":5}}`
63
+ const obj2 = JSON.parse(json2, Maybe.JSONReviver)
64
+ expect(obj2.prop).to.equal("value")
65
+ expect(obj2.some.isSome()).to.be.true
66
+ expect(obj2.some.value).to.equal(5)
67
+ })
68
+
69
+ it("revives a None", ({ expect }) => {
70
+ const json3 = `{"prop":"value","none":{"$_kind":"${$_kind}","$_variant":"${$_variant_None}"}}`
71
+ const obj3 = JSON.parse(json3, Maybe.JSONReviver)
72
+ expect(obj3.prop).to.equal("value")
73
+ expect(obj3.none).to.equal(None)
74
+ })
75
+
76
+ it("does a round trip", ({ expect }) => {
77
+ const json4 = JSON.stringify({ prop: "value", some: Some(5), none: None })
78
+ const obj4 = JSON.parse(json4, Maybe.JSONReviver)
79
+ expect(obj4.prop).to.equal("value")
80
+ expect(obj4.some.isSome()).to.be.true
81
+ expect(obj4.some.value).to.equal(5)
82
+ expect(obj4.none).to.equal(None)
83
+ })
84
+ })
85
+ })
@@ -0,0 +1,75 @@
1
+ import { identity } from "./index.ts"
2
+
3
+ interface API<T> {
4
+ isSome(this: Maybe<T>): this is Some<T>
5
+ isNone(this: Maybe<T>): this is None
6
+ orDefault(this: Maybe<T>, defaultValue: T): T
7
+ map<U>(this: Maybe<T>, f: (value: T) => U): Maybe<U>
8
+ flatMap<U>(this: Maybe<T>, f: (value: T) => Maybe<U>): Maybe<U>
9
+ toJSON(this: Maybe<T>): Object
10
+ }
11
+
12
+ export type Some<T> = { value: T } & API<T>
13
+ export type None = {} & API<never>
14
+ export type Maybe<T> = Some<T> | None
15
+
16
+ const $_kind = "@terrygonguet/utils/functional/maybe"
17
+ const $_variant_Some = "@terrygonguet/utils/functional/maybe/Some"
18
+ const $_variant_None = "@terrygonguet/utils/functional/maybe/None"
19
+
20
+ export function Some<T>(value: NonNullable<T>): Some<T> {
21
+ const SomePrototype: API<T> = {
22
+ isSome: () => true,
23
+ isNone: () => false,
24
+ orDefault(this: Some<T>) {
25
+ return this.value
26
+ },
27
+ map(this: Some<T>, f) {
28
+ return Some(f(this.value)!)
29
+ },
30
+ flatMap(this: Some<T>, f) {
31
+ return f(this.value)
32
+ },
33
+ toJSON(this: Some<T>) {
34
+ return { $_kind, $_variant: $_variant_Some, value: this.value }
35
+ },
36
+ }
37
+ return Object.create(SomePrototype, {
38
+ $_kind: { value: $_kind, enumerable: false, writable: false },
39
+ $_variant: { value: $_variant_Some, enumerable: false, writable: false },
40
+ value: { value, writable: false },
41
+ })
42
+ }
43
+
44
+ const NonePrototype: API<never> = {
45
+ isSome: () => false,
46
+ isNone: () => true,
47
+ orDefault: identity,
48
+ map: () => None,
49
+ flatMap: () => None,
50
+ toJSON: () => ({ $_kind, $_variant: $_variant_None }),
51
+ }
52
+ export const None: None = Object.create(NonePrototype, {
53
+ $_kind: { value: $_kind, enumerable: false, writable: false },
54
+ $_variant: { value: $_variant_None, enumerable: false, writable: false },
55
+ })
56
+
57
+ export const Maybe = {
58
+ from<T>(value: T | undefined | null): Maybe<T> {
59
+ switch (value) {
60
+ case null:
61
+ case undefined:
62
+ return None
63
+ default:
64
+ return Some(value!)
65
+ }
66
+ },
67
+ JSONReviver(_key: string, value: any) {
68
+ if (value?.$_kind == $_kind) {
69
+ const $_variant = value?.$_variant
70
+ if ($_variant == $_variant_Some) return Some<unknown>(value?.value)
71
+ else if ($_variant == $_variant_None) return None
72
+ else return value
73
+ } else return value
74
+ },
75
+ }
@@ -0,0 +1,150 @@
1
+ import { describe } from "vitest"
2
+ import { Success, Failure, Result } from "./result.ts"
3
+
4
+ describe.concurrent("Result", it => {
5
+ /** @type {Result<number, string>} */
6
+ const success = Success(5)
7
+ /** @type {Result<number, string>} */
8
+ const failure = Failure("reason")
9
+
10
+ it("isSuccess()", ({ expect }) => {
11
+ expect(success.isSuccess()).to.be.true
12
+ expect(failure.isSuccess()).to.be.false
13
+ })
14
+
15
+ it("isFailure()", ({ expect }) => {
16
+ expect(success.isFailure()).to.be.false
17
+ expect(failure.isFailure()).to.be.true
18
+ })
19
+
20
+ it("map()", ({ expect }) => {
21
+ const mappedSuccess = success.map(n => n * 2)
22
+ expect(mappedSuccess.isSuccess()).to.be.true
23
+ expect(mappedSuccess.value).to.equal(10)
24
+ const mappedFailure = failure.map(n => n * 2)
25
+ expect(mappedFailure.isSuccess()).to.be.false
26
+ })
27
+
28
+ it("flatMap()", ({ expect }) => {
29
+ const succ1 = success.flatMap(n => Success(n * 2))
30
+ expect(succ1.isSuccess()).to.be.true
31
+ expect(succ1.value).to.equal(10)
32
+
33
+ const fail1 = success.flatMap(n => Failure("fail"))
34
+ expect(fail1.isSuccess()).to.be.false
35
+ expect(fail1.reason).to.equal("fail")
36
+
37
+ const fail2 = failure.flatMap(n => Success(n * 2))
38
+ expect(fail2.isSuccess()).to.be.false
39
+ expect(fail2.reason).to.equal("reason")
40
+
41
+ const fail3 = failure.flatMap(n => Failure("fail"))
42
+ expect(fail3.isSuccess()).to.be.false
43
+ expect(fail3.reason).to.equal("reason")
44
+ })
45
+
46
+ it("toJSON()", ({ expect }) => {
47
+ expect(success.toJSON()).toMatchInlineSnapshot(`
48
+ {
49
+ "$_kind": "@terrygonguet/utils/functional/result",
50
+ "$_variant": "@terrygonguet/utils/functional/result/Success",
51
+ "value": 5,
52
+ }
53
+ `)
54
+ expect(failure.toJSON()).toMatchInlineSnapshot(`
55
+ {
56
+ "$_kind": "@terrygonguet/utils/functional/result",
57
+ "$_variant": "@terrygonguet/utils/functional/result/Failure",
58
+ "reason": "reason",
59
+ }
60
+ `)
61
+ })
62
+
63
+ describe.concurrent("Result.JSONReviver()", it => {
64
+ const $_kind = "@terrygonguet/utils/functional/result"
65
+ const $_variant_Success = "@terrygonguet/utils/functional/result/Success"
66
+ const $_variant_Failure = "@terrygonguet/utils/functional/result/Failure"
67
+
68
+ it("does nothing to normal objects", ({ expect }) => {
69
+ const json = `{"prop":"value"}`
70
+ const obj = JSON.parse(json, Result.JSONReviver)
71
+ expect(obj.prop).to.equal("value")
72
+ })
73
+
74
+ it("revives a Success", ({ expect }) => {
75
+ const json = `{
76
+ "prop":"value",
77
+ "success": {
78
+ "$_kind": "@terrygonguet/utils/functional/result",
79
+ "$_variant": "@terrygonguet/utils/functional/result/Success",
80
+ "value": 5
81
+ }
82
+ }`
83
+ const obj = JSON.parse(json, Result.JSONReviver)
84
+ expect(obj.prop).to.equal("value")
85
+ expect(obj.success.isSuccess()).to.be.true
86
+ expect(obj.success.value).to.equal(5)
87
+ })
88
+
89
+ it("revives a Failure", ({ expect }) => {
90
+ const json = `{
91
+ "prop":"value",
92
+ "failure": {
93
+ "$_kind": "@terrygonguet/utils/functional/result",
94
+ "$_variant": "@terrygonguet/utils/functional/result/Failure",
95
+ "reason": "reason"
96
+ }
97
+ }`
98
+ const obj = JSON.parse(json, Result.JSONReviver)
99
+ expect(obj.prop).to.equal("value")
100
+ expect(obj.failure.isSuccess()).to.be.false
101
+ expect(obj.failure.reason).to.equal("reason")
102
+ })
103
+
104
+ it("does a round trip", ({ expect }) => {
105
+ const json = JSON.stringify({ prop: "value", success, failure })
106
+ const obj = JSON.parse(json, Result.JSONReviver)
107
+ expect(obj.prop).to.equal("value")
108
+ expect(obj.success.isSuccess()).to.be.true
109
+ expect(obj.success.value).to.equal(5)
110
+ expect(obj.failure.isSuccess()).to.be.false
111
+ expect(obj.failure.reason).to.equal("reason")
112
+ })
113
+ })
114
+
115
+ describe("Result.try()", it => {
116
+ it("gets the value from the try function", ({ expect }) => {
117
+ const result = Result.try(() => {
118
+ const n = 5
119
+ return n * 2
120
+ }).exec()
121
+ expect(result.isSuccess()).to.be.true
122
+ expect(result.value).to.equal(10)
123
+ })
124
+
125
+ it("gets the value from catch on error", ({ expect }) => {
126
+ const result = Result.try(() => {
127
+ throw new Error("fail")
128
+ })
129
+ .catch(err => {
130
+ return err.message
131
+ })
132
+ .exec()
133
+ expect(result.isSuccess()).to.be.false
134
+ expect(result.reason).to.equal("fail")
135
+ })
136
+
137
+ it("ignores catch if try does not throw", ({ expect }) => {
138
+ const result = Result.try(() => {
139
+ const n = 5
140
+ return n * 2
141
+ })
142
+ .catch(err => {
143
+ throw new Error("Should not run")
144
+ })
145
+ .exec()
146
+ expect(result.isSuccess()).to.be.true
147
+ expect(result.value).to.equal(10)
148
+ })
149
+ })
150
+ })
@@ -0,0 +1,96 @@
1
+ import { identity } from "./index.ts"
2
+
3
+ interface API<S, F> {
4
+ isSuccess(this: Result<S, F>): this is Success<S, F>
5
+ isFailure(this: Result<S, F>): this is Failure<S, F>
6
+ map<S2>(this: Result<S, F>, f: (value: S) => S2): Result<S2, F>
7
+ flatMap<S2, F2>(this: Result<S, F>, f: (value: S) => Result<S2, F | F2>): Result<S2, F | F2>
8
+ toJSON(this: Result<S, F>): Object
9
+ }
10
+
11
+ export type Success<S, F> = { value: S } & API<S, F>
12
+ export type Failure<S, F> = { reason: F } & API<S, F>
13
+ export type Result<S, F> = Success<S, F> | Failure<S, F>
14
+
15
+ const $_kind = "@terrygonguet/utils/functional/result"
16
+ const $_variant_Success = "@terrygonguet/utils/functional/result/Success"
17
+ const $_variant_Failure = "@terrygonguet/utils/functional/result/Failure"
18
+
19
+ export function Success<S, F>(value: S): Success<S, F> {
20
+ const SuccessPrototype: API<S, F> = {
21
+ isSuccess: () => true,
22
+ isFailure: () => false,
23
+ map<S2>(this: Success<S, F>, f: (value: S) => S2) {
24
+ return Success(f(this.value))
25
+ },
26
+ flatMap<S2, F2>(this: Success<S, F>, f: (value: S) => Result<S2, F2>) {
27
+ return f(this.value)
28
+ },
29
+ toJSON(this: Success<S, F>) {
30
+ return { $_kind, $_variant: $_variant_Success, value: this.value }
31
+ },
32
+ }
33
+ return Object.create(SuccessPrototype, {
34
+ $_kind: { value: $_kind, enumerable: false, writable: false },
35
+ $_variant: { value: $_variant_Success, enumerable: false, writable: false },
36
+ value: { value, writable: false },
37
+ })
38
+ }
39
+
40
+ export function Failure<S, F>(reason: F): Failure<S, F> {
41
+ const FailurePrototype: API<S, F> = {
42
+ isSuccess: () => false,
43
+ isFailure: () => true,
44
+ map<S2>(this: Failure<S, F>) {
45
+ return this as unknown as Result<S2, F>
46
+ },
47
+ flatMap<S2, F2>(this: Failure<S, F>) {
48
+ return this as unknown as Result<S2, F | F2>
49
+ },
50
+ toJSON(this: Failure<S, F>) {
51
+ return { $_kind, $_variant: $_variant_Failure, reason: this.reason }
52
+ },
53
+ }
54
+ return Object.create(FailurePrototype, {
55
+ $_kind: { value: $_kind, enumerable: false, writable: false },
56
+ $_variant: { value: $_variant_Success, enumerable: false, writable: false },
57
+ reason: { value: reason, writable: false },
58
+ })
59
+ }
60
+
61
+ export const Result = {
62
+ try<S, F>(tryFn: () => S) {
63
+ return new TryCatch<S, F>(tryFn)
64
+ },
65
+ JSONReviver(_key: string, value: any) {
66
+ if (value?.$_kind == $_kind) {
67
+ const $_variant = value?.$_variant
68
+ if ($_variant == $_variant_Success) return Success<unknown, unknown>(value?.value)
69
+ else if ($_variant == $_variant_Failure) return Failure<unknown, unknown>(value?.reason)
70
+ else return value
71
+ } else return value
72
+ },
73
+ }
74
+
75
+ class TryCatch<S, F> {
76
+ tryFn: () => S
77
+ catchFn: (err: unknown) => F
78
+
79
+ constructor(tryFn: () => S) {
80
+ this.tryFn = tryFn
81
+ this.catchFn = identity as any
82
+ }
83
+
84
+ catch(catchFn: (err: unknown) => F) {
85
+ this.catchFn = catchFn
86
+ return this
87
+ }
88
+
89
+ exec(): Result<S, F> {
90
+ try {
91
+ return Success<S, F>(this.tryFn())
92
+ } catch (error) {
93
+ return Failure<S, F>(this.catchFn(error))
94
+ }
95
+ }
96
+ }
@@ -0,0 +1,43 @@
1
+ import { describe } from "vitest"
2
+ import { clamp, safeParse } from "./main.ts"
3
+
4
+ describe.concurrent("clamp()", it => {
5
+ it("does nothing to values within range", ({ expect }) => {
6
+ expect(clamp(5, 0, 10)).to.equal(5)
7
+ expect(clamp(10, 10, 10)).to.equal(10)
8
+ expect(clamp(0, 0, 10)).to.equal(0)
9
+ expect(clamp(10, 0, 10)).to.equal(10)
10
+ })
11
+
12
+ it("clamps values outside of range", ({ expect }) => {
13
+ expect(clamp(-5, 0, 10)).to.equal(0)
14
+ expect(clamp(15, 0, 10)).to.equal(10)
15
+ expect(clamp(-5, 10, 10)).to.equal(10)
16
+ expect(clamp(15, 10, 10)).to.equal(10)
17
+ })
18
+ })
19
+
20
+ describe.concurrent("safeParse()", it => {
21
+ it("works the same as JSON.parse for valid objects", ({ expect }) => {
22
+ const json = `{"prop":"value"}`
23
+ expect(safeParse(json, {})).to.deep.equal(JSON.parse(json))
24
+ })
25
+
26
+ it("uses default value for malformed JSON", ({ expect }) => {
27
+ const json = `{"prop":}`
28
+ expect(safeParse(json, { prop: "default" })).to.deep.equal({ prop: "default" })
29
+ })
30
+
31
+ it("uses revivers", ({ expect }) => {
32
+ const json = `{"prop":"value","other":"ignored"}`
33
+ function reviver(key, value) {
34
+ if (key == "prop") return "replaced"
35
+ else return value
36
+ }
37
+ const defaultValue = { prop: "value", other: "ignored" }
38
+ expect(safeParse(json, defaultValue, reviver)).to.deep.equal({
39
+ prop: "replaced",
40
+ other: "ignored",
41
+ })
42
+ })
43
+ })
package/src/main.ts CHANGED
@@ -1,3 +1,18 @@
1
+ /**
2
+ * Behaviour is undefined when max < min
3
+ */
1
4
  export function clamp(value: number, min: number, max: number) {
2
5
  return Math.min(Math.max(value, min), max)
3
- }
6
+ }
7
+
8
+ export function safeParse<T>(
9
+ str: string,
10
+ defaultValue: T,
11
+ reviver?: (key: string, value: any) => any,
12
+ ) {
13
+ try {
14
+ return JSON.parse(str, reviver)
15
+ } catch (_) {
16
+ return defaultValue
17
+ }
18
+ }
package/tsconfig.json CHANGED
@@ -3,12 +3,13 @@
3
3
  "target": "ES2020",
4
4
  "useDefineForClassFields": true,
5
5
  "module": "ESNext",
6
- "lib": ["ES2020"],
6
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
7
7
  "skipLibCheck": true,
8
8
 
9
9
  /* Bundler mode */
10
10
  "moduleResolution": "node16",
11
11
  "allowImportingTsExtensions": true,
12
+ "allowSyntheticDefaultImports": true,
12
13
  "resolveJsonModule": true,
13
14
  "isolatedModules": true,
14
15
  "declaration": true,
@@ -18,8 +19,7 @@
18
19
  /* Linting */
19
20
  "strict": true,
20
21
  "noUnusedLocals": true,
21
- "noUnusedParameters": true,
22
- "noFallthroughCasesInSwitch": true
22
+ "noUnusedParameters": true
23
23
  },
24
24
  "include": ["src"]
25
25
  }
@@ -0,0 +1 @@
1
+ export declare function wait(ms: number): Promise<void>;
@@ -0,0 +1,4 @@
1
+ export * from "./maybe.ts";
2
+ export * from "./result.ts";
3
+ export { default as compose } from "just-compose";
4
+ export declare function identity<T>(value: T): T;
@@ -0,0 +1,20 @@
1
+ interface API<T> {
2
+ isSome(this: Maybe<T>): this is Some<T>;
3
+ isNone(this: Maybe<T>): this is None;
4
+ orDefault(this: Maybe<T>, defaultValue: T): T;
5
+ map<U>(this: Maybe<T>, f: (value: T) => U): Maybe<U>;
6
+ flatMap<U>(this: Maybe<T>, f: (value: T) => Maybe<U>): Maybe<U>;
7
+ toJSON(this: Maybe<T>): Object;
8
+ }
9
+ export type Some<T> = {
10
+ value: T;
11
+ } & API<T>;
12
+ export type None = {} & API<never>;
13
+ export type Maybe<T> = Some<T> | None;
14
+ export declare function Some<T>(value: NonNullable<T>): Some<T>;
15
+ export declare const None: None;
16
+ export declare const Maybe: {
17
+ from<T>(value: T | null | undefined): Maybe<T>;
18
+ JSONReviver(_key: string, value: any): any;
19
+ };
20
+ export {};
@@ -0,0 +1,28 @@
1
+ interface API<S, F> {
2
+ isSuccess(this: Result<S, F>): this is Success<S, F>;
3
+ isFailure(this: Result<S, F>): this is Failure<S, F>;
4
+ map<S2>(this: Result<S, F>, f: (value: S) => S2): Result<S2, F>;
5
+ flatMap<S2, F2>(this: Result<S, F>, f: (value: S) => Result<S2, F | F2>): Result<S2, F | F2>;
6
+ toJSON(this: Result<S, F>): Object;
7
+ }
8
+ export type Success<S, F> = {
9
+ value: S;
10
+ } & API<S, F>;
11
+ export type Failure<S, F> = {
12
+ reason: F;
13
+ } & API<S, F>;
14
+ export type Result<S, F> = Success<S, F> | Failure<S, F>;
15
+ export declare function Success<S, F>(value: S): Success<S, F>;
16
+ export declare function Failure<S, F>(reason: F): Failure<S, F>;
17
+ export declare const Result: {
18
+ try<S, F>(tryFn: () => S): TryCatch<S, F>;
19
+ JSONReviver(_key: string, value: any): any;
20
+ };
21
+ declare class TryCatch<S, F> {
22
+ tryFn: () => S;
23
+ catchFn: (err: unknown) => F;
24
+ constructor(tryFn: () => S);
25
+ catch(catchFn: (err: unknown) => F): this;
26
+ exec(): Result<S, F>;
27
+ }
28
+ export {};
package/types/main.d.ts CHANGED
@@ -1 +1,5 @@
1
+ /**
2
+ * Behaviour is undefined when max < min
3
+ */
1
4
  export declare function clamp(value: number, min: number, max: number): number;
5
+ export declare function safeParse<T>(str: string, defaultValue: T, reviver?: (key: string, value: any) => any): any;
package/vite.config.js CHANGED
@@ -1,13 +1,15 @@
1
- import { resolve } from "path"
2
- import { defineConfig } from "vite"
3
-
4
- export default defineConfig({
5
- build: {
6
- lib: {
7
- formats: ["es"],
8
- entry: {
9
- main: resolve(__dirname, "src/main.ts"),
10
- },
11
- },
12
- },
13
- })
1
+ import { resolve } from "path"
2
+ import { defineConfig } from "vite"
3
+
4
+ export default defineConfig({
5
+ build: {
6
+ lib: {
7
+ formats: ["es"],
8
+ entry: {
9
+ main: resolve(__dirname, "src/main.ts"),
10
+ async: resolve(__dirname, "src/async.ts"),
11
+ functional: resolve(__dirname, "src/functional/index.ts"),
12
+ },
13
+ },
14
+ },
15
+ })