Skip to content

Commit de38b92

Browse files
committed
initial
1 parent 867f1c8 commit de38b92

File tree

15 files changed

+3527
-26
lines changed

15 files changed

+3527
-26
lines changed

.changeset/config.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
3+
"changelog": ["@svitejs/changesets-changelog-github-compact", { "repo": "ieedan/ts-cli-template" }],
4+
"commit": false,
5+
"fixed": [],
6+
"linked": [],
7+
"access": "public",
8+
"baseBranch": "main",
9+
"updateInternalDependencies": "patch",
10+
"ignore": [],
11+
"prettier": false
12+
}

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto

.github/workflows/ci.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
6+
jobs:
7+
CI:
8+
runs-on: ubuntu-latest
9+
10+
steps:
11+
- uses: actions/checkout@v4
12+
- uses: pnpm/action-setup@v4
13+
- uses: actions/setup-node@v4
14+
with:
15+
node-version: "20"
16+
cache: pnpm
17+
18+
- name: Install dependencies
19+
run: pnpm install
20+
21+
- name: Check Types
22+
run: pnpm check
23+
24+
- name: Test
25+
run: pnpm test
26+
27+
- name: Build
28+
run: pnpm build

.github/workflows/publish.yaml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Publish
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
concurrency: ${{ github.workflow }}-${{ github.ref }}
9+
10+
jobs:
11+
release:
12+
name: Build & Publish Release
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- uses: actions/checkout@v4
17+
- uses: pnpm/action-setup@v4
18+
- uses: actions/setup-node@v4
19+
with:
20+
node-version: "20"
21+
cache: pnpm
22+
23+
- name: Install dependencies
24+
run: pnpm install
25+
26+
- name: Create Release Pull Request or Publish
27+
id: changesets
28+
uses: changesets/action@v1
29+
with:
30+
commit: "chore(release): version package"
31+
title: "chore(release): version package"
32+
version: pnpm changeset:version
33+
publish: pnpm ci:release
34+
env:
35+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
36+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
37+
NODE_ENV: production

.gitignore

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ npm-debug.log*
55
yarn-debug.log*
66
yarn-error.log*
77
lerna-debug.log*
8+
.pnpm-debug.log*
89

910
# Diagnostic reports (https://nodejs.org/api/report.html)
1011
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
@@ -56,6 +57,12 @@ web_modules/
5657
# Optional stylelint cache
5758
.stylelintcache
5859

60+
# Microbundle cache
61+
.rpt2_cache/
62+
.rts2_cache_cjs/
63+
.rts2_cache_es/
64+
.rts2_cache_umd/
65+
5966
# Optional REPL history
6067
.node_repl_history
6168

@@ -67,8 +74,10 @@ web_modules/
6774

6875
# dotenv environment variable files
6976
.env
70-
.env.*
71-
!.env.example
77+
.env.development.local
78+
.env.test.local
79+
.env.production.local
80+
.env.local
7281

7382
# parcel-bundler cache (https://parceljs.org/)
7483
.cache
@@ -95,15 +104,6 @@ dist
95104
.temp
96105
.cache
97106

98-
# Sveltekit cache directory
99-
.svelte-kit/
100-
101-
# vitepress build output
102-
**/.vitepress/dist
103-
104-
# vitepress cache directory
105-
**/.vitepress/cache
106-
107107
# Docusaurus cache and generated files
108108
.docusaurus
109109

@@ -116,24 +116,15 @@ dist
116116
# DynamoDB Local files
117117
.dynamodb/
118118

119-
# Firebase cache directory
120-
.firebase/
121-
122119
# TernJS port file
123120
.tern-port
124121

125122
# Stores VSCode versions used for testing VSCode extensions
126123
.vscode-test
127124

128-
# yarn v3
125+
# yarn v2
126+
.yarn/cache
127+
.yarn/unplugged
128+
.yarn/build-state.yml
129+
.yarn/install-state.gz
129130
.pnp.*
130-
.yarn/*
131-
!.yarn/patches
132-
!.yarn/plugins
133-
!.yarn/releases
134-
!.yarn/sdks
135-
!.yarn/versions
136-
137-
# Vite logs files
138-
vite.config.js.timestamp-*
139-
vite.config.ts.timestamp-*

.vscode/settings.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"editor.codeActionsOnSave": {
3+
"source.fixAll.biome": "explicit",
4+
"source.organizeImports.biome": "explicit"
5+
},
6+
"editor.defaultFormatter": "biomejs.biome",
7+
"cSpell.words": [
8+
"justerror"
9+
]
10+
}

README.md

Lines changed: 148 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,149 @@
1-
# just-error
1+
# just-error ⚠️
2+
3+
![NPM Downloads](https://img.shields.io/npm/dm/just-error)
4+
25
A json-serializable, incredibly ergonomic way of declaring and working with errors in your TypeScript applications.
6+
7+
```ts
8+
import * as justerror from ".";
9+
10+
// Define your errors
11+
12+
export type Error<T extends keyof typeof error> = ReturnType<(typeof error)[T]>;
13+
14+
const error = justerror.create({
15+
ApiError: {
16+
code: "API_001",
17+
message: (args: { url: string }) => `Error fetching ${args.url}`,
18+
},
19+
EmailError: {
20+
code: "EMAIL_001",
21+
message: (args: { email: string }) => `Error sending email to ${args.email}`,
22+
},
23+
});
24+
25+
// Write safe code
26+
27+
import type { Result } from "neverthrow";
28+
import type { Error, error } from "./errors";
29+
30+
function safeFn(): Result<string, Error<"ApiError"> | Error<"EmailError">> {
31+
// ...
32+
}
33+
34+
const result = safeFn().match(
35+
(v) => console.log(v),
36+
(e) => {
37+
justerror.match(e, {
38+
ApiError: (e) => console.log(`We couldn't service your request to ${e.config.url}`),
39+
EmailError: () => console.error("We encountered an unexpected error"),
40+
});
41+
}
42+
);
43+
```
44+
45+
## Introduction
46+
47+
With the addition of libraries like [neverthrow](https://github.com/supermacro/neverthrow) the JS community has started to realize the power of "never throwing" and instead returning results. This library is a great way to compliment that pattern.
48+
49+
## Getting Started
50+
51+
Install `just-error`:
52+
53+
```sh
54+
npm i just-error
55+
```
56+
57+
Define your errors:
58+
59+
```ts
60+
import * as justerror from "just-error";
61+
62+
const error = justerror.create({
63+
ApiError: {
64+
code: "API_001",
65+
message: (args: { url: string }) => `Error fetching ${args.url}`,
66+
},
67+
EmailError: {
68+
code: "EMAIL_001",
69+
message: (args: { email: string }) => `Error sending email to ${args.email}`,
70+
},
71+
});
72+
```
73+
74+
Create errors by calling them as functions:
75+
76+
```ts
77+
import { ResultAsync } from "nevereverthrow";
78+
import { error } from "./errors";
79+
80+
const url = "https://api.example.com/data";
81+
82+
const result = ResultAsync.fromPromise(
83+
() => fetch(url),
84+
(e) => error.ApiError({ url }, e) // optionally add the cause
85+
);
86+
```
87+
88+
## Internal and User Facing Errors
89+
90+
Errors defined with the `userMessage` property considered user facing errors. These are errors that are allowed to be shown to the user.
91+
92+
> [!IMPORTANT] Internal errors should never be shown to the user.
93+
94+
### Error Handling Utilities
95+
96+
Often times error handling can be verbose and it is expected for you to create utility functions for handling your user facing errors.
97+
98+
We can import the `UserFacingError` type from `just-error` to ensure that we are only passing user facing errors to the function.
99+
100+
> For functions expecting only internal errors you can use the `InternalError` type.
101+
102+
```ts
103+
import { UserFacingError } from "just-error";
104+
105+
function showErrorToast(error: UserFacingError) {
106+
// ...
107+
}
108+
```
109+
110+
### Mapping Internal Errors to User Facing Errors
111+
112+
You will often find yourself wanting to map an internal error to better user facing message. This can be done with the `mapToUserFacingError` function.
113+
114+
> This can also be useful for localizing your error messages!
115+
116+
```ts
117+
import * as justerror from "just-error";
118+
119+
// ...
120+
121+
const userFacingError = result.mapError((e) => justerror.mapToUserFacingError(e, {
122+
ApiError: (e) => `There was an error serving your request from ${e.config.url}`,
123+
}));
124+
```
125+
126+
## Types
127+
128+
Here are a few types you may want to implement to make using `just-error` easier:
129+
130+
```ts
131+
import * as justerror from "just-error";
132+
133+
// allows you to get the type of an error by name i.e. Error<"ApiError">
134+
export type Error<T extends keyof typeof error> = ReturnType<(typeof error)[T]>;
135+
136+
// A union of all defined errors
137+
export type AnyError = InternalError<keyof typeof error>;
138+
139+
const error = justerror.create({
140+
ApiError: {
141+
code: "API_001",
142+
message: (args: { url: string }) => `Error fetching ${args.url}`,
143+
},
144+
EmailError: {
145+
code: "EMAIL_001",
146+
message: (args: { email: string }) => `Error sending email to ${args.email}`,
147+
},
148+
});
149+
```

biome.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"$schema": "https://biomejs.dev/schemas/2.1.1/schema.json",
3+
"vcs": {
4+
"enabled": false,
5+
"clientKind": "git",
6+
"useIgnoreFile": false
7+
},
8+
"files": {
9+
"ignoreUnknown": false,
10+
"includes": ["src/**/*", "tests/**/*"]
11+
},
12+
"formatter": {
13+
"enabled": true,
14+
"indentStyle": "tab"
15+
},
16+
"linter": {
17+
"enabled": true,
18+
"rules": {
19+
"recommended": true,
20+
"suspicious": {
21+
"noExplicitAny": "off"
22+
}
23+
}
24+
},
25+
"javascript": {
26+
"formatter": {
27+
"quoteStyle": "single"
28+
}
29+
}
30+
}

build.config.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { defineBuildConfig } from "unbuild";
2+
3+
export default defineBuildConfig({
4+
entries: ["src/index.ts", "src/utils.ts"],
5+
clean: true,
6+
declaration: "node16",
7+
rollup: {
8+
dts: {
9+
respectExternal: true,
10+
},
11+
},
12+
});

0 commit comments

Comments
 (0)