Skip to content

Minimal Result/Monad library inspired by Lua pcall, Elixir Result, and Rust Result with lifecycle hooks and zero dependencies

License

Notifications You must be signed in to change notification settings

metaory/pcall.js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
logo-of-pcall

ƀ𝖒𐀠LL.ᴊꜱ

Result/Monad like tuples for JS

unwrap promises safely with minimum footprint

── β•Άβ•΄β•Άβ•΄β•Άβ•΄β•Άβ•΄β•Άβ•΄β•Άβ•΄β•Άβ•΄ ──

πŸ“¦ Extremely Small

🧬 Lifecycle Hooks

🎯 Concise Signature

πŸ’  Group Side Effects

β›” try/catch HELL πŸ‘Ή

🌟 Better Visibility and Control

🌐 Works in ESM & CJS

✱ Minimal Obsessive Disorder



Inspiration

pcall.js is heavily inspired by

πŸ”Ή Lua pcall status, res

πŸ”Ή Elixir/Erlang Result Monad {:ok/:error, reason/value}

πŸ”Ή Rust Result<T, E>

πŸ”Ή Go []error

with superpowers πŸ¦„!


SYNOPSIS

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

[err, res]

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 err object,

Which is null if the call succeeds without errors.

And all results from the call, on second element; [null, {res}]


Usage

# install
npm install pcall.js
// ESM
import Pcall from 'pcall.js'

// CJS
const Pcall = require('pcall.js')
const [err, res] = await Pcall(asyncFn, a, b, c, /* Β·Β·Β· */)
const pcall = new Pcall({
  onSuccess: console.log,
  onFailure: console.error,
  onFinally: console.info,
  timeout: 30_000,
  transformOnSuccess: (res) => res,
  transformOnFailure: (err) => err,
  noTrace: false
})
const [err, res] = await pcall(asyncFn, a, b, c, /* Β·Β·Β· */)
:Fulfill [null, res]
:Reject  [err, null]

Convert

import { readFile } from 'node:fs/promises'

// πŸ”» BEFORE
try {
  const res = await readFile('./package.json', { encoding: 'utf8' })
} catch(error) {
  console.error(error, 'πŸ”₯')
}

// ─────────────────
// πŸ”ΉAFTER
import Pcall from 'pcall.js'
const [err, res] = await Pcall(readFile, './package.json', { encoding: 'utf8' })

// πŸ”ΈTHROW
err && throw new Error("XYZZY", { cause: err });

// ─────────────────
// πŸ”Έ MOCK
// const readJson = new Pcall({
//   fn: readFile,
//   args: [{ encoding: 'utf8' }],
//   transformOnSuccess: (res) => JSON.parse(res),
//   transformOnFailure: (err) => err.message,
// })
// const path = 'test/sample-good.json'
//
// const res = await readJson(path)
// log(res.hogo) // fuga

Options

import { readFile } from 'node:fs/promises'
import Pcall from 'pcall.js'

const pcall = new Pcall({
  onSuccess: console.log,
  onFailure: console.error,
  onFinally: (args, func, span) => { /* πŸ’£ πŸ’£ πŸ’₯ */ },
  transformOnSuccess: (res) => res,
  transformOnFailure: (err) => err,
  timeout: 30_000,
  noTrace: false,
})

const path = './package.json'
const opts = { encoding: 'utf8' }

const [err, res] = await pcall(readFile, path, opts)

πŸ’‘ Check test/ files for more examples


Development

# run test playground in watch mode
npm run dev

# build production
npm run build

# build stub
npm run build:stub

TODO

  • πŸŒ€ Lifecycle Hooks
  • [.] πŸ”Œ Serializer
  • [.] 🧬 Parser
  • [.] πŸ“œ JSDoc
  • [.] πŸ”§ ESLint
  • [o] πŸ“– Docs
  • [o] ⚠️ Tests
  • [o] πŸ’‘ Examples

License

MIT

About

Minimal Result/Monad library inspired by Lua pcall, Elixir Result, and Rust Result with lifecycle hooks and zero dependencies

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Contributors 2

  •  
  •