UNPKG

kss

Version:

The Node.js port of KSS: A methodology for documenting CSS and building style guides

176 lines (157 loc) 6.22 kB
'use strict'; /** * The core kss API can be imported with: * ``` * var kss = require('kss'); * ``` * * The main object is a function that will build a style guide given the correct * options. * ``` * kss(options); * ``` * The various constructors and methods can then be accessed with: * ``` * const KssStyleGuide = require('kss').KssStyleGuide; * const KssSection = require('kss').KssSection; * const KssModifier = require('kss').KssModifier; * const KssParameter = require('kss').KssParameter; * * const kss = require('kss'); * const traverse = require('kss').traverse(); * const parse = require('kss').parse(); * ``` * * The usual style guide build process: * - The command-line tool uses `lib/cli` to gather the command line options, * which passes the options to `kss()`. * - The `kss()` function takes an object of options and calls `traverse()`. * - The `traverse()` function reads all the `source` directories and calls * `parse()`. * - The `parse()` function finds the KSS comments in the provided text, creates * a JSON object containing all the parsed data and passes it the * `new KssStyleGuide(data)` constructor to create a style guide object. * - The `kss()` function loads the specified builder, which is a collection of * files and an optional module that provides a sub-class of `KssBuilderBase`. * - `kss()` passes its options to the builder the builder's `addOptions()` * method. * - The builder's `prepare()` method is given the `KssStyleGuide` object and * can do any pre-build tasks, like initializing its templating system (if it * has one.) * - The builder's `build()` method is run and the style guide files are * created in the specified destination. * @module kss */ const KssBuilderBase = require('../builder/base'), KssStyleGuide = require('./kss_style_guide.js'), path = require('path'), Promise = require('bluebird'), traverse = require('./traverse.js'); /** * Builds a style guide given the proper options. * * @param {object} [options] A collection of options. * @returns {Promise.<KssStyleGuide|null>} A `Promise` object resolving to a * `KssStyleGuide` object, or to `null` if the clone option is used. */ const kss = function(options) { options = options || {}; let builder; // Confirm this is a compatible builder. return KssBuilderBase.loadBuilder(options.builder ? KssBuilderBase.builderResolve(options.builder) : require('../builder/handlebars')).catch(error => { let catchLoadFailure; const supportedBuilders = [ 'builder/twig', 'builder/nunjucks' ]; // If the builder was specified and there was no existing // path relative to the working directory, we should try again while using // the path to kss-node's builder. // istanbul ignore if if (supportedBuilders.indexOf(options.builder) > -1) { options.builder = path.resolve(__dirname, '..', options.builder); catchLoadFailure = KssBuilderBase.loadBuilder(options.builder); } else { catchLoadFailure = Promise.reject(error); } return catchLoadFailure.catch(error => { // If we fail to create a builder, set up builder.logError() for the // next .catch(). builder = { logError: (typeof options.logErrorFunction === 'function') ? options.logErrorFunction : console.error }; throw error; }); }).then(newBuilder => { builder = newBuilder; // Add the options to the builder. builder.addOptions(options); // If requested, clone a builder and exit. if (builder.getOptions('clone')) { builder.log('Creating a new style guide builder in ' + builder.getOptions('clone') + '...'); return builder.clone(builder.getOptions('builder'), builder.getOptions('clone')).then(() => { builder.log('You can change it as you like, and use it to build your style guide using the "builder" option'); return Promise.resolve(); }); } // If no source is specified, display helpful error and exit. if (!builder.getOptions('source').length) { return Promise.reject(new Error('No "source" option specified.')); } let parseTask; // Check the 'source' array for paths ending in .json and convert the first // one into a KssStyleGuide object. let jsonInput = builder.getOptions('source').find(filePath => { return (path.extname(filePath) === '.json'); }); if (jsonInput) { try { let styleGuide = require(jsonInput); parseTask = Promise.resolve(new KssStyleGuide(styleGuide)); } catch (error) { parseTask = Promise.reject(new Error('Failed to open JSON file: ' + jsonInput)); } } // Then traverse the source and parse the files found. if (!parseTask) { if (builder.getOptions('verbose')) { builder.log('...Parsing your style guide:'); } parseTask = traverse(builder.getOptions('source'), { base: builder.getOptions('base'), header: true, markdown: true, markup: true, mask: builder.getOptions('mask'), custom: builder.getOptions('custom') }); } if (builder.getOptions('json')) { return parseTask.then(styleGuide => { return styleGuide.toJSON(); }); } return parseTask.then(styleGuide => { // Then allow the builder to prepare itself and the KssStyleGuide object. return builder.prepare(styleGuide); }).then(styleGuide => { // Then build the style guide. return builder.build(styleGuide); }).then(styleGuide => { if (builder.getOptions('verbose')) { builder.log('Style guide build completed successfully!'); } return Promise.resolve(styleGuide); }); }).catch(error => { builder.logError(error); throw error; }); }; module.exports = kss; module.exports.KssStyleGuide = require('./kss_style_guide.js'); module.exports.KssSection = require('./kss_section.js'); module.exports.KssModifier = require('./kss_modifier.js'); module.exports.KssParameter = require('./kss_parameter.js'); module.exports.parse = require('./parse.js'); module.exports.traverse = traverse;