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

xcson

v2.2.2

Published

Extensible CSON - build cson/json dynamically with mixins/plugins

Downloads

52

Readme

What is "xcson"?

xcson is eXtensible CSON, a node module that extends the CSON data format to include mixins and plugins.

You write in an extensible CSON format, you get JSON back. It's the DRYest way to build large JSON datasets with lots of repeating content.

Example

Let's say you need to create a huge, ugly JSON schema:

schema.json

{
    "title": "Example Schema",
    "type": "object",
    "properties": {
        "firstName": {
            "type": "string"
        },
        "lastName": {
            "type": "string"
        },
        "middleName": {
            "type": "string"
        }
}

In the xcson world, you would create a mixin file:

type/string.cson

{
    type: "string"
}

And rewrite the previous as follows:

schema.cson

{
    title: "Example Schema"
    type: "object"
    properties:
        "firstName, lastName, middleName": inherits "type/string"
}

Now we build everything:

var xcson = require('xcson');
output = new xcson('schema.cson');
console.log(output.toString());

Output will be equivalent to the first example.

Available plugins

These are the available plugins out of the box:

inherits

Merges the contents of each mixin specified, and can have a custom object as the last parameter:

key: inherits "foo", "bar", { object }

enumerate

Creates an array from a glob or list of mixins.

key: enumerate "files/*", "anotherfile"

repeat

Creates an array of content repeated n times.

key: repeat 4, { object }

multikey

Finds all comma delimited key names and expands them.

"foo, bar, baz": { object }

becomes:

foo: { object }
bar: { object }
baz: { object }

Make sure to enclose in quotes.

Creating plugins

There are two types of plugins: walkers and scope.

Both are registered in a similar manner:

var xcson = require('xcson');
xcson.walker('Name of your plugin', function);
xcson.scope('Name of your plugin', function);

Walkers

Walkers run once on every node as xcson traverses object trees. They receive the current node as an argument, and need to return the node when completed:

xcson.walker('MyWalkerPlugin', function(node){
  node.foo = "bar";
  return node;
});

Return values can also be Promises.

 xcson.walker('MyWalkerPlugin', function(node){
  new Promise(function(resolve, reject) {
     somethingAsync(){
        node.foo = "bar";
        resolve(node);
     }
  });
 });

Walker functions are also bound with a context object that contains some handy properties:

xcson.walker('MyWalkerPlugin', function(node){
  console.log(this);
  // this.parentNode = Parent node
  // this.key = Current key name
  // this.path = Array of path keys to current location inside object.
  // this.originalNode = The node as it began before being altered by any other walkers
  // this.file = The current file being walked, if any
});    

Walkers are run in a series, with each walker receiving the results of the previous. The final result will replace the node content.

See the multikey source for an example.

Scope

Scope plugins provide functions that are made available to each xcson file. These are like mixins.

xcson.scope('MyScopePlugin', function(text) { return text + " there" });

Now in your xcson file, you can reference your plugin:

foo: MyScopePlugin "hello"

With the final JSON output being:

{ foo: "hello there" }

See the source of inherits, repeat and enumerate for examples.

Debugging

Resolving huge Promise trees with secondary, inherited files can be messy business. For that reason, there is a console debugger that runs internally and takes wildcards:

$ DEBUG=xcson:* node yourscript.js

$ DEBUG=xcson:*filename.xcson* node yourscript.js

Notes

xcson is valid CSON. CSON is just Coffeescript. xcson files are valid Coffeescript.

output.toString() will, by default, sort all keynames.

You can omit the leading and trailing document brackets for extra cleanliness:

{ # Omit me
    foo:
        bar:
            baz: true
} # Omit me

Infinitely nested plugins/mixins are valid:

baz: "boo, woo": inherits "bar", thing: repeat 2, maybe: true

but will become difficult to read as a side effect of Coffee's expressive nature. To help readability, you should use parentheses, brackets and whitespace:

baz:
    "boo, woo": inherits "bar",
        thing: repeat(2, { maybe: true })

and don't forget to separate repeatable content blocks into mixins.

For reference, the JSON produced from either examples above would look like this:

{
  "baz": {
    "boo": {
      "bar": true,
      "thing": [
        {
          "maybe": true
        },
        {
          "maybe": true
        }
      ]
    },
    "woo": {
      "bar": true,
      "thing": [
        {
          "maybe": true
        },
        {
          "maybe": true
        }
      ]
    }
  }
}

Installation

via npm:

$ npm install xcson

xcson is UNLICENSED.