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 🙏

© 2025 – Pkg Stats / Ryan Hefner

cobalt-base

v1.0.9

Published

a tool for creating cli scaffolding tools

Readme

cobalt-base

You are a programmer who wastes a lot of time on coding repetitive, boilerplate stuff. For example, you want all your React components to be saved in a specific way:

  • You want them to be saved under ui/Components
  • You want them to have PascalCased filenames.
  • You also want each component to have its associated css file saved under client/stylesheets/
  • And you want the stylesheets to have underscored_names.

So, something like this:

project
└───ui
│   └───Components
│       │   MyFirstComponent.jsx
│       │   MySecondComponent.jsx
│   
└───client
    │   my_first_component.css
    │   my_second_component.css

What's more, you realize that you always have to code the same following lines for your react components:

import React, { Component, PropTypes } from 'react';

export default class MyFirstComponent extends React.Component {
  constructor () {
    super();
  }

  render () {
    return (
      <div className="my-first-component">
      </div>
    );
  }
}

MyFirstComponent.propTypes = {

};

MyFirstComponent.defaultProps = {

};

What if you could type something like generate component my-first-component in your terminal, and the rest was done automatically for you?

Enter cobalt

cobalt-base is a tool for creating cli scaffolding tools. (It's a tool that creates tools - so meta)

Cobalt handles:

  • Generating files: ... generate something somename
  • Deleting files: ... remove something somename
  • Overwriting: If the command you run might overwrite a file, cobalt asks if you're sure.
  • Commandline option parsing

How

You only need to do 2 things: create templates and their generator logics.

  • Create template at: templates/something/index.ejs
Hi! My name is <%= name %>.
I'm <%= age %> years old.
  • Add generator logic at: generators/something.js
module.exports = (options) => {
    filename: `${options.argv[0]}.txt`,
    parent: 'example_parent_folder',
    templateName: 'something.index',
    templateData: {
      name: 'MY NAME',
      age: 'MY AGE',
    },
};

Now you can just run node projectName/index.js generate something my_first_something, and this will create example_parent_folder/my_first_something.txt with the following content:

Hi! My name is MY NAME.
I'm MY AGE years old.

Tutorial

Note: For the sake of brevity, this tutorial has the following command node projectName/index.js generate something, shortened to ... generate something

In this tutorial, we will create a script that dynamically generates React components and their corresponding css files.

  • Follow the instructions at https://github.com/keremkazan/cobalt-starter to get the boilerplate code.
  • Create a file for the generator logic: generators/component.js
  • The filename is really important. It's how cobalt understands where to look. When you run ... generate something on the cli, cobalt will look for generators/something.js. Therefore when you run ... generate component, cobalt will look for generators/component.js.
  • As described in the intro, we want a template for our React component, and another one for its corresponding css file. There are two types of React components: stateful and stateless. So let's actually create the following 3 templates:
    • templates/Component/stateful_component.ejs
    • templates/Component/stateless_component.ejs
    • templates/Stylesheet/component.ejs

Our project directory should now look like this:

myScaffold
│   index.js
│   package.json
└───node_modules
│   └───cobalt-base
│   └───...
└───generators
│       │   component.js
└───templates
│   └───Component
│       │   stateful_component.ejs
│       │   stateless_component.ejs
│   └───Stylesheet
│       │   component.ejs
  • Let's populate these templates:
// templates/Component/stateful_component.ejs

import React, { Component, PropTypes } from 'react';

export default class <%= pascalCaseName %> extends React.Component {
  constructor () {
    super();
  }

  render () {
    return (
      <div className="<%= dashedName %>">
      </div>
    );
  }
}

<%= pascalCaseName %>.propTypes = {

};

<%= pascalCaseName %>.defaultProps = {

};
//templates/Component/stateless_component.ejs

export const <%= pascalCaseName %> = (props) => {

};
//templates/Stylesheet/component.ejs

.<%= dashedName %> {

}
  • Now let's code our generator logic. Every generator file has one responsibility: Exporting a function that tells cobalt what files to create, where to save them and what to put inside them.
  • This function takes in one param: options. This param will give us access to the variables we have typed on the cli. For example, ... generate component my-First-component my_second-Component --stateless will set the options variable to:

options {
  argv: [
    'my-First-component',
    'my_second-Component',
  ],
  stateless: true,
}
  • With that in mind, let's create the generator logic for the stateful component. In order to convert the user input to its camelCased, underscored, pascalCased etc. versions, we will use the corrected-names library. You don't need to worry about installing this library as cobalt-starter comes with it.
//generators/component.js

const getCorrectedNames = require('corrected-names');

module.exports = (options) => {
  const name = getCorrectedNames(options.argv[0]);
  return {
    filename: `${name.pascalCaseName}.js`,
    parent: 'ui/Components',
    templateName: 'Component.stateful_component',
    templateData: name,
  };
}
  • filename is the the name we want to give to the file. In our case, this will resolve to: MyFirstComponent.js
  • parent is where we want to save this file. Since we want to keep all of our react components in one place, we can hardcode that.
  • templateName is the name of the ejs template that cobalt uses. In our case, that is 'Component.stateful_component'. Cobalt will automatically resolve this and understand that it will need to look for templates/Component/stateful_component.ejs.
  • templateData is the data we want to pass to the template. If we look back at our template for stateful_component, we'll see that it uses two variables: pascalCaseName and dashedName. Now let's look at the variable name.
const name = getCorrectedNames(options.argv[0])

/*
name = {
  camelCaseName: 'myFirstComponent',
  pascalCaseName: 'MyFirstComponent',
  dashedName: 'my-first-component',
  underscoredName: 'my_first_component',
  originalName: 'my-First-component',
}
*/

Now, if we execute ... generate component my-First-component on the cli, cobalt will generate the React component, put it under ui/Components and give it the correct content. However, we also want to add stylesheets. This means that instead of a single object, our function should return an array of objects:

//generators/component.js

const getCorrectedNames = require('corrected-names');

module.exports = (options) => {
  const name = getCorrectedNames(options.argv[0]);
  return [
    {
      filename: `${name.pascalCaseName}.js`,
      parent: 'ui/Components',
      templateName: 'Component.stateful_component',
      templateData: name,
    },
    {
      filename: `${name.underscoredName}.css`,
      parent: 'client',
      templateName: 'Stylesheet.component',
      templateData: name,
    },
  ];
}

We also need to consider stateless components:

//generators/component.js

const getCorrectedNames = require('corrected-names');

module.exports = (options) => {
const name = getCorrectedNames(options.argv[0]);
  return [
    {
      filename: `${name.pascalCaseName}.js`,
      parent: 'ui/Components',
      templateName: options.stateless ?
        'Component.stateless_component' :
        'Component.stateful_component',
      templateData: name,
    },
    {
      filename: `${name.underscoredName}.css`,
      parent: 'client',
      templateName: 'Stylesheet.component',
      templateData: name,
    },
  ];
}
  • Finally, we need to tell cobalt that --stateless is a boolean option. Otherwise, cobalt won't be able to understand the cli options. In order to parse the cli options, cobalt uses this wonderful library: command-line-args
  • Add the following line to your index.js before run();.
config.OPTION_DEFINITIONS.push({ name: 'stateless', type: Boolean });
  • Once we update the index.js page, it should look like the following:
const path = require('path');
const { run, config } = require('cobalt-base');

config.TEMPLATES_DIR = path.join(__dirname, 'templates');
config.GENERATORS_DIR = path.join(__dirname, 'generators');

config.OPTION_DEFINITIONS.push({ name: 'stateless', type: Boolean });

run();

And that's it. Now we can execute ... generate component my-first-component and ... generate component my-second-component --stateless. This will create the files exactly the way we want them to be.

#Bin Executable

If you want to run your scaffolding tool as bin executable from the terminal, do the following:

  • Give your tool a command name, and assign it in your package.json file via the bin key. For example, if you want your scaffolder to run when you execute myscaffolder generate component my-first-component, replace starter with myscaffolder, so that you have the following in your packages.json file:
"bin": {
    "myscaffolder": "./index.js"
}
  • Finally, you need to make your module globally accessible. There are two ways of doing this.
  • While in the project directory, run npm link. This will create a global sym-link.
  • Publish your package on npm and install it globally

So now, instead of running node ~/.../my-scaffolder/index.js generate component my-first-component on your terminal, you can just run myscaffolder generate component my-first-component.