npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

painless-error

v0.2.0

Published

a Painless error library, naming error and matching them easily

Downloads

10

Readme

Painless Error

Easily create multiple types of Error and match them. You can create error in different type in a simple function call dynamically without defining a new class.

import {PainlessError} from './index.js'
const Perr = PainlessError

let n = Math.random()
try {
  if (n < 0.5) throw new Perr(`too-small: n ${n} too small`)
  else throw new Perr(`too-big: n ${n} too big`)
}
catch (err) {
  if (err.is('too-small')) n *= 2
  else if (err.is('too-big')) n /= 2
  else throw err
}

api

new

new PainlessError(name, [message, [cause]])
new PainlessError(`${name}: ${message}`, [cause])

name should be invariant. message is for human reading. cause can be any js value.

is (match)

test if an error match a name.

const err = new PainlessError('test-error/test-match: a error to test match')

err.is('test-error') == true
err.is('test-error/test-match') == true
err.is('test-match') == false
err.is('a error to test match') == false

it would be similar to the inherit error pattern, though it use the is method.

class TestError extends Error {}
class TestMatchError extends TestError {}
let tmerr = new TestMatchError()
(tmerr instanceof TestError) == true
(tmerr instanceof TestMatchError) == true

match with callback

match will execute the function whose name match the err. if nothing match and default is defined, it is executed. the longest name is matched first, and the tag is match in order.

const ctx = err.match({
  'test-error/test-match'(ctx) {
    ctx.error == err
    ctx.tag == 'test-other'
    ctx.goReturn = true
    return 'ret'
  },
  'test-other'(ctx) {
    ctx.tag == 'test-other'
    ctx.goReturn = true
  },
  default(ctx) {
    ctx.tag == 'default'
  }
})

match return a context object, which is pass to the executed callback too. you can pass state to outside by setting its properties. the matched callback's return value is stored in the ctx.result after the match return.

context would be useful if you want to return the outer function in some callback.

ctx.result == 'ret'
if (ctx.goReturn) return ctx.result

you can throw inside the callback too, thought it will introduce some more call stack.

since if ... else if ... is verbose, i write this method.

tag

you can tag a name with another name, and the error with this name will match the tag.

Perr.tagName(`${name}: ${tag1} ${tag2}`)
err = new Perr(`${name}: some message`)
err.is(tag1) == true
err.is(tag2) == true

it should be useful if you want some errors in different names could be catch with a single term.

Perr.tagName('file-miss: file-picker')
Perr.tagName('file-null: file-picker')
new Perr('file-miss').is('file-picker') == true
new Perr('file-null').is('file-picker') == true

wrap

wrap a object to a PainlessError, copy its {name, message}, and the object is store in the cause porperty.

let erro = new Error('some message')
err = Perr.wrap(erro)

err.match({
  Error() {
    console.log(`this will match since ${erro.name == 'Error'}`)
    err.name == erro.name
    err.message == erro.message
    err.cause == erro
  }
})

return the original object if the object is already a instance of PainlessError, except the second argument is true.

Perr.wrap(err) == err
Perr.wrap(err, true) != err

unwrap

return the original error if err.cause is a error, or return null.

erro = err.unwrap()
erro == err.cause

install

install from tarball, npm, or just import the index.js.

naming convension

a name should be non-space characters. i like kebab case so i use it. you can use camel case anyway, but the name always match the whole string or at the slash separator.

todo

  • wrap change the call stack
  • allow no readme msg
  • tag syntax test-error/example-error|tag1|tag2: a test error with tag