Skip to content

ivangabriele/rorre

Repository files navigation

Rorre

License NPM Version Build Status Code Coverage

Enumified, dictionary-based and dependenciless error library.

TOC

  1. Behaviors
  2. Getting Started
  3. Usage
  4. Localization
  5. Compatibility
  6. Best Practices
  7. API
  8. Contribute

Behaviors

  • As a developer:
    • I want the error library to be frozen.
    • I want an error dictionary.
    • I want the error dictionary to be declared only once.
    • I want the error dictionary to be frozen.
    • I want my errors to have a unique name.
    • I want my errors to have a mandatory message.
    • I want the error names to be enumable.
    • I want to get trackable error codes (= name) from my end-users.

Getting Started

npm i rorre

Typescript & Flow

The Typescript and Flow definitions are included in this library.

Usage

Declare your errors in a single file (called errors.js here):

const rorre = require("rorre");

module.exports = rorre.declare({
  ERR_ONE: `First error message.`,
  ERR_TWO: `Second error message.`
});

Throw them via their name:

const errors = require("./errors");

if (somethingWentWrong()) throw errors.error.ERR_ONE;

And that's all !

This will return an instance of RorreError, itself inherited from Error. Each error will get a name and a message matching the ones in the dictionary. In the case above, a throw errors.error.ERR_ONE would output:

ERR_ONE: First error message.
    at Object._ERROR.(anonymous function) [as ERR_ONE] .../node_modules/rorre/rorre.js:105:28)
    at Object.<anonymous> (.../index.js:3:20)
    at Module._compile (internal/modules/cjs/loader.js:688:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:699:10)
    at Module.load (internal/modules/cjs/loader.js:598:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:537:12)
    at Function.Module._load (internal/modules/cjs/loader.js:529:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:741:12)
    at startup (internal/bootstrap/node.js:285:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:739:3)

You obviously need to ignore the first Error Stack line since new RorreError() is called within Rorre library.

Typescript & Flow

In Typescript and Flow, you will benefit from the autocompletion thanks to the types inference patterns included in the typings declaration. It's advisable not to try custom-typing your Error Dictionary to avoid interfering with the inference process.

Localization

If you wish to use this library to also handle end-users errors and integrate your translations in the process, you can take advantage of the rorre.name enum. Your code could look like this:

const errors = require("./errors");
const locales = requires("../i18n/en.json");

if (somethingWentWrong()) showErrorWithMessage(locales[errors.name.ERR_ONE]);

Since there are many existing formats and conventions to handle localization, rorre does not implement anything specific regarding that. It's up to you to re-declare your error dictionary names within your localization files.

Compatibility

This CommonJS library is written and distributed in ES6. You may use a transpiler (i.e.: Babel) in order to make it ES5-compatible.

Node

Version Raw Transpiled
11
10
8
6
4
0.12
0.10

Browser

In progress...

Best Practices

  • Error names SHOULD be in SCREAMING_SNAKE_CASE.
    Why ? Because an error name is supposed to be easy to find, irrespective of the size of the codebase. In Javascript, most variable names are in camel-case. Therefore it's easier to run a case-sensitive search to look for the error name. Moreover it also catches the eye when lost in the middle of a log history.
  • Error messages SHOULD start with an Uppercase letter AND SHOULD end with a dot.
    Why ? Because an error message is supposed to be a humanely understandable message. We are used to read sentences starting with an uppercase letter and ending with a punctuation mark. Therefore it improves the readability.

API

Rorre Class

Rorre#declare(dictionary: Dictionary): Rorre

Return an frozen instance of Rorre.

The <dictionary> parameter must be a pure object made of Error names as its properties, and matching Error messages as its values. Both its properties and values are expected to be a string.

Rorre#dictionary: Dictionary

Getter for the Error Dictionary your declared with Rorre#declare(). All of its properties are read-only.

Rorre#error: { [keyof Dictionary]: () => RorreError }

Getter for the Error Dictionary your declared with Rorre#declare() returning .

Rorre#name: { [keyof Dictionary]: keyof Dictionary }

Getter for the Error Dictionary names (= its property names) in a simple enum form. It allows you to check the errors by their name in case you wish to compare them. All of its properties are read-only. This can be useful for testing purposes.

Example:

const rorre = require('rorre')

const errors = rorre.declare({
  ERR_FOO_VALIDATION_ASTRING_TYPE: `The <aString> param in foo() must be a string.`,
})

foo(aString) {
  if (typeof aString !== 'string') {
    throw errors.error.ERR_FOO_VALIDATION_ASTRING_TYPE
  }
}

describe('foo()', () => {
  it('should throw the expected error when <aString> is not a string', () => {
    let testErr
    try { foo(123) }
    catch(err) { testErr = err }
    assert.strictEqual(err.name, errors.name.ERR_FOO_VALIDATION_ASTRING_TYPE))
  })
})

RorreError Class

Note: The RorreError class is not exported and only described here for documentation sake.

This class is an extension of Error with a mandatory name property. Both its message and name properties are expected to be a string.

Contribute

git clone https://github.com/ivangabriele/rorre.git
cd rorre
npm install

Test

  • All Tests: npm test
  • Lint Tests: npm run test:lint
  • Unit Tests: npm run test:unit
  • Unit Tests (watch): npm run test:watch