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

snug

v0.3.0

Published

Make your functions safe.

Downloads

5

Readme

Snug

Build Status

Make your functions safe at run time. Sometimes your may get data from sources during run time (e.g. the web) where you are not able to take advantage of compile-time type checking. This is for handling checks and pattern matching at run time.

Install

npm install snug

Usage

Type Annotations

Make your input and output values snug. The inputs arrays corresponds to the respective input arguments. Functions are expected, so you can add whatever logic you desire for your type. If you do not specify any inputs or outputs, there will be no checks.

var snug = require('snug');

var sum = snug.annotate({
  inputs: [lodash.isNumber, lodash.isNumber],
  outputs: [lodash.isNumber],
  fn: function(a, b) {
    return a + b;
  }
});

sum(3, 4); // Returns 7
sum(3); // TypeError - Not enough arguments
sum(3, 4, 5); // TypeError - Too many arguments
sum('a', 'b'); // TypeError - wrong types

If you would like to define your annotations apart from your functions, simply leave off the fn property. You will then get a function in which you can pass in a function to annotate.

var snug = require('snug');

var sumAnnotation = snug.annotate({
  inputs: [lodash.isNumber, lodash.isNumber],
  outputs: [lodash.isNumber]
});

var sum = sumAnnotation(function(a, b) {
  return a + b;
});

sum(3, '4'); // TypeError

Catching Errors

Sometimes, you want to make a function fail gracefully. You can do this with the catch function.

var snug = require('snug');

var sum = snug.annotate({
  inputs: [lodash.isNumber, lodash.isNumber],
  outputs: [lodash.isNumber],
  fn: function(a, b) {
    return a + b;
  },
  catch: function(error) {
    return 0;
  }
});

sum('a', 'b'); // TypeError is caught, calls catch function, returns 0

Creating Prototype Chains

Sometimes you may want to create prototype chains. The code gets really ugly when doing that and using annotations. Using the create method will let you build a prototype chain that are annotation objects. Note how the fn functions use this.

var MyFunction = snug.create({
  constructor: {
    fn: function(a) {
      this.a = a;
    }
  },

  add: {
    inputs: [lodash.isNumber],
    outputs: [lodash.isNumber],
    fn: function(b) {
      return this.a + b;
    }
  }
});

var myFn = new MyFunction(1);
myFn.add(2); // Returns 3

Pattern Matching

You can take your annotations and call the first matching function using patternMatch.

var fib = snug.annotate({
  inputs: [lodash.isNumber],
  fn: snug.patternMatch([
    {
      inputs: [function(n) { return n === 0 || n === 1; }],
      fn: function() { return 1; }
    },
    {
      inputs: [function(n) { return n > 0; }],
      fn: function(n) { return fib(n - 2) + fib(n - 1); }
    }
  ])
});

fib(10); // 89
fib(-10); // Error: No pattern match found
fib('10'); // TypeError because it requires a number

You may use .extend to add a catch function for the patternMatch function, which returns an annotation.

Structures

You may want to iterate over an object or array to see if every item passes a certain check. There are two functions to help with this.

Typed Array Structure

This ensures that every item in the array passes a single test.

var check = snug.structures.typedArray(lodash.isNumber);
check([1, 2, 3]); // True
check([1, '2', 3]); // False

Compare Array

You can use this function to compare two arrays.

var check = snug.structures.compareArray([
  lodash.isNumber,
  lodash.isString,
  lodash.isNumber
]);

check([1, '2', 3]); // True
check([1, 2, 3]); // False

Object Structure

This looks at every key in an object and checks to see if each passes the check.

var check = snug.structures.object({
  foo: lodash.isNumber,
  bar: lodash.isBoolean
});

check({
  foo: 4,
  bar: true
}); // True

check({
  foo: 4,
  bar: 'true'
}); // False

check({
  foo: 4
}); // False

Logic

Sometimes, you need to get fancy with your annotations.

and

var check = snug.logic.and([
  lodash.isNumber,
  function(value) { return value < 10; }
]);

check(4); // True
check(100); // False

or

var check = snug.logic.or([
  lodash.isNumber,
  function(value) { return value === 'foobar'; }
]);

check(4); // True
check('foobar'); // True
check('hello world'); // False

nor

var check = snug.logic.nor([
  lodash.isNumber,
  function(value) { return value === 'foobar'; }
]);

check(9); // False
check('foobar'); // False
check('hello world'); // True

not

var check = snug.logic.not(lodash.isArray);

check(9); // True
check([1, 2, 3]); // False

wildcard

Maybe you don't care about the type of a given value. If so, you can use wildcard to say any type is fine.

var check = snug.logic.wildcard();

// No matter what value is given, it will be true
check('anything'); // True

optional

You may have figured out to use the or function with an isUndefined check as the first item to make checks options, but that gets kind of verbose after a while. You can use optional to do a check or pass if the value is undefined.

var check = snug.logic.optional(lodash.isNumber);

check(4); // True
check('4'); // False
check(); // True

equalLengthWith

One test is to ensure two arrays are of equal length.

var check = snug.logic.equalLengthWith([1, 2, 3]);

check([1, 2, 3]); // True
check([1, 2]); // False

equals

Allows for deep testing equality.

var check = snug.logic.equals([1, 2, 3]);

check([1, 2, 3]); // True
check([1, 2]); // False

Access to Config

Sometimes, when you create an annotation, you may want to access the configuration you passed to it. Each function exposes this through a $config property.

This is useful for testing annotations.

var sumAnnotation = snug.annotate({
  inputs: [lodash.isNumber, lodash.isNumber],
  outputs: [lodash.isNumber]
});

sumAnnotation.$config; // This is the object with inputs and outputs provided above

Extending Existing Annotations

If you want an annotation based on an existing annotation, you can use extend.

// This function does not have a catch function
var sum = snug.annotate({
  inputs: [lodash.isNumber, lodash.isNumber],
  outputs: [lodash.isNumber],
  fn: function(a, b) {
    return a + b
  }
});

// This one does, and is a new function
var sumWithCatch = sum.extend({
  catch: function(error) {}
});

sum('a'); // Error is not caught
sumWithCatch('a'); // Error is caught