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

trent

v0.0.2

Published

Type specifications

Downloads

5

Readme

Trent

Type specifications

npm install trent

npm Build Status Greenkeeper badge

This library provides runtime type specifications with a focus on:

  • A small, native-feeling syntax for defining specifications
  • Good error messages

Usage

import {createSpec} from 'trent'

const Matrix = createSpec(() => [[Number]])

const errors = Matrix.getErrors([
  [1, 2, 3],
  [4, 5, 'wrong']
])

console.log(errors)
/* => [ Error('Value[1][2] must be of type "number"') ] */

Documentation

createSpec(builder: builtInChecks -> Check): Spec

Create a Spec using the builder function which receives the built-in checks described below. The builder must return a valid check or an error throws. The Spec object returned has a method getErrors(value) which returns an array of type errors for value.

Checks


Spec

Check that a provided value matches the Spec.

import {createSpec} from 'trent'
import assert from 'assert'

const Num = createSpec(() => Number)
const Matrix = createSpec(() => [[Num]])

const errors = Matrix.getErrors([[1, 2, 3], [4, 5, 6]])
assert(errors.length === 0)

Constructor

Check that a provided value is an instanceof Constructor, or typeof if the constructor is for a primitive such as Number or String.

import {createSpec} from 'trent'
import assert from 'assert'

const Num = createSpec(() => Number)
const errors = Num.getErrors(8)
assert(errors.length === 0)

Note: Any Constructor will work if root[Constructor.name] === Constructor where root is the window in browsers and global in Node.


Array [check]

Check that a provided value is an array where every element passes the check.

import {createSpec} from 'trent'
import assert from 'assert'

const Numbers = createSpec(() => [Number])
const errors = Numbers.getErrors([8])
assert(errors.length === 0)

Object {key: check, ..., keyN: checkN}

Check that a provided value is an object where every key value passes its check.

import {createSpec} from 'trent'
import assert from 'assert'

const Point = createSpec(() => ({x: Number, y: Number}))
const errors = Point.getErrors({x: 8, y: 8})
assert(errors.length === 0)

is(value : any)

Check that a provided value must strictly equal (===) the value.

import {createSpec} from 'trent'
import assert from 'assert'

const Eight = createSpec(({is}) => is(8))
const errors = Eight.getErrors(8)
assert(errors.length === 0)

or(checks : [Check])

Check that a provided value matches at least one of the checks.

import {createSpec} from 'trent'
import assert from 'assert'

const NumberOrString = createSpec(({or}) => or([Number, String]))
const errors = NumberOrString.getErrors(8)
assert(errors.length === 0)

and(checks : [Check])

Check that a provided value matches at every one of the checks.

import {createSpec} from 'trent'
import assert from 'assert'

const Eight = createSpec(({and, is}) => and([Number, is(8)]))
const errors = Eight.getErrors(8)
assert(errors.length === 0)

not(check : Check)

Check that a provided value does not pass the check.

import {createSpec} from 'trent'
import assert from 'assert'

const Eight = createSpec(({not, is}) => not(is(9)))
const errors = Eight.getErrors(8)
assert(errors.length === 0)

maybe(check : Check)

Check that a provided value matches check or is null or undefined.

import {createSpec} from 'trent'
import assert from 'assert'

const Eight = createSpec(({maybe, is}) => maybe(is(8)))
assert(Eight.getErrors(8).length === 0)
assert(Eight.getErrors(null).length === 0)
assert(Eight.getErrors(undefined).length === 0)

tuple(checks : [Check])

Check that a provided value is an array with length equal to checks.length and the first element passes the first check and so on.

import {createSpec} from 'trent'
import assert from 'assert'

const Eight = createSpec(({tuple, is}) => tuple([is(8), is(8)]))
assert(Eight.getErrors([8, 8]).length === 0)

nullable(check : Check)

Check that a provided value matches check or is null.

import {createSpec} from 'trent'
import assert from 'assert'

const Eight = createSpec(({nullable, is}) => nullable(is(8)))
assert(Eight.getErrors(8).length === 0)
assert(Eight.getErrors(null).length === 0)

voidable(check : Check)

Check that a provided value matches check or is undefined.

import {createSpec} from 'trent'
import assert from 'assert'

const Eight = createSpec(({voidable, is}) => voidable(is(8)))
assert(Eight.getErrors(8).length === 0)
assert(Eight.getErrors(undefined).length === 0)

Using checkCustomCheck({descriptor: String, isValid: Function})

Create a check where descriptor fits the sentence {subject} must be {descriptor} for error messages and isValid(value: any) returns whether the value passes the check.

import {createSpec, createCustomCheck} from 'trent'
import assert from 'assert'

const lowercase = createCustomCheck({
  descriptor: 'lowercase',
  isValid (x) {
    return typeof x === 'string' && x.toLowerCase() === x
  }
})

const Code = createSpec(() => lowercase)
assert(Code.getErrors('8').length === 0)

Note: Custom checks cannot nest checks within them. In a tree structure analogy, custom checks must be leaves. The reason for this limitation is the complexity of creating good error messages.

createDependentSpecs(builder : builtInChecks -> {Check}) {Spec}

Create a collection of Specs which are dependent and/or recursive.

For example, we have two types Foo and Bar which both can contain each other. We can try to write this system with createSpec:

import {createSpec} from 'trent'
var Foo = createSpec(() => ({barList: [Bar]}))
var Bar = createSpec(() => ({fooList: [Foo]}))

Creating Foo with undefined Bar will not work. We need createDependentSpecs to enable a "late-binding" where order does not matter. We use the ref built-in check available to createDependentSpecs to reference Specs.

import {createDependentSpecs} from 'trent'
import assert from 'assert'
const {Foo} = createDependentSpecs(({ref}) => ({
  Foo: {barList: [ref('Bar')]},
  Bar: {fooList: [ref('Foo')]}
}))

assert(Foo.getErrors({
  barList: [{
    fooList: [{
      barList: [{
        fooList: []
      }]
    }]
  }]
}).length === 0)

Real-life example

I maintain the HTML parser Himalaya which follows a strict specification for its output. The output contains Nodes which can have children Nodes, so we need a recursive type.

import {
  createSpec,
  createDependentSpecs
} from 'trent'

// I pull this out to show that you can
const Text = createSpec(({is}) => ({
  type: is('text'),
  content: String
}))

export const {Node} = createDependentSpecs(({is, or, ref, nullable}) => ({
  Node: or([
    ref('Element'),
    ref('Comment'),
    Text
  ]),
  Element: {
    type: is('element'),
    tagName: String,
    children: [ref('Node')],
    attributes: [{
      key: String,
      value: nullable(String)
    }]
  },
  Comment: {
    type: is('comment'),
    content: String
  }
}))