SassDoc: A Documentation Tool for Sass

For a while now I have been using my own comment system to document my Sass functions and mixins. As of today, looks something like this:

// Clamp `$value` between `$min` and `$max`.
//
// @author Stan Angeloff
//
// @param {Number} $value   - value to clamp
// @param {Number} $min (0) - minimal value
// @param {Number} $max (1) - maximum value
//
// @throws All arguments must be numbers for `clamp`.
// 
// @return {Number} - clamped number

@function clamp($value, $min: 0, $max: 1) {
    @if type-of($value) != "number" or type-of($min) != "number" or type-of($max) != "number" {
      @warn "All arguments must be numbers for `clamp`.";
      @return null;
    }

  @return if($value > $max, $max, if($value < $min, $min, $value));
}

// @var {Bool} - Defines whether the library should support legacy browsers (e.g. IE8).
$legacy-support: true !global;

This syntax, while close to that of JSDoc, is quite personal. It not only helps me document my functions and mixins but also provides enough information to other developers using the code so they can understand what’s going on.

When other developers saw these comments in my code, they thought I was using this syntax to generate documentation. So I thought: What a brilliant idea! Why not using these comments to build a whole documentation system? It sounds like a great project!

Introducing SassDoc

So I built SassDoc, distributed as an npm package.

There are 2 ways to use SassDoc:

  1. Run it from your terminal on your Sass folder; or
  2. Use it in your JavaScript applications.

In either case, you need to install it first:

npm install -g sassdoc

Usage From the Command Line

Using it from the terminal is very simple:

sassdoc <src> <dest> [options]

Where:

  • <src> is the path to your Sass folder
  • <dest> is the path to the destination folder
  • [options] is basically -v or --verbose

For instance, on the official repository, when running:

sassdoc  examples/stylesheets  examples/dist  --verbose

… we get this (as long as we run in verbose mode):

2014-07-01 19:21:17 Folder `examples/dist` successfully removed.
2014-07-01 19:21:17 Folder `examples/dist` successfully generated.
2014-07-01 19:21:17 Folder `examples/stylesheets` successfully parsed.
2014-07-01 19:21:17 Documentation for folder `examples/stylesheets` successfully generated.
2014-07-01 19:21:17 Process over. Everything okay!

Then, the documentation file is generated at examples/dist/index.html and it looks like this:

SassDoc Example Documentation

Not bad for something generated from comments, right?

Usage in JavaScript

If for some reason the default generated documentation doesn’t fit your needs, you can use it in your own JavaScript applications, perhaps with Grunt or something:

var sassdoc = require('sassdoc');

sassdoc.parse('/your/path/here').then(function (items) {
  // Do whatever you want with `items`
});

As shown, all you have to do is require the sassdoc package. Then, you can call the parse method, which only needs a single argument: the path to your stylesheets folder. This method returns a promise, which yields an object containing the documentation of all your items. This object looks like this:

{
  "functions": [],
  "mixins": [],
  "variables": []
}

Each of these values is itself an array of objects. Functions and mixins both look alike. If we take our clamp function back as an example, here is what its object will look like:

{
  'parameters': [
    { 'type': 'Number', 'name': 'value', 'default': undefined, 'description': 'value to clamp' },
    { 'type': 'Number', 'name': 'min', 'default': 0, 'description': 'minimal value' },
    { 'type': 'Number', 'name': 'max', 'default': 1, 'description': 'maximal value' }
  ],
  'throws': [ 'All arguments must be numbers for `clamp`.' ],
  'alias': false,
  'aliased': [],
  'links': [],
  'todos': [],
  'requires': [],
  'usedBy': [],
  'description': 'Clamp `$value` between `$min` and `$max`.',
  'access': 'public',
  'deprecated': false,
  'author': "Stan Angeloff",
  'returns': {
    'type': [ 'Number' ],
    'description': 'Clamped number'
  },
  'type': 'function',
  'name': 'clamp'
}

Meanwhile, each item from the variables array looks like this:

{ 
  type: 'variable',
  datatype: ['Bool'],
  description: 'Defines whether the lib should support legacy browsers (e.g. `IE 8`).',
  name: 'support-legacy',
  value: 'true',
  access: 'global' 
}

Then it’s up to you what you want to do with that. ;)

Under the Hood of SassDoc

Now that you are familiar with how SassDoc works, and how you can use it, I thought I would explain how it’s built.

SassDoc is my first try with Node, and you might be able to tell it’s pretty experimental right now. While I had some knowledge on how to write “decent” (I won’t say “good”) JavaScript in the browser, I didn’t know the first thing about Node. Thankfully, Valérian Galliat helped me get started (thanks, buddy!).

It was a good opportunity to try fs, the file system API that ships with Node, which, in my opinion, is really cool. I had some experience with equivalent PHP functions but it didn’t go as well as it went with Node.

Q as a Promise Library

Also, I took this as an opportunity to learn more about promises in JavaScript. A promise is like a proxy for a value not necessarily known when the promise is created. Promises make it possible to build asynchronous scripts without falling into callback hell.

I eventually landed on Q, really because I had to choose a promise library. There are a lot of such libraries popping up these days, so feel free to pick the one you like best. I must say, Q is pretty neat and has the benefit of being simple to use.

For instance, here is what the main function from the SassDoc API looks like (minus logs):

documentize: function (source, destination) {
  fs.folder.refresh(destination)
    .then(function () { 
      return fs.getData(source);
    })
    .then(function (data) {
      return fs.generate(data, destination + '/index.html');
    })
    .then(function () {
      return fs.dumpAssets(destination);
    })
    .fail(function (err) {
      console.error(err);
    });
}

Quite pretty, isn’t it?

Swig as a Template Engine

In order to generate HTML files, I needed a template engine. But choosing one was not easy. The number of promise libraries is nothing compared to the number of available JavaScript templating engines.

I have some experience with Handlebars (which I hate), Liquid (which happens to have a Node port) and Twig (which I absolute love). Fortunately, there is also a Node port of Twig called Swig. Obviously I couldn’t refuse that.

To use Swig, you pre-compile a template — for instance a .html.swig file containing all the logic and stuff — to have a function. Then, you give any data you want to pass to the view to this function, and you end up with the final content. From there, you put it in a regular .html file and you’re done.

Final Thoughts

SassDoc is still quite raw, but it is already being used in several projects. For instance, I am successfully maintaining the documenation for SassyLists with SassDoc and this is really great: at this point, the code is basically documenting itself.

I am willing to add more features to SassDoc, starting with @example but also @group, @module, and much more but for that I need your help! I am currently using regular expressions to parse comments but it’s not good enough. I have started building an actual parser but it needs improvements.

In any case, any contribution, suggestion or comment is welcome. The GitHub repository has been quite active lately, so feel free to provide some feedback!

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://laurentperroteau.com/ Laurent Perroteau

    Awesome and thank you very much, this is what I was looking for some time

  • https://twitter.com/dmathisen36 dmathisen

    This is amazing! A project I’m currently on uses LESS. This won’t work with less, will it? If not, does anyone know of anything similar for less css?

    • http://hugogiraudel.com/ Hugo Giraudel

      It won’t work with LESS. It’s still very unstall for Sass. :D

  • http://hugogiraudel.com/ Hugo Giraudel

    It is not the same project. My work is distributed as a npm package, not a gem. Also, Eoneill’s SassDoc has been dead for 2 years so I thought it might be nice to give it a go.

  • http://viii.in Vinay Raghu

    This is one step forward for well documented code!

  • http://hugogiraudel.com/ Hugo Giraudel

    Yep. Hope you like it.

  • http://hugogiraudel.com/ Hugo Giraudel

    News: SassDoc 1.0.0 is out. And 1.1 is coming right away.