<commit_before>'use strict';

import fs from 'fs';
import path from 'path';
import './core/think.js';

//babel not export default property
//so can not use `import babel from 'babel-core'`
let babel = require('babel-core');

export default class {
  /**
   * init
   * @param  {Object} options [project options]
   * @return {}         []
   */
  constructor(options = {}){
    //extend options to think
    think.extend(think, this.getPath(), options);
    //parse data from process arguments
    let i = 2;
    let argv = process.argv[i];
    //get app mode from argv
    if (argv === 'production' || argv === 'development' || argv === 'testing') {
      think.env = argv;
      i++;
    }
    argv = process.argv[i];
    //get port or cli url from argv
    if (argv) {
      if (/^\d+$/.test(argv)) {
        think.port = argv;
      }else{
        think.cli = argv;
      }
    }
    //get app mode
    think.mode = this.getMode();
  }
  /**
   * get app mode
   * @return {Number} [app mode]
   */
  getMode(){
    let filepath = `${think.APP_PATH}/${think.dirname.controller}`;
    if (think.isDir(filepath)) {
      let files = fs.readdirSync(filepath);
      let flag = files.some(file => {
        if (think.isDir(`${filepath}/${file}`)) {
          return true;
        }
      });
      return flag ? think.mode_normal : think.mode_mini;
    }
    return think.mode_module;
  }
  /**
   * get app path
   * @return {Object} []
   */
  getPath(){
    let filepath = process.argv[1];
    let ROOT_PATH = path.dirname(filepath);
    let APP_PATH = `${path.dirname(ROOT_PATH)}/app`;
    return {
      APP_PATH,
      RESOURCE_PATH: ROOT_PATH,
      ROOT_PATH
    };
  }
  /**
   * check node env
   * @return {Boolean} []
   */
  checkEnv(){
    this.checkNodeVersion();
  }
  /**
   * check node version
   * @return {} []
   */
  checkNodeVersion(){
    let packageFile = `${think.THINK_PATH}/package.json`;
    let {engines} = JSON.parse(fs.readFileSync(packageFile, 'utf-8'));
    let needVersion = engines.node.substr(2);

    let nodeVersion = process.version;
    if(nodeVersion[0] === 'v'){
      nodeVersion = nodeVersion.slice(1);
    }

    if(needVersion > nodeVersion){
      think.log(colors => {
        return `${colors.red('[ERROR]')} ThinkJS need node version >= ${needVersion}, current version is ${nodeVersion}, please upgrade it.`;
      });
      console.log();
      process.exit();
    }
  }
  /**
   * check application filename is lower
   * @return {} []
   */
  checkFileName(){
    let files = think.getFiles(think.APP_PATH);
    let reg = /\.(js|html|tpl)$/;
    let uppercaseReg = /[A-Z]+/;
    let filter = item => {
      if(!reg.test(item)){
        return;
      }
      //ignore files in config/locale
      if(item.indexOf(`/${think.dirname.locale}/`) > -1){
        return;
      }
      return true;
    };
    files.forEach(item => {
      if(filter(item) && uppercaseReg.test(item)){
        think.log(colors => {
          return colors.yellow(`[WARNING]`) + ` file \`${item}\` has uppercase chars.`;
        });
      }
    });
  }
  /**
   * get app module list
   * @return {} []
   */
  getModule(){
    //only have default module in mini mode
    if (think.mode === think.mode_mini) {
      think.module = [think.config('default_module')];
      return think.module;
    }
    let modulePath = think.APP_PATH;
    if (think.mode === think.mode_normal) {
      modulePath += `/${think.dirname.controller}`;
    }
    if(!think.isDir(modulePath)){
      return [];
    }
    let modules = fs.readdirSync(modulePath);
    let denyModuleList = think.config('deny_module_list') || [];
    if (denyModuleList.length > 0) {
      modules = modules.filter(module => {
        if (denyModuleList.indexOf(module) === -1) {
          return module;
        }
      });
    }
    think.module = modules;
    return modules;
  }
  /**
   * load alias
   * @return {} []
   */
  loadAlias(){
    let aliasPath = `${think.THINK_LIB_PATH}/config/sys/alias.js`;
    thinkCache(thinkCache.ALIAS, require(aliasPath));
  }
  /**
   * load alias module export
   * @return {} []
   */
  loadAliasExport(){
    var alias = thinkCache(thinkCache.ALIAS);
    for(let key in alias){
      if (thinkCache(thinkCache.ALIAS_EXPORT, key)) {
        continue;
      }
      thinkCache(thinkCache.ALIAS_EXPORT, key, think.require(key));
    }
  }
  /**
   * load config
   * @return {} []
   */
  loadConfig(){
    //sys config
    let config = think.getModuleConfig(true);
    //common module config
    let commonConfig = think.getModuleConfig();
    let configs = think.extend(config, commonConfig);
    thinkCache(thinkCache.CONFIG, configs);
    let modules = this.getModule();
    //load modules config
    modules.forEach(module => {
      think.getModuleConfig(module);
    });
  }
  /**
   * load route
   * @return {} []
   */
  loadRoute(){
    think.route();
  }
  /**
   * load adapter
   * @return {} []
   */
  loadAdapter(){
    think.loadAdapter();
  }
  /**
   * load middleware
   * @return {} []
   */
  loadMiddleware(){
    let paths = [
      `${think.THINK_LIB_PATH}/middleware`,
      `${think.getPath(undefined, think.dirname.middleware)}`
    ];
    think.alias('middleware', paths);
    //middleware base class
    think.middleware.base = think.require('middleware_base');
  }
  /**
   * load hook
   * @return {} []
   */
  loadHook(){
    let hookPath = `${think.THINK_LIB_PATH}/config/hook.js`;
    let hook = think.extend({}, require(hookPath));
    let file = `${think.getPath(undefined, think.dirname.config)}/hook.js`;
    let data = think.extend({}, think.safeRequire(file));
    let key, value;
    for(key in data){
      value = data[key];
      if (!(key in hook)) {
        hook[key] = data[key];
      }else if (value[0] === 'append' || value[0] === 'prepend') {
        let flag = value.shift();
        if (flag === 'append') {
          hook[key] = hook[key].concat(value);
        }else{
          hook[key] = value.concat(hook[key]);
        }
      }else{
        hook[key] = value;
      }
    }
    thinkCache(thinkCache.HOOK, hook);
  }
  /**
   * load controller, model, logic, service files
   * @return {} []
   */
  loadMVC(){
    let types = {
      model: ['base', 'relation', 'mongo', 'adv'],
      controller: ['base', 'rest'],
      logic: ['base'],
      service: ['base']
    };
    for(let type in types){
      think.alias(type, `${think.THINK_LIB_PATH}/${type}`);
      types[type].forEach(item => {
        think[type][item] = think.require(`${type}_${item}`);
      });
      think.module.forEach(module => {
        let moduleType = `${module}/${type}`;
        let filepath = think.getPath(module, think.dirname[type]);
        think.alias(moduleType, filepath, true);
      });
    }
  }
  /**
   * load bootstrap
   * @return {} []
   */
  loadBootstrap(){
    let paths = [
      `${think.THINK_LIB_PATH}/bootstrap`,
      `${think.APP_PATH}/${think.dirname.common}/${think.dirname.bootstrap}`
    ];
    paths.forEach(item => {
      if (!think.isDir(item)) {
        return;
      }
      let files = fs.readdirSync(item);
      files.forEach(file => {
        think.safeRequire(`${item}/${file}`);
      });
    });
  }
  /**
   * load template file
   * add template files to cache
   * @return {} []
   */
  loadTemplate(){
    let data = {};

    let add = filepath => {
      if (!think.isDir(filepath)) {
        return;
      }
      let files = think.getFiles(filepath);
      files.forEach(file => {
        let key = path.normalize(`${filepath}/${file}`);
        data[key] = true;
      });
    };
    let {root_path} = think.config('view');
    if(root_path){
      add(root_path);
    }else{
      think.module.forEach(module => {
        add(think.getPath(module, think.dirname.view));
      });
    }
    thinkCache(thinkCache.TEMPLATE, data);
  }
  /**
   * load system error message
   * @return {} []
   */
  loadError(){
    let message = require(think.THINK_LIB_PATH + '/config/sys/error.js');
    thinkCache(thinkCache.ERROR, message);
  }
  /**
   * load all config or modules
   * @return {} []
   */
  load(){
    //clear all cache for reload
    thinkCache(thinkCache.ALIAS, null);
    thinkCache(thinkCache.ALIAS_EXPORT, null);
    thinkCache(thinkCache.MODULE_CONFIG, null);

    this.loadConfig();
    this.loadRoute();
    this.loadAlias();
    this.loadAdapter();
    this.loadMiddleware();
    this.loadMVC();
    this.loadHook();
    this.loadTemplate();
    this.loadError();

    this.loadBootstrap();

    //load alias export at last
    //this.loadAliasExport();
  }
  /**
   * auto reload user modified files
   * @return {} []
   */
  autoReload(){
    let autoReload = thinkCache(thinkCache.AUTO_RELOAD);
    //clear file cache
    let clearFileCache = file => {
      let mod = require.cache[file];
      //remove from parent module
      if(mod && mod.parent){
        mod.parent.children.splice(mod.parent.children.indexOf(mod), 1);
      }
      //remove children
      if(mod && mod.children){
        mod.children.length = 0;
      }
      //remove require cache
      require.cache[file] = null;
    };
    /**
     * log reload file
     * @param  {String} file []
     * @return {}      []
     */
    let log = file => {
      if(!think.config('log_auto_reload')){
        return;
      }
      file = file.slice(think.APP_PATH.length);
      think.log(`reload file ${file}`, 'RELOAD');
    };

    /**
     * check change form cache
     * @return {} []
     */
    let checkCacheChange = () => {
      let hasChange = false;
      for(let file in require.cache){
        if(!think.isFile(file)){
          clearFileCache(file);
          continue;
        }
        let mTime = fs.statSync(file).mtime.getTime();
        if(!autoReload[file]){
          autoReload[file] = mTime;
          continue;
        }
        if(mTime > autoReload[file]){
          clearFileCache(file);
          autoReload[file] = mTime;
          hasChange = true;
          log(file);
        }
      }
      return hasChange;
    };
    /**
     * check change from file
     * @return {} []
     */
    let prevFilesLength = 0;
    let checkFileChange = () => {
      let nowFilesLength = think.getFiles(think.APP_PATH).filter(file => {
        let extname = path.extname(file);
        return extname === '.js';
      }).length;
      let flag = prevFilesLength === nowFilesLength;
      prevFilesLength = nowFilesLength;
      return flag;
    };

    setInterval(() => {
      let hasChange = checkCacheChange() || checkFileChange();
      if(hasChange){
        this.load();
      }
    }, 200);
  }
  /**
   * capture error
   * @return {} []
   */
  captureError(){
    process.on('uncaughtException', function(err){
      let msg = err.message;
      err = think.error(err, 'port:' + think.config('port'));
      think.log(err);
      if(msg.indexOf(' EADDRINUSE ') > -1){
        process.exit();
      }
    });
  }
  /**
   * start
   * @return {} []
   */
  start(){
    this.checkEnv();
    this.checkFileName();
    this.load();
    this.captureError();
    if (think.config('auto_reload')) {
      this.autoReload();
    }
  }
  /**
   * run
   * @return {} []
   */
  run(){
    this.start();
    return think.require('app').run();
  }
  /**
   * use babel compile code
   * @return {} []
   */
  compile(srcPath, outPath, stopWatch){
    srcPath = srcPath || `${think.ROOT_PATH}/src`;
    outPath = outPath || `${think.ROOT_PATH}/app`;

    if(!think.isDir(srcPath)){
      return;
    }

    think.autoCompile = true;

    //store compiled files last mtime
    let compiledMtime = {};

    //compile single file
    let compileFile = (file, onlyCopy) => {
      let filePath = `${srcPath}/${file}`;
      let content = fs.readFileSync(filePath, 'utf8');
      if(!content){
        return;
      }
      if(onlyCopy){
        fs.writeFileSync(`${outPath}/${file}`, content);
        return;
      }
      let startTime = Date.now();
      try{
        let data = babel.transform(content, {
          retainLines: true,
          stage: 0,
          modules: 'common',
          loose: true,
          optional: 'runtime'
        });
        think.log(`compile file ${file}`, 'BABEL', startTime);
        think.mkdir(path.dirname(`${outPath}/${file}`));
        fs.writeFileSync(`${outPath}/${file}`, data.code);
      }catch(e){
        think.log(colors => {
          return colors.red(`compile file ${file} error`);
        }, 'BABEL');
        think.log(e);
      }
    };

    let fn = () => {
      let files = think.getFiles(srcPath);
      files.forEach(function(file){
        var extname = path.extname(file);
        if(extname !== '.js'){
          compileFile(file, true);
          return;
        }
        var mTime = fs.statSync(`${srcPath}/${file}`).mtime.getTime();
        if(!compiledMtime[file] || mTime > compiledMtime[file]){
          compileFile(file);
          compiledMtime[file] = mTime;
          return;
        }
      });
    };

    if(stopWatch){
      fn();
    }else{
      setInterval(fn, 100);
    }
  }
  /**
   * load, convenient for plugins
   * @return {} []
   */
  static load(){
    let instance = new this();
    instance.load();
  }
}<commit_msg>check some config must be set in common module<commit_after>'use strict';

import fs from 'fs';
import path from 'path';
import './core/think.js';

//babel not export default property
//so can not use `import babel from 'babel-core'`
let babel = require('babel-core');

export default class {
  /**
   * init
   * @param  {Object} options [project options]
   * @return {}         []
   */
  constructor(options = {}){
    //extend options to think
    think.extend(think, this.getPath(), options);
    //parse data from process arguments
    let i = 2;
    let argv = process.argv[i];
    //get app mode from argv
    if (argv === 'production' || argv === 'development' || argv === 'testing') {
      think.env = argv;
      i++;
    }
    argv = process.argv[i];
    //get port or cli url from argv
    if (argv) {
      if (/^\d+$/.test(argv)) {
        think.port = argv;
      }else{
        think.cli = argv;
      }
    }
    //get app mode
    think.mode = this.getMode();
  }
  /**
   * get app mode
   * @return {Number} [app mode]
   */
  getMode(){
    let filepath = `${think.APP_PATH}/${think.dirname.controller}`;
    if (think.isDir(filepath)) {
      let files = fs.readdirSync(filepath);
      let flag = files.some(file => {
        if (think.isDir(`${filepath}/${file}`)) {
          return true;
        }
      });
      return flag ? think.mode_normal : think.mode_mini;
    }
    return think.mode_module;
  }
  /**
   * get app path
   * @return {Object} []
   */
  getPath(){
    let filepath = process.argv[1];
    let ROOT_PATH = path.dirname(filepath);
    let APP_PATH = `${path.dirname(ROOT_PATH)}/app`;
    return {
      APP_PATH,
      RESOURCE_PATH: ROOT_PATH,
      ROOT_PATH
    };
  }
  /**
   * check node env
   * @return {Boolean} []
   */
  checkEnv(){
    this.checkNodeVersion();
  }
  /**
   * check node version
   * @return {} []
   */
  checkNodeVersion(){
    let packageFile = `${think.THINK_PATH}/package.json`;
    let {engines} = JSON.parse(fs.readFileSync(packageFile, 'utf-8'));
    let needVersion = engines.node.substr(2);

    let nodeVersion = process.version;
    if(nodeVersion[0] === 'v'){
      nodeVersion = nodeVersion.slice(1);
    }

    if(needVersion > nodeVersion){
      think.log(colors => {
        return `${colors.red('[ERROR]')} ThinkJS need node version >= ${needVersion}, current version is ${nodeVersion}, please upgrade it.`;
      });
      console.log();
      process.exit();
    }
  }
  /**
   * check application filename is lower
   * @return {} []
   */
  checkFileName(){
    let files = think.getFiles(think.APP_PATH);
    let reg = /\.(js|html|tpl)$/;
    let uppercaseReg = /[A-Z]+/;
    let filter = item => {
      if(!reg.test(item)){
        return;
      }
      //ignore files in config/locale
      if(item.indexOf(`/${think.dirname.locale}/`) > -1){
        return;
      }
      return true;
    };
    files.forEach(item => {
      if(filter(item) && uppercaseReg.test(item)){
        think.log(colors => {
          return colors.yellow(`[WARNING]`) + ` file \`${item}\` has uppercase chars.`;
        });
      }
    });
  }
  /**
   * get app module list
   * @return {} []
   */
  getModule(){
    //only have default module in mini mode
    if (think.mode === think.mode_mini) {
      think.module = [think.config('default_module')];
      return think.module;
    }
    let modulePath = think.APP_PATH;
    if (think.mode === think.mode_normal) {
      modulePath += `/${think.dirname.controller}`;
    }
    if(!think.isDir(modulePath)){
      return [];
    }
    let modules = fs.readdirSync(modulePath);
    let denyModuleList = think.config('deny_module_list') || [];
    if (denyModuleList.length > 0) {
      modules = modules.filter(module => {
        if (denyModuleList.indexOf(module) === -1) {
          return module;
        }
      });
    }
    think.module = modules;
    return modules;
  }
  /**
   * load alias
   * @return {} []
   */
  loadAlias(){
    let aliasPath = `${think.THINK_LIB_PATH}/config/sys/alias.js`;
    thinkCache(thinkCache.ALIAS, require(aliasPath));
  }
  /**
   * load alias module export
   * @return {} []
   */
  loadAliasExport(){
    var alias = thinkCache(thinkCache.ALIAS);
    for(let key in alias){
      if (thinkCache(thinkCache.ALIAS_EXPORT, key)) {
        continue;
      }
      thinkCache(thinkCache.ALIAS_EXPORT, key, think.require(key));
    }
  }
  /**
   * load config
   * @return {} []
   */
  loadConfig(){
    //sys config
    let config = think.getModuleConfig(true);
    //common module config
    let commonConfig = think.getModuleConfig();
    let configs = think.extend(config, commonConfig);
    thinkCache(thinkCache.CONFIG, configs);
    let modules = this.getModule();

    //load modules config
    modules.forEach(module => {
      think.getModuleConfig(module);
    });
  }
  /**
   * check module config
   * @return {} []
   */
  checkModuleConfig(){
    // check module config
    // some config must be set in common module
    let keys = [], errorKey = 'error_config_key';
    let errorConfigKeys = thinkCache(thinkCache.COLLECTION, errorKey);
    if(think.isEmpty(errorConfigKeys)){
      thinkCache(thinkCache.COLLECTION, errorKey, []);
      errorConfigKeys = thinkCache(thinkCache.COLLECTION, errorKey);
    }

    let checkModuleConfig = module => {
      if(keys.length === 0){
        keys = Object.keys(require(`${think.THINK_LIB_PATH}/config/config.js`));
      }
      let configFilePath = think.getPath(module, think.dirname.config) + '/config.js';
      if(!think.isFile(configFilePath)){
        return;
      }
      let config = require(configFilePath);
      keys.forEach(key => {
        if(config[key] && errorConfigKeys.indexOf(key) === -1){
          errorConfigKeys.push(key);
          think.log(colors => {
            return colors.red(`config key \`${key}\` can not be set in \`${module}\` module, must be set in \`common\` module`);
          }, 'CONFIG');
        }
      });
    };

    let modules = this.getModule();
    //load modules config
    modules.forEach(module => {
      if(think.mode === think.mode_module && module !== 'common'){
        checkModuleConfig(module);
      }
    });
  }
  /**
   * load route
   * @return {} []
   */
  loadRoute(){
    think.route();
  }
  /**
   * load adapter
   * @return {} []
   */
  loadAdapter(){
    think.loadAdapter();
  }
  /**
   * load middleware
   * @return {} []
   */
  loadMiddleware(){
    let paths = [
      `${think.THINK_LIB_PATH}/middleware`,
      `${think.getPath(undefined, think.dirname.middleware)}`
    ];
    think.alias('middleware', paths);
    //middleware base class
    think.middleware.base = think.require('middleware_base');
  }
  /**
   * load hook
   * @return {} []
   */
  loadHook(){
    let hookPath = `${think.THINK_LIB_PATH}/config/hook.js`;
    let hook = think.extend({}, require(hookPath));
    let file = `${think.getPath(undefined, think.dirname.config)}/hook.js`;
    let data = think.extend({}, think.safeRequire(file));
    let key, value;
    for(key in data){
      value = data[key];
      if (!(key in hook)) {
        hook[key] = data[key];
      }else if (value[0] === 'append' || value[0] === 'prepend') {
        let flag = value.shift();
        if (flag === 'append') {
          hook[key] = hook[key].concat(value);
        }else{
          hook[key] = value.concat(hook[key]);
        }
      }else{
        hook[key] = value;
      }
    }
    thinkCache(thinkCache.HOOK, hook);
  }
  /**
   * load controller, model, logic, service files
   * @return {} []
   */
  loadMVC(){
    let types = {
      model: ['base', 'relation', 'mongo', 'adv'],
      controller: ['base', 'rest'],
      logic: ['base'],
      service: ['base']
    };
    for(let type in types){
      think.alias(type, `${think.THINK_LIB_PATH}/${type}`);
      types[type].forEach(item => {
        think[type][item] = think.require(`${type}_${item}`);
      });
      think.module.forEach(module => {
        let moduleType = `${module}/${type}`;
        let filepath = think.getPath(module, think.dirname[type]);
        think.alias(moduleType, filepath, true);
      });
    }
  }
  /**
   * load bootstrap
   * @return {} []
   */
  loadBootstrap(){
    let paths = [
      `${think.THINK_LIB_PATH}/bootstrap`,
      `${think.APP_PATH}/${think.dirname.common}/${think.dirname.bootstrap}`
    ];
    paths.forEach(item => {
      if (!think.isDir(item)) {
        return;
      }
      let files = fs.readdirSync(item);
      files.forEach(file => {
        think.safeRequire(`${item}/${file}`);
      });
    });
  }
  /**
   * load template file
   * add template files to cache
   * @return {} []
   */
  loadTemplate(){
    let data = {};

    let add = filepath => {
      if (!think.isDir(filepath)) {
        return;
      }
      let files = think.getFiles(filepath);
      files.forEach(file => {
        let key = path.normalize(`${filepath}/${file}`);
        data[key] = true;
      });
    };
    let {root_path} = think.config('view');
    if(root_path){
      add(root_path);
    }else{
      think.module.forEach(module => {
        add(think.getPath(module, think.dirname.view));
      });
    }
    thinkCache(thinkCache.TEMPLATE, data);
  }
  /**
   * load system error message
   * @return {} []
   */
  loadError(){
    let message = require(think.THINK_LIB_PATH + '/config/sys/error.js');
    thinkCache(thinkCache.ERROR, message);
  }
  /**
   * load all config or modules
   * @return {} []
   */
  load(){
    //clear all cache for reload
    thinkCache(thinkCache.ALIAS, null);
    thinkCache(thinkCache.ALIAS_EXPORT, null);
    thinkCache(thinkCache.MODULE_CONFIG, null);

    this.loadConfig();
    this.loadRoute();
    this.loadAlias();
    this.loadAdapter();
    this.loadMiddleware();
    this.loadMVC();
    this.loadHook();
    this.loadTemplate();
    this.loadError();

    this.loadBootstrap();

    this.checkModuleConfig();

    //load alias export at last
    //this.loadAliasExport();
  }
  /**
   * auto reload user modified files
   * @return {} []
   */
  autoReload(){
    let autoReload = thinkCache(thinkCache.AUTO_RELOAD);
    //clear file cache
    let clearFileCache = file => {
      let mod = require.cache[file];
      //remove from parent module
      if(mod && mod.parent){
        mod.parent.children.splice(mod.parent.children.indexOf(mod), 1);
      }
      //remove children
      if(mod && mod.children){
        mod.children.length = 0;
      }
      //remove require cache
      require.cache[file] = null;
    };
    /**
     * log reload file
     * @param  {String} file []
     * @return {}      []
     */
    let log = file => {
      if(!think.config('log_auto_reload') || !file){
        return;
      }
      //only log app files changed
      if(file.indexOf(think.APP_PATH) === 0){
        file = file.slice(think.APP_PATH.length);
        think.log(`reload file ${file}`, 'RELOAD');
      }
    };

    /**
     * check change form cache
     * @return {} []
     */
    let checkCacheChange = () => {
      let hasChange = false;
      for(let file in require.cache){
        if(!think.isFile(file)){
          clearFileCache(file);
          continue;
        }
        let mTime = fs.statSync(file).mtime.getTime();
        if(!autoReload[file]){
          autoReload[file] = mTime;
          continue;
        }
        if(mTime > autoReload[file]){
          clearFileCache(file);
          autoReload[file] = mTime;
          hasChange = true;
          log(file);
        }
      }
      return hasChange;
    };
    /**
     * check change from file
     * @return {} []
     */
    let prevFilesLength = 0;
    let checkFileChange = () => {
      let nowFilesLength = think.getFiles(think.APP_PATH).filter(file => {
        let extname = path.extname(file);
        return extname === '.js';
      }).length;
      let flag = prevFilesLength === nowFilesLength;
      prevFilesLength = nowFilesLength;
      return flag;
    };

    setInterval(() => {
      let hasChange = checkCacheChange() || checkFileChange();
      if(hasChange){
        this.load();
      }
    }, 200);
  }
  /**
   * capture error
   * @return {} []
   */
  captureError(){
    process.on('uncaughtException', function(err){
      let msg = err.message;
      err = think.error(err, 'port:' + think.config('port'));
      think.log(err);
      if(msg.indexOf(' EADDRINUSE ') > -1){
        process.exit();
      }
    });
  }
  /**
   * start
   * @return {} []
   */
  start(){
    this.checkEnv();
    this.checkFileName();
    this.load();
    this.captureError();
    if (think.config('auto_reload')) {
      this.autoReload();
    }
  }
  /**
   * run
   * @return {} []
   */
  run(){
    this.start();
    return think.require('app').run();
  }
  /**
   * use babel compile code
   * @return {} []
   */
  compile(srcPath, outPath, disableWatch){
    srcPath = srcPath || `${think.ROOT_PATH}/src`;
    outPath = outPath || `${think.ROOT_PATH}/app`;

    if(!think.isDir(srcPath)){
      return;
    }

    think.autoCompile = true;

    //store compiled files last mtime
    let compiledMtime = {};

    //compile single file
    let compileFile = (file, onlyCopy) => {
      let filePath = `${srcPath}/${file}`;
      let content = fs.readFileSync(filePath, 'utf8');
      if(!content){
        return;
      }
      if(onlyCopy){
        fs.writeFileSync(`${outPath}/${file}`, content);
        return;
      }
      let startTime = Date.now();
      try{
        let data = babel.transform(content, {
          retainLines: true,
          stage: 0,
          modules: 'common',
          loose: true,
          optional: 'runtime'
        });
        think.log(`compile file ${file}`, 'BABEL', startTime);
        think.mkdir(path.dirname(`${outPath}/${file}`));
        fs.writeFileSync(`${outPath}/${file}`, data.code);
      }catch(e){
        think.log(colors => {
          return colors.red(`compile file ${file} error`);
        }, 'BABEL');
        think.log(e);
      }
    };

    let fn = () => {
      let files = think.getFiles(srcPath);
      files.forEach(function(file){
        var extname = path.extname(file);
        if(extname !== '.js'){
          compileFile(file, true);
          return;
        }
        var mTime = fs.statSync(`${srcPath}/${file}`).mtime.getTime();
        if(!compiledMtime[file] || mTime > compiledMtime[file]){
          compileFile(file);
          compiledMtime[file] = mTime;
          return;
        }
      });
    };

    if(disableWatch){
      fn();
    }else{
      setInterval(fn, 100);
    }
  }
  /**
   * load, convenient for plugins
   * @return {} []
   */
  static load(){
    let instance = new this();
    instance.load();
  }
}<|endoftext|>


<commit_before>const fs = require('fs');
const { COPYFILE_EXCL } = fs.constants;

fs.copyFile('.eslintrc', '../../.eslintrc', COPYFILE_EXCL, (err) => {
    if (err) console.log('Preserving .eslintrc file found at ' + cwd);
});<commit_msg>Fixes error message<commit_after>const cwd = require('path').resolve();
const fs = require('fs');
const { COPYFILE_EXCL } = fs.constants;

fs.copyFile('.eslintrc', '../../.eslintrc', COPYFILE_EXCL, (err) => {
    if (err) console.log('Preserving .eslintrc file found at ' + cwd);
});<|endoftext|>


<commit_before>import {Server as WebSocketServer} from 'ws';
import {Promise} from 'bluebird';
import {Connection} from './Connection';
import {QueryValidator} from './QueryValidator';
import rethinkdb from 'rethinkdb';

// Make sure to import r from rethinkdb-websocket-server instead of directly
// from rethinkdb to ensure you're using the same instance of the library when
// defining whitelisted queries.
export const r = rethinkdb;

// Use RP to construct query patterns for queryWhitelist. See
// WhitelistSyntax.js and QueryValidator.js for more information.
export {ReqlPattern as RP} from './WhitelistSyntax';

// Use RQ to construct query patterns for queryWhitelist. See QueryParser.js and
// QueryValidator.js for more information.
//
// This syntax is deprecated as of 0.4 and will be removed in a future version.
// Use vanilla ReQL syntax with RP from WhitelistSyntax.js instead.
export {RQ} from './QueryParser';

// Start a WebSocket server attached to the specified http.Server instance.
// Incoming WebSocket connections will parse incoming RethinkDB queries and
// forward them to the specified RethinkDB TCP address. Queries that don't pass
// validation of the queryWhitelist will not be forwarded.
//
// Return the underlying WebSocketServer object. This behavior is subject to change
// if the underlying transport library used in rethinkdb-websocket-server changes.
export function listen({

  // http.Server object, for new ws.Server({server: ...})
  httpServer,

  // HTTP path to listen on, for new ws.Server({path: ...})
  httpPath = '/',

  // RethinkDB host to connect to
  dbHost = 'localhost',

  // RethinkDB port to connect to
  dbPort = 28015,

  // RethinkDB authKey for authenticated connections
  dbAuthKey = null,

  // For TLS connections to RethinkDB, equivalent to ssl argument in r.connect
  dbSsl = false,

  // List of pattern RQs, where an incoming query must match at least one
  // (see QueryValidator.js)
  queryWhitelist = [],

  // If true, all queries pass validation regardless of queryWhitelist
  unsafelyAllowAnyQuery = false,

  // Function from URL query params object to promise that resolves to an
  // arbitrary session object. Session objects will be available during query
  // validation.
  sessionCreator = (urlQueryParams) => Promise.resolve({}),

  // Specify how much to log to the console
  // - 'all' logs everything
  // - 'denied' logs queries that aren't in the query whitelist
  // - 'none' logs nothing, other than exception stack traces
  loggingMode = 'all',

}) {
  const wsServer = new WebSocketServer({
    server: httpServer,
    path: httpPath,
    perMessageDeflate: false, // necessary due to https://github.com/websockets/ws/issues/523
  });
  const queryValidator = new QueryValidator({
    queryWhitelist,
    unsafelyAllowAnyQuery,
    loggingMode,
  });
  wsServer.on('connection', webSocket => {
    const connection = new Connection(queryValidator, webSocket, loggingMode);
    connection.start({sessionCreator, dbHost, dbPort, dbAuthKey, dbSsl});
  });
  return wsServer;
}
<commit_msg>Compression support for WebSocket (#31)<commit_after>import {Server as WebSocketServer} from 'ws';
import {Promise} from 'bluebird';
import {Connection} from './Connection';
import {QueryValidator} from './QueryValidator';
import rethinkdb from 'rethinkdb';

// Make sure to import r from rethinkdb-websocket-server instead of directly
// from rethinkdb to ensure you're using the same instance of the library when
// defining whitelisted queries.
export const r = rethinkdb;

// Use RP to construct query patterns for queryWhitelist. See
// WhitelistSyntax.js and QueryValidator.js for more information.
export {ReqlPattern as RP} from './WhitelistSyntax';

// Use RQ to construct query patterns for queryWhitelist. See QueryParser.js and
// QueryValidator.js for more information.
//
// This syntax is deprecated as of 0.4 and will be removed in a future version.
// Use vanilla ReQL syntax with RP from WhitelistSyntax.js instead.
export {RQ} from './QueryParser';

// Start a WebSocket server attached to the specified http.Server instance.
// Incoming WebSocket connections will parse incoming RethinkDB queries and
// forward them to the specified RethinkDB TCP address. Queries that don't pass
// validation of the queryWhitelist will not be forwarded.
//
// Return the underlying WebSocketServer object. This behavior is subject to change
// if the underlying transport library used in rethinkdb-websocket-server changes.
export function listen({

  // http.Server object, for new ws.Server({server: ...})
  httpServer,

  // HTTP path to listen on, for new ws.Server({path: ...})
  httpPath = '/',

  // RethinkDB host to connect to
  dbHost = 'localhost',

  // RethinkDB port to connect to
  dbPort = 28015,

  // RethinkDB authKey for authenticated connections
  dbAuthKey = null,

  // For TLS connections to RethinkDB, equivalent to ssl argument in r.connect
  dbSsl = false,

  // List of pattern RQs, where an incoming query must match at least one
  // (see QueryValidator.js)
  queryWhitelist = [],

  // If true, all queries pass validation regardless of queryWhitelist
  unsafelyAllowAnyQuery = false,

  // Function from URL query params object to promise that resolves to an
  // arbitrary session object. Session objects will be available during query
  // validation.
  sessionCreator = (urlQueryParams) => Promise.resolve({}),

  // Specify how much to log to the console
  // - 'all' logs everything
  // - 'denied' logs queries that aren't in the query whitelist
  // - 'none' logs nothing, other than exception stack traces
  loggingMode = 'all',

}) {
  const wsServer = new WebSocketServer({
    server: httpServer,
    path: httpPath,
    perMessageDeflate: true,
  });
  const queryValidator = new QueryValidator({
    queryWhitelist,
    unsafelyAllowAnyQuery,
    loggingMode,
  });
  wsServer.on('connection', webSocket => {
    const connection = new Connection(queryValidator, webSocket, loggingMode);
    connection.start({sessionCreator, dbHost, dbPort, dbAuthKey, dbSsl});
  });
  return wsServer;
}
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import lottie from 'lottie-web';

export default class Lottie extends React.Component {
  componentDidMount() {
    const {
      options: {
        loop,
        autoplay,
        animationData,
        rendererSettings
      },
      eventListeners,
    } = this.props;

    this.options = {
      container: this.el,
      renderer: 'svg',
      loop: loop !== false,
      autoplay: autoplay !== false,
      animationData,
      rendererSettings,
    };

    this.anim = lottie.loadAnimation(this.options);
    this.registerEvents(eventListeners);
  }

  componentWillUpdate(nextProps /* , nextState */) {
    /* Recreate the animation handle if the data is changed */
    if (this.options.animationData !== nextProps.options.animationData) {
      this.deRegisterEvents(this.props.eventListeners);
      this.destroy();
      this.options.animationData = nextProps.options.animationData;
      this.anim = lottie.loadAnimation(this.options);
      this.registerEvents(nextProps.eventListeners);
    }
  }

  componentDidUpdate() {
    this.props.isStopped ? this.stop() : this.play();
    this.pause();
    this.setSpeed();
    this.setDirection();
  }

  componentWillUnmount() {
    this.deRegisterEvents(this.props.eventListeners);
    this.destroy();
    this.options.animationData = null;
    this.anim = null;
  }

  setSpeed() {
    this.anim.setSpeed(this.props.speed);
  }

  setDirection() {
    this.anim.setDirection(this.props.direction);
  }

  play() {
    this.anim.play();
  }

  stop() {
    this.anim.stop();
  }

  pause() {
    if (this.props.isPaused && !this.anim.isPaused) {
      this.anim.pause();
    } else if (!this.props.isPaused && this.anim.isPaused) {
      this.anim.pause();
    }
  }

  destroy() {
    this.anim.destroy();
  }

  registerEvents(eventListeners) {
    eventListeners.forEach((eventListener) => {
      this.anim.addEventListener(eventListener.eventName, eventListener.callback);
    });
  }

  deRegisterEvents(eventListeners) {
    eventListeners.forEach((eventListener) => {
      this.anim.removeEventListener(eventListener.eventName, eventListener.callback);
    });
  }

  render() {
    const {width, height} = this.props;

    const getSize = (initial) => {
      let size;

      if (typeof initial === 'number') {
        size = `${initial}px`;
      } else {
        size = initial || '100%';
      }

      return size;
    };

    const lottieStyles = {
      width: getSize(width),
      height: getSize(height),
      overflow: 'hidden',
      margin: '0 auto',
    };

    return (
      <div
        ref={(c) => {
          this.el = c;
        }}
        style={lottieStyles}
      />
    );
  }
}

Lottie.propTypes = {
  eventListeners: PropTypes.arrayOf(PropTypes.object),
  options: PropTypes.object.isRequired,
  height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  isStopped: PropTypes.bool,
  isPaused: PropTypes.bool,
  speed: PropTypes.number,
  direction: PropTypes.number,
};

Lottie.defaultProps = {
  eventListeners: [],
  isStopped: false,
  isPaused: false,
  speed: 1,
};
<commit_msg>fix(ComponentWillUpdate) keep options received with new animation - this will make it so you can transition to a new animation with any options<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import lottie from 'lottie-web';

export default class Lottie extends React.Component {
  componentDidMount() {
    const {
      options: {
        loop,
        autoplay,
        animationData,
        rendererSettings
      },
      eventListeners,
    } = this.props;

    this.options = {
      container: this.el,
      renderer: 'svg',
      loop: loop !== false,
      autoplay: autoplay !== false,
      animationData,
      rendererSettings,
    };

    this.anim = lottie.loadAnimation(this.options);
    this.registerEvents(eventListeners);
  }

  componentWillUpdate(nextProps /* , nextState */) {
    /* Recreate the animation handle if the data is changed */
    if (this.options.animationData !== nextProps.options.animationData) {
      this.deRegisterEvents(this.props.eventListeners);
      this.destroy();
      this.options = {...this.options, ...nextProps.options};
      this.anim = lottie.loadAnimation(this.options);
      this.registerEvents(nextProps.eventListeners);
    }
  }

  componentDidUpdate() {
    this.props.isStopped ? this.stop() : this.play();
    this.pause();
    this.setSpeed();
    this.setDirection();
  }

  componentWillUnmount() {
    this.deRegisterEvents(this.props.eventListeners);
    this.destroy();
    this.options.animationData = null;
    this.anim = null;
  }

  setSpeed() {
    this.anim.setSpeed(this.props.speed);
  }

  setDirection() {
    this.anim.setDirection(this.props.direction);
  }

  play() {
    this.anim.play();
  }

  stop() {
    this.anim.stop();
  }

  pause() {
    if (this.props.isPaused && !this.anim.isPaused) {
      this.anim.pause();
    } else if (!this.props.isPaused && this.anim.isPaused) {
      this.anim.pause();
    }
  }

  destroy() {
    this.anim.destroy();
  }

  registerEvents(eventListeners) {
    eventListeners.forEach((eventListener) => {
      this.anim.addEventListener(eventListener.eventName, eventListener.callback);
    });
  }

  deRegisterEvents(eventListeners) {
    eventListeners.forEach((eventListener) => {
      this.anim.removeEventListener(eventListener.eventName, eventListener.callback);
    });
  }

  render() {
    const {width, height} = this.props;

    const getSize = (initial) => {
      let size;

      if (typeof initial === 'number') {
        size = `${initial}px`;
      } else {
        size = initial || '100%';
      }

      return size;
    };

    const lottieStyles = {
      width: getSize(width),
      height: getSize(height),
      overflow: 'hidden',
      margin: '0 auto',
    };

    return (
      <div
        ref={(c) => {
          this.el = c;
        }}
        style={lottieStyles}
      />
    );
  }
}

Lottie.propTypes = {
  eventListeners: PropTypes.arrayOf(PropTypes.object),
  options: PropTypes.object.isRequired,
  height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  isStopped: PropTypes.bool,
  isPaused: PropTypes.bool,
  speed: PropTypes.number,
  direction: PropTypes.number,
};

Lottie.defaultProps = {
  eventListeners: [],
  isStopped: false,
  isPaused: false,
  speed: 1,
};
<|endoftext|>


<commit_before>// registerapp.js
//
// Make a new app key and secret
//
// Copyright 2012, StatusNet Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

var _ = require('underscore'),
    postArgs = require('common').postArgs;

var argv = require('optimist')
        .usage("Usage: $0 -t title -e email [-w|-n]")
        .demand(['t'])
        .alias('t', 'title')
        .alias('e', 'email')
        .alias('w', 'web')
        .alias('n', 'native')
        .alias('s', 'server')
        .alias('P', 'port')
        .describe('t', "Title of the app")
        .describe('e', "Contact email")
        .describe('w', "Web application")
        .describe('n', "Native application")
        .describe('s', "Server name (default 'localhost')")
        .describe('P', "Port (default 8001)")
        .default('P', 8001)
        .default('s', 'localhost')
        .argv;

var server = argv.server,
    port = argv.port;

var args = {
    type: 'client_associate',
    application_name: argv.title
};

if (argv.web) {
    args.application_type = 'web';
} else if (argv['native']) {
    args.application_type = 'native';
}

if (argv.email) {
    args.contacts = argv.email;
};

postArgs('http://'+server+':'+port+'/api/client/register', args, function(err, res, body) {
    if (err) {
        console.error(err);
    } else {
        console.log(body);
    }
});
<commit_msg>common module local to this dir<commit_after>// registerapp.js
//
// Make a new app key and secret
//
// Copyright 2012, StatusNet Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

var _ = require('underscore'),
    postArgs = require('./common').postArgs;

var argv = require('optimist')
        .usage("Usage: $0 -t title -e email [-w|-n]")
        .demand(['t'])
        .alias('t', 'title')
        .alias('e', 'email')
        .alias('w', 'web')
        .alias('n', 'native')
        .alias('s', 'server')
        .alias('P', 'port')
        .describe('t', "Title of the app")
        .describe('e', "Contact email")
        .describe('w', "Web application")
        .describe('n', "Native application")
        .describe('s', "Server name (default 'localhost')")
        .describe('P', "Port (default 8001)")
        .default('P', 8001)
        .default('s', 'localhost')
        .argv;

var server = argv.server,
    port = argv.port;

var args = {
    type: 'client_associate',
    application_name: argv.title
};

if (argv.web) {
    args.application_type = 'web';
} else if (argv['native']) {
    args.application_type = 'native';
}

if (argv.email) {
    args.contacts = argv.email;
};

postArgs('http://'+server+':'+port+'/api/client/register', args, function(err, res, body) {
    if (err) {
        console.error(err);
    } else {
        console.log(body);
    }
});
<|endoftext|>


<commit_before>'use strict';
var assert = require('assert');
var helpers = require('./helpers');
var Flow = require('../lib/flow.js');
var ConfigWriter = require('../lib/configwriter.js');

describe('ConfigWriter', function () {
  before(helpers.directory('temp'));

  describe('constructor', function () {
    it('should check it\'s input');

    it('should allow for user-defined steps per block type', function () {
      var copy = {
        name: 'copy',
        createConfig: function () {
          return {};
        }
      };

      var flow = new Flow({
        steps: {
          js: ['concat', 'uglify', copy]
        },
        post: {}
      });
      var cfgw = new ConfigWriter(flow, {
        input: 'app',
        dest: 'dist',
        staging: '.tmp'
      });
      var stepNames = [];
      cfgw.stepWriters('js').forEach(function (s) {
        stepNames.push(s.name);
      });
      assert.deepEqual(stepNames, ['concat', 'uglify', 'copy']);
    });

    it('should use in and out dirs');
  });

  describe('process', function () {
    var blocks = helpers.blocks();

    it('should check for input parameters');

    it('should output a set of config', function () {
      var flow = new Flow({
        steps: {
          js: ['concat', 'uglify']
        }
      });
      var file = helpers.createFile('foo', 'app', blocks);
      var c = new ConfigWriter(flow, {
        input: 'app',
        dest: 'dist',
        staging: '.tmp'
      });
      var config = c.process(file);
      var expected = helpers.normalize({
        concat: {
          generated: {
            files: [{
              dest: '.tmp/concat/scripts/site.js',
              src: ['app/foo.js', 'app/bar.js', 'app/baz.js']
            }]
          }
        },
        uglify: {
          generated: {
            files: [{
              dest: 'dist/scripts/site.js',
              src: ['.tmp/concat/scripts/site.js']
            }]
          }
        }
      });

      assert.deepEqual(config, expected);
    });

    it('should have a configurable destination directory', function () {
      var flow = new Flow({
        steps: {
          js: ['concat', 'uglify']
        }
      });

      var file = helpers.createFile('foo', 'app', blocks);
      var c = new ConfigWriter(flow, {
        input: 'app',
        dest: 'destination',
        staging: '.tmp'
      });
      var config = c.process(file);
      var expected = helpers.normalize({
        concat: {
          generated: {
            files: [{
              dest: '.tmp/concat/scripts/site.js',
              src: ['app/foo.js', 'app/bar.js', 'app/baz.js']
            }]
          }
        },
        uglify: {
          generated: {
            files: [{
              dest: 'destination/scripts/site.js',
              src: ['.tmp/concat/scripts/site.js']
            }]
          }
        }
      });

      assert.deepEqual(config, expected);
    });

    it('should have a configurable staging directory', function () {
      var flow = new Flow({
        steps: {
          js: ['concat', 'uglify']
        }
      });

      var file = helpers.createFile('foo', 'app', blocks);
      var c = new ConfigWriter(flow, {
        input: 'app',
        dest: 'dist',
        staging: 'staging'
      });
      var config = c.process(file);
      var expected = helpers.normalize({
        concat: {
          generated: {
            files: [{
              dest: 'staging/concat/scripts/site.js',
              src: ['app/foo.js', 'app/bar.js', 'app/baz.js']
            }]
          }
        },
        uglify: {
          generated: {
            files: [{
              dest: 'dist/scripts/site.js',
              src: ['staging/concat/scripts/site.js']
            }]
          }
        }
      });

      assert.deepEqual(config, expected);
    });

    it('should allow for single step flow', function () {
      var flow = new Flow({
        steps: {
          js: ['uglify']
        }
      });

      var file = helpers.createFile('foo', 'app', blocks);
      var c = new ConfigWriter(flow, {
        input: 'app',
        dest: 'dist',
        staging: 'staging'
      });
      var config = c.process(file);
      var expected = helpers.normalize({
        uglify: {
          generated: {
            files: [{
              dest: 'dist/scripts/site.js',
              src: ['app/foo.js', 'app/bar.js', 'app/baz.js']
            }]
          }
        }
      });
      assert.deepEqual(config, expected);
    });

    it('should allow for a configuration of the flow\'s step order', function () {
      var flow = new Flow({
        steps: {
          js: ['uglify', 'concat']
        }
      });

      var file = helpers.createFile('foo', 'app', blocks);
      var c = new ConfigWriter(flow, {
        input: 'app',
        dest: 'dist',
        staging: 'staging'
      });
      var config = c.process(file);
      var expected = helpers.normalize({
        uglify: {
          generated: {
            files: [{
              dest: 'staging/uglify/foo.js',
              src: ['app/foo.js']
            }, {
              dest: 'staging/uglify/bar.js',
              src: ['app/bar.js']
            }, {
              dest: 'staging/uglify/baz.js',
              src: ['app/baz.js']
            }]
          }
        },
        concat: {
          generated: {
            files: [{
              dest: 'dist/scripts/site.js',
              src: ['staging/uglify/foo.js', 'staging/uglify/bar.js', 'staging/uglify/baz.js']
            }]
          }
        }
      });
      assert.deepEqual(config, expected);
    });

    it('should augment the furnished config', function () {
      var flow = new Flow({
        steps: {
          js: ['concat', 'uglify']
        }
      });
      var config = {
        concat: {
          misc: {
            'foo.js': 'bar.js'
          }
        }
      };
      var file = helpers.createFile('foo', 'app', blocks);
      var c = new ConfigWriter(flow, {
        input: 'app',
        dest: 'destination',
        staging: '.tmp'
      });
      config = c.process(file, config);
      var expected = helpers.normalize({
        concat: {
          generated: {
            files: [{
              dest: '.tmp/concat/scripts/site.js',
              src: ['app/foo.js', 'app/bar.js', 'app/baz.js']
            }]
          },
          misc: {
            'foo.js': 'bar.js'
          }
        },
        uglify: {
          generated: {
            files: [{
              dest: 'destination/scripts/site.js',
              src: ['.tmp/concat/scripts/site.js']
            }]
          }
        }
      });
      assert.deepEqual(config, expected);
    });
    it('should allow for a flow per block type');
    it('should allow for an empty flow');
    it('should allow for a filename as input');

    it('should deduplicate blocks', function () {
      var flow = new Flow({
        steps: {
          js: ['concat', 'uglify']
        }
      });
      var doubleBlocks = [blocks[0], blocks[0]];
      var file = helpers.createFile('foo', 'app', doubleBlocks);
      var c = new ConfigWriter(flow, {
        input: 'app',
        dest: 'dist',
        staging: '.tmp'
      });
      var config = c.process(file);
      var expected = helpers.normalize({
        concat: {
          generated: {
            files: [{
              dest: '.tmp/concat/scripts/site.js',
              src: ['app/foo.js', 'app/bar.js', 'app/baz.js']
            }]
          }
        },
        uglify: {
          generated: {
            files: [{
              dest: 'dist/scripts/site.js',
              src: ['.tmp/concat/scripts/site.js']
            }]
          }
        }
      });

      assert.deepEqual(config, expected);
    });
    it('should deduplicate blocks across files', function () {
      var flow = new Flow({
        steps: {
          js: ['concat', 'uglify']
        }
      });
      var file = helpers.createFile('foo', 'app', blocks);
      var c = new ConfigWriter(flow, {
        input: 'app',
        dest: 'dist',
        staging: '.tmp'
      });
      var firstConfig = c.process(file);
      var repeatConfig = c.process(file);
      var expectedFirst = helpers.normalize({
        concat: {
          generated: {
            files: [{
              dest: '.tmp/concat/scripts/site.js',
              src: ['app/foo.js', 'app/bar.js', 'app/baz.js']
            }]
          }
        },
        uglify: {
          generated: {
            files: [{
              dest: 'dist/scripts/site.js',
              src: ['.tmp/concat/scripts/site.js']
            }]
          }
        }
      });
      var expectedRepeat = helpers.normalize({
        concat: {
          generated: {}
        },
        uglify: {
          generated: {}
        }
      });

      assert.deepEqual(firstConfig, expectedFirst);
      assert.deepEqual(repeatConfig, expectedRepeat);
    });
    it('should throw with conflicting blocks', function () {
      var flow = new Flow({
        steps: {
          js: ['concat', 'uglify']
        }
      });
      var conflictBlock = {
        type: 'js',
        dest: 'scripts/site.js',
        searchPath: [],
        indent: '    ',
        src: [
          'foo.js',
          'bar.js',
          'baz.js',
          'fail.js'
        ],
        raw: [
          '    <!-- build:js scripts/site.js -->',
          '    <script src="foo.js"></script>',
          '    <script src="bar.js"></script>',
          '    <script src="baz.js"></script>',
          '    <script src="fail.js"></script>',
          '    <!-- endbuild -->'
        ]
      };
      var file = helpers.createFile('foo', 'app', [blocks[0], conflictBlock]);
      var c = new ConfigWriter(flow, {
        input: 'app',
        dest: 'dist',
        staging: '.tmp'
      });
      assert.throws(function () {
        c.process(file);
      });
    });

    describe('stepWriters', function () {
      it('should return all writers if called without block type', function () {
        var flow = new Flow({
          steps: {
            js: ['concat', 'uglify'],
            css: ['concat']
          }
        });
        var c = new ConfigWriter(flow, {
          input: 'app',
          dest: 'destination',
          staging: '.tmp'
        });
        var names = [];
        c.stepWriters().forEach(function (i) {
          names.push(i.name);
        });
        assert.deepEqual(names, ['concat', 'uglify']);
      });
    });

    it('should not add the same block multiple times though we call process() explicitly 2 times.', function () {
      var flow = new Flow({steps: {js: ['concat', 'uglify']}});

      var file = helpers.createFile('foo', 'app', blocks);
      var c = new ConfigWriter(flow, {input: 'app', dest: 'destination', staging: '.tmp'});
      var config = c.process(file);
      config = c.process(file, config);  // This second process is intentional. Details are in issue #307.
      var expected = helpers.normalize({
        concat: {generated: {files: [
          {dest: '.tmp/concat/scripts/site.js', src: ['app/foo.js', 'app/bar.js', 'app/baz.js']}
        ]}},
        uglify: {generated: {files: [
          {dest: 'destination/scripts/site.js', src: ['.tmp/concat/scripts/site.js']}
        ]}}
      });

      assert.deepEqual(config, expected);
    });
  });
});
<commit_msg>Fix typo.<commit_after>'use strict';
var assert = require('assert');
var helpers = require('./helpers');
var Flow = require('../lib/flow.js');
var ConfigWriter = require('../lib/configwriter.js');

describe('ConfigWriter', function () {
  before(helpers.directory('temp'));

  describe('constructor', function () {
    it('should check its input');

    it('should allow for user-defined steps per block type', function () {
      var copy = {
        name: 'copy',
        createConfig: function () {
          return {};
        }
      };

      var flow = new Flow({
        steps: {
          js: ['concat', 'uglify', copy]
        },
        post: {}
      });
      var cfgw = new ConfigWriter(flow, {
        input: 'app',
        dest: 'dist',
        staging: '.tmp'
      });
      var stepNames = [];
      cfgw.stepWriters('js').forEach(function (s) {
        stepNames.push(s.name);
      });
      assert.deepEqual(stepNames, ['concat', 'uglify', 'copy']);
    });

    it('should use in and out dirs');
  });

  describe('process', function () {
    var blocks = helpers.blocks();

    it('should check for input parameters');

    it('should output a set of config', function () {
      var flow = new Flow({
        steps: {
          js: ['concat', 'uglify']
        }
      });
      var file = helpers.createFile('foo', 'app', blocks);
      var c = new ConfigWriter(flow, {
        input: 'app',
        dest: 'dist',
        staging: '.tmp'
      });
      var config = c.process(file);
      var expected = helpers.normalize({
        concat: {
          generated: {
            files: [{
              dest: '.tmp/concat/scripts/site.js',
              src: ['app/foo.js', 'app/bar.js', 'app/baz.js']
            }]
          }
        },
        uglify: {
          generated: {
            files: [{
              dest: 'dist/scripts/site.js',
              src: ['.tmp/concat/scripts/site.js']
            }]
          }
        }
      });

      assert.deepEqual(config, expected);
    });

    it('should have a configurable destination directory', function () {
      var flow = new Flow({
        steps: {
          js: ['concat', 'uglify']
        }
      });

      var file = helpers.createFile('foo', 'app', blocks);
      var c = new ConfigWriter(flow, {
        input: 'app',
        dest: 'destination',
        staging: '.tmp'
      });
      var config = c.process(file);
      var expected = helpers.normalize({
        concat: {
          generated: {
            files: [{
              dest: '.tmp/concat/scripts/site.js',
              src: ['app/foo.js', 'app/bar.js', 'app/baz.js']
            }]
          }
        },
        uglify: {
          generated: {
            files: [{
              dest: 'destination/scripts/site.js',
              src: ['.tmp/concat/scripts/site.js']
            }]
          }
        }
      });

      assert.deepEqual(config, expected);
    });

    it('should have a configurable staging directory', function () {
      var flow = new Flow({
        steps: {
          js: ['concat', 'uglify']
        }
      });

      var file = helpers.createFile('foo', 'app', blocks);
      var c = new ConfigWriter(flow, {
        input: 'app',
        dest: 'dist',
        staging: 'staging'
      });
      var config = c.process(file);
      var expected = helpers.normalize({
        concat: {
          generated: {
            files: [{
              dest: 'staging/concat/scripts/site.js',
              src: ['app/foo.js', 'app/bar.js', 'app/baz.js']
            }]
          }
        },
        uglify: {
          generated: {
            files: [{
              dest: 'dist/scripts/site.js',
              src: ['staging/concat/scripts/site.js']
            }]
          }
        }
      });

      assert.deepEqual(config, expected);
    });

    it('should allow for single step flow', function () {
      var flow = new Flow({
        steps: {
          js: ['uglify']
        }
      });

      var file = helpers.createFile('foo', 'app', blocks);
      var c = new ConfigWriter(flow, {
        input: 'app',
        dest: 'dist',
        staging: 'staging'
      });
      var config = c.process(file);
      var expected = helpers.normalize({
        uglify: {
          generated: {
            files: [{
              dest: 'dist/scripts/site.js',
              src: ['app/foo.js', 'app/bar.js', 'app/baz.js']
            }]
          }
        }
      });
      assert.deepEqual(config, expected);
    });

    it('should allow for a configuration of the flow\'s step order', function () {
      var flow = new Flow({
        steps: {
          js: ['uglify', 'concat']
        }
      });

      var file = helpers.createFile('foo', 'app', blocks);
      var c = new ConfigWriter(flow, {
        input: 'app',
        dest: 'dist',
        staging: 'staging'
      });
      var config = c.process(file);
      var expected = helpers.normalize({
        uglify: {
          generated: {
            files: [{
              dest: 'staging/uglify/foo.js',
              src: ['app/foo.js']
            }, {
              dest: 'staging/uglify/bar.js',
              src: ['app/bar.js']
            }, {
              dest: 'staging/uglify/baz.js',
              src: ['app/baz.js']
            }]
          }
        },
        concat: {
          generated: {
            files: [{
              dest: 'dist/scripts/site.js',
              src: ['staging/uglify/foo.js', 'staging/uglify/bar.js', 'staging/uglify/baz.js']
            }]
          }
        }
      });
      assert.deepEqual(config, expected);
    });

    it('should augment the furnished config', function () {
      var flow = new Flow({
        steps: {
          js: ['concat', 'uglify']
        }
      });
      var config = {
        concat: {
          misc: {
            'foo.js': 'bar.js'
          }
        }
      };
      var file = helpers.createFile('foo', 'app', blocks);
      var c = new ConfigWriter(flow, {
        input: 'app',
        dest: 'destination',
        staging: '.tmp'
      });
      config = c.process(file, config);
      var expected = helpers.normalize({
        concat: {
          generated: {
            files: [{
              dest: '.tmp/concat/scripts/site.js',
              src: ['app/foo.js', 'app/bar.js', 'app/baz.js']
            }]
          },
          misc: {
            'foo.js': 'bar.js'
          }
        },
        uglify: {
          generated: {
            files: [{
              dest: 'destination/scripts/site.js',
              src: ['.tmp/concat/scripts/site.js']
            }]
          }
        }
      });
      assert.deepEqual(config, expected);
    });
    it('should allow for a flow per block type');
    it('should allow for an empty flow');
    it('should allow for a filename as input');

    it('should deduplicate blocks', function () {
      var flow = new Flow({
        steps: {
          js: ['concat', 'uglify']
        }
      });
      var doubleBlocks = [blocks[0], blocks[0]];
      var file = helpers.createFile('foo', 'app', doubleBlocks);
      var c = new ConfigWriter(flow, {
        input: 'app',
        dest: 'dist',
        staging: '.tmp'
      });
      var config = c.process(file);
      var expected = helpers.normalize({
        concat: {
          generated: {
            files: [{
              dest: '.tmp/concat/scripts/site.js',
              src: ['app/foo.js', 'app/bar.js', 'app/baz.js']
            }]
          }
        },
        uglify: {
          generated: {
            files: [{
              dest: 'dist/scripts/site.js',
              src: ['.tmp/concat/scripts/site.js']
            }]
          }
        }
      });

      assert.deepEqual(config, expected);
    });
    it('should deduplicate blocks across files', function () {
      var flow = new Flow({
        steps: {
          js: ['concat', 'uglify']
        }
      });
      var file = helpers.createFile('foo', 'app', blocks);
      var c = new ConfigWriter(flow, {
        input: 'app',
        dest: 'dist',
        staging: '.tmp'
      });
      var firstConfig = c.process(file);
      var repeatConfig = c.process(file);
      var expectedFirst = helpers.normalize({
        concat: {
          generated: {
            files: [{
              dest: '.tmp/concat/scripts/site.js',
              src: ['app/foo.js', 'app/bar.js', 'app/baz.js']
            }]
          }
        },
        uglify: {
          generated: {
            files: [{
              dest: 'dist/scripts/site.js',
              src: ['.tmp/concat/scripts/site.js']
            }]
          }
        }
      });
      var expectedRepeat = helpers.normalize({
        concat: {
          generated: {}
        },
        uglify: {
          generated: {}
        }
      });

      assert.deepEqual(firstConfig, expectedFirst);
      assert.deepEqual(repeatConfig, expectedRepeat);
    });
    it('should throw with conflicting blocks', function () {
      var flow = new Flow({
        steps: {
          js: ['concat', 'uglify']
        }
      });
      var conflictBlock = {
        type: 'js',
        dest: 'scripts/site.js',
        searchPath: [],
        indent: '    ',
        src: [
          'foo.js',
          'bar.js',
          'baz.js',
          'fail.js'
        ],
        raw: [
          '    <!-- build:js scripts/site.js -->',
          '    <script src="foo.js"></script>',
          '    <script src="bar.js"></script>',
          '    <script src="baz.js"></script>',
          '    <script src="fail.js"></script>',
          '    <!-- endbuild -->'
        ]
      };
      var file = helpers.createFile('foo', 'app', [blocks[0], conflictBlock]);
      var c = new ConfigWriter(flow, {
        input: 'app',
        dest: 'dist',
        staging: '.tmp'
      });
      assert.throws(function () {
        c.process(file);
      });
    });

    describe('stepWriters', function () {
      it('should return all writers if called without block type', function () {
        var flow = new Flow({
          steps: {
            js: ['concat', 'uglify'],
            css: ['concat']
          }
        });
        var c = new ConfigWriter(flow, {
          input: 'app',
          dest: 'destination',
          staging: '.tmp'
        });
        var names = [];
        c.stepWriters().forEach(function (i) {
          names.push(i.name);
        });
        assert.deepEqual(names, ['concat', 'uglify']);
      });
    });

    it('should not add the same block multiple times though we call process() explicitly 2 times.', function () {
      var flow = new Flow({steps: {js: ['concat', 'uglify']}});

      var file = helpers.createFile('foo', 'app', blocks);
      var c = new ConfigWriter(flow, {input: 'app', dest: 'destination', staging: '.tmp'});
      var config = c.process(file);
      config = c.process(file, config);  // This second process is intentional. Details are in issue #307.
      var expected = helpers.normalize({
        concat: {generated: {files: [
          {dest: '.tmp/concat/scripts/site.js', src: ['app/foo.js', 'app/bar.js', 'app/baz.js']}
        ]}},
        uglify: {generated: {files: [
          {dest: 'destination/scripts/site.js', src: ['.tmp/concat/scripts/site.js']}
        ]}}
      });

      assert.deepEqual(config, expected);
    });
  });
});
<|endoftext|>


<commit_before>import { map } from 'ramda';
import React, { Component } from 'react';
import { View } from 'react-native';
import { NativeRouter, Redirect, Route } from 'react-router-native';

import courses from './assets/courses.json';
import getExercise from './components/exercises';
import Course from './components/screens/Course';
import Exercise from './components/screens/Exercise';
import Splash from './components/screens/Splash';
import { LoadSounds } from './components/helpers/Audio';
import loadFonts from './components/helpers/fonts';
import { play, getSound } from './helpers/audio';
import { getWordObject } from './helpers/words';
import Interactor from './entities-interactor';
import Storage from './storage/CourseStorage';
import { PRIMARY } from './styles/colors';

export class AppRoutes extends Component {
  constructor(props) {
    super(props);

    const storage = new Storage(courses);
    const progress = null; // TODO:
    this.interactor = new Interactor(storage, progress);

    this.state = { course: null };
  }

  getNextChild = id => {
    return this.interactor.getNextChild(id);
  };

  getNextSibling = id => {
    return this.interactor.getNextSibling(id);
  };

  findEntity = id => {
    return this.interactor.findEntity(id);
  };

  markAsCorrect = id => {
    return this.interactor.markAsCorrect(id);
  };

  markAsIncorrect = id => {
    return this.interactor.markAsIncorrect(id);
  };

  componentDidMount() {
    this.interactor
      .loadCourse('09438926-b170-4005-a6e8-5dd8fba83cde')
      .then(() => {
        const course = this.interactor.getStructure();
        this.setState({ course });
      });
  }

  render() {
    return (
      <LoadSounds
        sounds={[
          require('./assets/sounds/correct.mp3'),
          require('./assets/sounds/wrong.mp3')
        ]}
        render={([correctSound, wrongSound]) => (
          <View
            style={{
              flex: 1,
              backgroundColor: PRIMARY
            }}
          >
            <Route
              exact
              path="/"
              render={({ history }) => (
                <Splash next={() => history.push('/course')} />
              )}
            />
            <Route
              path="/course"
              render={({ history }) => {
                if (!this.state.course) {
                  return null;
                }

                return (
                  <Course
                    course={this.state.course}
                    goToSection={id => history.push(`/section/${id}`)}
                  />
                );
              }}
            />
            <Route
              path="/section/:id"
              render={({ match }) => {
                if (!this.state.course) {
                  return null;
                }

                const exercise = this.getNextChild(match.params.id);

                if (exercise) {
                  return <Redirect to={`/exercise/${exercise.id}`} />;
                }

                const section = this.getNextSibling(match.params.id);

                if (section) {
                  return <Redirect to={`/section/${section.id}`} />;
                }

                return null;
              }}
            />
            <Route
              path="/exercise/:id"
              render={({ match, history }) => {
                const { id } = match.params;

                const entity = this.findEntity(id);

                if (!entity) {
                  return <Redirect to="/course" />;
                }

                const { type, props } = entity;

                const exerciseType = getExercise(type);

                if (!exerciseType) {
                  console.warn('no view found for type', type);
                  return null;
                }

                const exercise = new exerciseType.Exercise({
                  ...props,
                  sound: props.sound && getSound(props.sound),
                  sounds: map(getSound, props.sounds || []),
                  word: props.word && getWordObject(props.word),
                  words: map(getWordObject, props.words || [])
                });

                return (
                  <Exercise
                    exercise={exercise}
                    Component={exerciseType.Component}
                    goToNav={() => history.push('/course')}
                    onCorrect={() => {
                      play(correctSound).then(() => {
                        this.markAsCorrect(id);
                        history.push(`/section/${entity.parent}`);
                      });
                    }}
                    onWrong={() => {
                      play(wrongSound).then(() => {
                        this.markAsIncorrect(id);
                      });
                    }}
                  />
                );
              }}
            />
          </View>
        )}
      />
    );
  }
}

const App = () => (
  <NativeRouter>
    <AppRoutes />
  </NativeRouter>
);

export default loadFonts({
  norddruck: require('./assets/fonts/norddruck.ttf'),
  serlo: require('./assets/fonts/serlo.ttf')
})(App);
<commit_msg>fix: override `sounds` and `words` iff they are set (#178)<commit_after>import { map, mergeAll } from 'ramda';
import React, { Component } from 'react';
import { View } from 'react-native';
import { NativeRouter, Redirect, Route } from 'react-router-native';

import courses from './assets/courses.json';
import getExercise from './components/exercises';
import Course from './components/screens/Course';
import Exercise from './components/screens/Exercise';
import Splash from './components/screens/Splash';
import { LoadSounds } from './components/helpers/Audio';
import loadFonts from './components/helpers/fonts';
import { play, getSound } from './helpers/audio';
import { getWordObject } from './helpers/words';
import Interactor from './entities-interactor';
import Storage from './storage/CourseStorage';
import { PRIMARY } from './styles/colors';

export class AppRoutes extends Component {
  constructor(props) {
    super(props);

    const storage = new Storage(courses);
    const progress = null; // TODO:
    this.interactor = new Interactor(storage, progress);

    this.state = { course: null };
  }

  getNextChild = id => {
    return this.interactor.getNextChild(id);
  };

  getNextSibling = id => {
    return this.interactor.getNextSibling(id);
  };

  findEntity = id => {
    return this.interactor.findEntity(id);
  };

  markAsCorrect = id => {
    return this.interactor.markAsCorrect(id);
  };

  markAsIncorrect = id => {
    return this.interactor.markAsIncorrect(id);
  };

  componentDidMount() {
    this.interactor
      .loadCourse('09438926-b170-4005-a6e8-5dd8fba83cde')
      .then(() => {
        const course = this.interactor.getStructure();
        this.setState({ course });
      });
  }

  render() {
    return (
      <LoadSounds
        sounds={[
          require('./assets/sounds/correct.mp3'),
          require('./assets/sounds/wrong.mp3')
        ]}
        render={([correctSound, wrongSound]) => (
          <View
            style={{
              flex: 1,
              backgroundColor: PRIMARY
            }}
          >
            <Route
              exact
              path="/"
              render={({ history }) => (
                <Splash next={() => history.push('/course')} />
              )}
            />
            <Route
              path="/course"
              render={({ history }) => {
                if (!this.state.course) {
                  return null;
                }

                return (
                  <Course
                    course={this.state.course}
                    goToSection={id => history.push(`/section/${id}`)}
                  />
                );
              }}
            />
            <Route
              path="/section/:id"
              render={({ match }) => {
                if (!this.state.course) {
                  return null;
                }

                const exercise = this.getNextChild(match.params.id);

                if (exercise) {
                  return <Redirect to={`/exercise/${exercise.id}`} />;
                }

                const section = this.getNextSibling(match.params.id);

                if (section) {
                  return <Redirect to={`/section/${section.id}`} />;
                }

                return null;
              }}
            />
            <Route
              path="/exercise/:id"
              render={({ match, history }) => {
                const { id } = match.params;

                const entity = this.findEntity(id);

                if (!entity) {
                  return <Redirect to="/course" />;
                }

                const { type, props } = entity;

                const exerciseType = getExercise(type);

                if (!exerciseType) {
                  console.warn('no view found for type', type);
                  return null;
                }

                const exercise = new exerciseType.Exercise(
                  mergeAll([
                    props,
                    props.sound && { sound: getSound(props.sound) },
                    props.sounds && { sounds: map(getSound, props.sounds) },
                    props.word && { word: getWordObject(props.word) },
                    props.words && { words: map(getWordObject, props.words) }
                  ])
                );

                return (
                  <Exercise
                    exercise={exercise}
                    Component={exerciseType.Component}
                    goToNav={() => history.push('/course')}
                    onCorrect={() => {
                      play(correctSound).then(() => {
                        this.markAsCorrect(id);
                        history.push(`/section/${entity.parent}`);
                      });
                    }}
                    onWrong={() => {
                      play(wrongSound).then(() => {
                        this.markAsIncorrect(id);
                      });
                    }}
                  />
                );
              }}
            />
          </View>
        )}
      />
    );
  }
}

const App = () => (
  <NativeRouter>
    <AppRoutes />
  </NativeRouter>
);

export default loadFonts({
  norddruck: require('./assets/fonts/norddruck.ttf'),
  serlo: require('./assets/fonts/serlo.ttf')
})(App);
<|endoftext|>


<commit_before>const { resolve } = require('path')
const { Nuxt, Builder } = require('nuxt')

const NuxtPlugin = {

    name: 'nuxt',

    pkg: require('../package.json'),

    async register (server, config) {

        // If config is not provided try nuxt.config.js
        if (!config || Object.keys(config).length === 0) {
            config = 'nuxt.config.js'
        }

        // Resolve config location if is provided as string
        if(typeof config === 'string') {
            try {
                const path = resolve(process.cwd(), config)
                config = require(path)
            } catch (e) {
                // DO NOTHING
            }
        }

        // Create nuxt instance using options
        const nuxt = new Nuxt(config)
        server.expose('nuxt', nuxt)

        // Nuxt handler
        server.route({
            method: 'GET',
            path: '/{path*}',
            config: {
                id: 'NuxtController.render',
                auth: false,
            },
            handler (request, h) {
                const {req, res} = request.raw

                nuxt.render(req, res)

                // https://hapijs.com/api#h.abandon
                return h.abandon
            }
        })

        // Dev
        if (nuxt.options.dev && nuxt.options.startOnly !== false) {
            // Build nuxt
            console.log('Building nuxt ...')
            const builder = new Builder(nuxt);
            server.expose('builder', builder);
            await builder.build()
        }
    }
}

module.exports = NuxtPlugin
<commit_msg>fix: rebuild without blocking hapi start during dev<commit_after>const { resolve } = require('path')
const { Nuxt, Builder } = require('nuxt')

const NuxtPlugin = {

    name: 'nuxt',

    pkg: require('../package.json'),

    async register (server, config) {

        // If config is not provided try nuxt.config.js
        if (!config || Object.keys(config).length === 0) {
            config = 'nuxt.config.js'
        }

        // Resolve config location if is provided as string
        if(typeof config === 'string') {
            try {
                const path = resolve(process.cwd(), config)
                config = require(path)
            } catch (e) {
                // DO NOTHING
            }
        }

        // Create nuxt instance using options
        const nuxt = new Nuxt(config)
        server.expose('nuxt', nuxt)

        // Nuxt handler
        server.route({
            method: 'GET',
            path: '/{path*}',
            config: {
                id: 'NuxtController.render',
                auth: false,
            },
            handler (request, h) {
                const {req, res} = request.raw

                nuxt.render(req, res)

                // https://hapijs.com/api#h.abandon
                return h.abandon
            }
        })

        // Dev
        if (nuxt.options.dev && nuxt.options.startOnly !== false) {
            // Build nuxt
            console.log('Building nuxt ...')
            const builder = new Builder(nuxt);
            server.expose('builder', builder);
            builder.build().catch(console.error)
        }
    }
}

module.exports = NuxtPlugin
<|endoftext|>


<commit_before>//Js file for the block games web app.
//Created by rationalAsh :D
//Now live on github.io

var cellSize = 20;

var cont = document.getElementById('container');
var sBox = document.getElementById('SettingsBox');
var posDisp = document.getElementById('mPos');
var scoreBoard = document.getElementById('score');
var mpFlag = 0;
var prevTBase = 0;
var eatFlag = 0;
var score = 0;

//var wHeight = screen.availHeight;
//var wWidth  = screen.availWidth;

var wHeight = window.innerHeight - 3;
var wWidth  = window.innerWidth - 5;
//alert(wHeight);
//alert(wWidth);

var i=0;
var j=0;

var rows = Math.round(wHeight/cellSize);
var cols = Math.round(wWidth/cellSize);
var gridLinesY = new Array();
var gridLinesX = new Array();
var cells = new Array();
var cTemp = new Array();
var celBuf = new Array();
var dotBuf = new Array();
var snakeState = [];
var snakeVel   = [1,0]; //Normal Vector velocities
var dotPos = [5,5];
var swallowed = new Array();

for(i=0; i<rows; i++)
{
  cTemp = new Array();
  for(j=0; j<cols; j++)
  {
    cTemp.push(0);
  }
  celBuf.push(cTemp);
  dotBuf.push(cTemp);
}

function clearBuf(array)
{
  for(i=0; i<rows; i++)
  {
    for(j=0; j<cols; j++)
    {
      array[i][j] = 0;
    }
  }
}

//console.log(String(celBuf));

function fillCell(X,Y)
{
  var gridX = Math.floor(X/cellSize);
  var gridY = Math.floor(Y/cellSize);
  animLayer.add(cells[gridY][gridX]);
  console.log(String([gridX, gridY]))
}

//console.log(snakeState);
//posDisp.innerHTML = "Hello!"
//cont.onmousemove = function(e){

//Make box visible on hover
//if((e.pageX > 1500) && (e.pageY < 410))
//    {
//	sBox.style.opacity = 0.8;
//	sBox.style.zIndex = 1;
//	sBox.style.visibility = "visible";
//    }
//    else
//    {
//	//sBox.style.opacity = 0.1;
//	sBox.style.zIndex  = -1;
//	sBox.style.visibility = "hidden";
//    }
//
//}

sBox.style.opacity = 0.8;
sBox.style.zIndex = 1;
sBox.style.visibility = "visible";

cont.onclick = function(e){
  //alert("Click at: "+ e.pageX + "," + e.pageY);
  //fillCell(e.pageX, e.pageY);
  //celBuf[Math.floor(e.pageY/cellSize)][Math.floor(e.pageX/cellSize)] ^= 1;
}

document.onkeydown = function(e){
  code = e.keyCode;

  switch(code)
  {
    case 38:
      console.log('UP');
      snakeVel = [0, -1];
      break;
    case 40:
      console.log('Down');
      snakeVel = [0, 1];
      break;
    case 39:
      console.log('Right');
      snakeVel = [1, 0];
      break;
    case 37:
      console.log('Left');
      snakeVel = [-1, 0];
      break;
  }
}

var stage = new Kinetic.Stage({
  container: 'container',
  width: wWidth,
  height: wHeight
});

var animLayer = new Kinetic.Layer();
var statLayer = new Kinetic.Layer();

//Loop to make Y gridlines
for(i=0; i<rows; i++)
{
  gridLinesY.push(
    new Kinetic.Line(
      {
        points: [0, i*cellSize, wWidth, i*cellSize],
	stroke: 'black',
	strokeWidth: 0.8,
	lineCap: 'round',
        lineJoin: 'round'
      }
    )
  )
}
//Loop to make X gridlines
for(j=0; j<cols; j++)
{
  gridLinesX.push(
    new Kinetic.Line(
      {
        points: [j*cellSize, 0, j*cellSize, wHeight],
        stroke: 'black',
	strokeWidth: 0.8,
        lineCap: 'round',
        lineJoin: 'round'
      }
    )
  )
}

//Adding Y lines to static layer so it doesn't have to update
for(i=0; i<rows; i++)
{
  statLayer.add(gridLinesY[i]);
}

//Adding X lines to static layer so that it doesn't have to update
for(j=0; j<cols; j++)
{
  statLayer.add(gridLinesX[j]);
}

//Making the cells
for(i=0; i<rows; i++)
{
  cTemp = new Array();
  for(j=0; j<cols; j++)
  {
    cTemp.push(
      new Kinetic.Rect(
        {
          x: j*cellSize + 1,
          y: i*cellSize + 1,
          width: cellSize - 2,
          height: cellSize - 2,
          fill: '#554a8c',
          stroke: '#554a8c',
          strokeWidth: 0
        }
      )
    )
  }
  cells.push(cTemp);
}

//animLayer.add(cells[0][0]);
animLayer.draw();
statLayer.draw();

// add the layer to the stage
stage.add(animLayer).add(statLayer);

//Initialize the snake with an initial position
snakeState.push([10,10]);
snakeState.push([11,10]);
snakeState.push([12,10]);
console.log(String(snakeState));

//This is the code where all the stuff that updates
//in the next animation frame happens.
var anim = new Kinetic.Animation(function(frame){
  var time = frame.time,
      timeDIff = frame.timeDiff,
      frameRate = frame.frameRate;
  var xTime = Math.floor(time/300);

  //update stuff
  //posDisp.innerHTML = "Framerate: "+frameRate;

  //If one second has passed change the snake to move in the
  //Direction specified by the snakeVel var
  if(xTime>prevTBase)
  {
    snakeState.push([(snakeState[snakeState.length - 1][0]) + snakeVel[0], (snakeState[snakeState.length - 1][1]) + snakeVel[1]]);

    var rem = snakeState.shift();
    cells[rem[1]][rem[0]].remove();

    //If head is at a dot add the dot to the list of swallowedstuff
    if((snakeState[snakeState.length-1][0]==dotPos[1])&&(snakeState[snakeState.length-1][1]==dotPos[0]))
    {
      score += 5;
      swallowed.push(dotPos);
      dotPos = [Math.floor(Math.random() * (rows-30)), Math.floor(Math.random() * (cols-20))];
      console.log('Head: '+String(dotPos));
      snakeState.unshift(swallowed.shift());
      scoreBoard.innerHTML = 'Score: '+String(score);
    }

    //Checking if tail is at a dot
    //This works because if the snake enters a dot then the
    //Whole body has to pass through the dot.
    if((snakeState[0][0]==swallowed[0])&&(snakeState[0][0]==swallowed[1]))
    {
      //Eat the dot and grow longer
      //I'll try adding the new dot at the end of the snake for now.
      //eatFlag = 1;
      //console.log('Tail at dot');
    }

    for(i=0; i<snakeState.length; i++)
    {
      animLayer.add(cells[snakeState[i][1]][snakeState[i][0]]);
    }
    animLayer.add(cells[dotPos[0]][dotPos[1]]);

  }

  prevTBase = xTime;

}, animLayer);

anim.start();
<commit_msg>Updated README, script comments<commit_after>//Js file for the block games web app.
//Created by rationalAsh :D
//Now live on github.io

var cellSize = 20;

var cont = document.getElementById('container');
var sBox = document.getElementById('SettingsBox');
var posDisp = document.getElementById('mPos');
var scoreBoard = document.getElementById('score');
var mpFlag = 0;
var prevTBase = 0;
var eatFlag = 0;
var score = 0;

//var wHeight = screen.availHeight;
//var wWidth  = screen.availWidth;

var wHeight = window.innerHeight - 3;
var wWidth  = window.innerWidth - 5;
//alert(wHeight);
//alert(wWidth);

var i=0;
var j=0;

var rows = Math.round(wHeight/cellSize);
var cols = Math.round(wWidth/cellSize);
var gridLinesY = new Array();
var gridLinesX = new Array();
var cells = new Array();
var cTemp = new Array();
var celBuf = new Array();
var dotBuf = new Array();
var snakeState = [];
var snakeVel   = [1,0]; //Normal Vector velocities
var dotPos = [5,5];
var swallowed = new Array();

for(i=0; i<rows; i++)
{
  cTemp = new Array();
  for(j=0; j<cols; j++)
  {
    cTemp.push(0);
  }
  celBuf.push(cTemp);
  dotBuf.push(cTemp);
}

function clearBuf(array)
{
  for(i=0; i<rows; i++)
  {
    for(j=0; j<cols; j++)
    {
      array[i][j] = 0;
    }
  }
}

//console.log(String(celBuf));

function fillCell(X,Y)
{
  var gridX = Math.floor(X/cellSize);
  var gridY = Math.floor(Y/cellSize);
  animLayer.add(cells[gridY][gridX]);
  console.log(String([gridX, gridY]))
}

//console.log(snakeState);
//posDisp.innerHTML = "Hello!"
//cont.onmousemove = function(e){

//Make box visible on hover
//if((e.pageX > 1500) && (e.pageY < 410))
//    {
//	sBox.style.opacity = 0.8;
//	sBox.style.zIndex = 1;
//	sBox.style.visibility = "visible";
//    }
//    else
//    {
//	//sBox.style.opacity = 0.1;
//	sBox.style.zIndex  = -1;
//	sBox.style.visibility = "hidden";
//    }
//
//}

sBox.style.opacity = 0.8;
sBox.style.zIndex = 1;
sBox.style.visibility = "visible";

cont.onclick = function(e){
  //alert("Click at: "+ e.pageX + "," + e.pageY);
  //fillCell(e.pageX, e.pageY);
  //celBuf[Math.floor(e.pageY/cellSize)][Math.floor(e.pageX/cellSize)] ^= 1;
}

document.onkeydown = function(e){
  code = e.keyCode;

  switch(code)
  {
    case 38:
      console.log('UP');
      snakeVel = [0, -1];
      break;
    case 40:
      console.log('Down');
      snakeVel = [0, 1];
      break;
    case 39:
      console.log('Right');
      snakeVel = [1, 0];
      break;
    case 37:
      console.log('Left');
      snakeVel = [-1, 0];
      break;
  }
}

var stage = new Kinetic.Stage({
  container: 'container',
  width: wWidth,
  height: wHeight
});

var animLayer = new Kinetic.Layer();
var statLayer = new Kinetic.Layer();

//Loop to make Y gridlines
for(i=0; i<rows; i++)
{
  gridLinesY.push(
    new Kinetic.Line(
      {
        points: [0, i*cellSize, wWidth, i*cellSize],
	stroke: 'black',
	strokeWidth: 0.8,
	lineCap: 'round',
        lineJoin: 'round'
      }
    )
  )
}
//Loop to make X gridlines
for(j=0; j<cols; j++)
{
  gridLinesX.push(
    new Kinetic.Line(
      {
        points: [j*cellSize, 0, j*cellSize, wHeight],
        stroke: 'black',
	strokeWidth: 0.8,
        lineCap: 'round',
        lineJoin: 'round'
      }
    )
  )
}

//Adding Y lines to static layer so it doesn't have to update
for(i=0; i<rows; i++)
{
  statLayer.add(gridLinesY[i]);
}

//Adding X lines to static layer so that it doesn't have to update
for(j=0; j<cols; j++)
{
  statLayer.add(gridLinesX[j]);
}

//Making the cells
for(i=0; i<rows; i++)
{
  cTemp = new Array();
  for(j=0; j<cols; j++)
  {
    cTemp.push(
      new Kinetic.Rect(
        {
          x: j*cellSize + 1,
          y: i*cellSize + 1,
          width: cellSize - 2,
          height: cellSize - 2,
          fill: '#554a8c',
          stroke: '#554a8c',
          strokeWidth: 0
        }
      )
    )
  }
  cells.push(cTemp);
}

//animLayer.add(cells[0][0]);
animLayer.draw();
statLayer.draw();

// add the layer to the stage
stage.add(animLayer).add(statLayer);

//Initialize the snake with an initial position
snakeState.push([10,10]);
snakeState.push([11,10]);
snakeState.push([12,10]);
console.log(String(snakeState));

//This is the code where all the stuff that updates
//in the next animation frame happens.
var anim = new Kinetic.Animation(function(frame){
  var time = frame.time,
      timeDIff = frame.timeDiff,
      frameRate = frame.frameRate;
  var xTime = Math.floor(time/300);

  //update stuff
  //posDisp.innerHTML = "Framerate: "+frameRate;

  //If one second has passed change the snake to move in the
  //Direction specified by the snakeVel var
  if(xTime>prevTBase)
  {
    snakeState.push([(snakeState[snakeState.length - 1][0]) + snakeVel[0], (snakeState[snakeState.length - 1][1]) + snakeVel[1]]);

    var rem = snakeState.shift();
    cells[rem[1]][rem[0]].remove();

    //If head is at a dot add the dot to the list of swallowedstuff and add
    //Dot to end of snake
    if((snakeState[snakeState.length-1][0]==dotPos[1])&&(snakeState[snakeState.length-1][1]==dotPos[0]))
    {
      score += 5;
      swallowed.push(dotPos);
      dotPos = [Math.floor(Math.random() * (rows-30)), Math.floor(Math.random() * (cols-20))];
      console.log('Head: '+String(dotPos));
      snakeState.unshift(swallowed.shift());
      scoreBoard.innerHTML = 'Score: '+String(score);
    }

    //Checking if tail is at a dot
    //This works because if the snake enters a dot then the
    //Whole body has to pass through the dot.
    if((snakeState[0][0]==swallowed[0])&&(snakeState[0][0]==swallowed[1]))
    {
      //Eat the dot and grow longer
      //I'll try adding the new dot at the end of the snake for now.
      //eatFlag = 1;
      //console.log('Tail at dot');
    }

    for(i=0; i<snakeState.length; i++)
    {
      animLayer.add(cells[snakeState[i][1]][snakeState[i][0]]);
    }
    animLayer.add(cells[dotPos[0]][dotPos[1]]);

  }

  prevTBase = xTime;

}, animLayer);

anim.start();
<|endoftext|>