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

mog

v1.1.3

Published

Modern Object Grammar

Downloads

10

Readme

Mog Logo

MOG: Modern Object Grammar

Mog is a simple DSL for describing and asserting the state of an object.

The story of Mog.

Remember when we all wrote XML? then someone said 'Hey this is verbose and silly, lets come up with something simpler, easier to read and easier to write' and so JSON was invented, and we were all glad.

However we lost something useful: validation. So we wrote a lot of manual type-checking in our APIs, we asserted that values existed and that they were good and wholesome, because we didn't want our servers to explode.

But writing lots of type-checking logic is tiresome, so we invented [schemas for JSON] (http://json-schema.org) to get the job done for us, but just like XML, JSON schemas were verbose and silly. They were also overkill when we just wanted to stop our API servers exploding from some dud input.

And so Mog was invented as a simple way to describe our expectations about some data. It looks a bit like java/js/py/??-Doc format, and that's because schemas should be read like documentation, so we based it on a documentation format we're probably already familiar with :)

So what does a Mog schema look like?

dot.path @validator [optional, enum] {optional : 'arguments'}  -- optional comments!
  • The dot path locates the element we're looking to validate.
  • the @validator selects a validator to use (we can add our own custom ones pretty easily!)
  • Optionally we can provide an enum of allowed values.
  • Some validators take arguments that alter how validation works.
  • Comments are a great way of telling other devs your intentions :)

Lets see how it works with some real world examples:

how?

basics

import mog from 'mog'

const m = mog()

let cat = m` 
   cat          @Object                                
   cat.fur      @String [black, white, orange, brown]  -- Cats have fur colour!
   cat.lives    @Number { min : 1, max : 9 }           -- Lives remaining` 

let validCat = cat( { fur : 'black', lives : 3 })

errors

Mog will attempt to fix input if possible, for instance a @Number will accept a string containing a number, ie: '1.2' vs 1.2. Mog follows the mandate: Be liberal in what you accept, and strict in what you hand out.

If however the object fails to validate against the Mog schema, an error will be thrown.

let validCat = cat( { fur : 'black', lives : 30 })
/Users/pomke/code/mog/mog.js:37
          throw err;
          ^
Number must be less than 9, got 30

1.        cat          @Object
2.        cat.fur      @String [black, white, orange, brown]  -- Cats have fur colour!
3. >>>    cat.lives    @Number { min : 1, max : 9 }           -- Lives remaining

middleware

Mog returns a validator function which also operates as a middleware for connect / express apps:


app.put('/cat/:id', m`
  req.params.id     @Number                                -- Cat's ID
  req.body          @Object                                -- Cat is an object
  req.body.fur      @String [black, white, orange, brown]  -- Cats have fur colour!
  req.body.lives    @Number { min : 1, max : 9 }           -- Lives remaining`,
  (req, res) => {
    // Access req.body.cat with impunity, knowing that it must be valid  
    console.log(req.body.fur)
  })

Creating your own validators

It's super easy to create your own validators. Your mog instance has an add method that takes a validator name, and a function which takes the object to be validated, params then enums. It should either throw with an error, or return the validated (or coerced) value.

Here's an example validator that only accepts Odd numbers.


m.add('OddNumber', (data, params, enums) => {
  if(params.opt && data == null) return // handle the opt param
  let parsed = parseFloat(data)
  if(parsed % 2) {
    return parsed
  } else {
    throw new Error(`Expected an odd number, got an even one!`)
  }
})

Now you can use this just like any built-in validator with @OddNumber.

You can find the built-in validators here.

Mog Laughing Let's kick this up a notch

BOOM! ok, this is where we let you in on a little secret, a mog schema IS a validator in it's own right. What does that mean? It means that you can pass a mog schema to m.add with a name, then you can use that to validate things in other schemas! Here's an example:

Given a validator that validates a cat:

let cat = m`
    cat          @Object
    cat.name     @String                                -- What is my name? 
    cat.dob      @Date { opt }                          -- Date of birth
    cat.fur      @String [black, white, orange, brown]  -- Cats have fur colour!
    cat.lives    @Number { min : 1, max : 9, opt }      -- Lives remaining` 

We can then register that as a validator called @Cat:

m.add('Cat', cat);

Now let's make a cat carrier that contains a cat:

let catCarrier = m`
  carrier.label     @String         -- Label on the cat carrier
  carrier.contents  @Cat { opt }    -- Carrier contains an optional Cat`

Which works as you'd expect:

let catInCarrier = catCarrier(
  {label : 'Ship to Mexico!',
   contents : { name : 'Neko', fur : 'brown' }})

Mog Love It's cats all the way down!

Imagine you want to model a bubushka doll, you know those little wooden dolls which have a copy of themselves inside? Mog allows you to reference a mog schema validator from within itself:

// register a validator that references it's self. Note that it should 
// be optional, or the final child node will be invalid. 
m.add('Bubushka', m`
      bub.name     @String
      bub.child    @Bubushka {opt}`);
    
// now we can use this as normal
let checkBubas = m`top @Bubushka`;

checkBubas( { name : 'Adel', child : { 
                name : 'Betty', child : { 
                  name : 'Claire', child : { 
                    name : 'Bruce'} } } } );

Sadly, Bruce was unable to continue the Bubushka line.