UNPKG

sgcss

Version:

Create styleguides from CSS comments

125 lines (107 loc) 3.49 kB
var fs = require('fs'), fsp = require('fs-promise'), marked = require('marked'), path = require('path'), _ = require('lodash'); var Renderer = require('./lib/renderer'), util = require('./lib/util'); var isDoc = /^\/*\?\s*/; module.exports = require('postcss').plugin('sgcss', function (opts) { // set options object opts = Object(opts); /* set options */ opts.index = opts.index || 'index.html'; // index file opts.theme = opts.theme || require('sgcss-theme-default'); // theme or default opts.destination = path.join(process.cwd(), opts.destination || 'styleguide'); // destination path opts.assets = opts.assets || {js: [], css: []}; if (typeof opts.theme !== 'function') throw Error('The theme failed to load'); // throw if theme is not a function if (opts.theme.type === 'sgcss-theme') opts.theme = opts.theme(opts); // conditionally set theme as executed theme var renderer = new Renderer({ classPrefix: 'sg-', assets: opts.assets }); // return plugin return function (css, result) { // set current css directory or current directory var dir = css.source.input.file ? path.dirname(css.source.input.file) : process.cwd(); // set documentation list, hash, and unique identifier var list = []; var hash = {}; // walk comments css.walkComments(function (comment) { // if comment is documentation if (isDoc.test(comment.text)) { var text = comment.text.replace(isDoc, ''); // console.log(text); // set documentation object var doc = {}; var tokens = marked.lexer(text); tokens.map(function(token) { if(token.type === 'heading') { if(token.depth === 1) { doc.section = token.text; } else if(token.depth === 2) { doc.title = token.text; } return; } }); doc.content = marked.parser(tokens, {renderer: renderer}); // set documentation context doc.context = comment; var name = doc.section || doc.title; var uniq = util.uniqname(name); if(name) { doc.name = util.slug(name); } // push documentation to hash using an unique name hash[uniq] = doc; } }); // console.log(Object.keys(hash)); // walk hashes var section; Object.keys(hash).forEach(function (name) { // set documentation var doc = hash[name]; if('section' in doc) { section = doc; doc.children = doc.children || []; list.push(doc); } else { section.children.push(doc); } }); // return theme executed with parsed list, destination return opts.theme({ list: list, opts: opts }).then(function (docs) { // empty the destination directory return fsp.emptyDir(opts.destination) // then copy the theme assets into the destination .then(function (assets) { return fsp.copy(docs.assets, opts.destination); }) // then copy the compiled template into the destination .then(function () { return fsp.outputFile(path.join(opts.destination, opts.index), docs.template); }) // then copy any of the additional assets into the destination .then(function () { var assets = _.flatten(_.values(opts.assets)); return Promise.all(assets.map(function (src) { return fsp.copy(constructFullAssetPath(src), path.join(opts.destination, src)); })); }); }); }; }); function titleToName(title) { return title.replace(/\s+/g, '-').replace(/[^A-z0-9_-]/g, '').toLowerCase(); } function constructFullAssetPath(src) { return path.join(process.cwd(), src); }