JSPM

  • Created
  • Published
  • 0
  • Score
    100M100P100Q57706F
  • License MIT

🛟 Protected Asynchronous Operations ┊ 📦 zero-dependency╶╴〽️ minimal╶╴⚙️ 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╶╴〽️ minimal and elegant╶╴⚙️ extendable


Features

  • 〽️ Minimal: Obsessive Minimal Disorder
  • 📦 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

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 = (name, family) => new Promise(resolve => resolve(`Hi ${name} :: ${family} !`))

import Pcall from 'pcall.js'

const [ok, res] = await Pcall(prom, 'zed', 'hoge')

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 when promise is settled
  cleanup: (args) => { /* 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, 'zed', 'hoge')

console.log(ok, res)
// <true|false>,  Hi zed :: hoge

Development

# run test playground in watch mode
npm run dev

# build production
npm run build

# build stub
npm run build:stub

# publish
npm run publish

TODO

  • 🌀 Lifecycle Hooks
  • [.] 🔌 Serializer
  • [.] 🧬 Parser
  • [.] 📜 JSDoc
  • [.] 🔧 ESLint
  • [o] 📖 Docs
  • [o] ⚠️ Tests
  • [.] 💡 Examples

License

MIT