Home Reference Source Repository

src/index.js

import {EventEmitter} from 'events';
import path from 'path';

import debugModule from 'debug';
import ejs from 'ejs';
import fs from 'fs-extra';
import walk from 'walk';

const debug = debugModule('dokata');
const CONFIG_FILE_NAME = 'dokata.json';
const TEMPLATE_DIR_NAME = 'template';


/**
 * Project Generator
 */
class Generator extends EventEmitter {

  /**
   * constructor
   *
   * @param {string} baseDir base directory path
   */
  constructor(baseDir) {
    super();
    this.baseDir = baseDir;
    this.templateDir = path.join(this.baseDir, TEMPLATE_DIR_NAME);
    this.context = {};

    this.loadConfig();
  }

  /**
   * Generate files from settings of dokata template
   *
   * @param {string} outputDir output directory path
   */
  execute(outputDir) {
    const walker = walk.walk(this.templateDir);

    fs.mkdirs(outputDir);

    walker.on('directories', (root, stats, next) => {
      const basePath = path.relative(this.templateDir, root);
      stats.forEach(stat => {
        const outputPath = path.join(basePath, stat.name);
        fs.mkdirs(path.join(outputDir, outputPath));
        this.emit('create:dir', outputPath);
      });
      next();
    });

    walker.on('file', (root, stat, next) => {
      const basePath = path.relative(this.templateDir, root);
      const outputPath = path.join(basePath, stat.name);
      const data = fs.readFileSync(path.resolve(root, stat.name));
      fs.writeFileSync(
        path.join(outputDir, outputPath),
        ejs.render(data.toString('utf8'), this.context)
      );
      this.emit('create:file', outputPath);
      next();
    });

    walker.on('errors', (root, nodeStats, next) => {
      this.emit('error:walk', root, nodeStats);
      next();
    });

    walker.on('end', () => {
      this.emit('done');
    });
  }


  /**
   * Load config from dokata config file
   */
  loadConfig() {
    const defaultConfig = {
      questions: []
    };
    this.config = Object.assign(
      {},
      defaultConfig,
      fs.readJsonSync(path.join(this.baseDir, CONFIG_FILE_NAME))
    );
  }

  /**
   * Update context
   *
   * @param {Object} context template context for generating files
   */
  updateContext(context) {
    this.context = context;
  }
}


/**
 * Project Generator
 */
export default class Dokata {

  /**
   * Constructor
   *
   * @param {string|undefined} baseDir dokata template directory path
   */
  constructor(baseDir) {
    debug('baseDir', baseDir);
    if (baseDir !== undefined) {
      this.baseDir = path.resolve(baseDir);
    }
  }

  /**
   * Get list of generator config data
   *
   * @return {Object[]}
   */
  getGeneratorConfigs() {
    if (!this.baseDir) {
      return [];
    }
    return fs.readdirSync(this.baseDir).map(filename => {
      const fp = path.join(this.baseDir, filename);
      if (!fs.statSync(fp).isDirectory()) {
        return null;
      }
      if (!fs.existsSync(path.join(fp, 'dokata.json'))) {
        return null;
      }
      return {
        path: fp,
        name: filename
      };
    }).filter(c => c !== null);
  }

  /**
   * Create Generator
   *
   * @param {string} name generator name
   * @return {Generator|null}
   */
  createGenerator(name) {
    if (this.isPath(name)) {
      return new Generator(path.resolve(name));
    }
    const config = this.getGeneratorConfigs().find(c => {
      return c.name === name;
    });
    if (config) {
      return new Generator(config.path);
    }
    return null;
  }

  /**
   * isPath
   *
   * @param {string} name generator name
   * @return {boolean}
   */
  isPath(name) {
    return /^(?:\.\.?|\~|)\//.test(name);
  }
}


export {Dokata, Generator};