errore 0.11.0 → 0.12.0
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/README.md +55 -0
- package/SKILL.md +997 -128
- package/dist/disposable.d.ts +120 -0
- package/dist/disposable.d.ts.map +1 -0
- package/dist/disposable.js +239 -0
- package/dist/disposable.test.d.ts +2 -0
- package/dist/disposable.test.d.ts.map +1 -0
- package/dist/disposable.test.js +602 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.test.js +17 -0
- package/package.json +8 -1
- package/src/disposable.test.ts +507 -0
- package/src/disposable.ts +253 -0
- package/src/index.test.ts +17 -1
- package/src/index.ts +3 -0
package/README.md
CHANGED
|
@@ -365,6 +365,11 @@ const response = await errore.tryAsync({
|
|
|
365
365
|
})
|
|
366
366
|
```
|
|
367
367
|
|
|
368
|
+
> **Best practices for `try` / `tryAsync`:**
|
|
369
|
+
> - **Use as low as possible in the call stack** — only at boundaries with uncontrolled dependencies (third-party libs, `JSON.parse`, `fetch`, file I/O). Your own functions should return errors as values, never throw.
|
|
370
|
+
> - **Keep the callback minimal** — wrap only the single throwing call, not your business logic. The `try` callback should be a one-liner.
|
|
371
|
+
> - **Always prefer `errore.try` over `errore.tryFn`** — they are the same function, but `try` is the canonical name.
|
|
372
|
+
|
|
368
373
|
### Transformations
|
|
369
374
|
|
|
370
375
|
**Transform and chain** operations:
|
|
@@ -385,6 +390,54 @@ const posts = errore.andThen(user, u => fetchPosts(u.id))
|
|
|
385
390
|
const logged = errore.tap(user, u => console.log('Got user:', u.name))
|
|
386
391
|
```
|
|
387
392
|
|
|
393
|
+
### Resource Cleanup (defer)
|
|
394
|
+
|
|
395
|
+
errore ships `DisposableStack` and `AsyncDisposableStack` polyfills for Go-like `defer` cleanup. Works in every runtime — no native `DisposableStack` support needed:
|
|
396
|
+
|
|
397
|
+
```ts
|
|
398
|
+
import * as errore from 'errore'
|
|
399
|
+
|
|
400
|
+
async function processRequest(id: string): Promise<DbError | Result> {
|
|
401
|
+
// await using = cleanup runs automatically when scope exits
|
|
402
|
+
await using cleanup = new errore.AsyncDisposableStack()
|
|
403
|
+
|
|
404
|
+
const db = await connectDb()
|
|
405
|
+
cleanup.defer(() => db.close())
|
|
406
|
+
|
|
407
|
+
const cache = await openCache()
|
|
408
|
+
cleanup.defer(() => cache.flush())
|
|
409
|
+
|
|
410
|
+
// ... use db and cache ...
|
|
411
|
+
return result
|
|
412
|
+
// cleanup runs in LIFO order: cache.flush() → db.close()
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
Resources are released in **reverse order** (last deferred = first cleaned up), just like Go's `defer`. Cleanup runs on normal return, early error return, or thrown exception.
|
|
417
|
+
|
|
418
|
+
```ts
|
|
419
|
+
// Sync version with using
|
|
420
|
+
function readConfig(path: string): ParseError | Config {
|
|
421
|
+
using cleanup = new errore.DisposableStack()
|
|
422
|
+
|
|
423
|
+
const file = openFileSync(path)
|
|
424
|
+
cleanup.defer(() => file.closeSync())
|
|
425
|
+
|
|
426
|
+
const lock = acquireLock(path)
|
|
427
|
+
cleanup.defer(() => lock.release())
|
|
428
|
+
|
|
429
|
+
return parseConfig(file.readSync())
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
You can also register existing `Disposable` objects directly:
|
|
434
|
+
|
|
435
|
+
```ts
|
|
436
|
+
await using cleanup = new errore.AsyncDisposableStack()
|
|
437
|
+
cleanup.use(dbConnection) // calls dbConnection[Symbol.dispose]() on exit
|
|
438
|
+
cleanup.adopt(handle, (h) => h.close()) // custom cleanup for non-disposable values
|
|
439
|
+
```
|
|
440
|
+
|
|
388
441
|
### Extraction
|
|
389
442
|
|
|
390
443
|
**Extract values** or throw, **split arrays** by success/error:
|
|
@@ -679,6 +732,8 @@ Effect is powerful if you need its full feature set. But if you just want type-s
|
|
|
679
732
|
| Learning curve | Steep (new paradigm) | Minimal (just `instanceof`) |
|
|
680
733
|
| Codebase impact | Pervasive (everything becomes an Effect) | Surgical (adopt incrementally) |
|
|
681
734
|
| Bundle size | ~50KB+ | **~0 bytes** |
|
|
735
|
+
| Resource cleanup | `Scope` + `addFinalizer` + `acquireRelease` | `using` + `DisposableStack.defer()` |
|
|
736
|
+
| Cancellation | Fiber interruption model | Native `AbortController` |
|
|
682
737
|
| Use case | Full FP framework | Just error handling |
|
|
683
738
|
|
|
684
739
|
**Use Effect** when you want dependency injection, structured concurrency, and the full functional programming experience.
|