'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.Generator = undefined;

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _fs = require('fs');

var _fs2 = _interopRequireDefault(_fs);

var _path = require('path');

var _path2 = _interopRequireDefault(_path);

var _bluebird = require('bluebird');

var _bluebird2 = _interopRequireDefault(_bluebird);

var _util = require('../util');

var _chalk = require('chalk');

var _chalk2 = _interopRequireDefault(_chalk);

var _yeomanGenerator = require('yeoman-generator');

var _generatorBase = require('../generator-base');

var _insightInit = require('../insight-init');

var _insightInit2 = _interopRequireDefault(_insightInit);

var _child_process = require('child_process');

var _gulpBabel = require('gulp-babel');

var _gulpBabel2 = _interopRequireDefault(_gulpBabel);

var _gulpBeautify = require('gulp-beautify');

var _gulpBeautify2 = _interopRequireDefault(_gulpBeautify);

var _gulpFilter = require('gulp-filter');

var _gulpFilter2 = _interopRequireDefault(_gulpFilter);

var _semver = require('semver');

var _semver2 = _interopRequireDefault(_semver);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var Generator = exports.Generator = function (_Base) {
  _inherits(Generator, _Base);

  function Generator() {
    var _Object$getPrototypeO;

    _classCallCheck(this, Generator);

    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
      args[_key] = arguments[_key];
    }

    var _this = _possibleConstructorReturn(this, (_Object$getPrototypeO = Object.getPrototypeOf(Generator)).call.apply(_Object$getPrototypeO, [this].concat(args)));

    _this.argument('name', { type: String, required: false });

    _this.option('skip-install', {
      desc: 'Do not install dependencies',
      type: Boolean,
      defaults: false
    });

    _this.option('app-suffix', {
      desc: 'Allow a custom suffix to be added to the module name',
      type: String,
      defaults: 'App'
    });
    return _this;
  }

  _createClass(Generator, [{
    key: 'initializing',
    get: function get() {
      return {
        init: function init() {
          var _this2 = this;

          this.config.set('generatorVersion', this.rootGeneratorVersion());
          this.filters = {};

          // init shared generator properies and methods
          var genBasePromise = (0, _generatorBase.genBase)(this);
          var promises = [genBasePromise];

          if (process.env.CI) {
            _insightInit2.default.optOut = true;
          } else if (_insightInit2.default.optOut === undefined) {
            promises.push(new _bluebird2.default(function (resolve, reject) {
              _insightInit2.default.askPermission(null, function (err, optIn) {
                if (err) return reject(err);else return resolve(optIn);
              });
            }));
          }

          _insightInit2.default.track('generator', this.rootGeneratorVersion());
          this.nodeVersion = _semver2.default.clean(process.version);
          this.semver = _semver2.default;
          _insightInit2.default.track('node', this.nodeVersion);
          _insightInit2.default.track('platform', process.platform);

          var npmVersionPromise = (0, _util.runCmd)('npm --version').then(function (stdout) {
            _this2.npmVersion = stdout.toString().trim();
            return _insightInit2.default.track('npm', _this2.npmVersion);
          });
          promises.push(npmVersionPromise);

          return _bluebird2.default.all(promises);
        },
        info: function info() {
          this.log(this.yoWelcome);
          this.log('Out of the box I create an AngularJS app with an Express server.\n');
        },
        checkForConfig: function checkForConfig() {
          var _this3 = this;

          var existingFilters = this.config.get('filters');

          if (existingFilters) {
            return this.prompt([{
              type: 'confirm',
              name: 'skipConfig',
              message: 'Existing .yo-rc configuration found, would you like to use it?',
              default: true
            }]).then(function (answers) {
              _this3.skipConfig = answers.skipConfig;

              if (_this3.skipConfig) {
                _insightInit2.default.track('skipConfig', 'true');
                _this3.filters = existingFilters;

                _this3.scriptExt = _this3.filters.ts ? 'ts' : 'js';
                _this3.templateExt = _this3.filters.jade ? 'jade' : 'html';
                _this3.styleExt = _this3.filters.sass ? 'scss' : _this3.filters.less ? 'less' : _this3.filters.stylus ? 'styl' : 'css';
              } else {
                _insightInit2.default.track('skipConfig', 'false');
                _this3.filters = {};
                _this3.forceConfig = true;
                _this3.config.set('filters', _this3.filters);
                _this3.config.forceSave();
              }
            });
          }
        }
      };
    }
  }, {
    key: 'prompting',
    get: function get() {
      return {
        clientPrompts: function clientPrompts() {
          var _this4 = this;

          if (this.skipConfig) return;

          this.log('# Client\n');

          return this.prompt([{
            type: 'list',
            name: 'transpiler',
            message: 'What would you like to write scripts with?',
            choices: ['Babel', 'TypeScript'],
            filter: function filter(val) {
              return {
                'Babel': 'babel',
                'TypeScript': 'ts'
              }[val];
            }
          }, {
            // TODO: enable once Babel setup supports Flow
            //   type: 'confirm',
            //   name: 'flow',
            //   message: 'Would you like to use Flow types with Babel?',
            //   when: answers => answers.transpiler === 'babel'
            // }, {
            type: 'list',
            name: 'markup',
            message: 'What would you like to write markup with?',
            choices: ['HTML', 'Jade'],
            filter: function filter(val) {
              return val.toLowerCase();
            }
          }, {
            type: 'list',
            name: 'stylesheet',
            default: 1,
            message: 'What would you like to write stylesheets with?',
            choices: ['CSS', 'Sass', 'Stylus', 'Less'],
            filter: function filter(val) {
              return val.toLowerCase();
            }
          }, {
            type: 'list',
            name: 'router',
            default: 1,
            message: 'What Angular router would you like to use?',
            choices: ['ngRoute', 'uiRouter'],
            filter: function filter(val) {
              return val.toLowerCase();
            }
          }, {
            type: 'confirm',
            name: 'bootstrap',
            message: 'Would you like to include Bootstrap?'
          }, {
            type: 'confirm',
            name: 'uibootstrap',
            message: 'Would you like to include UI Bootstrap?',
            when: function when(answers) {
              return answers.bootstrap;
            }
          }]).then(function (answers) {
            _this4.filters.js = true;
            _this4.filters[answers.transpiler] = true;
            _insightInit2.default.track('transpiler', answers.transpiler);

            _this4.filters.flow = !!answers.flow;
            _insightInit2.default.track('flow', !!answers.flow);

            _this4.filters[answers.markup] = true;
            _insightInit2.default.track('markup', answers.markup);

            _this4.filters[answers.stylesheet] = true;
            _insightInit2.default.track('stylesheet', answers.stylesheet);

            _this4.filters[answers.router] = true;
            _insightInit2.default.track('router', answers.router);

            _this4.filters.bootstrap = !!answers.bootstrap;
            _insightInit2.default.track('bootstrap', !!answers.bootstrap);

            _this4.filters.uibootstrap = !!answers.uibootstrap;
            _insightInit2.default.track('uibootstrap', !!answers.uibootstrap);

            _this4.scriptExt = answers.transpiler === 'ts' ? 'ts' : 'js';
            _this4.templateExt = answers.markup;

            var styleExt = { sass: 'scss', stylus: 'styl' }[answers.stylesheet];
            _this4.styleExt = styleExt ? styleExt : answers.stylesheet;
          });
        },
        serverPrompts: function serverPrompts() {
          var _this5 = this;

          if (this.skipConfig) return;
          var self = this;

          this.log('\n# Server\n');

          return this.prompt([{
            type: 'checkbox',
            name: 'odms',
            message: 'What would you like to use for data modeling?',
            choices: [{
              value: 'mongoose',
              name: 'Mongoose (MongoDB)',
              checked: true
            }, {
              value: 'sequelize',
              name: 'Sequelize (MySQL, SQLite, MariaDB, PostgreSQL)',
              checked: false
            }]
          }, {
            type: 'list',
            name: 'models',
            message: 'What would you like to use for the default models?',
            choices: ['Mongoose', 'Sequelize'],
            filter: function filter(val) {
              return val.toLowerCase();
            },
            when: function when(answers) {
              return answers.odms && answers.odms.length > 1;
            }
          }, {
            type: 'confirm',
            name: 'auth',
            message: 'Would you scaffold out an authentication boilerplate?',
            when: function when(answers) {
              return answers.odms && answers.odms.length !== 0;
            }
          }, {
            type: 'checkbox',
            name: 'oauth',
            message: 'Would you like to include additional oAuth strategies?',
            when: function when(answers) {
              return answers.auth;
            },
            choices: [{
              value: 'googleAuth',
              name: 'Google',
              checked: false
            }, {
              value: 'facebookAuth',
              name: 'Facebook',
              checked: false
            }, {
              value: 'twitterAuth',
              name: 'Twitter',
              checked: false
            }]
          }, {
            type: 'confirm',
            name: 'socketio',
            message: 'Would you like to use socket.io?',
            // to-do: should not be dependent on ODMs
            when: function when(answers) {
              return answers.odms && answers.odms.length !== 0;
            },
            default: true
          }]).then(function (answers) {
            if (answers.socketio) _this5.filters.socketio = true;
            _insightInit2.default.track('socketio', !!answers.socketio);

            if (answers.auth) _this5.filters.auth = true;
            _insightInit2.default.track('auth', !!answers.auth);

            if (answers.odms && answers.odms.length > 0) {
              var models;
              if (!answers.models) {
                models = answers.odms[0];
              } else {
                models = answers.models;
              }
              _this5.filters.models = true;
              _this5.filters[models + 'Models'] = true;
              answers.odms.forEach(function (odm) {
                _this5.filters[odm] = true;
              });
              _insightInit2.default.track('oauth', !!answers.oauth);
            } else {
              _this5.filters.noModels = true;
            }
            _insightInit2.default.track('odms', answers.odms && answers.odms.length > 0);
            _insightInit2.default.track('mongoose', !!_this5.filters.mongoose);
            _insightInit2.default.track('mongooseModels', !!_this5.filters.mongooseModels);
            _insightInit2.default.track('sequelize', !!_this5.filters.sequelize);
            _insightInit2.default.track('sequelizeModels', !!_this5.filters.sequelizeModels);

            if (answers.oauth) {
              if (answers.oauth.length) _this5.filters.oauth = true;
              answers.oauth.forEach(function (oauthStrategy) {
                _this5.filters[oauthStrategy] = true;
              });
            }
            _insightInit2.default.track('oauth', !!_this5.filters.oauth);
            _insightInit2.default.track('google-oauth', !!_this5.filters['googleAuth']);
            _insightInit2.default.track('facebook-oauth', !!_this5.filters['facebookAuth']);
            _insightInit2.default.track('twitter-oauth', !!_this5.filters['twitterAuth']);
          });
        },
        projectPrompts: function projectPrompts() {
          var _this6 = this;

          if (this.skipConfig) return;
          var self = this;

          this.log('\n# Project\n');

          return this.prompt([{
            type: 'list',
            name: 'buildtool',
            message: 'Would you like to use Gulp or Grunt?',
            choices: ['Gulp', 'Grunt (deprecated)'],
            default: 0,
            filter: function filter(val) {
              return {
                'Gulp': 'gulp',
                'Grunt (deprecated)': 'grunt'
              }[val];
            }
          }, {
            type: 'list',
            name: 'testing',
            message: 'What would you like to write tests with?',
            choices: ['Jasmine', 'Mocha + Chai + Sinon'],
            default: 1,
            filter: function filter(val) {
              return {
                'Jasmine': 'jasmine',
                'Mocha + Chai + Sinon': 'mocha'
              }[val];
            }
          }, {
            type: 'list',
            name: 'chai',
            message: 'What would you like to write Chai assertions with?',
            choices: ['Expect', 'Should'],
            filter: function filter(val) {
              return val.toLowerCase();
            },
            when: function when(answers) {
              return answers.testing === 'mocha';
            }
          }]).then(function (answers) {
            _this6.filters[answers.buildtool] = true;
            _insightInit2.default.track('buildtool', answers.buildtool);

            _this6.filters[answers.testing] = true;
            _insightInit2.default.track('testing', answers.testing);
            if (answers.testing === 'mocha') {
              _this6.filters.jasmine = false;
              _this6.filters.should = false;
              _this6.filters.expect = false;
              _this6.filters[answers.chai] = true;
              _insightInit2.default.track('chai-assertions', answers.chai);
            }
            if (answers.testing === 'jasmine') {
              _this6.filters.mocha = false;
              _this6.filters.should = false;
              _this6.filters.expect = false;
            }
          });
        }
      };
    }
  }, {
    key: 'configuring',
    get: function get() {
      return {
        saveSettings: function saveSettings() {
          if (this.skipConfig) return;
          this.config.set('endpointDirectory', 'server/api/');
          this.config.set('insertRoutes', true);
          this.config.set('registerRoutesFile', 'server/routes.js');
          this.config.set('routesNeedle', '// Insert routes below');

          this.config.set('routesBase', '/api/');
          this.config.set('pluralizeRoutes', true);

          this.config.set('insertSockets', true);
          this.config.set('registerSocketsFile', 'server/config/socketio.js');
          this.config.set('socketsNeedle', '// Insert sockets below');

          this.config.set('insertModels', true);
          this.config.set('registerModelsFile', 'server/sqldb/index.js');
          this.config.set('modelsNeedle', '// Insert models below');

          this.config.set('filters', this.filters);
          this.config.forceSave();
        },
        ngComponent: function ngComponent() {
          var _this7 = this;

          if (this.skipConfig) return;
          var appPath = 'client/app/';
          var extensions = [];
          var filters = ['ngroute', 'uirouter', 'jasmine', 'mocha', 'expect', 'should'].filter(function (v) {
            return _this7.filters[v];
          });

          if (this.filters.ngroute) filters.push('ngroute');
          if (this.filters.uirouter) filters.push('uirouter');
          if (this.filters.babel) extensions.push('babel');
          if (this.filters.ts) extensions.push('ts');
          if (this.filters.js) extensions.push('js');
          if (this.filters.html) extensions.push('html');
          if (this.filters.jade) extensions.push('jade');
          if (this.filters.css) extensions.push('css');
          if (this.filters.stylus) extensions.push('styl');
          if (this.filters.sass) extensions.push('scss');
          if (this.filters.less) extensions.push('less');

          filters.push('es6'); // Generate ES6 syntax code

          this.composeWith('ng-component', {
            options: {
              'routeDirectory': appPath,
              'directiveDirectory': appPath,
              'filterDirectory': appPath,
              'serviceDirectory': appPath,
              'componentDirectory': appPath + 'components/',
              'filters': filters,
              'extensions': extensions,
              'basePath': 'client',
              'forceConfig': this.forceConfig
            }
          }, { local: require.resolve('generator-ng-component/app/index.js') });
        },
        ngModules: function ngModules() {
          var angModules = ['\'' + this.scriptAppName + '.constants\'', "'ngCookies'", "'ngResource'", "'ngSanitize'"];
          if (this.filters.ngroute) angModules.push("'ngRoute'");
          if (this.filters.socketio) angModules.push("'btford.socket-io'");
          if (this.filters.uirouter) angModules.push("'ui.router'");
          if (this.filters.uibootstrap) angModules.push("'ui.bootstrap'");
          if (this.filters.auth) {
            angModules.unshift('\'' + this.scriptAppName + '.admin\'');
            angModules.unshift('\'' + this.scriptAppName + '.auth\'');
            angModules.push("'validation.match'");
          }

          this.angularModules = '\n  ' + angModules.join(',\n  ') + '\n';
        }
      };
    }
  }, {
    key: 'default',
    get: function get() {
      return {};
    }
  }, {
    key: 'writing',
    get: function get() {
      return {
        generateProject: function generateProject() {
          /**
           * var tap = require('gulp-tap');
             this.registerTransformStream([
                extensionFilter,
                tap(function(file, t) {
                    var contents = file.contents.toString();
                    contents = beautify_js(contents, config);
                    file.contents = new Buffer(contents);
                }),
                //prettifyJs(config),
                extensionFilter.restore
             ]);
           */

          var babelPlugins = ['babel-plugin-syntax-flow', 'babel-plugin-syntax-class-properties'];

          // TODO: enable once Babel setup supports Flow
          // if(this.filters.babel && !this.filters.flow) {
          babelPlugins.push('babel-plugin-transform-flow-strip-types');
          // }

          var jsFilter = (0, _gulpFilter2.default)(['client/**/*.js'], { restore: true });
          this.registerTransformStream([jsFilter, (0, _gulpBabel2.default)({
            plugins: babelPlugins.map(require.resolve),
            /* Babel get's confused about these if you're using an `npm link`ed
                generator-angular-fullstack, thus the `require.resolve` */
            // retainLines: true,
            babelrc: false // don't grab the generator's `.babelrc`
          }), (0, _gulpBeautify2.default)({
            "indent_size": 2,
            "indent_char": " ",
            "indent_level": 0,
            "indent_with_tabs": false,
            "preserve_newlines": true,
            "max_preserve_newlines": 10,
            "jslint_happy": false,
            "space_after_anon_function": false,
            "brace_style": "collapse",
            "keep_array_indentation": false,
            "keep_function_indentation": false,
            "space_before_conditional": true,
            "break_chained_methods": true,
            "eval_code": false,
            "unescape_strings": false,
            "wrap_line_length": 100,
            "wrap_attributes": "auto",
            "wrap_attributes_indent_size": 4,
            "end_with_newline": true
          }), jsFilter.restore]);

          var self = this;
          this.sourceRoot(_path2.default.join(__dirname, '../../templates/app'));
          this.processDirectory('.', '.');
        },
        generateEndpoint: function generateEndpoint() {
          var models;
          if (this.filters.mongooseModels) {
            models = 'mongoose';
          } else if (this.filters.sequelizeModels) {
            models = 'sequelize';
          }
          this.composeWith('angular-fullstack:endpoint', {
            options: {
              route: '/api/things',
              models: models
            },
            args: ['thing']
          });
        }
      };
    }
  }, {
    key: 'install',
    get: function get() {
      return {
        installDeps: function installDeps() {
          this.installDependencies({
            skipInstall: this.options['skip-install']
          });
        }
      };
    }
  }, {
    key: 'end',
    get: function get() {
      return {};
    }
  }]);

  return Generator;
}(_yeomanGenerator.Base);

module.exports = Generator;