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

khyron

v0.2.1

Published

Run-time type checking for JavaScript

Downloads

5

Readme

Khyron

Khyron provides run-time type checking for JavaScript. Static type checkers can miss mismatched types because they cannot "see" or analyze all of your program's code. Khyron, on the other hand, waits until your program is executed, and then it only checks the actual data that is passed to a function.

Additionally, Khyron is pure JavaScript. There's no new syntax to learn!

Engineers coming from strongly or statically typed languages such as Java and C# are probably familiar with the idea of a contract between a function and its callers. Khyron brings this idea to JavaScript without undermining its dynamic types and performance.

Khyron was inspired by Chapters 16 and 17 of Reliable JavaScript: How to Code Safely in the World's Most Dangerous Language by Seth Richards and Lawrence Spencer (ISBN 9781119028727).

Getting Started

Install Khyron into your project with

npm install khyron

Suppose you have a simple math library, and you want to integrate Khyron into it. Currently, the math library looks like this:

const simpleMath = {
    add: function( a, b ) {
        return a + b;
    },

    multiply: function( a, b ) {
        return a * b;
    },

    exec: function( a, b, operation ) {
        return operation( a, b );
    }
};

export default simpleMath;

Obviously, we will need to import Khyron. Then we will need to define a pre-condition. The pre-condition specifies the inputs to a given function.

import khyron from 'khyron';

khyron.define( 'two-numbers', {
    type: 'array',
    items: [
        { type: 'number' },
        { type: 'number' }
    ]
} );

const simpleMath = {
    add: function( a, b ) {
        return a + b;
    },

    multiply: function( a, b ) {
        return a * b;
    },

    exec: function( a, b, operation ) {
        return operation( a, b );
    }
};

khyron( simpleMath, 'add' ).precondition( 'two-numbers' );
khyron( simpleMath, 'multiply' ).precondition( 'two-numbers' );

export default simpleMath;

In short, we used the define function to create a condition called "two-numbers." Then we used the precondition function to attach the "two numbers" condition to the add and multiply functions as a precondition.

Best Practices

At this time, a function must be exposed as a property on an object for Khyron to work with it. For example, this works:

const library = {
    coolFunctionBro() { /* Do stuff */ }
}

These will not work:

function notCoolMan() { /* Do stuff */ }

const stillNotCool = function() { /* Do stuff */ }

Inline Definitions

We can take advantage of JavaScript's "variable hoisting" mechanism to make ouse definitions a little more readable. First, define the library object (which will be exported) near the top of the file. Below it, add functions. Finally, place the Khyron definition just before the function. We will use Khyron's "in-line" definition syntax to further improve readability.

We end up with something like this:

// Define and export the library object
const library = {
    notCoolMan
};
export default library;

// Write functions and attach Khyron
khyron( library, 'notCoolMan' ).pre( { type: 'Array',
    items: [
        { type: 'number' },
        { type: 'number' }
    ]
} );
function notCoolMan( a, b ) { /* Do stuff */ }

Types File

If you have object types or "shapes" that are reused throughout your project, it may make sense to store those definitions in a types.js file in the root of your project (i.e., next to package.json). For example, it might look like this:

export const myTypes = {
    Request: {
        type: 'object',
        properties: {
            cookies: { type: 'object' },
            session: { type: 'object' }
        }
    },

    Response: {
        type: 'object',
        properties: {
            clearCookie: { instanceof: 'Function' },
            cookie: { instanceof: 'Function' }
        }
    }
}

Then you can use it like this:

import { myTypes } from './types.js';

// Define and export the library object
const library = {
    middleware
}
export default library;

// Write functions and attach Khyron
khyron( library, 'middleware' ).pre( { type: 'Array',
    items: [
        myTypes.Request,
        myTypes.Response
    ]
} );
function middleware( request, response ) { /* Do middleware stuff */}

API

Khyron is still evolving, so this section is incomplete at the moment. You can look at the tests for usage examples, or just read the source code. It's not terribly complex—less than 200 lines!

Future directions

  1. Reduce boilerplate
  2. Is there a way to wrap a returned function (e.g. such as the one in Glados.Cookies.getMiddlewareFunction)? I could add a post-condition for the "get middleware" function, but that doesn't ensure the middleware is used correctly.
  3. Add ability to attach directly to functions. Is this even possible?

License

The content of this repository is licensed under the BSD 3-Clause license.

Contributing

Tickets are welcome. Pull requests are better!