JSPM

  • Created
  • Published
  • Downloads 10
  • Score
    100M100P100Q57822F
  • License MIT

🛟 Protected Asynchronous Operations ▎📦 zero-dependency╶╴🚀 zero-configuration╶╴⚙️ extendable

Package Exports

  • pcall.js

Readme

PCALL.js

🛟 Protected Asynchronous Operations


logo-of-pcall

Centralize Error handling, Monitoring, Notification and more

✴️nested try...catch✴️

▁▁▁▁▁▁▁▁

📦 zero-dependency╶╴🚀 zero-configuration╶╴⚙️ extendable


🚧 NOT PRODUCTION READY ☢️

Features

  • 📦 Zero-dependency: Works in Node.js (ESM & CJS) and all modern browsers
  • 🚀 Zero-configuration: Provides opt-in configuration for advance usage
  • ⚙️ Extendable: Lifecycle Hooks, Processors, Serializer, Parser
  • 🛡️ Fault-tolerant: Uniform and deterministic asynchronous operations
  • 👻 Humanized API: Simple to get started with a reasonable API
  • 🌬️ Lightweight: under (2 KB)

Prelude

You might have an entire function wrapped in a try..catch; In which you have to figure out which call throw the error, Lack of control and visibility.

You might wrap each async call in it's own try...catch; Which is ugly and too verbose.

You might write a utility to wrap an capture each call.

It's fragmented, hacky and not consistent.


Inspiration

Lua approach to error handling is simple yet powerful. ^Lua:5.4 ^Lua:8.4, ^Lua:8.5

🔹 pcall.js is heavily inspired by Lua pcall with superpowers🦄!


SYNOPSIS

pcall({f}, {arg1}, {...})

pcall() Calls function {f} with the given arguments in protected mode. This means that any error inside {f} is not propagated;

Instead, pcall catches the error and returns a tuple.

Its first element is the status code (a boolean), which is true if the call succeeds without errors. And all results from the call, on second element; [true, {res}]

In case of any error, pcall returns false plus the error message; [false, {err}]


Installation

# install
npm install pcall.js

Usage

// ESM
import Pcall from 'pcall.js'

// CJS
const Pcall = require('pcall.js')

Basic Usage

// some promise
const prom = (...x) =>
  new Promise((resolve, reject) =>
    Math.random() > 0.5 ? resolve(x) : reject(x),
  );
import Pcall from 'pcall.js'

const [ok, res] = await Pcall(prom, 'hoge', [99, 7], { xorg: 'X11' });

console.log(ok, res)
// <true|false>,  <...>

Advance Usage*

import Pcall from 'pcall.js'

// Create a custom pcall instance for advance usage
const pcall = new Pcall({
  // 🚧 runs on success, passing context and result
  onSuccess: (args, res) => { /* do stuff */ },

  // 🚧 runs on failure, passing context and error
  onFailure: (args, err) => { /* do stuff */ },

  // 🚧 runs before success hook, transform the success result
  successSerializer: (res) => ({ hoge: 'fuga', ...res }),

  // 🚧 runs before failure hook, transform the failure error
  failureSerializer: (err) => ({ frob: 'xyzzy', err.message })

  // NOTE: the transformers only modify the success/failure message
  // NOT the structure
})

const [ok, res] = await pcall(prom, 'hoge', ['fuga', 'nyoro'], { xorg: 'X11' });

console.log(ok, res)
// <true|false>,  <...>

Development

# run test playground in watch mode
npm run dev

# build production
npm run build

# build stub
npm run build:stub

TODO

  • [.] 🌀 Lifecycle Hooks
  • [.] 📦 Transformers for Success/Failure
  • [.] 🔌 Serializer
  • [.] 🧬 Parser
  • [.] 📜 JSDoc
  • [.] 🔧 ESLint
  • [.] 📖 Docs
  • [.] ⚠️ Tests
  • [.] 💡 Examples

License

MIT