@vltpkg/error-cause 0.0.0-0.1730239248325
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/LICENSE +15 -0
- package/README.md +353 -0
- package/dist/esm/index.d.ts +145 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Copyright (c) vlt technology, Inc.
|
|
2
|
+
|
|
3
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
4
|
+
|
|
5
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
6
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
7
|
+
Subject to the terms and conditions of this license, each copyright holder and contributor hereby grants to those receiving rights under this license a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except for failure to satisfy the conditions of this license) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer this software, where such license applies only to those patent claims, already acquired or hereafter acquired, licensable by such copyright holder or contributor that are necessarily infringed by:
|
|
8
|
+
|
|
9
|
+
(a) their Contribution(s) (the licensed copyrights of copyright holders and non-copyrightable additions of contributors, in source or binary form) alone; or
|
|
10
|
+
(b) combination of their Contribution(s) with the work of authorship to which such Contribution(s) was added by such copyright holder or contributor, if, at the time the Contribution is added, such addition causes such combination to be necessarily infringed. The patent license shall not apply to any other combinations which include the Contribution.
|
|
11
|
+
Except as expressly stated above, no rights or licenses from any copyright holder or contributor is granted under this license, whether expressly, by implication, estoppel or otherwise.
|
|
12
|
+
|
|
13
|
+
DISCLAIMER
|
|
14
|
+
|
|
15
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
ADDED
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
# `@vltpkg/error-cause`
|
|
2
|
+
|
|
3
|
+
Utility functions for `Error` creation to help enforce vlt's
|
|
4
|
+
`Error.cause` conventions.
|
|
5
|
+
|
|
6
|
+
## USAGE
|
|
7
|
+
|
|
8
|
+
```js
|
|
9
|
+
import { error, typeError } from '@vltpkg/error-cause'
|
|
10
|
+
|
|
11
|
+
// create an error when a lower-level thing fails
|
|
12
|
+
try {
|
|
13
|
+
doSomethign()
|
|
14
|
+
} catch (er) {
|
|
15
|
+
throw error('The something for the whatever failed', er)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// create an error with some extra information
|
|
19
|
+
if (!thing.valid) {
|
|
20
|
+
throw error('the thing is not valid', {
|
|
21
|
+
code: 'EINVAL',
|
|
22
|
+
found: thing,
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// create an error from a lower-level error with extra info
|
|
27
|
+
try {
|
|
28
|
+
doSomethign(thing)
|
|
29
|
+
} catch (er) {
|
|
30
|
+
throw error('the thing is not valid', {
|
|
31
|
+
code: 'EINVAL',
|
|
32
|
+
found: thing,
|
|
33
|
+
cause: er,
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// create an error and prune some stack frames
|
|
38
|
+
// use this when we want to report the location of a
|
|
39
|
+
// function call, not its internals.
|
|
40
|
+
const checkBar = () => {
|
|
41
|
+
if (!bar) {
|
|
42
|
+
// will report from the checkBar() call, not here.
|
|
43
|
+
throw error('no bar', { found: bar, wanted: true }, checkBar)
|
|
44
|
+
}
|
|
45
|
+
// ...
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The functions will create an error object with a `cause` property
|
|
50
|
+
if set, and the type checks will ensure that the `cause` object
|
|
51
|
+
matches vlt's conventions.
|
|
52
|
+
|
|
53
|
+
## Why
|
|
54
|
+
|
|
55
|
+
Most node programs have a mishmash of error codes and various
|
|
56
|
+
`Error` subtypes, all in different shapes, making error handling
|
|
57
|
+
and reporting more difficult at the top level. This negatively
|
|
58
|
+
impacts debugging and user experience.
|
|
59
|
+
|
|
60
|
+
The JavaScript `Error` constructor has a [`cause`
|
|
61
|
+
option](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/cause)
|
|
62
|
+
which is supported since Node 16.9. We should use it!
|
|
63
|
+
|
|
64
|
+
This module makes that easy.
|
|
65
|
+
|
|
66
|
+
## Challenges of Error Reporting
|
|
67
|
+
|
|
68
|
+
- Provide enough information to be useful. On full inspection, we
|
|
69
|
+
should ideally always get back to not just the initial error
|
|
70
|
+
that was thrown, but also all locations where the error might
|
|
71
|
+
have been caught and handled in some way.
|
|
72
|
+
- Do not provide more information than is useful. Eg,
|
|
73
|
+
`console.error(er)` should not fill the entire scrollback
|
|
74
|
+
buffer.
|
|
75
|
+
- New modules and libraries should have minimal friction in
|
|
76
|
+
creating a new style of error when needed. This means, minimize
|
|
77
|
+
the amount that any module needs to know about the errors
|
|
78
|
+
raised by any other module, including especially top-level
|
|
79
|
+
error handling.
|
|
80
|
+
- _Some_ information about the error must be known to our
|
|
81
|
+
top-level error handler, so that it can usefully report errors
|
|
82
|
+
and suggest corrections.
|
|
83
|
+
|
|
84
|
+
## Solution
|
|
85
|
+
|
|
86
|
+
- A strictly upheld convention of Error object creation using the
|
|
87
|
+
`cause` property.
|
|
88
|
+
- Top level error handler can have special logic where necessary
|
|
89
|
+
for known error codes, but will still be able to do something
|
|
90
|
+
more useful when an Error object follows our conventions, even
|
|
91
|
+
if it's not a code that it knows.
|
|
92
|
+
|
|
93
|
+
## Conventions
|
|
94
|
+
|
|
95
|
+
The following conventions should be followed for all `Error`
|
|
96
|
+
creation and handling throughout the vlt codebase.
|
|
97
|
+
|
|
98
|
+
- **If you can't help, get out of the way.** Just let throws pass
|
|
99
|
+
through to the top when nothing can be done to assist.
|
|
100
|
+
- **Add information by using thrown error as `cause`.** Use a
|
|
101
|
+
previously-thrown error as the `cause` option.
|
|
102
|
+
- **Add even more info with a double-`cause`.** If more info can
|
|
103
|
+
be added to a prior throw, nest the `cause` properties like
|
|
104
|
+
`{ some, other, info, cause: priorError }`.
|
|
105
|
+
- **Always set `cause`, even if no prior error.** Use a plain-old
|
|
106
|
+
JavaScript object following our field conventions.
|
|
107
|
+
- **Rare exception: synthetic ErrnoException style errors.** If we are
|
|
108
|
+
doing something that is similar to a system operation, it's
|
|
109
|
+
sometimes ok to mimic node's pattern.
|
|
110
|
+
- **Do not subclass `Error`.** Just create a plain old Error, and
|
|
111
|
+
set the `cause` with additional information.
|
|
112
|
+
|
|
113
|
+
### If you can't help, don't get in the way.
|
|
114
|
+
|
|
115
|
+
Whenever possible, if no remediation or extra information can
|
|
116
|
+
usefully be added, it's best to just not handle errors and let
|
|
117
|
+
them be raised at the higher level. For example, instead of this:
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
let data
|
|
121
|
+
try {
|
|
122
|
+
data = await readFile(someFile)
|
|
123
|
+
} catch (er) {
|
|
124
|
+
throw new Error('could not read some file!')
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
this is preferred:
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
const data = await readFile(someFile)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Add information by using thrown error as `cause`.
|
|
135
|
+
|
|
136
|
+
If we can add information or do something else useful for the
|
|
137
|
+
user in understanding the problem, do so by creating a new
|
|
138
|
+
`Error` and setting the original thrown error as the `cause`.
|
|
139
|
+
|
|
140
|
+
```js
|
|
141
|
+
let data
|
|
142
|
+
try {
|
|
143
|
+
data = await readFile(someFile, 'utf8')
|
|
144
|
+
} catch (er) {
|
|
145
|
+
// adds semantic information about what the file was for
|
|
146
|
+
throw error('The lock file was not found', er)
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Add even more info with a double-`cause`.
|
|
151
|
+
|
|
152
|
+
If we can add even more information, that should ideally _not_ be
|
|
153
|
+
put on the Error we throw, but on a `cause` object. Because
|
|
154
|
+
`cause` objects can nest, we can do something like this:
|
|
155
|
+
|
|
156
|
+
```js
|
|
157
|
+
let data
|
|
158
|
+
try {
|
|
159
|
+
data = await readFile(someFile, 'utf8')
|
|
160
|
+
} catch (er) {
|
|
161
|
+
throw error(`could not resolve '${name}'`, {
|
|
162
|
+
// extra data about the situation
|
|
163
|
+
// it's ok to put big noisy objects in here, not on the error
|
|
164
|
+
// object itself!
|
|
165
|
+
name,
|
|
166
|
+
spec,
|
|
167
|
+
target,
|
|
168
|
+
// original error that was thrown
|
|
169
|
+
cause: er,
|
|
170
|
+
})
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Always set `cause`, even if no prior error.
|
|
175
|
+
|
|
176
|
+
Instead of this:
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
throw Object.assign(new Error('could not resolve'), {
|
|
180
|
+
code: 'ERESOLVE',
|
|
181
|
+
from,
|
|
182
|
+
spec,
|
|
183
|
+
registry,
|
|
184
|
+
})
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Do this instead:
|
|
188
|
+
|
|
189
|
+
```js
|
|
190
|
+
throw error('could not resolve', {
|
|
191
|
+
code: 'ERESOLVE',
|
|
192
|
+
from,
|
|
193
|
+
spec,
|
|
194
|
+
registry,
|
|
195
|
+
})
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
This makes any big objects easily skipped if we want to just
|
|
199
|
+
output the error with `console.error()` or something, but still
|
|
200
|
+
preserves any debugging information that might be useful all the
|
|
201
|
+
way down the chain.
|
|
202
|
+
|
|
203
|
+
### Rare exception: synthetic ErrnoException style errors.
|
|
204
|
+
|
|
205
|
+
In some rare low-level cases, there are operations we perform
|
|
206
|
+
that are very similar to a node filesystem operation.
|
|
207
|
+
|
|
208
|
+
For example, the `@vltpkg/which` module raises an error that is
|
|
209
|
+
intentionally similar to node's filesystem `ENOENT` errors,
|
|
210
|
+
because that is semantically sensible.
|
|
211
|
+
|
|
212
|
+
In those cases, the error _must_ follow node's conventions as
|
|
213
|
+
close as possible. If we feel the need to add additional
|
|
214
|
+
information beyond a known system error code, string path, etc.,
|
|
215
|
+
or if the message isn't one that is typically raised by the
|
|
216
|
+
underlying system, then it's a good sign that we ought to be
|
|
217
|
+
creating an `Error` with a `cause` so that it can be reported
|
|
218
|
+
more usefully.
|
|
219
|
+
|
|
220
|
+
In such cases, this is fine:
|
|
221
|
+
|
|
222
|
+
```js
|
|
223
|
+
// identical to the error thrown by node's fs
|
|
224
|
+
throw Object.assign(new Error('not found'), {
|
|
225
|
+
path: someFile,
|
|
226
|
+
code: 'ENOENT',
|
|
227
|
+
})
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
But this is way out of bounds and makes no sense:
|
|
231
|
+
|
|
232
|
+
```
|
|
233
|
+
throw Object.assign(new Error('could not resolve'), {
|
|
234
|
+
code: 'EPERM',
|
|
235
|
+
spec,
|
|
236
|
+
config: someHugeConfigObjectOrSomething,
|
|
237
|
+
})
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Do not** copy properties from a lower-level error or cause onto
|
|
241
|
+
the new cause object. That is unnecessary, and obscures the
|
|
242
|
+
origin of problems. Instead, just include the lower-level error
|
|
243
|
+
as the `cause` property. If you already have a low-level error,
|
|
244
|
+
you don't need to invent a synthetic one!
|
|
245
|
+
|
|
246
|
+
For example, do not do this:
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
let data
|
|
250
|
+
try {
|
|
251
|
+
data = await readFile(lockFile, 'utf8')
|
|
252
|
+
} catch (er) {
|
|
253
|
+
throw error('lockfile not found', {
|
|
254
|
+
code: er.code,
|
|
255
|
+
path: er.path,
|
|
256
|
+
})
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Instead, do this:
|
|
261
|
+
|
|
262
|
+
```js
|
|
263
|
+
let data
|
|
264
|
+
try {
|
|
265
|
+
data = await readFile(lockFile, 'utf8')
|
|
266
|
+
} catch (er) {
|
|
267
|
+
throw new Error('lockfile not found', { cause: er })
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Do not subclass `Error`.
|
|
272
|
+
|
|
273
|
+
Just use the `Error` classes defined in the language. Additional
|
|
274
|
+
information about error causes should be on the `cause` property,
|
|
275
|
+
not implicit in the constructor type.
|
|
276
|
+
|
|
277
|
+
Ie, do not do this:
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
class VersionError extends Error {
|
|
281
|
+
version?: Version
|
|
282
|
+
constructor(version: Version | string) {
|
|
283
|
+
super('Could not version')
|
|
284
|
+
this.version = Version.parse(version)
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
// ...
|
|
288
|
+
throw new VersionError(myVersion)
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Instead, do this:
|
|
292
|
+
|
|
293
|
+
```js
|
|
294
|
+
throw error('Could not version', { version })
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## `cause` Field Conventions
|
|
298
|
+
|
|
299
|
+
All of these are optional. Additional fields may be used where
|
|
300
|
+
appropriate, and should be added to this list over time.
|
|
301
|
+
|
|
302
|
+
- `cause` - The `cause` field within a `cause` object should
|
|
303
|
+
always be an `Error` object that was previously thrown. Note
|
|
304
|
+
that the `cause` on an Error itself might _also_ be a
|
|
305
|
+
previously thrown error, if no additional information could be
|
|
306
|
+
usefully added beyond improving the message.
|
|
307
|
+
- `name` - String. The name of something.
|
|
308
|
+
- `offset` - Number. The offset in a Buffer or file where we are
|
|
309
|
+
trying to read or write.
|
|
310
|
+
- `registry` - String or URL. A package registry.
|
|
311
|
+
- `code` - This must be a string if set, and should
|
|
312
|
+
only be present if it's one of our creation, not a code raised
|
|
313
|
+
on a system error. Eg, `ERESOLVE`, not `ENOENT`.
|
|
314
|
+
- `path` - The target of a file system operation.
|
|
315
|
+
- `target` - path on disk that is being written or extracted to
|
|
316
|
+
- `spec` - a `@vltpkg/spec.Spec` object relevant to the operation
|
|
317
|
+
that failed.
|
|
318
|
+
- `from` - string. The file path origin of a resolution that
|
|
319
|
+
failed, for example in the case of relative `file:` specifiers.
|
|
320
|
+
- `status` - Number or null. Either the exit code of a process or
|
|
321
|
+
an HTTP response status code.
|
|
322
|
+
- `signal` - `NodeJS.Signals` string or null, indicating the
|
|
323
|
+
signal that terminated a process.
|
|
324
|
+
- `validOptions` - Array of valid options when something is not a
|
|
325
|
+
valid option. (For use in `did you mean X?` output.)
|
|
326
|
+
- `todo` - String message indicating what bit of work this might
|
|
327
|
+
be a part of, what feature needs to be implemented, etc. Eg, `{
|
|
328
|
+
todo: 'nested workspace support' }`.
|
|
329
|
+
- `wanted` - A desired value that was not found, or a regular
|
|
330
|
+
expression or other pattern describing it.
|
|
331
|
+
- `found` - The actual value, which was not wanted.
|
|
332
|
+
- `max` - A maximum value, which was exceeded.
|
|
333
|
+
- `min` - A minimum value, which was not met.
|
|
334
|
+
- `response` - An HTTP response or
|
|
335
|
+
`@vltpkg/registry-client.CacheEntry`
|
|
336
|
+
- `url` - A string or URL object
|
|
337
|
+
- `repository` - String git repository remote
|
|
338
|
+
- `version` - string or `@vltpkg/semver.Version`
|
|
339
|
+
- `range` - string or `@vltpkg/semver.Range`
|
|
340
|
+
- `manifest` - `@vltpkg/pick-manifest.Manifest`
|
|
341
|
+
- `packument` - `@vltpkg/pick-manifest.Packument`
|
|
342
|
+
- `cwd` - The current working directory of a process that failed
|
|
343
|
+
|
|
344
|
+
## Error Types
|
|
345
|
+
|
|
346
|
+
- If there is a _type_ problem with an argument, for example a
|
|
347
|
+
`string` was expected and a `number` was provided, throw a
|
|
348
|
+
`TypeError`. **Do not** use it for a value that is the correct
|
|
349
|
+
type but otherwise invalid, such as a `string` argument that is
|
|
350
|
+
actually a `string` but does not match an expected pattern.
|
|
351
|
+
- If the type is fine, but a parsed string is invalid and not
|
|
352
|
+
parseable, use `SyntaxError`.
|
|
353
|
+
- In all other cases, use `Error`.
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import type { IncomingMessage } from 'http';
|
|
2
|
+
/**
|
|
3
|
+
* Codification of vlt's Error.cause conventions
|
|
4
|
+
*
|
|
5
|
+
* Add new properties to this list as needed.
|
|
6
|
+
*
|
|
7
|
+
* Several of these types are just very basic duck-typing, because referencing
|
|
8
|
+
* internal types directly would create a workspace dependency cycle.
|
|
9
|
+
*/
|
|
10
|
+
export type ErrorCauseObject = {
|
|
11
|
+
/**
|
|
12
|
+
* The `cause` field within a `cause` object should
|
|
13
|
+
* always be an `Error` object that was previously thrown. Note
|
|
14
|
+
* that the `cause` on an Error itself might _also_ be a
|
|
15
|
+
* previously thrown error, if no additional information could be
|
|
16
|
+
* usefully added beyond improving the message.
|
|
17
|
+
*/
|
|
18
|
+
cause?: ErrorCause;
|
|
19
|
+
/** the name of something */
|
|
20
|
+
name?: string;
|
|
21
|
+
/** byte offset in a Buffer or file */
|
|
22
|
+
offset?: number;
|
|
23
|
+
/**
|
|
24
|
+
* This should only be a string code that we set. See {@link Codes} for
|
|
25
|
+
* the supported options. Lower-level system codes like `ENOENT` should
|
|
26
|
+
* remain on the errors that generated them.
|
|
27
|
+
*/
|
|
28
|
+
code?: Codes;
|
|
29
|
+
/** target of a file system operation */
|
|
30
|
+
path?: string;
|
|
31
|
+
/**
|
|
32
|
+
* file path origin of a resolution that failed, for example in the case
|
|
33
|
+
* of `file://` specifiers.
|
|
34
|
+
*/
|
|
35
|
+
from?: string;
|
|
36
|
+
/** path on disk that is being written, linked, or extracted to */
|
|
37
|
+
target?: string;
|
|
38
|
+
/** Spec object/string relevant to an operation that failed */
|
|
39
|
+
spec?: string | {
|
|
40
|
+
type: 'file' | 'git' | 'registry' | 'remote' | 'workspace';
|
|
41
|
+
spec: string;
|
|
42
|
+
[k: number | string | symbol]: any;
|
|
43
|
+
};
|
|
44
|
+
/** exit code of a process, or HTTP response status code */
|
|
45
|
+
status?: number | null;
|
|
46
|
+
/** null or a signal that a process received */
|
|
47
|
+
signal?: NodeJS.Signals | null;
|
|
48
|
+
/** the root of a project */
|
|
49
|
+
projectRoot?: string;
|
|
50
|
+
/** the current working directory of a process */
|
|
51
|
+
cwd?: string;
|
|
52
|
+
/** a command being run in a child process */
|
|
53
|
+
command?: string;
|
|
54
|
+
/** the arguments passed to a process */
|
|
55
|
+
args?: string[];
|
|
56
|
+
/** standard output from a process */
|
|
57
|
+
stdout?: Buffer | string | null;
|
|
58
|
+
/** standard error from a process */
|
|
59
|
+
stderr?: Buffer | string | null;
|
|
60
|
+
/**
|
|
61
|
+
* Array of valid options when something is not a valid option.
|
|
62
|
+
* (For use in `did you mean X?` output.)
|
|
63
|
+
*/
|
|
64
|
+
validOptions?: any[];
|
|
65
|
+
/**
|
|
66
|
+
* message indicating what bit of work this might be a part of, what feature
|
|
67
|
+
* needs to be implemented, etc. Eg, `{ todo: 'nested workspace support' }`.
|
|
68
|
+
*/
|
|
69
|
+
todo?: string;
|
|
70
|
+
/**
|
|
71
|
+
* A desired value that was not found, or a regular expression or other
|
|
72
|
+
* pattern describing it.
|
|
73
|
+
*/
|
|
74
|
+
wanted?: any;
|
|
75
|
+
/** actual value, which was not wanted */
|
|
76
|
+
found?: any;
|
|
77
|
+
/** HTTP message, fetch.Response, or `@vltpkg/registry-client.CacheEntry` */
|
|
78
|
+
response?: IncomingMessage | Response | {
|
|
79
|
+
statusCode: number;
|
|
80
|
+
headers: Buffer[] | Record<string, string[] | string>;
|
|
81
|
+
text: () => string;
|
|
82
|
+
[k: number | string | symbol]: any;
|
|
83
|
+
};
|
|
84
|
+
/** string or URL object */
|
|
85
|
+
url?: URL | string;
|
|
86
|
+
/** git repository remote or path */
|
|
87
|
+
repository?: string;
|
|
88
|
+
/** string or `@vltpkg/semver.Version` object */
|
|
89
|
+
version?: string | {
|
|
90
|
+
raw: string;
|
|
91
|
+
major: number;
|
|
92
|
+
minor: number;
|
|
93
|
+
patch: number;
|
|
94
|
+
[k: number | string | symbol]: any;
|
|
95
|
+
};
|
|
96
|
+
/** string or `@vltpkg/semver.Range` object */
|
|
97
|
+
range?: string | {
|
|
98
|
+
raw: string;
|
|
99
|
+
isAny: boolean;
|
|
100
|
+
includePrerelease: boolean;
|
|
101
|
+
[k: number | string | symbol]: any;
|
|
102
|
+
};
|
|
103
|
+
/** a package manifest, either from `package.json` or a registry */
|
|
104
|
+
manifest?: DuckTypeManifest;
|
|
105
|
+
/** registry top-level package document */
|
|
106
|
+
packument?: {
|
|
107
|
+
name: string;
|
|
108
|
+
'dist-tags': Record<string, string>;
|
|
109
|
+
versions: Record<string, DuckTypeManifest>;
|
|
110
|
+
time?: Record<string, string>;
|
|
111
|
+
};
|
|
112
|
+
/** maximum value, which was exceeded */
|
|
113
|
+
max?: any;
|
|
114
|
+
/** minimum value, which was not met */
|
|
115
|
+
min?: any;
|
|
116
|
+
};
|
|
117
|
+
export type DuckTypeManifest = Record<string, any> & {
|
|
118
|
+
name?: string;
|
|
119
|
+
version?: string;
|
|
120
|
+
deprecated?: string;
|
|
121
|
+
engines?: Record<string, string>;
|
|
122
|
+
os?: string[] | string;
|
|
123
|
+
arch?: string[] | string;
|
|
124
|
+
dist?: {
|
|
125
|
+
integrity?: string;
|
|
126
|
+
shasum?: string;
|
|
127
|
+
tarball?: string;
|
|
128
|
+
fileCount?: number;
|
|
129
|
+
unpackedSize?: number;
|
|
130
|
+
signatures?: {
|
|
131
|
+
keyid: string;
|
|
132
|
+
sig: string;
|
|
133
|
+
}[];
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
export type ErrorCause = Error | ErrorCauseObject;
|
|
137
|
+
/**
|
|
138
|
+
* Valid properties for the 'code' field in an Error cause.
|
|
139
|
+
* Add new options to this list as needed.
|
|
140
|
+
*/
|
|
141
|
+
export type Codes = 'EEXIST' | 'EINTEGRITY' | 'EINVAL' | 'ELIFECYCLE' | 'EMAXREDIRECT' | 'ENEEDAUTH' | 'ENOENT' | 'ENOGIT' | 'ERESOLVE' | 'EUNKNOWN';
|
|
142
|
+
export declare const error: (message: string, cause?: ErrorCause, from?: ((...a: any[]) => any) | (new (...a: any[]) => any)) => Error;
|
|
143
|
+
export declare const typeError: (message: string, cause?: ErrorCause, from?: ((...a: any[]) => any) | (new (...a: any[]) => any)) => Error;
|
|
144
|
+
export declare const syntaxError: (message: string, cause?: ErrorCause, from?: ((...a: any[]) => any) | (new (...a: any[]) => any)) => Error;
|
|
145
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const create = (cls, defaultFrom, message, cause, from = defaultFrom) => {
|
|
2
|
+
const er = new cls(message, cause ? { cause } : undefined);
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
4
|
+
Error.captureStackTrace?.(er, from);
|
|
5
|
+
return er;
|
|
6
|
+
};
|
|
7
|
+
export const error = (message, cause, from) => create(Error, error, message, cause, from);
|
|
8
|
+
export const typeError = (message, cause, from) => create(TypeError, typeError, message, cause, from);
|
|
9
|
+
export const syntaxError = (message, cause, from) => create(SyntaxError, syntaxError, message, cause, from);
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAiMA,MAAM,MAAM,GAAG,CACb,GAAiB,EACjB,WAAgE,EAChE,OAAe,EACf,KAAkB,EAClB,OAEiC,WAAW,EAC5C,EAAE;IACF,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IAC1D,uEAAuE;IACvE,KAAK,CAAC,iBAAiB,EAAE,CAAC,EAAE,EAAE,IAAI,CAAC,CAAA;IACnC,OAAO,EAAE,CAAA;AACX,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,CACnB,OAAe,EACf,KAAkB,EAClB,IAA0D,EAC1D,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA;AAE/C,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,OAAe,EACf,KAAkB,EAClB,IAA0D,EAC1D,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA;AAEvD,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,OAAe,EACf,KAAkB,EAClB,IAA0D,EAC1D,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA","sourcesContent":["import type { IncomingMessage } from 'http'\n\n/**\n * Codification of vlt's Error.cause conventions\n *\n * Add new properties to this list as needed.\n *\n * Several of these types are just very basic duck-typing, because referencing\n * internal types directly would create a workspace dependency cycle.\n */\nexport type ErrorCauseObject = {\n /**\n * The `cause` field within a `cause` object should\n * always be an `Error` object that was previously thrown. Note\n * that the `cause` on an Error itself might _also_ be a\n * previously thrown error, if no additional information could be\n * usefully added beyond improving the message.\n */\n cause?: ErrorCause\n\n /** the name of something */\n name?: string\n\n /** byte offset in a Buffer or file */\n offset?: number\n\n /**\n * This should only be a string code that we set. See {@link Codes} for\n * the supported options. Lower-level system codes like `ENOENT` should\n * remain on the errors that generated them.\n */\n code?: Codes\n\n /** target of a file system operation */\n path?: string\n\n /**\n * file path origin of a resolution that failed, for example in the case\n * of `file://` specifiers.\n */\n from?: string\n\n /** path on disk that is being written, linked, or extracted to */\n target?: string\n\n /** Spec object/string relevant to an operation that failed */\n spec?:\n | string\n | {\n type: 'file' | 'git' | 'registry' | 'remote' | 'workspace'\n spec: string\n [k: number | string | symbol]: any\n }\n\n /** exit code of a process, or HTTP response status code */\n status?: number | null\n\n /** null or a signal that a process received */\n signal?: NodeJS.Signals | null\n\n /** the root of a project */\n projectRoot?: string\n\n /** the current working directory of a process */\n cwd?: string\n\n /** a command being run in a child process */\n command?: string\n\n /** the arguments passed to a process */\n args?: string[]\n\n /** standard output from a process */\n stdout?: Buffer | string | null\n\n /** standard error from a process */\n stderr?: Buffer | string | null\n\n /**\n * Array of valid options when something is not a valid option.\n * (For use in `did you mean X?` output.)\n */\n validOptions?: any[]\n\n /**\n * message indicating what bit of work this might be a part of, what feature\n * needs to be implemented, etc. Eg, `{ todo: 'nested workspace support' }`.\n */\n todo?: string\n\n /**\n * A desired value that was not found, or a regular expression or other\n * pattern describing it.\n */\n wanted?: any\n\n /** actual value, which was not wanted */\n found?: any\n\n /** HTTP message, fetch.Response, or `@vltpkg/registry-client.CacheEntry` */\n response?:\n | IncomingMessage\n | Response\n | {\n statusCode: number\n headers: Buffer[] | Record<string, string[] | string>\n text: () => string\n [k: number | string | symbol]: any\n }\n\n /** string or URL object */\n url?: URL | string\n\n /** git repository remote or path */\n repository?: string\n\n /** string or `@vltpkg/semver.Version` object */\n version?:\n | string\n | {\n raw: string\n major: number\n minor: number\n patch: number\n [k: number | string | symbol]: any\n }\n\n /** string or `@vltpkg/semver.Range` object */\n range?:\n | string\n | {\n raw: string\n isAny: boolean\n includePrerelease: boolean\n [k: number | string | symbol]: any\n }\n\n /** a package manifest, either from `package.json` or a registry */\n manifest?: DuckTypeManifest\n\n /** registry top-level package document */\n packument?: {\n name: string\n 'dist-tags': Record<string, string>\n versions: Record<string, DuckTypeManifest>\n time?: Record<string, string>\n }\n\n /** maximum value, which was exceeded */\n max?: any\n\n /** minimum value, which was not met */\n min?: any\n}\n\nexport type DuckTypeManifest = Record<string, any> & {\n name?: string\n version?: string\n deprecated?: string\n engines?: Record<string, string>\n os?: string[] | string\n arch?: string[] | string\n dist?: {\n integrity?: string\n shasum?: string\n tarball?: string\n fileCount?: number\n unpackedSize?: number\n signatures?: {\n keyid: string\n sig: string\n }[]\n }\n}\n\nexport type ErrorCause = Error | ErrorCauseObject\n\n/**\n * Valid properties for the 'code' field in an Error cause.\n * Add new options to this list as needed.\n */\nexport type Codes =\n | 'EEXIST'\n | 'EINTEGRITY'\n | 'EINVAL'\n | 'ELIFECYCLE'\n | 'EMAXREDIRECT'\n | 'ENEEDAUTH'\n | 'ENOENT'\n | 'ENOGIT'\n | 'ERESOLVE'\n | 'EUNKNOWN'\n\nconst create = (\n cls: typeof Error,\n defaultFrom: ((...a: any[]) => any) | (new (...a: any[]) => any),\n message: string,\n cause?: ErrorCause,\n from:\n | ((...a: any[]) => any)\n | (new (...a: any[]) => any) = defaultFrom,\n) => {\n const er = new cls(message, cause ? { cause } : undefined)\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n Error.captureStackTrace?.(er, from)\n return er\n}\n\nexport const error = (\n message: string,\n cause?: ErrorCause,\n from?: ((...a: any[]) => any) | (new (...a: any[]) => any),\n) => create(Error, error, message, cause, from)\n\nexport const typeError = (\n message: string,\n cause?: ErrorCause,\n from?: ((...a: any[]) => any) | (new (...a: any[]) => any),\n) => create(TypeError, typeError, message, cause, from)\n\nexport const syntaxError = (\n message: string,\n cause?: ErrorCause,\n from?: ((...a: any[]) => any) | (new (...a: any[]) => any),\n) => create(SyntaxError, syntaxError, message, cause, from)\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vltpkg/error-cause",
|
|
3
|
+
"description": "vlts Error.cause convention",
|
|
4
|
+
"version": "0.0.0-0.1730239248325",
|
|
5
|
+
"tshy": {
|
|
6
|
+
"selfLink": false,
|
|
7
|
+
"dialects": [
|
|
8
|
+
"esm"
|
|
9
|
+
],
|
|
10
|
+
"exports": {
|
|
11
|
+
"./package.json": "./package.json",
|
|
12
|
+
".": "./src/index.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@eslint/js": "^9.8.0",
|
|
17
|
+
"@types/eslint__js": "^8.42.3",
|
|
18
|
+
"@types/node": "^22.4.1",
|
|
19
|
+
"eslint": "^9.8.0",
|
|
20
|
+
"prettier": "^3.3.2",
|
|
21
|
+
"tap": "^21.0.1",
|
|
22
|
+
"tshy": "^3.0.2",
|
|
23
|
+
"typescript": "^5.5.4",
|
|
24
|
+
"typescript-eslint": "^8.0.1"
|
|
25
|
+
},
|
|
26
|
+
"license": "BSD-2-Clause-Patent",
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": "20 || >=22"
|
|
29
|
+
},
|
|
30
|
+
"tap": {
|
|
31
|
+
"extends": "../../tap-config.yaml"
|
|
32
|
+
},
|
|
33
|
+
"prettier": "../../.prettierrc.js",
|
|
34
|
+
"module": "./dist/esm/index.js",
|
|
35
|
+
"type": "module",
|
|
36
|
+
"exports": {
|
|
37
|
+
"./package.json": "./package.json",
|
|
38
|
+
".": {
|
|
39
|
+
"import": {
|
|
40
|
+
"types": "./dist/esm/index.d.ts",
|
|
41
|
+
"default": "./dist/esm/index.js"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"files": [
|
|
46
|
+
"dist"
|
|
47
|
+
],
|
|
48
|
+
"scripts": {
|
|
49
|
+
"format": "prettier --write . --log-level warn --ignore-path ../../.prettierignore --cache",
|
|
50
|
+
"format:check": "prettier --check . --ignore-path ../../.prettierignore --cache",
|
|
51
|
+
"lint": "eslint . --fix",
|
|
52
|
+
"lint:check": "eslint .",
|
|
53
|
+
"presnap": "tshy",
|
|
54
|
+
"snap": "tap",
|
|
55
|
+
"pretest": "tshy",
|
|
56
|
+
"test": "tap"
|
|
57
|
+
}
|
|
58
|
+
}
|