SockDrawer/SockBot

View on GitHub
build/post-commit.js

Summary

Maintainability
A
0 mins
Test Coverage
'use strict';

/* eslint-disable require-jsdoc */

const fs = require('fs'),
    jsdoc2md = require('jsdoc-to-markdown'),
    mkdirp = require('mkdirp'),
    path = require('path'),
    glob = require('glob');

const git = require('simple-git')('.');

const docDest = path.join('docs', 'api');

function getChanges(filter) {
    return new Promise((resolve, reject) => {
        git.log({
            from: 'HEAD~1',
            to: 'HEAD'
        }, (logErr, logData) => {
            if (logErr) {
                reject(logErr);
            } else {
                git.show([logData.latest.hash], (err, diff) => {
                    if (err) {
                        reject(err);
                    } else {
                        const files = {};
                        diff.split('\n').map((line) => {
                            const file = /^diff --git a\/(.*) b\/(.*)/.exec(line);
                            if (file && file[1] === file[2]) {
                                files[file[1]] = 1;
                            }
                        });
                        resolve(Object.keys(files).filter((file) => filter.test(file)));
                    }
                });
            }
        });
    });
}

function getDestination(file) {
    const dir = path.join(docDest, path.dirname(file)),
        name = `${path.basename(file, '.js') }.md`,
        dest = path.join(dir, name);
    return {
        target: file,
        dir: dir,
        name: name,
        path: dest
    };
}

function documentPath(toDoc) {
    return new Promise((resolve, reject) => {
        const dest = getDestination(toDoc);
        mkdirp(dest.dir, (err) => {
            if (err) {
                reject();
            }
            jsdoc2md.render({
                files: [toDoc]
            }).then((docs) => {
                fs.writeFile(dest.path, docs, 'utf8', (err2) => {
                    if (err) {
                        return reject(err2);
                    }
                    return resolve(dest.path);
                });
            });
        });
    });
}

function verifyDocument(file) {
    return new Promise((resolve, reject) => {
        fs.stat(file, (err, stats) => {
            if (err) {
                return reject(err);
            }
            return git.add(file, () => {
                const origFile = `.${file.replace(/[.]md$/, '.js').slice(docDest.length)}`;
                if (stats.size === 0) {
                    console.warn(`${origFile} has no jsdocs, please add some?`); //eslint-disable-line no-console
                    return removeStale(origFile).then(resolve, reject);
                }
                return resolve();
            });
        });
    });
}

function removeStale(file) {
    return new Promise((resolve, reject) => {
        const dest = getDestination(file).path;
        git.rm([dest], (err) => {
            if (err) {
                fs.unlink(dest, (err2) => err2 ? reject(err2) : resolve());
            } else {
                resolve();
            }
        });
    });
}

function processFile(file) {
    return documentPath(file).then((dest) => {
        return verifyDocument(dest);
    }, (err) => {
        if (err.code === 'ENOENT') {
            return removeStale(file);
        }
        throw err;
    });
}

function commitDocs() {
    return new Promise((resolve, reject) => {
        git.commit(['docs: Update API Documentation'], (err) => err ? reject(err) : resolve());
    });
}


const args = process.argv.slice();
args.shift();
args.shift();

let targets;
if (!args.length) {
    targets = getChanges(/[.]js$/i);
} else {
    targets = Promise.all(args.map((arg) => new Promise((res, rej) => glob(arg, (err, files) => {
        if (err) {
            return rej(err);
        }
        return res(files);
    }))))
        .then((res) => res.reduce((acc, val) => acc.concat(val), []));
}

targets.then((files) => Promise.all(files.map((file) => processFile(file))))
    .then(commitDocs)
    .then(() => console.log('Documentation Built')) //eslint-disable-line no-console
    .catch((err) => console.log(err)); //eslint-disable-line no-console