@oricardopestana/ts-utils 1.0.1 → 1.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/.github/workflows/publish.yml +51 -0
- package/README.md +1 -0
- package/global.d.ts +6 -0
- package/package.json +6 -3
- package/use-async/index.spec.ts +56 -0
- package/use-async/index.ts +26 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: Test & Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: actions/setup-node@v4
|
|
15
|
+
with:
|
|
16
|
+
node-version: 22.13
|
|
17
|
+
- uses: pnpm/action-setup@v4
|
|
18
|
+
with:
|
|
19
|
+
version: latest
|
|
20
|
+
- run: pnpm install --frozen-lockfile
|
|
21
|
+
- run: pnpm test
|
|
22
|
+
|
|
23
|
+
publish:
|
|
24
|
+
needs: test
|
|
25
|
+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
permissions:
|
|
28
|
+
contents: write
|
|
29
|
+
id-token: write
|
|
30
|
+
steps:
|
|
31
|
+
- uses: actions/checkout@v4
|
|
32
|
+
- uses: actions/setup-node@v4
|
|
33
|
+
with:
|
|
34
|
+
node-version: 22.13
|
|
35
|
+
- uses: pnpm/action-setup@v4
|
|
36
|
+
with:
|
|
37
|
+
version: latest
|
|
38
|
+
- run: pnpm install --frozen-lockfile
|
|
39
|
+
|
|
40
|
+
- run: npm version patch --no-git-tag-version
|
|
41
|
+
|
|
42
|
+
- run: |
|
|
43
|
+
git config user.name "github-actions[bot]"
|
|
44
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
45
|
+
git add package.json
|
|
46
|
+
git commit -m "chore: bump version to $(node -p "require('./package.json').version") [skip ci]"
|
|
47
|
+
git tag v$(node -p "require('./package.json').version")
|
|
48
|
+
git push --tags
|
|
49
|
+
git push
|
|
50
|
+
|
|
51
|
+
- run: pnpm publish --provenance --access public
|
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# ts-utils
|
package/global.d.ts
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oricardopestana/ts-utils",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "TypeScript utilities",
|
|
5
5
|
"homepage": "https://github.com/oricardopestana/ts-utils#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -14,7 +14,10 @@
|
|
|
14
14
|
"author": "Ricardo Pestana (https://github.com/oricardopestana)",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"main": "index.js",
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"vitest": "^4.1.8"
|
|
19
|
+
},
|
|
17
20
|
"scripts": {
|
|
18
|
-
"test": "
|
|
21
|
+
"test": "vitest run"
|
|
19
22
|
}
|
|
20
|
-
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { useAsync } from "./index";
|
|
3
|
+
|
|
4
|
+
describe("useAsync", () => {
|
|
5
|
+
it("should return [data, null] when the promise resolves", async () => {
|
|
6
|
+
const [data, error] = await useAsync(() => Promise.resolve(42));
|
|
7
|
+
expect(data).toBe(42);
|
|
8
|
+
expect(error).toBeNull();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("should return [null, reason] when the promise rejects with an Error", async () => {
|
|
12
|
+
const [data, error] = await useAsync(() => Promise.reject(new Error("Something went wrong")));
|
|
13
|
+
expect(data).toBeNull();
|
|
14
|
+
expect(error).toBeInstanceOf(Error);
|
|
15
|
+
expect((error as Error).message).toBe("Something went wrong");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("should return [null, reason] when the promise rejects with a string", async () => {
|
|
19
|
+
const [data, error] = await useAsync(() => Promise.reject("Oops!"));
|
|
20
|
+
expect(data).toBeNull();
|
|
21
|
+
expect(error).toBe("Oops!");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should return [null, reason] when the promise rejects with a number", async () => {
|
|
25
|
+
const [data, error] = await useAsync(() => Promise.reject(404));
|
|
26
|
+
expect(data).toBeNull();
|
|
27
|
+
expect(error).toBe(404);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("should handle a callback that throws synchronously", async () => {
|
|
31
|
+
const [data, error] = await useAsync(() => {
|
|
32
|
+
throw new Error("Sync throw");
|
|
33
|
+
});
|
|
34
|
+
expect(data).toBeNull();
|
|
35
|
+
expect(error).toBeInstanceOf(Error);
|
|
36
|
+
expect((error as Error).message).toBe("Sync throw");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("should handle resolved undefined", async () => {
|
|
40
|
+
const [data, error] = await useAsync(() => Promise.resolve(undefined));
|
|
41
|
+
expect(data).toBeUndefined();
|
|
42
|
+
expect(error).toBeNull();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("should handle resolved null", async () => {
|
|
46
|
+
const [data, error] = await useAsync(() => Promise.resolve(null));
|
|
47
|
+
expect(data).toBeNull();
|
|
48
|
+
expect(error).toBeNull();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("should handle an empty async function", async () => {
|
|
52
|
+
const [data, error] = await useAsync(async () => {});
|
|
53
|
+
expect(data).toBeUndefined();
|
|
54
|
+
expect(error).toBeNull();
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type AsyncResult<ResolveData, RejectionReason> =
|
|
2
|
+
| [data: null, reason: RejectionReason]
|
|
3
|
+
| [data: ResolveData, reason: null];
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Gracefully handles a callback that returns a promise.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* await useAsync(() => Promise.resolve(123))
|
|
10
|
+
* // [123, null]
|
|
11
|
+
*
|
|
12
|
+
* await useAsync(() => Promise.reject(new Error('Error message')))
|
|
13
|
+
* // [null, new Error('Oops!')]
|
|
14
|
+
*/
|
|
15
|
+
export async function useAsync<ResolveData = unknown, RejectionReason = Error>(
|
|
16
|
+
callback: () => Promise<ResolveData>,
|
|
17
|
+
): Promise<AsyncResult<ResolveData, RejectionReason>> {
|
|
18
|
+
try {
|
|
19
|
+
const data = await callback().catch((error) => {
|
|
20
|
+
throw error;
|
|
21
|
+
});
|
|
22
|
+
return [data, null];
|
|
23
|
+
} catch (error: unknown) {
|
|
24
|
+
return [null, error as RejectionReason];
|
|
25
|
+
}
|
|
26
|
+
}
|