MCPcopy Index your code
hub / github.com/calvintwr/not

github.com/calvintwr/not @v5.0.1

Chat with this repo
repository ↗ · DeepWiki ↗ · release v5.0.1 ↗ · + Follow
3 symbols 3 edges 3 files 0 documented · 0% 1 cross-repo links updated 3y agov1.0.5 · 2021-10-20★ 74
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

You Are Not

npm version Build Status Coverage Status license install size

Not is a minimal, blazing fast, intuitive, and customisable type-checking helper. Meet project deadlines. Code with accuracy. No compiling required. Not checks at runtime, useful to complement Typescript.

This module has no dependencies.

Simple Usage

Double Negative Mechanism #not

Not uses a double negative mechanism (it is more powerful and will be explain further below). Simplest usage looks like this:

const Not = require('you-are-not')
let not   = Not.create()
let str   = 'string'
not('number', str) // throws error "Wrong Type: Expecting `number` but got `string`."

//or check objects
let anotherNot = Object.create(Not)
let schema = {
    { string: 'string', number: 'number' } // a schema that replicates intuitively your object structure
}
let candidateToCheck = { string: 123, number: '123' } // wrong typing.
let errors = anotherNot.checkObject(
    'objectName',
    schema,
    candidateToCheck
)
// throws error, errors are organised neatly into an array.

Why Not?

Let's face it, we seldom type-check, because we're missing something.

Not is that small and convenient type-checking validation library you have been missing to do just that. It also overcomes JS quirks that gets in the way, like: typeof null // 'object'.

If you use Typescript, it is not the full solution. Not fills in the gap.

Typescript doesn't check at runtime, you need to complete it with Not. Written in full JS and assailed with tests, it doesn't add to your compilation time.

Restore Javascript Flexibility, Solidify Your Client-Facing APIs.

Unlock flexibility of Javascript, where typing need not be strict, and functions/APIs (especially client-facing ones) are made powerful by being able to accept different argument types, or error gracefully.

Meet Deadlines With Accurate Code

Write good code quickly; find the balance in code accuracy and writing speed. Leverage flexibility that Javascript has intended for.

Installation

npm i --save you-are-not

Double Negative Mechanism Explained

Not prefers a more powerful "double negative" mechanism, to definitively return false when the check passes. It follows the sensible human logic -- "Let's check if something is wrong (not what I want), so that I will do something. Nope, lets move on":

if (not('string', 'i am string')) // do something
// Nope, let's move on.

When Not fails, it throws an error by default. Or, you can cleverly return a string which can be used to evaluate to true to perform some operations!

const not = Not.create({ willThrowError: false })
// instead of throwing, `not` will return string

let input  = ['a', 'sentence']
let result = not('string', input) // returns a string, which can evaluate `true`

if (result) input = input.join(' ')
// so you can do your own error handling, or transformation

// code below can safely use `input` as string :)
input.toLowerCase()

Full Usage

Standard Example

const Not = require('you-are-not')

function test(foo, bar) {
    let not = Not.create()

    // usage (accepts 4 arguments):
    not(

        'string',
        // type to expect
        //can be STRING or an ARRAY OF STRINGS

        foo,
        // the candidate being checked,

        'FOO',
        // (optional) name of the candidate
        // to prepare error message

        '[MESSAGE or TIMESTAMP]'
        // (optional) any additional notes
        // will be added to the message.
    )

    not(['undefined', 'number'], bar, 'bar')
    // this means `bar` can optional,
    // if not must be a number.
}

let fooNotString = ['foo']
test(fooNotString)
// will throw: ! Wrong Type (FOO): Expect type `string` but got `array`. [MESSAGE or TIMESTAMP].

Need Heavy Lifting? Bulk Check Objects

Using #checkObject

In the real world, the our API params checking is a ~~leaning~~ tower of code. Not makes it neat and produces super user-friendly error messages. No one loses hair:

const Not = require('you-are-not')
someAPIEndPoint((request, response) => {

    /* checking starts */
    let apiNot = Object.create(Not) // use the full object, don't call #create.
    apiNot.willThrowError = false

    /* Usage
    #checkObject(
        name of object,
        expectations <object>,
        what you got <object>,
        callback <function> [optional]
    )

    or

    #checkObject(
        name of object,
        expectations <object>,
        what you got <object>,
        {
            callback <function> [optional],
            returnPayload <boolean> [optional]
        }
    )
    */

    let errors = apiNot.checkObject('request', {
        name: 'string',
        subscribe: 'boolean',
        "info?": { // not that for objects that are optional, use "__optional" or suffix "?".
            gender: 'string',
            age: ['string', 'optional'] // it can be optional, or if present, it must be string.
        }
    }, request.body, callback)
    // provide `callback` if you wish to handle the error yourself.

    if (errors) return response.status(500).send({ error })
    response.status(200).send('Success!')

})

Not can sanitise your payload:

let schema = {
    valid: 'string',
    toSanitise: {
        keepThis: 'array'
    }
}
let payload = {
    valid: 'abc',
    toSanitise: {
        keepThis: [],
        omitThis: 123
    }
}
let sanitised = apiNot.checkObject(
    'request',
    schema,
    payload, {
        callback: function(errors, payload) { ... },
        returnPayload: true
    }
})

// if is array, means something failed.
if(Array.isArray(sanitised)) throw sanitised

doSomethingWithYourPayload(sanitised)

You can also use #lodge And #resolve to bulk checking with more control:


apiNot.lodge('string', request.name, 'name')
apiNot.lodge('boolean', request.subscribe, 'subscribe')
apiNot.lodge(['string', 'array'], request.friends, 'friends')
apiNot.lodge(['number', 'string'], request.age, 'age')
// and many more lines

apiNot.resolve()
/* OR */
apiNot.resolve(errors => {
    // optional callback, custom handling
    throw errors
})

The valid types you can check for are:

Primitives:
'string'
'number'
'nan' // this is an opinion. NaN should not be of type number in the literal sense.
'array'
'object'
'function'
'boolean'
'null'
'undefined'

Aggregated:
'optional' // which means 'null' and 'undefined'

Not Also Has #is

let is = Not.createIs()
is('array', []) // returns true
is('number', NaN) // returns false

Because #is needs to return true when the check passes, it is not as powerful as #not.

Example - Checking Multiple Types

Instead of the horrible:

if (
    typeof foo !== 'string'
    || (typeof foo !== 'number'
    || (typeof foo === 'number' && !isNaN(chk)))
    || !Array.isArray(chk)
) {

    throw Error("Not valid, but I don't know why.")
}

You write:

not(['string', 'number', 'array'], foo)
// or
is(['string', 'number', 'array'], foo)

Define your own checks

let not = Object.create(Not)

not.defineType({
    primitive: 'number', // you must define your primitives
    type: 'integer', // name your test
    pass: function(candidate) {
        return candidate.toFixed(0) === candidate.toString()
    }
})
not.not('integer', 4.4) // gives error message
not.is('integer', 4.4) // returns false

not.defineType({
    primitive: ['null', 'undefined', 'boolean', 'object', 'nan', 'array' ],
    type: 'falsey',
    pass: function(candidate) {
        if (not.is('object', candidate)) return Object.keys(candidate).length === 0
        if (not.is('array', candidate)) return candidate.length === 0
        if (not.is('boolean', candidate)) return candidate === false
        // its the other primitives null, undefined and nan
        // which is to be passed as falsey straight away without checking
        return true
    }
})

not.not('falsey', {}) // returns false
not.not('falsey', [null]) // returns error message
not.is('falsey', []) // returns true
not.is('falsey', undefined) // returns true
not.is(['falsey', 'function'], function() {}) // returns true

Options - Not's Type-Checking Logic ("Opinions")

Native Javscript typing has a few quirks:

typeof [] // object
typeof null // object
typeof NaN // number

Those are technically not wrong (or debatable), but often gets in the way.

By default, Not will apply the following treatment:

  1. NaN is not a 'number', and will be 'nan'.
  2. Array and [] are of 'array' type, and not 'object'.
  3. null is 'null' and not an 'object'.
  4. Instance of #String is 'string' and not an 'object'.

Switch Off Not's Opinions

You can switch off opinionated type-checking:

let not = Not.create({ isOpinionated: false })

When false, all Javascript the quirks will be restored, on top of Not's opinions: An Array will both be an 'array' as well as 'object', and null will both be 'null' and 'object':

not('object', []) // returns false -- `[]` is an object
not('array', []) // returns false -- `[]` is an array
not('object', null) // returns false -- `null` is an object

Switch Off Opinions Partially

// both #createIs and #create can take in the same options
let NotWithPartialOpinions = Not.createIs({
    opinionatedOnNaN:    false
    opinionatedOnArray:  false
    opinionatedOnNull:   false
    opinionatedOnString: false
})

// or mutate the object before instantiating.
let NotWithPartialOpinions = Object.create(Not)
Object.assign(NotWithPartialOptions, {
    opinionatedOnNaN:    false
    opinionatedOnArray:  false
    opinionatedOnNull:   false
    opinionatedOnString: false
})
let not = NotWithPartialOpinions.create()
let is  = NotWithPartialOpinions.createIs()

More Advanced Usage

Customise your message, by replacing the #msg method

You have to mutate the prototype:

const CustomNot = require('you-are-not')

//overwrite the msg function with your own
CustomNot.msg = function(expect, got, name, note) {
    let msg = 'Hey there! We are sorry that something broke, please try again!'
    let hint = ` [Hint: (${name}) expect ${expect} got ${got} at ${note}.]`
    return global.isDeveloperMode ? msg += hint : msg
}
let customNot = CustomNot.create()
global.isDeveloperMode = true
customNot('string', [], 'someWrongInput', 'file.js - xxx function')

Will throw:

! Error: Hey there! We are sorry that something broke, please try again! [Hint: (someWrongInput) expect string got array at file.js - xx function. ]

License

Not is MIT licensed.

Core symbols most depended-on inside this repo

get
called by 0
src/index.js
set
called by 0
src/index.js

Shape

Function 3

Languages

TypeScript100%

Modules by API surface

src/index.js2 symbols
test/index.test.js1 symbols

Used by 1 indexed graphs manifest dependencies, hub-wide

For agents

$ claude mcp add not \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact