JSPM

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

✱ Minimal Result/Monad like tuples for JS ── zero-dependency ␥

Package Exports

  • pcall.js

Readme

logo-of-pcall

Ƥ𝖢𐤠LL.ᴊꜱ

Result/Monad like tuples for JS

unwrap promises safely with minimum footprint

── ╶╴╶╴╶╴╶╴╶╴╶╴╶╴ ──
pcall_basic

🧬 Lifecycle Hooks

📦 Zero Dependency

🎯 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 🦄!

In Lua Errors are detected and explained in terms of Lua. ^Lua:5.4 ^Lua:8.4, ^Lua:8.5

You can contrast that with C, where the behavior of many wrong programs can only be explained in terms of the underling hardware and error positions are given as a program counter

Activities start from a call by the application, usually asking to run a chunk.

If there is any error, this call returns an error code and the application can take appropriate actions


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 error code status code (a boolean),

Which is false if the call succeeds without errors.

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

In case of any error,

Pcall returns true plus the error message; [true, {err}]


Usage

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

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

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 });

// ─────────────────
// 🔸 NO @ITERATOR
import Pcall from 'pcall.js'
const pcall = new Pcall({ noError: true })
const res = await pcall(readFile, './package.json', { encoding: 'utf8' })

// ─────────────────
// 🔸 MOCK
const readJson = new Pcall({
  fn: readFile,
  noError: true,
  args: [{ encoding: 'utf8' }],
  transformOnSuccess: (args, res) => JSON.parse(res),
  transformOnFailure: (args, { name, message }) => ({ name, 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: (args, res) => res,
  transformOnFailure: (args, err) => err,
  timeout: 60_000,
  noError: false,
  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
  • [.] 💡 Examples

License

MIT