├── .editorconfig
├── .gitattributes
├── .github
├── dependabot.yml
└── workflows
│ ├── main.yml
│ └── pull_request.yml
├── .gitignore
├── .npmignore
├── .npmrc
├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── examples
├── handle-errors.js
└── prototypes.js
├── package.json
├── src
└── index.js
└── test
└── index.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | indent_style = space
7 | indent_size = 2
8 | end_of_line = lf
9 | charset = utf-8
10 | trim_trailing_whitespace = true
11 | insert_final_newline = true
12 | max_line_length = 100
13 | indent_brace_style = 1TBS
14 | spaces_around_operators = true
15 | quote_type = auto
16 |
17 | [package.json]
18 | indent_style = space
19 | indent_size = 2
20 |
21 | [*.md]
22 | trim_trailing_whitespace = false
23 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: npm
4 | directory: '/'
5 | schedule:
6 | interval: daily
7 | - package-ecosystem: 'github-actions'
8 | directory: '/'
9 | schedule:
10 | # Check for updates to GitHub Actions every weekday
11 | interval: 'daily'
12 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: main
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 |
8 | jobs:
9 | contributors:
10 | if: "${{ github.event.head_commit.message != 'build: contributors' }}"
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: Checkout
14 | uses: actions/checkout@v4
15 | with:
16 | fetch-depth: 0
17 | token: ${{ secrets.GITHUB_TOKEN }}
18 | - name: Setup Node.js
19 | uses: actions/setup-node@v4
20 | with:
21 | node-version: lts/*
22 | - name: Contributors
23 | run: |
24 | git config --global user.email ${{ secrets.GIT_EMAIL }}
25 | git config --global user.name ${{ secrets.GIT_USERNAME }}
26 | npm run contributors
27 | - name: Push changes
28 | run: |
29 | git push origin ${{ github.head_ref }}
30 |
31 | release:
32 | if: |
33 | !startsWith(github.event.head_commit.message, 'chore(release):') &&
34 | !startsWith(github.event.head_commit.message, 'docs:') &&
35 | !startsWith(github.event.head_commit.message, 'ci:')
36 | needs: [contributors]
37 | runs-on: ubuntu-latest
38 | steps:
39 | - name: Checkout
40 | uses: actions/checkout@v4
41 | with:
42 | fetch-depth: 2
43 | token: ${{ secrets.GITHUB_TOKEN }}
44 | - name: Setup Node.js
45 | uses: actions/setup-node@v4
46 | with:
47 | node-version: lts/*
48 | - name: Setup PNPM
49 | uses: pnpm/action-setup@v4
50 | with:
51 | version: latest
52 | run_install: true
53 | - name: Test
54 | run: npm test
55 | - name: Report
56 | run: npx c8 report --reporter=text-lcov > coverage/lcov.info
57 | - name: Coverage
58 | uses: coverallsapp/github-action@main
59 | with:
60 | github-token: ${{ secrets.GITHUB_TOKEN }}
61 | - name: Release
62 | env:
63 | GH_TOKEN: ${{ secrets.GH_TOKEN }}
64 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
65 | run: |
66 | git config --global user.email ${{ secrets.GIT_EMAIL }}
67 | git config --global user.name ${{ secrets.GIT_USERNAME }}
68 | git pull origin master
69 | npm run release
70 |
--------------------------------------------------------------------------------
/.github/workflows/pull_request.yml:
--------------------------------------------------------------------------------
1 | name: pull_request
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | pull_request:
8 | branches:
9 | - master
10 |
11 | jobs:
12 | test:
13 | if: github.ref != 'refs/heads/master'
14 | runs-on: ubuntu-latest
15 | steps:
16 | - name: Checkout
17 | uses: actions/checkout@v4
18 | with:
19 | token: ${{ secrets.GITHUB_TOKEN }}
20 | - name: Setup Node.js
21 | uses: actions/setup-node@v4
22 | with:
23 | node-version: lts/*
24 | - name: Setup PNPM
25 | uses: pnpm/action-setup@v4
26 | with:
27 | version: latest
28 | run_install: true
29 | - name: Test
30 | run: npm test
31 | - name: Report
32 | run: npx c8 report --reporter=text-lcov > coverage/lcov.info
33 | - name: Coverage
34 | uses: coverallsapp/github-action@main
35 | with:
36 | github-token: ${{ secrets.GITHUB_TOKEN }}
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ############################
2 | # npm
3 | ############################
4 | node_modules
5 | npm-debug.log
6 |
7 |
8 | ############################
9 | # tmp, editor & OS files
10 | ############################
11 | .tmp
12 | *.swo
13 | *.swp
14 | *.swn
15 | *.swm
16 | .DS_STORE
17 | *#
18 | *~
19 | .idea
20 | nbproject
21 |
22 |
23 | ############################
24 | # Tests
25 | ############################
26 | testApp
27 | coverage
28 | .nyc_output
29 |
30 | ############################
31 | # Other
32 | ############################
33 | .node_history
34 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .project
3 | *.sublime-*
4 | .DS_Store
5 | *.seed
6 | *.log
7 | *.csv
8 | *.dat
9 | *.out
10 | *.pid
11 | *.swp
12 | *.swo
13 | node_modules
14 | coverage
15 | *.tgz
16 | *.xml
17 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | unsafe-perm=true
2 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4 |
5 | ### 5.0.1 (2025-01-28)
6 |
7 |
8 | ### Bug Fixes
9 |
10 | * merging props ([#47](https://github.com/kikobeats/whoops/issues/47)) ([e9e24d6](https://github.com/kikobeats/whoops/commit/e9e24d6c1ad2d9cd178c056bfd09889216af0d7f))
11 |
12 | ## 5.0.0 (2025-01-28)
13 |
14 |
15 | ### ⚠ BREAKING CHANGES
16 |
17 | * simplify implementation (#46)
18 |
19 | ### Features
20 |
21 | * simplify implementation ([#46](https://github.com/kikobeats/whoops/issues/46)) ([86f8d7a](https://github.com/kikobeats/whoops/commit/86f8d7a124c343cee2c790af7f5a51fd73b0a171))
22 |
23 | ### 4.1.8 (2025-01-27)
24 |
25 | ### 4.1.7 (2023-10-29)
26 |
27 | ### 4.1.6 (2023-10-24)
28 |
29 | ### 4.1.5 (2023-09-05)
30 |
31 | ### 4.1.4 (2023-04-14)
32 |
33 | ### 4.1.3 (2023-04-14)
34 |
35 |
36 | ### Bug Fixes
37 |
38 | * **extend-error:** handle undefined error#stack ([#42](https://github.com/kikobeats/whoops/issues/42)) ([2dc0cd1](https://github.com/kikobeats/whoops/commit/2dc0cd156d71d6b5e51958627f766a3b6ca9048b))
39 |
40 | ### 4.1.2 (2022-07-20)
41 |
42 | ### 4.1.1 (2022-05-27)
43 |
44 |
45 | ### Bug Fixes
46 |
47 | * add nano-staged config ([f741480](https://github.com/kikobeats/whoops/commit/f741480cd7fb486651fbe01b911289149f10b030))
48 |
49 | ## 4.1.0 (2019-12-15)
50 |
51 | * build: update dependencies ([af7e392](https://github.com/kikobeats/whoops/commit/af7e392))
52 | * fix(package): update clean-stack to version 2.1.0 ([3275e3c](https://github.com/kikobeats/whoops/commit/3275e3c))
53 | * fix(package): update mimic-fn to version 2.1.0 ([db95daa](https://github.com/kikobeats/whoops/commit/db95daa))
54 | * fix(package): update mimic-fn to version 3.0.0 ([e1cc912](https://github.com/kikobeats/whoops/commit/e1cc912))
55 |
56 |
57 |
58 |
59 | ## 4.0.2 (2019-03-08)
60 |
61 | * fix(package): update clean-stack to version 2.0.0 ([24952ae](https://github.com/kikobeats/whoops/commit/24952ae))
62 | * fix(package): update mimic-fn to version 1.2.0 ([719fc26](https://github.com/kikobeats/whoops/commit/719fc26))
63 | * fix(package): update mimic-fn to version 2.0.0 ([d5c78a1](https://github.com/kikobeats/whoops/commit/d5c78a1))
64 | * Refactor ([64f751b](https://github.com/kikobeats/whoops/commit/64f751b))
65 | * Update compositor.json ([e26b0fd](https://github.com/kikobeats/whoops/commit/e26b0fd))
66 | * Update compositor.json ([da98ea7](https://github.com/kikobeats/whoops/commit/da98ea7))
67 | * Update README.md ([0228c84](https://github.com/kikobeats/whoops/commit/0228c84))
68 | * docs(readme): add Greenkeeper badge ([4e1a125](https://github.com/kikobeats/whoops/commit/4e1a125))
69 |
70 |
71 |
72 |
73 | ## 4.0.1 (2017-08-08)
74 |
75 | * Reducing library size ([ce26a2d](https://github.com/kikobeats/whoops/commit/ce26a2d))
76 | * Update README.md ([2e71ec2](https://github.com/kikobeats/whoops/commit/2e71ec2))
77 |
78 |
79 |
80 |
81 | # 4.0.0 (2017-08-08)
82 |
83 | * refactor ([ca6e60e](https://github.com/kikobeats/whoops/commit/ca6e60e))
84 | * Remove unnecessasry ([6ec4220](https://github.com/kikobeats/whoops/commit/6ec4220))
85 | * Support attach props into constructor ([8dd67b9](https://github.com/kikobeats/whoops/commit/8dd67b9))
86 | * Update builds ([6e6275c](https://github.com/kikobeats/whoops/commit/6e6275c))
87 | * Update docs ([515c498](https://github.com/kikobeats/whoops/commit/515c498))
88 | * Update README.md ([a0dc9b0](https://github.com/kikobeats/whoops/commit/a0dc9b0))
89 | * Update README.md ([b289826](https://github.com/kikobeats/whoops/commit/b289826))
90 | * Update README.md ([bf87a1f](https://github.com/kikobeats/whoops/commit/bf87a1f))
91 |
92 |
93 |
94 |
95 | ## 3.1.1 (2017-07-18)
96 |
97 | * Update README.md ([4561a8b](https://github.com/kikobeats/whoops/commit/4561a8b))
98 | * docs(readme): add Greenkeeper badge ([9b93e2c](https://github.com/kikobeats/whoops/commit/9b93e2c))
99 | * chore(package): update clean-stack to version 1.2.0 ([b2cb039](https://github.com/kikobeats/whoops/commit/b2cb039))
100 | * chore(package): update clean-stack to version 1.3.0 ([12fb684](https://github.com/kikobeats/whoops/commit/12fb684))
101 |
102 |
103 |
104 |
105 | # 3.1.0 (2016-12-19)
106 |
107 | * Add description field ([6b3b308](https://github.com/kikobeats/whoops/commit/6b3b308))
108 | * Drop node 5 from testing ([c223c7f](https://github.com/kikobeats/whoops/commit/c223c7f))
109 |
110 |
111 |
112 |
113 | ## 3.0.3 (2016-12-19)
114 |
115 | * 80 → 100 lines ([a117bb8](https://github.com/kikobeats/whoops/commit/a117bb8))
116 | * Avoid inline regexp declaration ([2f91173](https://github.com/kikobeats/whoops/commit/2f91173))
117 | * Better docs ([591d743](https://github.com/kikobeats/whoops/commit/591d743))
118 | * Test refactor ([58fb3dc](https://github.com/kikobeats/whoops/commit/58fb3dc))
119 | * Update deps ([c0d5a49](https://github.com/kikobeats/whoops/commit/c0d5a49))
120 | * Update README.md ([c9c32f8](https://github.com/kikobeats/whoops/commit/c9c32f8))
121 |
122 |
123 |
124 |
125 | ## 3.0.2 (2016-09-13)
126 |
127 | * chore(package): update clean-stack to version 1.0.0 ([ff0f4ce](https://github.com/kikobeats/whoops/commit/ff0f4ce))
128 | * Update ([ce66183](https://github.com/kikobeats/whoops/commit/ce66183))
129 |
130 |
131 |
132 |
133 | ## 3.0.1 (2016-08-01)
134 |
135 | * Avoid eval for setup function name ([1ecde20](https://github.com/kikobeats/whoops/commit/1ecde20))
136 | * Remove interface string façade ([14c5932](https://github.com/kikobeats/whoops/commit/14c5932))
137 | * Remove unncessary check ([6a4d469](https://github.com/kikobeats/whoops/commit/6a4d469))
138 | * Rename extend-error → create-extend-error ([fd3726e](https://github.com/kikobeats/whoops/commit/fd3726e))
139 | * Setup Error name in constructor ([4ac076d](https://github.com/kikobeats/whoops/commit/4ac076d))
140 |
141 |
142 |
143 |
144 | # 3.0.0 (2016-07-30)
145 |
146 | * Add clean-stack dep ([7f32385](https://github.com/kikobeats/whoops/commit/7f32385))
147 | * Drop < 4 node support ([185ae66](https://github.com/kikobeats/whoops/commit/185ae66))
148 | * Fix dep ([a87c1ea](https://github.com/kikobeats/whoops/commit/a87c1ea))
149 | * Refactor fn template ([942a189](https://github.com/kikobeats/whoops/commit/942a189))
150 | * Remove capture-stack-trace dep ([5fdae23](https://github.com/kikobeats/whoops/commit/5fdae23))
151 | * Remove string interface with 3 params ([5439d61](https://github.com/kikobeats/whoops/commit/5439d61))
152 | * Remove unnecessary dep ([78d6dac](https://github.com/kikobeats/whoops/commit/78d6dac))
153 | * Update docs ([34f5e8c](https://github.com/kikobeats/whoops/commit/34f5e8c))
154 |
155 |
156 |
157 |
158 | # 2.2.0 (2016-07-30)
159 |
160 | * Add coverage ([1547649](https://github.com/kikobeats/whoops/commit/1547649))
161 | * Move pretty on different pkg ([3640943](https://github.com/kikobeats/whoops/commit/3640943))
162 | * Refactor scaffold ([5907391](https://github.com/kikobeats/whoops/commit/5907391))
163 | * Remove browser build ([e0e3621](https://github.com/kikobeats/whoops/commit/e0e3621))
164 |
165 |
166 |
167 |
168 | # 2.1.0 (2016-05-19)
169 |
170 | * Add missing dependency ([b832bf0](https://github.com/kikobeats/whoops/commit/b832bf0))
171 | * Add pretty output ([a1c6e4c](https://github.com/kikobeats/whoops/commit/a1c6e4c))
172 | * Update docs ([1b6c6a8](https://github.com/kikobeats/whoops/commit/1b6c6a8))
173 | * Update README.md ([30224fe](https://github.com/kikobeats/whoops/commit/30224fe))
174 | * Update travis builds ([44e69b5](https://github.com/kikobeats/whoops/commit/44e69b5))
175 |
176 |
177 |
178 |
179 | ## 2.0.1 (2016-02-07)
180 |
181 |
182 | * lock dependency ([9d36dd5](https://github.com/kikobeats/whoops/commit/9d36dd5))
183 |
184 |
185 |
186 |
187 | # 2.0.0 (2016-02-03)
188 |
189 |
190 | * 2.0.0 releases ([c7ba44a](https://github.com/kikobeats/whoops/commit/c7ba44a))
191 | * Little refactor ([4fb84a1](https://github.com/kikobeats/whoops/commit/4fb84a1))
192 | * Refactor tests ([5fc36b1](https://github.com/kikobeats/whoops/commit/5fc36b1))
193 | * Setup correctly instanceof ([6436f3e](https://github.com/kikobeats/whoops/commit/6436f3e))
194 | * YEAH ([2c8b56b](https://github.com/kikobeats/whoops/commit/2c8b56b))
195 |
196 |
197 |
198 |
199 | ## 1.1.1 (2016-01-28)
200 |
201 |
202 | * 1.1.1 releases ([60cb701](https://github.com/kikobeats/whoops/commit/60cb701))
203 | * Add standard as devDependency ([313a136](https://github.com/kikobeats/whoops/commit/313a136))
204 | * Remove lodash.forEach dep ([f5f96ee](https://github.com/kikobeats/whoops/commit/f5f96ee))
205 | * setup correctly bumped ([75d190b](https://github.com/kikobeats/whoops/commit/75d190b))
206 | * Update README.md ([ec8d39c](https://github.com/kikobeats/whoops/commit/ec8d39c))
207 | * Update README.md ([ff486b4](https://github.com/kikobeats/whoops/commit/ff486b4))
208 | * Update README.md ([23527e7](https://github.com/kikobeats/whoops/commit/23527e7))
209 |
210 |
211 |
212 |
213 | # 1.1.0 (2016-01-14)
214 |
215 |
216 | * releases ([5fff532](https://github.com/kikobeats/whoops/commit/5fff532))
217 | * Add .create method ([1315768](https://github.com/kikobeats/whoops/commit/1315768))
218 | * Add coffe as devDependency ([ce75ae9](https://github.com/kikobeats/whoops/commit/ce75ae9))
219 | * Add custom message function in object factory ([470414c](https://github.com/kikobeats/whoops/commit/470414c))
220 | * bye coffee ([6a3a1d4](https://github.com/kikobeats/whoops/commit/6a3a1d4))
221 | * bye config ([e920003](https://github.com/kikobeats/whoops/commit/e920003))
222 | * Little tests refactor ([d3abb53](https://github.com/kikobeats/whoops/commit/d3abb53))
223 | * Update description and documentation ([0ad3cba](https://github.com/kikobeats/whoops/commit/0ad3cba))
224 | * Update scripts ([29240d2](https://github.com/kikobeats/whoops/commit/29240d2))
225 |
226 |
227 |
228 |
229 | ## 1.0.1 (2015-11-23)
230 |
231 |
232 | * 1.0.1 releases ([56e26f2](https://github.com/kikobeats/whoops/commit/56e26f2))
233 | * Fix typos in README.md ([e9063f2](https://github.com/kikobeats/whoops/commit/e9063f2))
234 | * Merge branch 'master' of github.com:kikobeats/whoops ([a363134](https://github.com/kikobeats/whoops/commit/a363134))
235 | * Merge pull request #4 from jorrit/patch-1 ([d9156f6](https://github.com/kikobeats/whoops/commit/d9156f6))
236 | * rewrite to avoid new ([23e586b](https://github.com/kikobeats/whoops/commit/23e586b))
237 | * update to upgrade bower.json ([b18589d](https://github.com/kikobeats/whoops/commit/b18589d))
238 |
239 |
240 |
241 |
242 | # 1.0.0 (2015-11-20)
243 |
244 |
245 | * 1.0.0 releases ([447ae1e](https://github.com/kikobeats/whoops/commit/447ae1e))
246 | * refactored and renamed ([cf2b458](https://github.com/kikobeats/whoops/commit/cf2b458))
247 | * removed extra spaces ([931245d](https://github.com/kikobeats/whoops/commit/931245d))
248 | * updated ([9bf0fde](https://github.com/kikobeats/whoops/commit/9bf0fde))
249 | * updated bumped config ([4583c59](https://github.com/kikobeats/whoops/commit/4583c59))
250 | * updated dependencies ([3d7ec1b](https://github.com/kikobeats/whoops/commit/3d7ec1b))
251 | * updated documentation ([6ea514b](https://github.com/kikobeats/whoops/commit/6ea514b))
252 | * updated renaming ([4b9306c](https://github.com/kikobeats/whoops/commit/4b9306c))
253 | * updated travis builds ([a330eae](https://github.com/kikobeats/whoops/commit/a330eae))
254 |
255 |
256 |
257 |
258 | # 0.2.0 (2015-10-01)
259 |
260 |
261 | * 0.2.0 releases ([aff1849](https://github.com/kikobeats/whoops/commit/aff1849))
262 | * Added format for string constructor ([d584188](https://github.com/kikobeats/whoops/commit/d584188))
263 | * improve example ([aa2d318](https://github.com/kikobeats/whoops/commit/aa2d318))
264 | * little suite of tests 😁 ([5e11def](https://github.com/kikobeats/whoops/commit/5e11def))
265 | * Update package.json ([1120535](https://github.com/kikobeats/whoops/commit/1120535))
266 | * updated ([d5fc2d9](https://github.com/kikobeats/whoops/commit/d5fc2d9))
267 |
268 |
269 |
270 |
271 | ## 0.1.3 (2015-07-28)
272 |
273 |
274 | * 0.1.3 releases ([e0de222](https://github.com/kikobeats/whoops/commit/e0de222))
275 | * fixed devDependencies ([bccbf41](https://github.com/kikobeats/whoops/commit/bccbf41))
276 | * updated bumped settings ([67ff23e](https://github.com/kikobeats/whoops/commit/67ff23e))
277 |
278 |
279 |
280 |
281 | ## 0.1.2 (2015-07-28)
282 |
283 |
284 | * 0.1.2 releases ([7273df6](https://github.com/kikobeats/whoops/commit/7273df6))
285 |
286 |
287 |
288 |
289 | ## 0.1.1 (2015-07-28)
290 |
291 |
292 | * 0.1.1 release ([6fcf6d7](https://github.com/kikobeats/whoops/commit/6fcf6d7))
293 | * 0.1.1 releases ([15d607b](https://github.com/kikobeats/whoops/commit/15d607b))
294 | * Update README.md ([d5e55b8](https://github.com/kikobeats/whoops/commit/d5e55b8))
295 | * Update README.md ([869be0a](https://github.com/kikobeats/whoops/commit/869be0a))
296 | * Update README.md ([8344dab](https://github.com/kikobeats/whoops/commit/8344dab))
297 | * updated dependencies ([afe3a10](https://github.com/kikobeats/whoops/commit/afe3a10))
298 |
299 |
300 |
301 |
302 | # 0.1.0 (2015-07-26)
303 |
304 |
305 | * 0.1.0 releases ([594c110](https://github.com/kikobeats/whoops/commit/594c110))
306 | * added documentation and more examples ([3e68abb](https://github.com/kikobeats/whoops/commit/3e68abb))
307 | * first approach ([c52341b](https://github.com/kikobeats/whoops/commit/c52341b))
308 | * Update README.md ([e7172ab](https://github.com/kikobeats/whoops/commit/e7172ab))
309 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright © 2015 Kiko Beats
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # whoops
2 |
3 | 
4 | [](https://coveralls.io/github/Kikobeats/whoops)
5 | [](https://www.npmjs.org/package/whoops)
6 |
7 | > It makes simple throw qualified errors. Inspired in [errno](https://github.com/rvagg/node-errno), [create-error-class](https://github.com/floatdrop/create-error-class) and [fault](https://github.com/wooorm/fault).
8 |
9 | ## Why
10 |
11 | - An easy way to create qualified errors.
12 | - Using the standard `Error` interface in browser and NodeJS.
13 | - Attach extra information, being flexible with whatever user case.
14 | - Less than 50 lines (~500 bytes)
15 |
16 | This library is a compromise to provide a clean API for use `Error` native class.
17 |
18 | ## Install
19 |
20 | ```bash
21 | npm install whoops --save
22 | ```
23 |
24 | Basically it turns:
25 |
26 | ```js
27 | const error = Error('Something is wrong')
28 | error.name = 'DAMNError'
29 | throw error // => 'DAMNError: ENOFILE, Something is wrong'
30 | ```
31 |
32 | Into a one line more productive declaration:
33 |
34 | ```js
35 | const whoops = require('whoops')
36 | const userError = whoops('UserError')
37 |
38 | throw userError('User not found') // => 'UserError: User not found'
39 | ```
40 |
41 | ## Creating Qualified Errors
42 |
43 | Call `whoops` to get a constructor function. Every time you call the constructor, you get an `Error` instance:
44 |
45 | ```js
46 | const whoops = require('whoops')
47 | const myError = whoops()
48 | throw myError()
49 | ```
50 |
51 | Create domain specific errors providing a `className` as first argument:
52 |
53 | ```js
54 | const whoops = require('whoops')
55 | const userError = whoops('userError')
56 | throw userError()
57 | ```
58 |
59 | The qualified error will be extends from `Error`:
60 |
61 | ```js
62 | const whoops = require('whoops')
63 | const userError = whoops('userError')
64 | const error = userError()
65 | console.log(error instanceof Error); // => true
66 | ```
67 |
68 | Attach extra information passing a `props` as second argument:
69 |
70 | ```js
71 | const whoops = require('whoops')
72 | const userError = whoops('userError', {code: 'ENOVALID'})
73 | const err = userError()
74 | console.log(`My error code is ${err.code}`) // => My error code is ENOVALID
75 | ```
76 |
77 | You can associate dynamic `props` as well:
78 |
79 | ```js
80 | const whoops = require('whoops')
81 | const userError = whoops('userError', {
82 | code: 'ENOVALID',
83 | message: props => `User '${props.username}' not found`
84 | })
85 |
86 | const err = userError({username: 'kiko'})
87 | console.log(err.message) // => User 'kiko' not found
88 | ```
89 |
90 | ## Error Types
91 |
92 | By default you will get `Error` instances calling whoops, but you can get different errors calling the properly method:
93 |
94 | | Name | Method |
95 | |----------------|------------------|
96 | | [Error](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) | whoops |
97 | | [TypeError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError) | whoops.type |
98 | | [RangeError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError) | whoops.range |
99 | | [EvalError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/EvalError) | whoops.eval |
100 | | [SyntaxError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError) | whoops.syntax |
101 | | [ReferenceError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError) | whoops.reference |
102 | | [URIError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/URIError) | whoops.uri |
103 |
104 | ## Extra: Always throw/return an Error!
105 |
106 | If you code implementation is
107 |
108 | - **synchronous**, throws `Error`. If you just return the `Error` nothings happens!.
109 | - **asynchronous**, returns `Error` in the first argument of the callback (or using promises).
110 |
111 | About asynchronous code, is correct return a `Object` that is not a `Error` in the first argument of the callback to express unexpected behavior, but the `Object` doesn't have a type and definitely can't follow a error interface for determinate a special behavior:
112 |
113 | ```js
114 | callback('LOL something was wrong') // poor
115 | callback({message: 'LOL something was wrong' } // poor, but better
116 | callback(whoops('LOL, something was wrong') // BEST!
117 | ```
118 |
119 | Passing always an `Error` you can can associated different type of error with different behavior:
120 |
121 | ```js
122 | switch (err.name) {
123 | case 'JSONError':
124 | console.log('your error logic here')
125 | break
126 | default:
127 | console.log('undefined code')
128 | break
129 | };
130 | ```
131 |
132 | ## Related
133 |
134 | - [create-error-class](https://github.com/floatdrop/create-error-class) – Create error class.
135 | - [fault](https://github.com/wooorm/fault) – Functional errors with formatted output.
136 |
137 |
138 | ## License
139 |
140 | MIT © [Kiko Beats](http://www.kikobeats.com)
141 |
--------------------------------------------------------------------------------
/examples/handle-errors.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const fs = require('fs')
4 | const Whoops = require('..')
5 |
6 | console.log('\n[ Standard NodeJS errors ]\n')
7 |
8 | try {
9 | fs.readFileSync('filename')
10 | } catch (err) {
11 | console.log(' message :', err.message)
12 | console.log(' name\t :', err.name)
13 | console.log(' code\t :', err.code)
14 | console.log(' path\t :', err.path)
15 | console.log(' errno\t :', err.errno)
16 |
17 | // { [Error: ENOENT, open 'filename']
18 | // errno: 34,
19 | // code: 'ENOENT',
20 | // path: 'filename' }
21 | }
22 |
23 | console.log('\n[ Whoops Object Constructor ]\n')
24 |
25 | const errObjt = new Whoops({
26 | message: 'The format of the JSON is invalid',
27 | name: 'JSONError',
28 | code: 'NotValidJSON',
29 | path: 'filename',
30 | errno: 127,
31 | foo: 'bar'
32 | })
33 |
34 | console.log(' message :', errObjt.message)
35 | console.log(' name\t :', errObjt.name)
36 | console.log(' code\t :', errObjt.code)
37 | console.log(' path\t :', errObjt.path)
38 | console.log(' errno\t :', errObjt.errno)
39 | console.log(' foo\t :', errObjt.foo)
40 |
41 | console.log('\n[ Whoops String constructor ]\n')
42 |
43 | const errString = new Whoops('JSONError', 'NotValidJSON', 'The format of the JSON is invalid')
44 |
45 | console.log(' message :', errString.message)
46 | console.log(' name\t :', errString.name)
47 | console.log(' code\t :', errString.code)
48 |
49 | console.log('\n[ constructor comparation ]\n')
50 |
51 | console.log('same message?\t', errString.message === errObjt.message)
52 | console.log('same name?\t', errString.name === errObjt.name)
53 | console.log('same typeof?\t', typeof errString === typeof errObjt)
54 |
55 | console.log('\n[ handling err codes ]\n')
56 |
57 | switch (errObjt.name) {
58 | case 'JSONError':
59 | console.log('your error logic here')
60 | break
61 | default:
62 | console.log('Standard Error name')
63 | break
64 | }
65 |
--------------------------------------------------------------------------------
/examples/prototypes.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const whoops = require('..')
4 | const DAMNError = whoops.create('DAMNError')
5 | const err = DAMNError('Something is wrong')
6 |
7 | console.log('static ::')
8 | console.log(DAMNError)
9 | console.log('DAMNError instanceof Error?', DAMNError instanceof Error)
10 | console.log()
11 | console.log('instance ::')
12 | console.log(err)
13 | console.log('err instanceof Error?', err instanceof Error)
14 | console.log('err instanceof DAMNError?', err instanceof Error)
15 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "whoops",
3 | "description": "It makes simple throw qualified errors.",
4 | "homepage": "https://github.com/Kikobeats/whoops",
5 | "version": "5.0.1",
6 | "main": "src/index.js",
7 | "author": {
8 | "email": "josefrancisco.verdu@gmail.com",
9 | "name": "Kiko Beats",
10 | "url": "https://github.com/Kikobeats"
11 | },
12 | "contributors": [
13 | {
14 | "name": "Jorrit Schippers",
15 | "email": "jorrit@ncode.nl"
16 | },
17 | {
18 | "name": "Prasad Nayak",
19 | "email": "prasadnayak1006@gmail.com"
20 | }
21 | ],
22 | "repository": {
23 | "type": "git",
24 | "url": "git+https://github.com/kikobeats/whoops.git"
25 | },
26 | "bugs": {
27 | "url": "https://github.com/Kikobeats/whoops/issues"
28 | },
29 | "keywords": [
30 | "constructor",
31 | "custom",
32 | "error",
33 | "simple",
34 | "throw"
35 | ],
36 | "devDependencies": {
37 | "@commitlint/cli": "latest",
38 | "@commitlint/config-conventional": "latest",
39 | "@ksmithut/prettier-standard": "latest",
40 | "c8": "latest",
41 | "ci-publish": "latest",
42 | "finepack": "latest",
43 | "git-authors-cli": "latest",
44 | "github-generate-release": "latest",
45 | "nano-staged": "latest",
46 | "should": "latest",
47 | "simple-git-hooks": "latest",
48 | "standard": "latest",
49 | "standard-markdown": "latest",
50 | "standard-version": "latest"
51 | },
52 | "engines": {
53 | "node": ">= 8"
54 | },
55 | "files": [
56 | "src"
57 | ],
58 | "scripts": {
59 | "clean": "rm -rf node_modules",
60 | "contributors": "(npx git-authors-cli && npx finepack && git add package.json && git commit -m 'build: contributors' --no-verify) || true",
61 | "coveralls": "nyc report --reporter=text-lcov | coveralls",
62 | "lint": "standard",
63 | "postrelease": "npm run release:tags && npm run release:github && (ci-publish || npm publish --access=public)",
64 | "pretest": "npm run lint",
65 | "release": "standard-version -a",
66 | "release:github": "github-generate-release",
67 | "release:tags": "git push --follow-tags origin HEAD:master",
68 | "test": "c8 node --test"
69 | },
70 | "license": "MIT",
71 | "commitlint": {
72 | "extends": [
73 | "@commitlint/config-conventional"
74 | ],
75 | "rules": {
76 | "body-max-line-length": [
77 | 0
78 | ]
79 | }
80 | },
81 | "nano-staged": {
82 | "*.js": [
83 | "prettier-standard",
84 | "standard --fix"
85 | ],
86 | "*.md": [
87 | "standard-markdown"
88 | ],
89 | "package.json": [
90 | "finepack"
91 | ]
92 | },
93 | "simple-git-hooks": {
94 | "commit-msg": "npx commitlint --edit",
95 | "pre-commit": "npx nano-staged"
96 | },
97 | "standard": {
98 | "globals": [
99 | "describe",
100 | "it"
101 | ]
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | function createErrorClass (ErrorClass) {
4 | return (name, defaults) => {
5 | class CustomError extends ErrorClass {
6 | constructor (raw = {}) {
7 | super(raw)
8 | const { message, ...props } = Object.assign(
9 | {},
10 | defaults,
11 | typeof raw === 'string' ? { message: raw } : raw
12 | )
13 | Object.keys(props).forEach(key => (this[key] = props[key]))
14 | if (message) this.description = typeof message === 'function' ? message(props) : message
15 | this.message = this.code ? `${this.code}, ${this.description}` : this.description
16 | this.name = name || ErrorClass.name
17 | }
18 | }
19 |
20 | // Function to create an instance, allowing use without `new`
21 | function CustomErrorFactory (props) {
22 | return new CustomError(props)
23 | }
24 |
25 | // Ensure the function's name matches the class name for consistency
26 | Object.defineProperty(CustomErrorFactory, 'name', {
27 | value: name || ErrorClass.name,
28 | writable: false
29 | })
30 |
31 | // Make `instanceof` checks work with both the class and factory
32 | CustomErrorFactory.prototype = CustomError.prototype
33 |
34 | return CustomErrorFactory
35 | }
36 | }
37 |
38 | module.exports = createErrorClass(Error)
39 | module.exports.type = createErrorClass(TypeError)
40 | module.exports.range = createErrorClass(RangeError)
41 | module.exports.eval = createErrorClass(EvalError)
42 | module.exports.syntax = createErrorClass(SyntaxError)
43 | module.exports.reference = createErrorClass(ReferenceError)
44 | module.exports.uri = createErrorClass(URIError)
45 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const { describe, it } = require('node:test')
4 |
5 | const whoops = require('..')
6 |
7 | describe('constructor', () => {
8 | ;[
9 | [Error, whoops],
10 | [TypeError, whoops.type],
11 | [RangeError, whoops.range],
12 | [EvalError, whoops.eval],
13 | [SyntaxError, whoops.syntax],
14 | [ReferenceError, whoops.reference],
15 | [URIError, whoops.uri]
16 | ].forEach(([ErrorClass, whoops]) => {
17 | describe(ErrorClass.name, () => {
18 | ;[
19 | { name: 'without providing a class name', input: undefined },
20 | { name: 'providing a class name', input: 'UserError' }
21 | ].forEach(({ name, input }) => {
22 | it(name, t => {
23 | const userError = whoops(input)
24 | t.assert.equal(typeof userError, 'function')
25 | t.assert.equal(userError.name, input || ErrorClass.name)
26 | t.assert.equal(userError().name, input || ErrorClass.name)
27 | t.assert.equal(userError().message, undefined)
28 | t.assert.equal(userError().description, undefined)
29 | t.assert.equal(userError().code, undefined)
30 | t.assert.equal(userError() instanceof userError, true)
31 | t.assert.equal(userError() instanceof ErrorClass, true)
32 | })
33 | })
34 | })
35 | })
36 |
37 | it('attach props', t => {
38 | const userError = whoops('UserError', { code: 'ENOVALID' })
39 | t.assert.equal(typeof userError, 'function')
40 | t.assert.equal(userError.name, 'UserError')
41 | const error = userError({ message: 'user not found' })
42 | t.assert.equal(error.message, 'ENOVALID, user not found')
43 | t.assert.equal(error.code, 'ENOVALID')
44 | t.assert.equal(error.description, 'user not found')
45 | })
46 |
47 | describe('instance', () => {
48 | describe('passing message prop', () => {
49 | it('as string', t => {
50 | const userError = whoops('UserError')
51 | const error = userError('user not found')
52 | t.assert.equal(error instanceof userError, true)
53 | t.assert.equal(error instanceof Error, true)
54 | t.assert.equal(error.message, 'user not found')
55 | t.assert.equal(error.description, 'user not found')
56 | })
57 |
58 | it('as object', t => {
59 | const userError = whoops('UserError')
60 | const error = userError({ message: 'user not found' })
61 | t.assert.equal(error instanceof userError, true)
62 | t.assert.equal(error instanceof Error, true)
63 | t.assert.equal(error.message, 'user not found')
64 | t.assert.equal(error.description, 'user not found')
65 | })
66 | })
67 |
68 | it('passing message & code props', t => {
69 | const userError = whoops('UserError', {
70 | message: ({ username }) => `user '${username}' not found`,
71 | code: 'ENOVALID'
72 | })
73 |
74 | const error = userError({ username: 'kikobeats' })
75 |
76 | t.assert.equal(error.message, "ENOVALID, user 'kikobeats' not found")
77 | t.assert.equal(error.code, 'ENOVALID')
78 | t.assert.equal(error.description, "user 'kikobeats' not found")
79 |
80 | t.assert.equal(error instanceof userError, true)
81 | t.assert.equal(error instanceof Error, true)
82 | })
83 |
84 | it('passing message, code & extra props', t => {
85 | const userError = whoops('UserError')
86 | const error = userError({
87 | username: 'kikobeats',
88 | message: props => `user '${props.username}' not found`,
89 | code: 'ENOVALID'
90 | })
91 | t.assert.equal(error instanceof userError, true)
92 | t.assert.equal(error instanceof Error, true)
93 | t.assert.equal(error.message, "ENOVALID, user 'kikobeats' not found")
94 | t.assert.equal(error.code, 'ENOVALID')
95 | t.assert.equal(error.description, "user 'kikobeats' not found")
96 | t.assert.equal(error.username, 'kikobeats')
97 | })
98 | })
99 | })
100 |
--------------------------------------------------------------------------------