webdevian/generator-style-guider

View on GitHub
generators/app/index.js

Summary

Maintainability
A
2 hrs
Test Coverage
'use strict'
const Generator = require('yeoman-generator')
const path = require('path')
const slugify = require('slugify')

/**
 * Yeoman generator for main app
 * @type {Class}
 */
module.exports = class extends Generator {
  /**
   * Yeoman init
   */
  initializing () {
    this.props = {}
  }

  /**
   * Yeoman prompting
   */
  prompting () {
    this.log('Welcome to the style-guider generator!')

    const prompts = [{
      type: 'input',
      name: 'name',
      message: 'Your style guide name (Used in title and filenames)',
      default: path.basename(process.cwd()),
      store: true
    }, {
      type: 'list',
      name: 'depManager',
      message: 'User NPM or Yarn to manage dependencies?',
      choices: ['npm', 'yarn'],
      default: 'npm',
      store: true
    }, {
      type: 'confirm',
      name: 'husky',
      message: 'Install Useful git hooks (with husky)?',
      default: true,
      store: true
    }]

    return this.prompt(prompts).then(props => {
      props.longName = props.name

      // Set name to slug, so it can be used in filenames
      props.name = this._slugName(props.name)
      props.yarn = props.depManager === 'yarn'
      props.npm = props.depManager === 'npm'

      this.props = props
      this.config.set(props)
    })
  }

  /**
   * Yeoman writing. Copy over all root files and
   * set up the folder structure
   */
  writing () {
    this._template([
      'root/.*',
      'root/*',
      'docs/**/*',
      'img/.gitkeep',
      'schema/**/*',
      'pug/**/*',
      'js/**/*',
      'scss/**/*'
    ], [
      '',
      '',
      'docs',
      'img/.gitkeep',
      'schema',
      'pug',
      'js',
      'scss'
    ], this.props)

    this.fs.move(
      this.destinationPath('package.json.template'),
      this.destinationPath('package.json')
    )

    this.fs.move(
      this.destinationPath('scss/app.scss'),
      this.destinationPath('scss/' + this.props.name + '.scss')
    )
  }

  /**
   * Yeoman install step
   */
  install () {
    if (this.props.husky) {
      this.spawnCommandSync('git', ['init', '--quiet'])
    }
    if (this.props.yarn) {
      if (!this.options.skipInstall) {
        this.spawnCommandSync('yarn', ['install'])
        this.spawnCommandSync('yarn', ['run', 'build'])
      }
    } else {
      this.npmInstall().then(() => {
        if (!this.options.skipInstall) {
          return this.spawnCommand('npm', ['run', '--silent', 'build'])
        }
      })
    }
  }

  /**
   * Check if a string needs slugifying, if it does
   * log the change
   *
   * @param  {String} name String to be slugified
   * @return {String}      Slugified string
   */
  _slugName (name) {
    const slug = slugify(name).toLowerCase()

    if (slug !== name) {
      this.log(`Converting name to url friendly format: '${name} => '${slug}'`)
    }
    return slug
  }

  /**
   * Copy template files to the work
   * destination. If data is passed,
   * run ejs
   *
   * @param  {Array|String} from file name/path to copy from
   * @param  {Array|String} to   file name/path to copy to
   * @param  {Object} data data to pass to template
   * @return promise
   */
  _template (from, to, data) {
    if (typeof from === 'string') {
      from = [from]
      to = [to]
    }
    from.forEach((str, i) => {
      this.fs.copyTpl(
        this.templatePath(from[i]),
        this.destinationPath(to[i]),
        data
      )
    })
  }

  /**
   * Add some content to a file before or after a specific marker
   * @param  {String} path   The file you want to insert into
   * @param  {String} find   The marker string
   * @param  {String} insert The string you want to insert
   * @param  {Boolean} after Should the insert string go after the hook
   * @param  {Integer} indent Does the new line need indentation, how much?
   */
  _insert (path, find, insert, after, indent) {
    const file = this.fs.read(path)
    if (!file || file.indexOf(find) !== -1) {
      if (file.indexOf(insert.replace(/,\s*$/, '')) === -1) {
        let replace
        const spaces = Array((indent || 0) + 1).join('  ')

        if (after) {
          replace = find + '\n' + spaces + insert
        } else {
          replace = insert + '\n' + spaces + find
        }

        this.fs.write(path, file.replace(find, replace))

        this.log('Including in ' + path)
      } else {
        this.log('Duplicate found in ' + path)
      }
    } else {
      this.log('Yeoman include hook missing in ' + path)
    }
  }
}