@terrygonguet/utils 0.0.1 → 0.0.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/package.json CHANGED
@@ -1,20 +1,35 @@
1
1
  {
2
2
  "name": "@terrygonguet/utils",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
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
  }
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,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,81 @@
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<T>
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<T> = API<T>
14
+ export type Maybe<T> = Some<T> | None<T>
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
+ return Object.create(
22
+ {
23
+ isSome: () => true,
24
+ isNone: () => false,
25
+ orDefault(this: Some<T>) {
26
+ return this.value
27
+ },
28
+ map(this: Some<T>, f) {
29
+ return Some(f(this.value)!)
30
+ },
31
+ flatMap(this: Some<T>, f) {
32
+ return f(this.value)
33
+ },
34
+ toJSON(this: Some<T>) {
35
+ return { $_kind, $_variant: $_variant_Some, value: this.value }
36
+ },
37
+ } as API<T>,
38
+ {
39
+ $_kind: { value: $_kind, enumerable: false, writable: false },
40
+ $_variant: { value: $_variant_Some, enumerable: false, writable: false },
41
+ value: { value, writable: false },
42
+ },
43
+ )
44
+ }
45
+
46
+ export const None: None<any> = Object.create(
47
+ {
48
+ isSome: () => false,
49
+ isNone: () => true,
50
+ orDefault: identity,
51
+ map: () => None,
52
+ flatMap: () => None,
53
+ toJSON: () => ({ $_kind, $_variant: $_variant_None }),
54
+ } as API<any>,
55
+ {
56
+ $_kind: { value: $_kind, enumerable: false, writable: false },
57
+ $_variant: { value: $_variant_None, enumerable: false, writable: false },
58
+ },
59
+ )
60
+
61
+ export const Maybe = {
62
+ Some,
63
+ None,
64
+ from<T>(value: T | undefined | null): Maybe<T> {
65
+ switch (value) {
66
+ case null:
67
+ case undefined:
68
+ return None
69
+ default:
70
+ return Some(value!)
71
+ }
72
+ },
73
+ JSONReviver(_key: string, value: any) {
74
+ if (value?.$_kind == $_kind) {
75
+ const $_variant = value?.$_variant
76
+ if ($_variant == $_variant_Some) return Some<unknown>(value?.value)
77
+ else if ($_variant == $_variant_None) return None
78
+ else return value
79
+ } else return value
80
+ },
81
+ }
@@ -0,0 +1,102 @@
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
+ return Object.create(
21
+ {
22
+ isSuccess: () => true,
23
+ isFailure: () => false,
24
+ map<S2>(this: Success<S, F>, f: (value: S) => S2) {
25
+ return Success(f(this.value))
26
+ },
27
+ flatMap<S2, F2>(this: Success<S, F>, f: (value: S) => Result<S2, F2>) {
28
+ return f(this.value)
29
+ },
30
+ toJSON(this: Success<S, F>) {
31
+ return { $_kind, $_variant: $_variant_Success, value: this.value }
32
+ },
33
+ } as API<S, F>,
34
+ {
35
+ $_kind: { value: $_kind, enumerable: false, writable: false },
36
+ $_variant: { value: $_variant_Success, enumerable: false, writable: false },
37
+ value: { value, writable: false },
38
+ },
39
+ )
40
+ }
41
+
42
+ export function Failure<S, F>(reason: F): Failure<S, F> {
43
+ return Object.create(
44
+ {
45
+ isSuccess: () => false,
46
+ isFailure: () => true,
47
+ map<S2>(this: Failure<S, F>) {
48
+ return this as unknown as Result<S2, F>
49
+ },
50
+ flatMap<S2, F2>(this: Failure<S, F>) {
51
+ return this as unknown as Result<S2, F | F2>
52
+ },
53
+ toJSON(this: Failure<S, F>) {
54
+ return { $_kind, $_variant: $_variant_Failure, reason: this.reason }
55
+ },
56
+ } as API<S, F>,
57
+ {
58
+ $_kind: { value: $_kind, enumerable: false, writable: false },
59
+ $_variant: { value: $_variant_Success, enumerable: false, writable: false },
60
+ reason: { value: reason, writable: false },
61
+ },
62
+ )
63
+ }
64
+
65
+ export const Result = {
66
+ Success,
67
+ Failure,
68
+ try<S, F>(tryFn: () => S) {
69
+ return new TryCatch<S, F>(tryFn)
70
+ },
71
+ JSONReviver(_key: string, value: any) {
72
+ if (value?.$_kind == $_kind) {
73
+ const $_variant = value?.$_variant
74
+ if ($_variant == $_variant_Success) return Success<unknown, unknown>(value?.value)
75
+ else if ($_variant == $_variant_Failure) return Failure<unknown, unknown>(value?.reason)
76
+ else return value
77
+ } else return value
78
+ },
79
+ }
80
+
81
+ export class TryCatch<S, F> {
82
+ tryFn: () => S
83
+ catchFn: (err: unknown) => F
84
+
85
+ constructor(tryFn: () => S) {
86
+ this.tryFn = tryFn
87
+ this.catchFn = identity as any
88
+ }
89
+
90
+ catch(catchFn: (err: unknown) => F) {
91
+ this.catchFn = catchFn
92
+ return this
93
+ }
94
+
95
+ exec(): Result<S, F> {
96
+ try {
97
+ return Success<S, F>(this.tryFn())
98
+ } catch (error) {
99
+ return Failure<S, F>(this.catchFn(error))
100
+ }
101
+ }
102
+ }
package/src/main.ts CHANGED
@@ -1,3 +1,25 @@
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
+ type JSONReviver = (key: string, value: any) => any
9
+
10
+ export function safeParse<T>(str: string, defaultValue: T, reviver?: JSONReviver) {
11
+ try {
12
+ return JSON.parse(str, reviver)
13
+ } catch (_) {
14
+ return defaultValue
15
+ }
16
+ }
17
+
18
+ export function composeJSONRevivers(...revivers: JSONReviver[]): JSONReviver {
19
+ return function (key, value) {
20
+ for (const reviver of revivers) {
21
+ value = reviver(key, value)
22
+ }
23
+ return value
24
+ }
25
+ }
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,22 @@
1
+ interface API<T> {
2
+ isSome(this: Maybe<T>): this is Some<T>;
3
+ isNone(this: Maybe<T>): this is None<T>;
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<T> = API<T>;
13
+ export type Maybe<T> = Some<T> | None<T>;
14
+ export declare function Some<T>(value: NonNullable<T>): Some<T>;
15
+ export declare const None: None<any>;
16
+ export declare const Maybe: {
17
+ Some: typeof Some;
18
+ None: None<any>;
19
+ from<T>(value: T | null | undefined): Maybe<T>;
20
+ JSONReviver(_key: string, value: any): any;
21
+ };
22
+ export {};
@@ -0,0 +1,30 @@
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
+ Success: typeof Success;
19
+ Failure: typeof Failure;
20
+ try<S, F>(tryFn: () => S): TryCatch<S, F>;
21
+ JSONReviver(_key: string, value: any): any;
22
+ };
23
+ export declare class TryCatch<S, F> {
24
+ tryFn: () => S;
25
+ catchFn: (err: unknown) => F;
26
+ constructor(tryFn: () => S);
27
+ catch(catchFn: (err: unknown) => F): this;
28
+ exec(): Result<S, F>;
29
+ }
30
+ export {};
package/types/main.d.ts CHANGED
@@ -1 +1,8 @@
1
+ /**
2
+ * Behaviour is undefined when max < min
3
+ */
1
4
  export declare function clamp(value: number, min: number, max: number): number;
5
+ type JSONReviver = (key: string, value: any) => any;
6
+ export declare function safeParse<T>(str: string, defaultValue: T, reviver?: JSONReviver): any;
7
+ export declare function composeJSONRevivers(...revivers: JSONReviver[]): JSONReviver;
8
+ export {};
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
+ })