<commit_before>'use strict';

var expect            = require('chai').expect;
var EOL               = require('os').EOL;
var SilentError       = require('silent-error');
var commandOptions    = require('../../factories/command-options');
var stub              = require('../../helpers/stub');
var processHelpString = require('../../helpers/process-help-string');
var MockProject       = require('../../helpers/mock-project');
var Promise           = require('../../../lib/ext/promise');
var Task              = require('../../../lib/models/task');
var Blueprint         = require('../../../lib/models/blueprint');
var GenerateCommand   = require('../../../lib/commands/generate');

var safeRestore = stub.safeRestore;
stub = stub.stub;

describe('generate command', function() {
  var options, command;

  beforeEach(function() {
    var project = new MockProject();

    project.isEmberCLIProject = function() {
      return true;
    };

    project.blueprintLookupPaths = function() {
      return [];
    };

    options = commandOptions({
      project: project,

      tasks: {
        GenerateFromBlueprint: Task.extend({
          project: project,
          run: function(options) {
            return Promise.resolve(options);
          }
        })
      }
    });

    //nodeModulesPath: 'somewhere/over/the/rainbow'
    command = new GenerateCommand(options);
  });

  afterEach(function() {
    safeRestore(Blueprint, 'list');
  });

  it('runs GenerateFromBlueprint but with null nodeModulesPath', function() {
    command.project.hasDependencies = function() { return false; };

    expect(function() {
      command.validateAndRun(['controller', 'foo']);
    }).to.throw(SilentError, 'node_modules appears empty, you may need to run `npm install`');
  });

  it('runs GenerateFromBlueprint with expected options', function() {
    return command.validateAndRun(['controller', 'foo'])
      .then(function(options) {
        expect(options.pod).to.be.false;
        expect(options.dryRun).to.be.false;
        expect(options.verbose).to.be.false;
        expect(options.args).to.deep.equal(['controller', 'foo']);
      });
  });

  it('does not throws errors when beforeRun is invoked without the blueprint name', function() {
    expect(function() {
      command.beforeRun([]);
    }).to.not.throw();
  });

  it('complains if no blueprint name is given', function() {
    return command.validateAndRun([])
      .then(function() {
        expect(false, 'should not have called run').to.be.ok;
      })
      .catch(function(error) {
        expect(error.message).to.equal(
            'The `ember generate` command requires a ' +
            'blueprint name to be specified. ' +
            'For more details, use `ember help`.');
      });
  });

  describe('help', function() {
    it('lists available blueprints', function() {
      stub(Blueprint, 'list', [
        {
          source: 'my-app',
          blueprints: [
            {
              name: 'my-blueprint',
              availableOptions: [],
              printBasicHelp: function() {
                return this.name;
              }
            },
            {
              name: 'other-blueprint',
              availableOptions: [],
              printBasicHelp: function() {
                return this.name;
              }
            }
          ]
        }
      ]);

      command.printDetailedHelp({});

      var output = options.ui.output;

      var testString = processHelpString(EOL + '\
  Available blueprints:' + EOL + '\
    my-app:' + EOL + '\
my-blueprint' + EOL + '\
other-blueprint' + EOL + '\
' + EOL);

      expect(output).to.equal(testString);
    });

    it('lists available blueprints json', function() {
      stub(Blueprint, 'list', [
        {
          source: 'my-app',
          blueprints: [
            {
              name: 'my-blueprint',
              availableOptions: [],
              getJson: function() {
                return {
                  name: this.name
                };
              }
            },
            {
              name: 'other-blueprint',
              availableOptions: [],
              getJson: function() {
                return {
                  name: this.name
                };
              }
            }
          ]
        }
      ]);

      var json = {};

      command.addAdditionalJsonForHelp(json, {
        json: true
      });

      expect(json.availableBlueprints).to.deep.equal([
        {
          'my-app': [
            {
              name: 'my-blueprint',
            },
            {
              name: 'other-blueprint',
            }
          ]
        }
      ]);
    });

    it('works with single blueprint', function() {
      stub(Blueprint, 'list', [
        {
          source: 'my-app',
          blueprints: [
            {
              name: 'my-blueprint',
              availableOptions: [],
              printBasicHelp: function() {
                return this.name;
              }
            },
            {
              name: 'skipped-blueprint'
            }
          ]
        }
      ]);

      command.printDetailedHelp({
        rawArgs: ['my-blueprint']
      });

      var output = options.ui.output;

      var testString = processHelpString('\
my-blueprint' + EOL + '\
' + EOL);

      expect(output).to.equal(testString);
    });

    it('works with single blueprint json', function() {
      stub(Blueprint, 'list', [
        {
          source: 'my-app',
          blueprints: [
            {
              name: 'my-blueprint',
              availableOptions: [],
              getJson: function() {
                return {
                  name: this.name
                };
              }
            },
            {
              name: 'skipped-blueprint'
            }
          ]
        }
      ]);

      var json = {};

      command.addAdditionalJsonForHelp(json, {
        rawArgs: ['my-blueprint'],
        json: true
      });

      expect(json.availableBlueprints).to.deep.equal([
        {
          'my-app': [
            {
              name: 'my-blueprint',
            }
          ]
        }
      ]);
    });

    it('handles missing blueprint', function() {
      stub(Blueprint, 'list', [
        {
          source: 'my-app',
          blueprints: [
            {
              name: 'my-blueprint'
            }
          ]
        }
      ]);

      command.printDetailedHelp({
        rawArgs: ['missing-blueprint']
      });

      var output = options.ui.output;

      var testString = processHelpString('\
\u001b[33mThe \'missing-blueprint\' blueprint does not exist in this project.\u001b[39m' + EOL + '\
' + EOL);

      expect(output).to.equal(testString);
    });

    it('handles missing blueprint json', function() {
      stub(Blueprint, 'list', [
        {
          source: 'my-app',
          blueprints: [
            {
              name: 'my-blueprint'
            }
          ]
        }
      ]);

      var json = {};

      command.addAdditionalJsonForHelp(json, {
        rawArgs: ['missing-blueprint'],
        json: true
      });

      expect(json.availableBlueprints).to.deep.equal([
        {
          'my-app': []
        }
      ]);
    });

    it('ignores overridden blueprints when verbose false', function() {
      stub(Blueprint, 'list', [
        {
          source: 'my-app',
          blueprints: [
            {
              name: 'my-blueprint',
              availableOptions: [],
              printBasicHelp: function() {
                return this.name;
              },
              overridden: true
            }
          ]
        }
      ]);

      command.printDetailedHelp({});

      var output = options.ui.output;

      var testString = processHelpString(EOL + '\
  Available blueprints:' + EOL + '\
' + EOL);

      expect(output).to.equal(testString);
    });

    it('shows overridden blueprints when verbose true', function() {
      stub(Blueprint, 'list', [
        {
          source: 'my-app',
          blueprints: [
            {
              name: 'my-blueprint',
              availableOptions: [],
              printBasicHelp: function() {
                return this.name;
              },
              overridden: true
            }
          ]
        }
      ]);

      command.printDetailedHelp({
        verbose: true
      });

      var output = options.ui.output;

      var testString = processHelpString(EOL + '\
  Available blueprints:' + EOL + '\
    my-app:' + EOL + '\
my-blueprint' + EOL + '\
' + EOL);

      expect(output).to.equal(testString);
    });
  });
});
<commit_msg>tests/commands/generate: Use testdouble for mocks<commit_after>'use strict';

var expect            = require('chai').expect;
var EOL               = require('os').EOL;
var SilentError       = require('silent-error');
var commandOptions    = require('../../factories/command-options');
var processHelpString = require('../../helpers/process-help-string');
var MockProject       = require('../../helpers/mock-project');
var Promise           = require('../../../lib/ext/promise');
var Task              = require('../../../lib/models/task');
var Blueprint         = require('../../../lib/models/blueprint');
var GenerateCommand   = require('../../../lib/commands/generate');
var td = require('testdouble');

describe('generate command', function() {
  var options, command;

  beforeEach(function() {
    var project = new MockProject();

    project.isEmberCLIProject = function() {
      return true;
    };

    project.blueprintLookupPaths = function() {
      return [];
    };

    options = commandOptions({
      project: project,

      tasks: {
        GenerateFromBlueprint: Task.extend({
          project: project,
          run: function(options) {
            return Promise.resolve(options);
          }
        })
      }
    });

    command = new GenerateCommand(options);
  });

  afterEach(function() {
    td.reset();
  });

  it('runs GenerateFromBlueprint but with null nodeModulesPath', function() {
    command.project.hasDependencies = function() { return false; };

    expect(function() {
      command.validateAndRun(['controller', 'foo']);
    }).to.throw(SilentError, 'node_modules appears empty, you may need to run `npm install`');
  });

  it('runs GenerateFromBlueprint with expected options', function() {
    return command.validateAndRun(['controller', 'foo'])
      .then(function(options) {
        expect(options.pod).to.be.false;
        expect(options.dryRun).to.be.false;
        expect(options.verbose).to.be.false;
        expect(options.args).to.deep.equal(['controller', 'foo']);
      });
  });

  it('does not throws errors when beforeRun is invoked without the blueprint name', function() {
    expect(function() {
      command.beforeRun([]);
    }).to.not.throw();
  });

  it('complains if no blueprint name is given', function() {
    return command.validateAndRun([])
      .then(function() {
        expect(false, 'should not have called run').to.be.ok;
      })
      .catch(function(error) {
        expect(error.message).to.equal(
            'The `ember generate` command requires a ' +
            'blueprint name to be specified. ' +
            'For more details, use `ember help`.');
      });
  });

  describe('help', function() {
    beforeEach(function() {
      td.replace(Blueprint, 'list', td.function());
    });

    it('lists available blueprints', function() {
      td.when(Blueprint.list(), {ignoreExtraArgs: true}).thenReturn([
        {
          source: 'my-app',
          blueprints: [
            {
              name: 'my-blueprint',
              availableOptions: [],
              printBasicHelp: function() {
                return this.name;
              }
            },
            {
              name: 'other-blueprint',
              availableOptions: [],
              printBasicHelp: function() {
                return this.name;
              }
            }
          ]
        }
      ]);

      command.printDetailedHelp({});

      var output = options.ui.output;

      var testString = processHelpString(EOL + '\
  Available blueprints:' + EOL + '\
    my-app:' + EOL + '\
my-blueprint' + EOL + '\
other-blueprint' + EOL + '\
' + EOL);

      expect(output).to.equal(testString);
    });

    it('lists available blueprints json', function() {
      td.when(Blueprint.list(), {ignoreExtraArgs: true}).thenReturn([
        {
          source: 'my-app',
          blueprints: [
            {
              name: 'my-blueprint',
              availableOptions: [],
              getJson: function() {
                return {
                  name: this.name
                };
              }
            },
            {
              name: 'other-blueprint',
              availableOptions: [],
              getJson: function() {
                return {
                  name: this.name
                };
              }
            }
          ]
        }
      ]);

      var json = {};

      command.addAdditionalJsonForHelp(json, {
        json: true
      });

      expect(json.availableBlueprints).to.deep.equal([
        {
          'my-app': [
            {
              name: 'my-blueprint',
            },
            {
              name: 'other-blueprint',
            }
          ]
        }
      ]);
    });

    it('works with single blueprint', function() {
      td.when(Blueprint.list(), {ignoreExtraArgs: true}).thenReturn([
        {
          source: 'my-app',
          blueprints: [
            {
              name: 'my-blueprint',
              availableOptions: [],
              printBasicHelp: function() {
                return this.name;
              }
            },
            {
              name: 'skipped-blueprint'
            }
          ]
        }
      ]);

      command.printDetailedHelp({
        rawArgs: ['my-blueprint']
      });

      var output = options.ui.output;

      var testString = processHelpString('\
my-blueprint' + EOL + '\
' + EOL);

      expect(output).to.equal(testString);
    });

    it('works with single blueprint json', function() {
      td.when(Blueprint.list(), {ignoreExtraArgs: true}).thenReturn([
        {
          source: 'my-app',
          blueprints: [
            {
              name: 'my-blueprint',
              availableOptions: [],
              getJson: function() {
                return {
                  name: this.name
                };
              }
            },
            {
              name: 'skipped-blueprint'
            }
          ]
        }
      ]);

      var json = {};

      command.addAdditionalJsonForHelp(json, {
        rawArgs: ['my-blueprint'],
        json: true
      });

      expect(json.availableBlueprints).to.deep.equal([
        {
          'my-app': [
            {
              name: 'my-blueprint',
            }
          ]
        }
      ]);
    });

    it('handles missing blueprint', function() {
      td.when(Blueprint.list(), {ignoreExtraArgs: true}).thenReturn([
        {
          source: 'my-app',
          blueprints: [
            {
              name: 'my-blueprint'
            }
          ]
        }
      ]);

      command.printDetailedHelp({
        rawArgs: ['missing-blueprint']
      });

      var output = options.ui.output;

      var testString = processHelpString('\
\u001b[33mThe \'missing-blueprint\' blueprint does not exist in this project.\u001b[39m' + EOL + '\
' + EOL);

      expect(output).to.equal(testString);
    });

    it('handles missing blueprint json', function() {
      td.when(Blueprint.list(), {ignoreExtraArgs: true}).thenReturn([
        {
          source: 'my-app',
          blueprints: [
            {
              name: 'my-blueprint'
            }
          ]
        }
      ]);

      var json = {};

      command.addAdditionalJsonForHelp(json, {
        rawArgs: ['missing-blueprint'],
        json: true
      });

      expect(json.availableBlueprints).to.deep.equal([
        {
          'my-app': []
        }
      ]);
    });

    it('ignores overridden blueprints when verbose false', function() {
      td.when(Blueprint.list(), {ignoreExtraArgs: true}).thenReturn([
        {
          source: 'my-app',
          blueprints: [
            {
              name: 'my-blueprint',
              availableOptions: [],
              printBasicHelp: function() {
                return this.name;
              },
              overridden: true
            }
          ]
        }
      ]);

      command.printDetailedHelp({});

      var output = options.ui.output;

      var testString = processHelpString(EOL + '\
  Available blueprints:' + EOL + '\
' + EOL);

      expect(output).to.equal(testString);
    });

    it('shows overridden blueprints when verbose true', function() {
      td.when(Blueprint.list(), {ignoreExtraArgs: true}).thenReturn([
        {
          source: 'my-app',
          blueprints: [
            {
              name: 'my-blueprint',
              availableOptions: [],
              printBasicHelp: function() {
                return this.name;
              },
              overridden: true
            }
          ]
        }
      ]);

      command.printDetailedHelp({
        verbose: true
      });

      var output = options.ui.output;

      var testString = processHelpString(EOL + '\
  Available blueprints:' + EOL + '\
    my-app:' + EOL + '\
my-blueprint' + EOL + '\
' + EOL);

      expect(output).to.equal(testString);
    });
  });
});
<|endoftext|>


<commit_before>/*
 * The MIT License
 *
 * Copyright (c) 2015, Patrick Fitzgerald
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the 'Software'), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

'use strict';

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var openURL = require('open');
var lazypipe = require('lazypipe');
var rimraf = require('rimraf');
var wiredep = require('wiredep').stream;
var runSequence = require('run-sequence');

var yeoman = {
  app: require('./bower.json').appPath || 'app',
  dist: 'dist'
};

var paths = {
  scripts: [yeoman.app + '/scripts/**/*.js'],
  styles: [yeoman.app + '/styles/**/*.css'],
  test: ['test/spec/**/*.js'],
  testRequire: [
    yeoman.app + '/bower_components/angular/angular.js',
    yeoman.app + '/bower_components/angular-mocks/angular-mocks.js',
    yeoman.app + '/bower_components/angular-resource/angular-resource.js',
    yeoman.app + '/bower_components/angular-cookies/angular-cookies.js',
    yeoman.app + '/bower_components/angular-sanitize/angular-sanitize.js',
    yeoman.app + '/bower_components/angular-route/angular-route.js',
    'test/mock/**/*.js',
    'test/spec/**/*.js'
  ],
  karma: 'karma.conf.js',
  views: {
    main: yeoman.app + '/index.html',
    files: [ yeoman.app + '/views/**/*.html' ]
  }
};

////////////////////////
// Reusable pipelines //
////////////////////////

var lintScripts = lazypipe()
  .pipe($.jshint, '.jshintrc')
  .pipe($.jshint.reporter, 'jshint-stylish');

var styles = lazypipe()
  .pipe($.autoprefixer, 'last 1 version')
  .pipe(gulp.dest, '.tmp/styles');

///////////
// Tasks //
///////////

gulp.task('styles', function () {
  return gulp.src(paths.styles)
    .pipe(styles());
});

gulp.task('lint:scripts', function () {
  return gulp.src(paths.scripts)
    .pipe(lintScripts());
});

gulp.task('clean:tmp', function (cb) {
  rimraf('./.tmp', cb);
});

gulp.task('watch', function () {
  gulp.watch('bower.json', ['bower']);
});

// inject bower components
gulp.task('bower', function () {
  return gulp.src(paths.views.main)
    .pipe(wiredep({
      directory: yeoman.app + '/bower_components',
      ignorePath: '..'
    }))
  .pipe(gulp.dest(yeoman.app + '/views'));
});

gulp.task('html', function () {
  return gulp.src(yeoman.app + '/views/**/*')
    .pipe(gulp.dest(yeoman.dist + '/views'));
});

gulp.task('html:app', function () {
  return gulp.src(yeoman.app + '/scripts/app/views/**/*.html')
    .pipe(gulp.dest(yeoman.dist + '/scripts/app/views'));
});

gulp.task('html:cluster', function () {
  return gulp.src(yeoman.app + '/scripts/modules/cluster/views/**/*.html')
    .pipe(gulp.dest(yeoman.dist + '/scripts/modules/cluster/views'));
});

///////////
// Build //
///////////

gulp.task('clean:dist', function (cb) {
  rimraf('./dist', cb);
});

gulp.task('client:build', [ 'html', 'html:app', 'html:cluster', 'styles' ], function () {
  var jsFilter = $.filter('**/*.js', {restore: true});
  var cssFilter = $.filter('**/*.css', {restore: true});

  return gulp.src(paths.views.main)
    .pipe($.useref({searchPath: [yeoman.app, '.tmp']}))
    .pipe(jsFilter)
    .pipe($.ngAnnotate())
    .pipe($.uglify())
    .pipe(jsFilter.restore())
    .pipe(cssFilter)
    .pipe($.minifyCss({cache: true}))
    .pipe(cssFilter.restore())
    .pipe($.rev())
    .pipe($.revReplace())
    // .pipe(header(getLicense()))
    // .pipe(header('/* ' + pkg.name + ' version ' + pkg.version + ' */ \n' ))
    .pipe(gulp.dest(yeoman.dist));
});

gulp.task('rename:index', function () {
  return gulp.src(yeoman.dist + '/*.html')
    .pipe($.rename('/index.html'))
    .pipe(gulp.dest(yeoman.dist));
});

gulp.task('ngm:images', function () {
  return gulp.src(yeoman.app + '/images/**/*')
    .pipe($.cache($.imagemin({
        optimizationLevel: 5,
        progressive: true,
        interlaced: true
    })))
    .pipe(gulp.dest(yeoman.dist + '/images'));
});

gulp.task('bower:images', function () {
  return gulp.src(yeoman.app + '/../bower_components/**/images/**/*')
    .pipe($.flatten())
    .pipe(gulp.dest(yeoman.dist + '/styles/images'));
});

gulp.task('fullscreen:images', function () {
  return gulp.src(yeoman.app + '/images/fullscreen.png')
    .pipe(gulp.dest(yeoman.dist + '/styles'));
});

gulp.task('copy:static', function () {
  return gulp.src(yeoman.app + '/static/**/*')
    .pipe(gulp.dest(yeoman.dist + '/static'));
});

gulp.task('copy:extras', function () {
  return gulp.src(yeoman.app + '/*/.*', { dot: true })
    .pipe(gulp.dest(yeoman.dist));
});

gulp.task('copy:widgets', function () {
  // widgets
  gulp.src(yeoman.app + '/scripts/widgets/**/*.js')
    .pipe(gulp.dest(yeoman.dist + '/scripts/widgets'));
  // html
  gulp.src(yeoman.app + '/scripts/widgets/**/*.html')
    .pipe(gulp.dest(yeoman.dist + '/scripts/widgets'));
});

gulp.task('copy:fonts', function () {
  return gulp.src(yeoman.app + '/fonts/**/*')
    .pipe(gulp.dest(yeoman.dist + '/fonts'));
});

gulp.task('copy:mfonts', function () {
  return gulp.src(yeoman.app + '/../bower_components/materialize/fonts/**/*')
    .pipe(gulp.dest(yeoman.dist + '/fonts'));
});

gulp.task('build', ['clean:dist'], function () {
  runSequence(['ngm:images', 'bower:images', 'fullscreen:images', 'copy:static', 'copy:extras', 'copy:widgets', 'copy:fonts', 'copy:mfonts', 'client:build'], 'rename:index');
});

gulp.task('default', ['build']);

<commit_msg>gulp: update to gulp to include views for country module. This UI framework needs a re-write<commit_after>/*
 * The MIT License
 *
 * Copyright (c) 2015, Patrick Fitzgerald
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the 'Software'), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

'use strict';

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var openURL = require('open');
var lazypipe = require('lazypipe');
var rimraf = require('rimraf');
var wiredep = require('wiredep').stream;
var runSequence = require('run-sequence');

var yeoman = {
  app: require('./bower.json').appPath || 'app',
  dist: 'dist'
};

var paths = {
  scripts: [yeoman.app + '/scripts/**/*.js'],
  styles: [yeoman.app + '/styles/**/*.css'],
  test: ['test/spec/**/*.js'],
  testRequire: [
    yeoman.app + '/bower_components/angular/angular.js',
    yeoman.app + '/bower_components/angular-mocks/angular-mocks.js',
    yeoman.app + '/bower_components/angular-resource/angular-resource.js',
    yeoman.app + '/bower_components/angular-cookies/angular-cookies.js',
    yeoman.app + '/bower_components/angular-sanitize/angular-sanitize.js',
    yeoman.app + '/bower_components/angular-route/angular-route.js',
    'test/mock/**/*.js',
    'test/spec/**/*.js'
  ],
  karma: 'karma.conf.js',
  views: {
    main: yeoman.app + '/index.html',
    files: [ yeoman.app + '/views/**/*.html' ]
  }
};

////////////////////////
// Reusable pipelines //
////////////////////////

var lintScripts = lazypipe()
  .pipe($.jshint, '.jshintrc')
  .pipe($.jshint.reporter, 'jshint-stylish');

var styles = lazypipe()
  .pipe($.autoprefixer, 'last 1 version')
  .pipe(gulp.dest, '.tmp/styles');

///////////
// Tasks //
///////////

gulp.task('styles', function () {
  return gulp.src(paths.styles)
    .pipe(styles());
});

gulp.task('lint:scripts', function () {
  return gulp.src(paths.scripts)
    .pipe(lintScripts());
});

gulp.task('clean:tmp', function (cb) {
  rimraf('./.tmp', cb);
});

gulp.task('watch', function () {
  gulp.watch('bower.json', ['bower']);
});

// inject bower components
gulp.task('bower', function () {
  return gulp.src(paths.views.main)
    .pipe(wiredep({
      directory: yeoman.app + '/bower_components',
      ignorePath: '..'
    }))
  .pipe(gulp.dest(yeoman.app + '/views'));
});

gulp.task('html', function () {
  return gulp.src(yeoman.app + '/views/**/*')
    .pipe(gulp.dest(yeoman.dist + '/views'));
});

gulp.task('html:app', function () {
  return gulp.src(yeoman.app + '/scripts/app/views/**/*.html')
    .pipe(gulp.dest(yeoman.dist + '/scripts/app/views'));
});

gulp.task('html:cluster', function () {
  return gulp.src(yeoman.app + '/scripts/modules/cluster/views/**/*.html')
    .pipe(gulp.dest(yeoman.dist + '/scripts/modules/cluster/views'));
});

gulp.task('html:country', function () {
  return gulp.src(yeoman.app + '/scripts/modules/country/ethiopia/views/**/*.html')
    .pipe(gulp.dest(yeoman.dist + '/scripts/modules/country/ethiopia/views'));
});

///////////
// Build //
///////////

gulp.task('clean:dist', function (cb) {
  rimraf('./dist', cb);
});

gulp.task('client:build', [ 'html', 'html:app', 'html:cluster', 'styles' ], function () {
  var jsFilter = $.filter('**/*.js', {restore: true});
  var cssFilter = $.filter('**/*.css', {restore: true});

  return gulp.src(paths.views.main)
    .pipe($.useref({searchPath: [yeoman.app, '.tmp']}))
    .pipe(jsFilter)
    .pipe($.ngAnnotate())
    .pipe($.uglify())
    .pipe(jsFilter.restore())
    .pipe(cssFilter)
    .pipe($.minifyCss({cache: true}))
    .pipe(cssFilter.restore())
    .pipe($.rev())
    .pipe($.revReplace())
    // .pipe(header(getLicense()))
    // .pipe(header('/* ' + pkg.name + ' version ' + pkg.version + ' */ \n' ))
    .pipe(gulp.dest(yeoman.dist));
});

gulp.task('rename:index', function () {
  return gulp.src(yeoman.dist + '/*.html')
    .pipe($.rename('/index.html'))
    .pipe(gulp.dest(yeoman.dist));
});

gulp.task('ngm:images', function () {
  return gulp.src(yeoman.app + '/images/**/*')
    .pipe($.cache($.imagemin({
        optimizationLevel: 5,
        progressive: true,
        interlaced: true
    })))
    .pipe(gulp.dest(yeoman.dist + '/images'));
});

gulp.task('bower:images', function () {
  return gulp.src(yeoman.app + '/../bower_components/**/images/**/*')
    .pipe($.flatten())
    .pipe(gulp.dest(yeoman.dist + '/styles/images'));
});

gulp.task('fullscreen:images', function () {
  return gulp.src(yeoman.app + '/images/fullscreen.png')
    .pipe(gulp.dest(yeoman.dist + '/styles'));
});

gulp.task('copy:static', function () {
  return gulp.src(yeoman.app + '/static/**/*')
    .pipe(gulp.dest(yeoman.dist + '/static'));
});

gulp.task('copy:extras', function () {
  return gulp.src(yeoman.app + '/*/.*', { dot: true })
    .pipe(gulp.dest(yeoman.dist));
});

gulp.task('copy:widgets', function () {
  // widgets
  gulp.src(yeoman.app + '/scripts/widgets/**/*.js')
    .pipe(gulp.dest(yeoman.dist + '/scripts/widgets'));
  // html
  gulp.src(yeoman.app + '/scripts/widgets/**/*.html')
    .pipe(gulp.dest(yeoman.dist + '/scripts/widgets'));
});

gulp.task('copy:fonts', function () {
  return gulp.src(yeoman.app + '/fonts/**/*')
    .pipe(gulp.dest(yeoman.dist + '/fonts'));
});

gulp.task('copy:mfonts', function () {
  return gulp.src(yeoman.app + '/../bower_components/materialize/fonts/**/*')
    .pipe(gulp.dest(yeoman.dist + '/fonts'));
});

gulp.task('build', ['clean:dist'], function () {
  runSequence(['ngm:images', 'bower:images', 'fullscreen:images', 'copy:static', 'copy:extras', 'copy:widgets', 'copy:fonts', 'copy:mfonts', 'client:build'], 'rename:index');
});

gulp.task('default', ['build']);

<|endoftext|>


<commit_before>'use strict';

const Boom = require('boom'); // error handling https://github.com/hapijs/boom
const assert = require('assert'); // use assert to check if options are set
const JWT = require('jsonwebtoken'); // https://github.com/docdis/learn-json-web-tokens
const extract = require('./extract'); // extract token from Auth Header, URL or Coookie
const pkg = require('../package.json'); // use package name and version rom package.json
const internals = {}; // see: http://hapijs.com/styleguide#module-globals

/**
 * register registers the name and exposes the implementation of the plugin
 * see: http://hapijs.com/api#serverplugins for plugin format
 * @param {Object} server - the hapi server to which we are attaching the plugin
 * @param {Object} options - any options set during plugin registration
 * in this case we are not using the options during register but we do later.
 * @param {Function} next - the callback called once registration succeeds
 * @returns {Function} next - returns (calls) the callback when complete.
 */
exports.plugin = {
  register: function(server, options) {
    server.auth.scheme('jwt', internals.implementation); // hapijs.com/api#serverauthapi
  },
};

/**
 * attributes merely aliases the package.json (re-uses package name & version)
 * simple example: github.com/hapijs/hapi/blob/master/API.md#serverplugins
 */
exports.plugin.pkg = pkg; // hapi requires attributes for a plugin.
// also see: http://hapijs.com/tutorials/plugins

/**
 * specify peer dependency on hapi, enforced by hapi at runtime
 */
exports.plugin.requirements = {
  hapi: '>=17',
};

/**
 * checkObjectType returns the class of the object's prototype
 * @param {Object} objectToCheck - the object for which we want to check the type
 * @returns {String} - the string of the object class
 */
internals.checkObjectType = function(objectToCheck) {
  const toString = Object.prototype.toString;
  return toString.call(objectToCheck);
};

/**
 * isFunction checks if a given value is a function.
 * @param {Object} functionToCheck - the object we want to confirm is a function
 * @returns {Boolean} - true if the functionToCheck is a function. :-)
 */
internals.isFunction = function(functionToCheck) {
  return (
    functionToCheck &&
    (internals.checkObjectType(functionToCheck) === '[object Function]' ||
      internals.checkObjectType(functionToCheck) === '[object AsyncFunction]')
  );
};

internals.getKeys = async function(decoded, options) {
  // if keyFunc is function allow dynamic key lookup: https://git.io/vXjvY
  const { key, ...extraInfo } = internals.isFunction(options.key)
    ? await options.key(decoded)
    : { key: options.key };
  const keys = Array.isArray(key) ? key : [key];
  return { keys, extraInfo };
};

internals.verifyJwt = function(token, keys, options) {
  let error;
  for (const k of keys) {
    try {
      return JWT.verify(token, k, options.verifyOptions);
    } catch (verify_err) {
      error = verify_err;
    }
  }
  throw error;
};

/**
 * implementation is the "main" interface to the plugin and contains all the
 * "implementation details" (methods) such as authenicate, response & raiseError
 * @param {Object} server - the Hapi.js server object we are attaching the
 * the hapi-auth-jwt2 plugin to.
 * @param {Object} options - any configuration options passed in.
 * @returns {Function} authenicate - we return the authenticate method after
 * registering the plugin as that's the method that gets called for each route.
 */
internals.implementation = function(server, options) {
  assert(options, 'options are required for jwt auth scheme'); // pre-auth checks
  assert(
    options.validate || options.verify,
    'validate OR verify function is required!'
  );

  // allow custom error raising or default to Boom if no errorFunc is defined
  function raiseError(errorType, message, scheme, attributes) {
    let errorContext = {
      errorType: errorType,
      message: message,
      scheme: scheme,
      attributes: attributes,
    };

    if (internals.isFunction(options.errorFunc)) {
      errorContext = options.errorFunc(errorContext);
    }
    // Since it is clearly speacified in the docs that
    // the errorFunc must return an object with keys:
    // errorType and message, we need not worry about
    // errorContext being undefined
    const _errorType = errorContext.errorType;
    const _message = errorContext.message;
    const _scheme = errorContext.scheme;
    const _attributes = errorContext.attributes;

    return Boom[_errorType](_message, _scheme, _attributes);
  }

  return {
    /**
     * authenticate is the "work horse" of the plugin. it's the method that gets
     * called every time a route is requested and needs to validate/verify a JWT
     * @param {Object} request - the standard route handler request object
     * @param {Object} h - the standard hapi reply interface
     * @returns {Boolean} if the JWT is valid we return a credentials object
     * otherwise throw an error to inform the app & client of unauthorized req.
     */
    authenticate: async function(request, h) {
      let token = extract(request, options); // extract token Header/Cookie/Query
      let tokenType = options.tokenType || 'Token'; // see: https://git.io/vXje9
      let decoded;

      if (!token) {
        return h.unauthenticated(raiseError('unauthorized', null, tokenType), {
          credentials: tokenType,
        });
      }

      // If we are receiving a headerless JWT token let reconstruct it using the custom function
      if (
        options.headless &&
        typeof options.headless === 'object' &&
        extract.isHeadless(token)
      ) {
        token = `${Buffer.from(JSON.stringify(options.headless)).toString(
          'base64'
        )}.${token}`;
      }

      // quick check for validity of token format
      if (!extract.isValid(token)) {
        return h.unauthenticated(
          raiseError('unauthorized', 'Invalid token format', tokenType),
          { credentials: token }
        );
      }
      // verification is done later, but we want to avoid decoding if malformed
      request.auth.token = token; // keep encoded JWT available in the request
      // otherwise use the same key (String) to validate all JWTs
      try {
        decoded = JWT.decode(token, { complete: options.complete || false });
      } catch (e) {
        return h.unauthenticated(
          raiseError('unauthorized', 'Invalid token format', tokenType),
          { credentials: token }
        );
      }

      if (typeof options.validate === 'function') {
        const { keys, extraInfo } = await internals.getKeys(decoded, options);

        /* istanbul ignore else */
        if (extraInfo) {
          request.plugins[pkg.name] = { extraInfo };
        }

        let verify_decoded;
        try {
          verify_decoded = internals.verifyJwt(token, keys, options);
        } catch (verify_err) {
          let err_message =
            verify_err.message === 'jwt expired'
              ? 'Expired token'
              : 'Invalid token';
          return h.unauthenticated(
            raiseError('unauthorized', err_message, tokenType),
            { credentials: token }
          );
        }

        try {
          let { isValid, credentials, response } = await options.validate(
            verify_decoded,
            request,
            h
          );
          if (response !== undefined) {
            return h.response(response).takeover();
          }
          if (!isValid) {
            // invalid credentials
            return h.unauthenticated(
              raiseError('unauthorized', 'Invalid credentials', tokenType),
              { credentials: decoded }
            );
          }
          // valid key and credentials
          return h.authenticated({
            credentials:
              credentials && typeof credentials === 'object'
                ? credentials
                : decoded,
            artifacts: token,
          });
        } catch (validate_err) {
          return h.unauthenticated(raiseError('boomify', validate_err), {
            credentials: decoded,
          });
        }
      }
      // see: https://github.com/dwyl/hapi-auth-jwt2/issues/130
      try {
        let { isValid, credentials } = await options.verify(decoded, request);
        if (!isValid) {
          return h.unauthenticated(
            raiseError('unauthorized', 'Invalid credentials', tokenType),
            { credentials: decoded }
          );
        }

        return h.authenticated({
          credentials: credentials,
          artifacts: token,
        });
      } catch (verify_error) {
        return h.unauthenticated(raiseError('boomify', verify_error), {
          credentials: decoded,
        });
      }
    },
    // payload is an Optional method called if an options.payload is set.
    // cf. https://hapijs.com/tutorials/auth?lang=en_US
    /**
     * response is an Optional method called if an options.responseFunc is set.
     * @param {Object} request - the standard route handler request object
     * @param {Object} h - the standard hapi reply interface ...
     * after we run the custom options.responseFunc we h.continue to execute
     * the next plugin in the list.
     * @returns {Boolean} true. always return true (unless there's an error...)
     */
    response: function(request, h) {
      const responseFunc = options.responseFunc;
      if (responseFunc && typeof responseFunc === 'function') {
        if (
          internals.checkObjectType(responseFunc) === '[object AsyncFunction]'
        ) {
          return responseFunc(request, h)
            .then(() => h.continue)
            .catch(err => raiseError('boomify', err));
        }
        try {
          // allow responseFunc to decorate or throw
          responseFunc(request, h);
        } catch (err) {
          throw raiseError('boomify', err);
        }
      }
      return h.continue;
    },

    verify: async function(auth) {
      const token = auth.artifacts;
      const decoded = JWT.decode(token, {
        complete: options.complete || false,
      });
      const { keys } = await internals.getKeys(decoded, options);
      internals.verifyJwt(token, keys, options);
    },
  };
};
<commit_msg>RaiseError: Removing surplus constants<commit_after>'use strict';

const Boom = require('boom'); // error handling https://github.com/hapijs/boom
const assert = require('assert'); // use assert to check if options are set
const JWT = require('jsonwebtoken'); // https://github.com/docdis/learn-json-web-tokens
const extract = require('./extract'); // extract token from Auth Header, URL or Coookie
const pkg = require('../package.json'); // use package name and version rom package.json
const internals = {}; // see: http://hapijs.com/styleguide#module-globals

/**
 * register registers the name and exposes the implementation of the plugin
 * see: http://hapijs.com/api#serverplugins for plugin format
 * @param {Object} server - the hapi server to which we are attaching the plugin
 * @param {Object} options - any options set during plugin registration
 * in this case we are not using the options during register but we do later.
 * @param {Function} next - the callback called once registration succeeds
 * @returns {Function} next - returns (calls) the callback when complete.
 */
exports.plugin = {
  register: function(server, options) {
    server.auth.scheme('jwt', internals.implementation); // hapijs.com/api#serverauthapi
  },
};

/**
 * attributes merely aliases the package.json (re-uses package name & version)
 * simple example: github.com/hapijs/hapi/blob/master/API.md#serverplugins
 */
exports.plugin.pkg = pkg; // hapi requires attributes for a plugin.
// also see: http://hapijs.com/tutorials/plugins

/**
 * specify peer dependency on hapi, enforced by hapi at runtime
 */
exports.plugin.requirements = {
  hapi: '>=17',
};

/**
 * checkObjectType returns the class of the object's prototype
 * @param {Object} objectToCheck - the object for which we want to check the type
 * @returns {String} - the string of the object class
 */
internals.checkObjectType = function(objectToCheck) {
  const toString = Object.prototype.toString;
  return toString.call(objectToCheck);
};

/**
 * isFunction checks if a given value is a function.
 * @param {Object} functionToCheck - the object we want to confirm is a function
 * @returns {Boolean} - true if the functionToCheck is a function. :-)
 */
internals.isFunction = function(functionToCheck) {
  return (
    functionToCheck &&
    (internals.checkObjectType(functionToCheck) === '[object Function]' ||
      internals.checkObjectType(functionToCheck) === '[object AsyncFunction]')
  );
};

internals.getKeys = async function(decoded, options) {
  // if keyFunc is function allow dynamic key lookup: https://git.io/vXjvY
  const { key, ...extraInfo } = internals.isFunction(options.key)
    ? await options.key(decoded)
    : { key: options.key };
  const keys = Array.isArray(key) ? key : [key];
  return { keys, extraInfo };
};

internals.verifyJwt = function(token, keys, options) {
  let error;
  for (const k of keys) {
    try {
      return JWT.verify(token, k, options.verifyOptions);
    } catch (verify_err) {
      error = verify_err;
    }
  }
  throw error;
};

/**
 * implementation is the "main" interface to the plugin and contains all the
 * "implementation details" (methods) such as authenicate, response & raiseError
 * @param {Object} server - the Hapi.js server object we are attaching the
 * the hapi-auth-jwt2 plugin to.
 * @param {Object} options - any configuration options passed in.
 * @returns {Function} authenicate - we return the authenticate method after
 * registering the plugin as that's the method that gets called for each route.
 */
internals.implementation = function(server, options) {
  assert(options, 'options are required for jwt auth scheme'); // pre-auth checks
  assert(
    options.validate || options.verify,
    'validate OR verify function is required!'
  );

  // allow custom error raising or default to Boom if no errorFunc is defined
  function raiseError(errorType, message, scheme, attributes) {
    let errorContext = {
      errorType: errorType,
      message: message,
      scheme: scheme,
      attributes: attributes,
    };

    if (internals.isFunction(options.errorFunc)) {
      errorContext = options.errorFunc(errorContext);
    }
    // Since it is clearly speacified in the docs that
    // the errorFunc must return an object with keys:
    // errorType and message, we need not worry about
    // errorContext being undefined

    return Boom[errorContext.errorType](
      errorContext.message,
      errorContext.scheme,
      errorContext.attributes
    );
  }

  return {
    /**
     * authenticate is the "work horse" of the plugin. it's the method that gets
     * called every time a route is requested and needs to validate/verify a JWT
     * @param {Object} request - the standard route handler request object
     * @param {Object} h - the standard hapi reply interface
     * @returns {Boolean} if the JWT is valid we return a credentials object
     * otherwise throw an error to inform the app & client of unauthorized req.
     */
    authenticate: async function(request, h) {
      let token = extract(request, options); // extract token Header/Cookie/Query
      let tokenType = options.tokenType || 'Token'; // see: https://git.io/vXje9
      let decoded;

      if (!token) {
        return h.unauthenticated(raiseError('unauthorized', null, tokenType), {
          credentials: tokenType,
        });
      }

      // If we are receiving a headerless JWT token let reconstruct it using the custom function
      if (
        options.headless &&
        typeof options.headless === 'object' &&
        extract.isHeadless(token)
      ) {
        token = `${Buffer.from(JSON.stringify(options.headless)).toString(
          'base64'
        )}.${token}`;
      }

      // quick check for validity of token format
      if (!extract.isValid(token)) {
        return h.unauthenticated(
          raiseError('unauthorized', 'Invalid token format', tokenType),
          { credentials: token }
        );
      }
      // verification is done later, but we want to avoid decoding if malformed
      request.auth.token = token; // keep encoded JWT available in the request
      // otherwise use the same key (String) to validate all JWTs
      try {
        decoded = JWT.decode(token, { complete: options.complete || false });
      } catch (e) {
        return h.unauthenticated(
          raiseError('unauthorized', 'Invalid token format', tokenType),
          { credentials: token }
        );
      }

      if (typeof options.validate === 'function') {
        const { keys, extraInfo } = await internals.getKeys(decoded, options);

        /* istanbul ignore else */
        if (extraInfo) {
          request.plugins[pkg.name] = { extraInfo };
        }

        let verify_decoded;
        try {
          verify_decoded = internals.verifyJwt(token, keys, options);
        } catch (verify_err) {
          let err_message =
            verify_err.message === 'jwt expired'
              ? 'Expired token'
              : 'Invalid token';
          return h.unauthenticated(
            raiseError('unauthorized', err_message, tokenType),
            { credentials: token }
          );
        }

        try {
          let { isValid, credentials, response } = await options.validate(
            verify_decoded,
            request,
            h
          );
          if (response !== undefined) {
            return h.response(response).takeover();
          }
          if (!isValid) {
            // invalid credentials
            return h.unauthenticated(
              raiseError('unauthorized', 'Invalid credentials', tokenType),
              { credentials: decoded }
            );
          }
          // valid key and credentials
          return h.authenticated({
            credentials:
              credentials && typeof credentials === 'object'
                ? credentials
                : decoded,
            artifacts: token,
          });
        } catch (validate_err) {
          return h.unauthenticated(raiseError('boomify', validate_err), {
            credentials: decoded,
          });
        }
      }
      // see: https://github.com/dwyl/hapi-auth-jwt2/issues/130
      try {
        let { isValid, credentials } = await options.verify(decoded, request);
        if (!isValid) {
          return h.unauthenticated(
            raiseError('unauthorized', 'Invalid credentials', tokenType),
            { credentials: decoded }
          );
        }

        return h.authenticated({
          credentials: credentials,
          artifacts: token,
        });
      } catch (verify_error) {
        return h.unauthenticated(raiseError('boomify', verify_error), {
          credentials: decoded,
        });
      }
    },
    // payload is an Optional method called if an options.payload is set.
    // cf. https://hapijs.com/tutorials/auth?lang=en_US
    /**
     * response is an Optional method called if an options.responseFunc is set.
     * @param {Object} request - the standard route handler request object
     * @param {Object} h - the standard hapi reply interface ...
     * after we run the custom options.responseFunc we h.continue to execute
     * the next plugin in the list.
     * @returns {Boolean} true. always return true (unless there's an error...)
     */
    response: function(request, h) {
      const responseFunc = options.responseFunc;
      if (responseFunc && typeof responseFunc === 'function') {
        if (
          internals.checkObjectType(responseFunc) === '[object AsyncFunction]'
        ) {
          return responseFunc(request, h)
            .then(() => h.continue)
            .catch(err => raiseError('boomify', err));
        }
        try {
          // allow responseFunc to decorate or throw
          responseFunc(request, h);
        } catch (err) {
          throw raiseError('boomify', err);
        }
      }
      return h.continue;
    },

    verify: async function(auth) {
      const token = auth.artifacts;
      const decoded = JWT.decode(token, {
        complete: options.complete || false,
      });
      const { keys } = await internals.getKeys(decoded, options);
      internals.verifyJwt(token, keys, options);
    },
  };
};
<|endoftext|>


<commit_before>import assert from 'assert';
import path from 'path';
import Promise from 'bluebird';
import requireAll from 'require-all';
import mapValues from 'lodash/object/mapValues';
import isArray from 'lodash/lang/isArray';
import Adapter from './adapter';
import RawAdapter from './adapters/raw';
import MongooseAdapter from './adapters/mongoose';
import Serializer from './serializer';
import JSONAPISerializer from './serializers/jsonapi';
import RootSerializer from './serializers/root';
import FlatSerializer from './serializers/flat';

export {
  Serializer,
  JSONAPISerializer,
  RootSerializer,
  FlatSerializer,
  Adapter,
  RawAdapter,
  MongooseAdapter
};

/**
 * Create a blackburn middleware function that will override res.render to use
 * the blackburn serializers and renderers. The res.render method takes to
 * arguments:
 *
 * * `payload` - either a record, an array of records, or an Error object. Can
 *   also be a Promise which resolves to any of those.
 * * `options` - any options to pass to the serializer or adapter. Blackburn
 *   doesn't use any of these options out of the box, but this allows you to
 *   pass additional information into any custom adapters or serializers.
 *
 * `res.render()` will return a promise which resolves once the response has
 * been rendered.
 *
 * @example
 *
 * import blackburn, { RawAdapter } from 'blackburn';
 *
 * app.use(blackburn({ adapter: RawAdapter }))
 * app.get('/posts', function(req, res, next) {
 *   res.render(Post.find());
 * });
 *
 * @method blackburn
 *
 * @param  {Object}  options
 * @param  {String|Object}  options.adapter - the adapter to use to interrogate
 * model instances
 * @param  {String|Object}   options.serializers - either the path to the
 * directory of serializers, or an object whose keys are model types, and
 * whose values are instances of their respective Serializers. Defaults to
 * 'serializers'. The "application" serializer will be used when no type
 * specific serializer is found.
 * @param  {String}          options.renderMethodName - the name of the render
 * method to attach to the response object. Defaults to 'render', which will
 * override the Express default render method.
 *
 * @return {Function}        blackburn middleware function
 */
export default function blackburn(options = {}) {
  // Load adapters
  let adapters;
  options.adapters = options.adapters || './adapters';
  if (typeof options.adapters === 'string') {
    adapters = requireAll(path.join(process.cwd(), options.adapters));
  } else {
    adapters = options.adapters;
  }
  // Allow for a single universal adapter (just make it the fallback)
  if (options.adapter) {
    adapters.application = options.adapter;
  }

  // Load serializers
  let serializers;
  options.serializers = options.serializers || './serializers';
  if (typeof options.serializers === 'string') {
    serializers = requireAll(path.join(process.cwd(), options.serializers));
  } else {
    serializers = options.serializers;
  }

  // Ensure they are instantiated
  function instantiate(Klass, type) {
    return typeof Klass !== 'function' ? Klass : new Klass({
      serializers,
      adapters,
      type
    });
  }
  serializers = mapValues(serializers, instantiate);
  adapters = mapValues(adapters, instantiate);

  let renderMethodName = options.renderMethodName || 'render';

  return function blackburnMiddleware(req, res, next) {
    res[renderMethodName] = function render(status, payloadPromise, opts) {

      // Ensure we don't double render
      assert(!res._rendered, `res.${ renderMethodName } called twice! You can only call it once per request.`);
      res._rendered = true;

      // Normalize arguments
      // res.render(payload);
      if (!payloadPromise && status) {
        opts = {};
        payloadPromise = status;
        status = null;
      // res.render(status, payload);
      } else if (typeof status === 'number' && !opts) {
        opts = {};
      // res.render(payload, options);
      } else if (typeof status !== 'number' && !opts) {
        opts = payloadPromise;
        payloadPromise = status;
        status = null;
      }

      return Promise.resolve(payloadPromise)
        .catch((error) => { return error; })
        .then((payload) => {

          // Determine the status code - 500 for errors, supplied (or 200) for
          // anything else
          if (payload instanceof Error) {
            res.status(payload.status || 500);
          } else {
            res.status(status || 200);
          }

          let adapter;
          // Adapter name is supplied
          if (typeof opts.adapter === 'string') {
            adapter = adapters[opts.adapter];
          // Adapter instance is supplied
          } else if (opts.adapter) {
            adapter = opts.adapter;
          // No adapter supplied, fall back to application adapter
          }
          opts.adapter = adapter || adapters.application;
          assert(opts.adapter, `Unable to render response! You didn't supply an adapter and you didn't supply an application adapter as a fallback.`);

          let serializer;
          // Serializer name is supplied
          if (typeof opts.serializer === 'string') {
            serializer = serializers[opts.serializer];
          // Serializer instance is supplied
          } else if (opts.serializer) {
            serializer = opts.serializer;
          // No serializer supplied - check the payload to try inferring
          } else {
            let sample = isArray(payload) ? payload[0] : payload;
            try {
              serializer = serializers[adapter.typeForRecord(sample)];
            } catch(e) {
              serializer = serializers.application;
            }
          }
          serializer = serializer || serializers.application;
          assert(serializer, `Unable to render response! You didn't supply a serializer, no serializer found matched the payload's type, and you didn't supply an application serializer as a fallback.`);

          res.json(serializer.render(payload, opts));

        }).catch((error) => {
          console.log('[blackburn] Error attempting to render a response:');
          console.log(error.stack || error);
        });
    };
    next();
  };
}
<commit_msg>fix adapter ref<commit_after>import assert from 'assert';
import path from 'path';
import Promise from 'bluebird';
import requireAll from 'require-all';
import mapValues from 'lodash/object/mapValues';
import isArray from 'lodash/lang/isArray';
import Adapter from './adapter';
import RawAdapter from './adapters/raw';
import MongooseAdapter from './adapters/mongoose';
import Serializer from './serializer';
import JSONAPISerializer from './serializers/jsonapi';
import RootSerializer from './serializers/root';
import FlatSerializer from './serializers/flat';

export {
  Serializer,
  JSONAPISerializer,
  RootSerializer,
  FlatSerializer,
  Adapter,
  RawAdapter,
  MongooseAdapter
};

/**
 * Create a blackburn middleware function that will override res.render to use
 * the blackburn serializers and renderers. The res.render method takes to
 * arguments:
 *
 * * `payload` - either a record, an array of records, or an Error object. Can
 *   also be a Promise which resolves to any of those.
 * * `options` - any options to pass to the serializer or adapter. Blackburn
 *   doesn't use any of these options out of the box, but this allows you to
 *   pass additional information into any custom adapters or serializers.
 *
 * `res.render()` will return a promise which resolves once the response has
 * been rendered.
 *
 * @example
 *
 * import blackburn, { RawAdapter } from 'blackburn';
 *
 * app.use(blackburn({ adapter: RawAdapter }))
 * app.get('/posts', function(req, res, next) {
 *   res.render(Post.find());
 * });
 *
 * @method blackburn
 *
 * @param  {Object}  options
 * @param  {String|Object}  options.adapter - the adapter to use to interrogate
 * model instances
 * @param  {String|Object}   options.serializers - either the path to the
 * directory of serializers, or an object whose keys are model types, and
 * whose values are instances of their respective Serializers. Defaults to
 * 'serializers'. The "application" serializer will be used when no type
 * specific serializer is found.
 * @param  {String}          options.renderMethodName - the name of the render
 * method to attach to the response object. Defaults to 'render', which will
 * override the Express default render method.
 *
 * @return {Function}        blackburn middleware function
 */
export default function blackburn(options = {}) {
  // Load adapters
  let adapters;
  options.adapters = options.adapters || './adapters';
  if (typeof options.adapters === 'string') {
    adapters = requireAll(path.join(process.cwd(), options.adapters));
  } else {
    adapters = options.adapters;
  }
  // Allow for a single universal adapter (just make it the fallback)
  if (options.adapter) {
    adapters.application = options.adapter;
  }

  // Load serializers
  let serializers;
  options.serializers = options.serializers || './serializers';
  if (typeof options.serializers === 'string') {
    serializers = requireAll(path.join(process.cwd(), options.serializers));
  } else {
    serializers = options.serializers;
  }

  // Ensure they are instantiated
  function instantiate(Klass, type) {
    return typeof Klass !== 'function' ? Klass : new Klass({
      serializers,
      adapters,
      type
    });
  }
  serializers = mapValues(serializers, instantiate);
  adapters = mapValues(adapters, instantiate);

  let renderMethodName = options.renderMethodName || 'render';

  return function blackburnMiddleware(req, res, next) {
    res[renderMethodName] = function render(status, payloadPromise, opts) {

      // Ensure we don't double render
      assert(!res._rendered, `res.${ renderMethodName } called twice! You can only call it once per request.`);
      res._rendered = true;

      // Normalize arguments
      // res.render(payload);
      if (!payloadPromise && status) {
        opts = {};
        payloadPromise = status;
        status = null;
      // res.render(status, payload);
      } else if (typeof status === 'number' && !opts) {
        opts = {};
      // res.render(payload, options);
      } else if (typeof status !== 'number' && !opts) {
        opts = payloadPromise;
        payloadPromise = status;
        status = null;
      }

      return Promise.resolve(payloadPromise)
        .catch((error) => { return error; })
        .then((payload) => {

          // Determine the status code - 500 for errors, supplied (or 200) for
          // anything else
          if (payload instanceof Error) {
            res.status(payload.status || 500);
          } else {
            res.status(status || 200);
          }

          let adapter;
          // Adapter name is supplied
          if (typeof opts.adapter === 'string') {
            adapter = adapters[opts.adapter];
          // Adapter instance is supplied
          } else if (opts.adapter) {
            adapter = opts.adapter;
          // No adapter supplied, fall back to application adapter
          }
          opts.adapter = adapter || adapters.application;
          assert(opts.adapter, `Unable to render response! You didn't supply an adapter and you didn't supply an application adapter as a fallback.`);

          let serializer;
          // Serializer name is supplied
          if (typeof opts.serializer === 'string') {
            serializer = serializers[opts.serializer];
          // Serializer instance is supplied
          } else if (opts.serializer) {
            serializer = opts.serializer;
          // No serializer supplied - check the payload to try inferring
          } else {
            let sample = isArray(payload) ? payload[0] : payload;
            try {
              serializer = serializers[opts.adapter.typeForRecord(sample)];
            } catch (e) {
              serializer = serializers.application;
            }
          }
          serializer = serializer || serializers.application;
          assert(serializer, `Unable to render response! You didn't supply a serializer, no serializer found matched the payload's type, and you didn't supply an application serializer as a fallback.`);

          res.json(serializer.render(payload, opts));

        }).catch((error) => {
          console.log('[blackburn] Error attempting to render a response:');
          console.log(error.stack || error);
        });
    };
    next();
  };
}
<|endoftext|>


<commit_before>var   _             = require('underscore')
    , sys           = require('util')
    , th            = require('../support/test_helper.js')
    , RedisPool     = require('redis-mpool')
    , assert        = require('assert')
    , redis         = require('redis')
    , Step          = require('step')
    , serverOptions = require('../support/server_options')
    , MapStore      = require('../../lib/windshaft/mapstore')
    , MapConfig     = require('../../lib/windshaft/mapconfig')
;

suite('mapstore', function() {

    var redis_client = redis.createClient(serverOptions.redis.port);
    var redis_pool = new RedisPool(serverOptions.redis.port);

    suiteSetup(function(done) {
      // Check that we start with an empty redis db
      redis_client.keys("*", function(err, matches) {
          assert.equal(matches.length, 0);
          done();
      });
    });

    test('fails loading unexistent map', function(done){
      var map_store = new MapStore({pool:redis_pool, expire_time:50000});
      Step(
        function getMap() {
          map_store.load('unexistent', this);
        },
        function checkErr(err) {
          assert.ok(err);
          return null;
        },
        function finish(err) {
          done(err);
        }
      );
    });

    test('can save a map and tell if it existed already', function(done) {
      var map_store = new MapStore({pool:redis_pool, expire_time:50000});
      var map = new MapConfig({
        version: '1.0.1',
        layers: [
           { options: {
               sql: 'select the_geom from test_table limit 1',
               cartocss: '#layer { marker-fill:red }',
               cartocss_version: '2.0.1'
             } }
        ]
      });
      var mapID;
      Step(
        function saveMap() {
          map_store.save(map, this);
        },
        function checkSaved_reSave(err, id, known) {
          if ( err ) throw err;
          mapID = id;
          assert.ok(!known);
          map_store.save(map, this);
        },
        function checkReSaved(err, id, known) {
          if ( err ) throw err;
          assert.ok(known);
          return null;
        },
        function delMap(err) {
          var next = this;
          map_store.del(mapID, function(e) {
            if ( e ) console.err("Could not delete map " + mapID + ": " + e);
            next(err);
          });
        },
        function finish(err) {
          done(err);
        }
      );
    });

    suiteTeardown(function(done) {
      // Flush redis cache
      // See https://github.com/Vizzuality/Windshaft/issues/24
      redis_client.flushall(done);
    });

});

<commit_msg>It looks like console has no "err" method<commit_after>var   _             = require('underscore')
    , sys           = require('util')
    , th            = require('../support/test_helper.js')
    , RedisPool     = require('redis-mpool')
    , assert        = require('assert')
    , redis         = require('redis')
    , Step          = require('step')
    , serverOptions = require('../support/server_options')
    , MapStore      = require('../../lib/windshaft/mapstore')
    , MapConfig     = require('../../lib/windshaft/mapconfig')
;

suite('mapstore', function() {

    var redis_client = redis.createClient(serverOptions.redis.port);
    var redis_pool = new RedisPool(serverOptions.redis.port);

    suiteSetup(function(done) {
      // Check that we start with an empty redis db
      redis_client.keys("*", function(err, matches) {
          assert.equal(matches.length, 0);
          done();
      });
    });

    test('fails loading unexistent map', function(done){
      var map_store = new MapStore({pool:redis_pool, expire_time:50000});
      Step(
        function getMap() {
          map_store.load('unexistent', this);
        },
        function checkErr(err) {
          assert.ok(err);
          return null;
        },
        function finish(err) {
          done(err);
        }
      );
    });

    test('can save a map and tell if it existed already', function(done) {
      var map_store = new MapStore({pool:redis_pool, expire_time:50000});
      var map = new MapConfig({
        version: '1.0.1',
        layers: [
           { options: {
               sql: 'select the_geom from test_table limit 1',
               cartocss: '#layer { marker-fill:red }',
               cartocss_version: '2.0.1'
             } }
        ]
      });
      var mapID;
      Step(
        function saveMap() {
          map_store.save(map, this);
        },
        function checkSaved_reSave(err, id, known) {
          if ( err ) throw err;
          mapID = id;
          assert.ok(!known);
          map_store.save(map, this);
        },
        function checkReSaved(err, id, known) {
          if ( err ) throw err;
          assert.ok(known);
          return null;
        },
        function delMap(err) {
          var next = this;
          map_store.del(mapID, function(e) {
            if ( e ) console.log("Could not delete map " + mapID + ": " + e);
            next(err);
          });
        },
        function finish(err) {
          done(err);
        }
      );
    });

    suiteTeardown(function(done) {
      // Flush redis cache
      // See https://github.com/Vizzuality/Windshaft/issues/24
      redis_client.flushall(done);
    });

});

<|endoftext|>


<commit_before>Tinytest.addAsync(
  'Hijacks - Collections - insert',
  function (test, next) {
    Zone.Reporters.removeAll();
    Zone.Reporters.add('test-reporter', function (zone) {

      // test whether zone has correct owner info
      var owner = zone.owner;
      var expected = {
        args: [
          [{_id: 'foo', bar: 'baz'}],
          {returnStubValue: true}
        ],
        name: '/test-collection/insert',
        type: 'Connection.apply',
        // zoneId: 123
      };

      test.equal('object', typeof owner);
      test.equal('number', typeof owner.zoneId);
      delete owner.zoneId;
      test.equal(expected, owner);

      // test whether zone has correct info
      // the parent zone contains method info
      var info = zone.infoMap[zone.parent.id];
      var expectedInfo = {
        method: {
          name: '/test-collection/insert',
          args: [
            [{_id: 'foo', bar: 'baz'}],
            {returnStubValue: true}
          ],
        }
      };

      test.equal('object', typeof info);
      test.equal(expectedInfo, info);

      // reset zone for other tests and continue
      Zone.Reporters.add(Zone.longStackTrace);
      Zone.Reporters.remove('test-reporter');
      next();
    });

    TestCollection.remove({_id: 'foo'}, function () {
      TestCollection.insert({_id: 'foo', bar: 'baz'}, function () {
        throw new Error('test-error');
      });
    });
  }
);

Tinytest.addAsync(
  'Hijacks - Collections - update',
  function (test, next) {
    Zone.Reporters.removeAll();
    Zone.Reporters.add('test-reporter', function (zone) {

      // test whether zone has correct owner info
      var owner = zone.owner;
      var expected = {
        args: [
          [{_id: 'foo'}, {$set: {bar: 'bat'}}, {}],
          {returnStubValue: true}
        ],
        name: '/test-collection/update',
        type: 'Connection.apply',
        // zoneId: 123
      };

      test.equal('object', typeof owner);
      test.equal('number', typeof owner.zoneId);
      delete owner.zoneId;
      test.equal(expected, owner);

      // test whether zone has correct info
      // the parent zone contains method info
      var info = zone.infoMap[zone.parent.id];
      var expectedInfo = {
        method: {
          name: '/test-collection/update',
          args: [
            [{_id: 'foo'}, {$set: {bar: 'bat'}}, {}],
            {returnStubValue: true}
          ],
        }
      };

      test.equal('object', typeof info);
      test.equal(expectedInfo, info);

      // reset zone for other tests and continue
      Zone.Reporters.add(Zone.longStackTrace);
      Zone.Reporters.remove('test-reporter');
      next();
    });

    TestCollection.remove({_id: 'foo'}, function () {
      TestCollection.insert({_id: 'foo', bar: 'baz'}, function () {
        TestCollection.update({_id: 'foo'}, {$set: {bar: 'bat'}}, function () {
          throw new Error('test-error');
        });
      });
    });
  }
);

Tinytest.addAsync(
  'Hijacks - Collections - upsert (new)',
  function (test, next) {
    Zone.Reporters.removeAll();
    Zone.Reporters.add('test-reporter', function (zone) {

      // test whether zone has correct owner info
      var owner = zone.owner;
      var expected = {
        args: [
          [
            {_id: 'foo'},
            {$set: {bar: 'bat'}},
            {
              _returnObject: true,
              upsert: true,
              // insertedId: 'asd'
            }
          ],
          {returnStubValue: true}
        ],
        name: '/test-collection/update',
        type: 'Connection.apply',
        // zoneId: 123
      };

      test.equal('object', typeof owner);
      test.equal('number', typeof owner.zoneId);
      delete owner.zoneId;
      if(owner.args[0][2].insertedId) {
        test.equal('string', typeof owner.args[0][2].insertedId);
      }
      delete owner.args[0][2].insertedId;
      test.equal(expected, owner);

      // test whether zone has correct info
      // the parent zone contains method info
      var info = zone.infoMap[zone.parent.id];
      var expectedInfo = {
        method: {
          name: '/test-collection/update',
          args: [
            [
              {_id: 'foo'},
              {$set: {bar: 'bat'}},
              {
                _returnObject: true,
                upsert: true,
                // insertedId: 'asd'
              }
            ],
            {returnStubValue: true}
          ],
        }
      };

      test.equal('object', typeof info);
      test.equal(expectedInfo, info);

      // reset zone for other tests and continue
      Zone.Reporters.add(Zone.longStackTrace);
      Zone.Reporters.remove('test-reporter');
      next();
    });

    TestCollection.remove({_id: 'foo'}, function () {
      TestCollection.upsert({_id: 'foo'}, {$set: {bar: 'bat'}}, function () {
        throw new Error('test-error');
      });
    });
  }
);

Tinytest.addAsync(
  'Hijacks - Collections - upsert',
  function (test, next) {
    Zone.Reporters.removeAll();
    Zone.Reporters.add('test-reporter', function (zone) {

      // test whether zone has correct owner info
      var owner = zone.owner;
      var expected = {
        args: [
          [
            {_id: 'foo'},
            {$set: {bar: 'bat'}},
            {
              _returnObject: true,
              upsert: true,
              // insertedId: 'asd'
            }
          ],
          {returnStubValue: true}
        ],
        name: '/test-collection/update',
        type: 'Connection.apply',
        // zoneId: 123
      };

      test.equal('object', typeof owner);
      test.equal('number', typeof owner.zoneId);
      delete owner.zoneId;
      if(owner.args[0][2].insertedId) {
        test.equal('string', typeof owner.args[0][2].insertedId);
      }
      delete owner.args[0][2].insertedId;
      test.equal(expected, owner);

      // test whether zone has correct info
      // the parent zone contains method info
      var info = zone.infoMap[zone.parent.id];
      var expectedInfo = {
        method: {
          name: '/test-collection/update',
          args: [
            [
              {_id: 'foo'},
              {$set: {bar: 'bat'}},
              {
                _returnObject: true,
                upsert: true,
                // insertedId: 'asd'
              }
            ],
            {returnStubValue: true}
          ],
        }
      };

      test.equal('object', typeof info);
      test.equal(expectedInfo, info);
      console.log('-- expectedInfo', expectedInfo)
      console.log('-- info', info)

      // reset zone for other tests and continue
      Zone.Reporters.add(Zone.longStackTrace);
      Zone.Reporters.remove('test-reporter');
      next();
    });

    TestCollection.remove({_id: 'foo'}, function () {
      TestCollection.insert({_id: 'foo', bar: 'baz'}, function () {
        TestCollection.upsert({_id: 'foo'}, {$set: {bar: 'bat'}}, function () {
          throw new Error('test-error');
        });
      });
    });
  }
);

Tinytest.addAsync(
  'Hijacks - Collections - remove',
  function (test, next) {
    Zone.Reporters.removeAll();
    Zone.Reporters.add('test-reporter', function (zone) {

      // test whether zone has correct owner info
      var owner = zone.owner;
      var expected = {
        args: [
          [{_id: 'foo'}],
          {returnStubValue: true}
        ],
        name: '/test-collection/remove',
        type: 'Connection.apply',
        // zoneId: 123
      };

      test.equal('object', typeof owner);
      test.equal('number', typeof owner.zoneId);
      delete owner.zoneId;
      test.equal(expected, owner);

      // test whether zone has correct info
      // the parent zone contains method info
      var info = zone.infoMap[zone.parent.id];
      var expectedInfo = {
        method: {
          name: '/test-collection/remove',
          args: [
            [{_id: 'foo'}],
            {returnStubValue: true}
          ],
        }
      };

      test.equal('object', typeof info);
      test.equal(expectedInfo, info);

      // reset zone for other tests and continue
      Zone.Reporters.add(Zone.longStackTrace);
      Zone.Reporters.remove('test-reporter');
      next();
    });

    TestCollection.remove({_id: 'foo'}, function () {
      TestCollection.insert({_id: 'foo', bar: 'baz'}, function () {
        TestCollection.remove({_id: 'foo'}, function () {
          throw new Error('test-error');
        });
      });
    });
  }
);
<commit_msg>Remove console.log<commit_after>Tinytest.addAsync(
  'Hijacks - Collections - insert',
  function (test, next) {
    Zone.Reporters.removeAll();
    Zone.Reporters.add('test-reporter', function (zone) {

      // test whether zone has correct owner info
      var owner = zone.owner;
      var expected = {
        args: [
          [{_id: 'foo', bar: 'baz'}],
          {returnStubValue: true}
        ],
        name: '/test-collection/insert',
        type: 'Connection.apply',
        // zoneId: 123
      };

      test.equal('object', typeof owner);
      test.equal('number', typeof owner.zoneId);
      delete owner.zoneId;
      test.equal(expected, owner);

      // test whether zone has correct info
      // the parent zone contains method info
      var info = zone.infoMap[zone.parent.id];
      var expectedInfo = {
        method: {
          name: '/test-collection/insert',
          args: [
            [{_id: 'foo', bar: 'baz'}],
            {returnStubValue: true}
          ],
        }
      };

      test.equal('object', typeof info);
      test.equal(expectedInfo, info);

      // reset zone for other tests and continue
      Zone.Reporters.add(Zone.longStackTrace);
      Zone.Reporters.remove('test-reporter');
      next();
    });

    TestCollection.remove({_id: 'foo'}, function () {
      TestCollection.insert({_id: 'foo', bar: 'baz'}, function () {
        throw new Error('test-error');
      });
    });
  }
);

Tinytest.addAsync(
  'Hijacks - Collections - update',
  function (test, next) {
    Zone.Reporters.removeAll();
    Zone.Reporters.add('test-reporter', function (zone) {

      // test whether zone has correct owner info
      var owner = zone.owner;
      var expected = {
        args: [
          [{_id: 'foo'}, {$set: {bar: 'bat'}}, {}],
          {returnStubValue: true}
        ],
        name: '/test-collection/update',
        type: 'Connection.apply',
        // zoneId: 123
      };

      test.equal('object', typeof owner);
      test.equal('number', typeof owner.zoneId);
      delete owner.zoneId;
      test.equal(expected, owner);

      // test whether zone has correct info
      // the parent zone contains method info
      var info = zone.infoMap[zone.parent.id];
      var expectedInfo = {
        method: {
          name: '/test-collection/update',
          args: [
            [{_id: 'foo'}, {$set: {bar: 'bat'}}, {}],
            {returnStubValue: true}
          ],
        }
      };

      test.equal('object', typeof info);
      test.equal(expectedInfo, info);

      // reset zone for other tests and continue
      Zone.Reporters.add(Zone.longStackTrace);
      Zone.Reporters.remove('test-reporter');
      next();
    });

    TestCollection.remove({_id: 'foo'}, function () {
      TestCollection.insert({_id: 'foo', bar: 'baz'}, function () {
        TestCollection.update({_id: 'foo'}, {$set: {bar: 'bat'}}, function () {
          throw new Error('test-error');
        });
      });
    });
  }
);

Tinytest.addAsync(
  'Hijacks - Collections - upsert (new)',
  function (test, next) {
    Zone.Reporters.removeAll();
    Zone.Reporters.add('test-reporter', function (zone) {

      // test whether zone has correct owner info
      var owner = zone.owner;
      var expected = {
        args: [
          [
            {_id: 'foo'},
            {$set: {bar: 'bat'}},
            {
              _returnObject: true,
              upsert: true,
              // insertedId: 'asd'
            }
          ],
          {returnStubValue: true}
        ],
        name: '/test-collection/update',
        type: 'Connection.apply',
        // zoneId: 123
      };

      test.equal('object', typeof owner);
      test.equal('number', typeof owner.zoneId);
      delete owner.zoneId;
      if(owner.args[0][2].insertedId) {
        test.equal('string', typeof owner.args[0][2].insertedId);
      }
      delete owner.args[0][2].insertedId;
      test.equal(expected, owner);

      // test whether zone has correct info
      // the parent zone contains method info
      var info = zone.infoMap[zone.parent.id];
      var expectedInfo = {
        method: {
          name: '/test-collection/update',
          args: [
            [
              {_id: 'foo'},
              {$set: {bar: 'bat'}},
              {
                _returnObject: true,
                upsert: true,
                // insertedId: 'asd'
              }
            ],
            {returnStubValue: true}
          ],
        }
      };

      test.equal('object', typeof info);
      test.equal(expectedInfo, info);

      // reset zone for other tests and continue
      Zone.Reporters.add(Zone.longStackTrace);
      Zone.Reporters.remove('test-reporter');
      next();
    });

    TestCollection.remove({_id: 'foo'}, function () {
      TestCollection.upsert({_id: 'foo'}, {$set: {bar: 'bat'}}, function () {
        throw new Error('test-error');
      });
    });
  }
);

Tinytest.addAsync(
  'Hijacks - Collections - upsert',
  function (test, next) {
    Zone.Reporters.removeAll();
    Zone.Reporters.add('test-reporter', function (zone) {

      // test whether zone has correct owner info
      var owner = zone.owner;
      var expected = {
        args: [
          [
            {_id: 'foo'},
            {$set: {bar: 'bat'}},
            {
              _returnObject: true,
              upsert: true,
              // insertedId: 'asd'
            }
          ],
          {returnStubValue: true}
        ],
        name: '/test-collection/update',
        type: 'Connection.apply',
        // zoneId: 123
      };

      test.equal('object', typeof owner);
      test.equal('number', typeof owner.zoneId);
      delete owner.zoneId;
      if(owner.args[0][2].insertedId) {
        test.equal('string', typeof owner.args[0][2].insertedId);
      }
      delete owner.args[0][2].insertedId;
      test.equal(expected, owner);

      // test whether zone has correct info
      // the parent zone contains method info
      var info = zone.infoMap[zone.parent.id];
      var expectedInfo = {
        method: {
          name: '/test-collection/update',
          args: [
            [
              {_id: 'foo'},
              {$set: {bar: 'bat'}},
              {
                _returnObject: true,
                upsert: true,
                // insertedId: 'asd'
              }
            ],
            {returnStubValue: true}
          ],
        }
      };

      test.equal('object', typeof info);
      test.equal(expectedInfo, info);

      // reset zone for other tests and continue
      Zone.Reporters.add(Zone.longStackTrace);
      Zone.Reporters.remove('test-reporter');
      next();
    });

    TestCollection.remove({_id: 'foo'}, function () {
      TestCollection.insert({_id: 'foo', bar: 'baz'}, function () {
        TestCollection.upsert({_id: 'foo'}, {$set: {bar: 'bat'}}, function () {
          throw new Error('test-error');
        });
      });
    });
  }
);

Tinytest.addAsync(
  'Hijacks - Collections - remove',
  function (test, next) {
    Zone.Reporters.removeAll();
    Zone.Reporters.add('test-reporter', function (zone) {

      // test whether zone has correct owner info
      var owner = zone.owner;
      var expected = {
        args: [
          [{_id: 'foo'}],
          {returnStubValue: true}
        ],
        name: '/test-collection/remove',
        type: 'Connection.apply',
        // zoneId: 123
      };

      test.equal('object', typeof owner);
      test.equal('number', typeof owner.zoneId);
      delete owner.zoneId;
      test.equal(expected, owner);

      // test whether zone has correct info
      // the parent zone contains method info
      var info = zone.infoMap[zone.parent.id];
      var expectedInfo = {
        method: {
          name: '/test-collection/remove',
          args: [
            [{_id: 'foo'}],
            {returnStubValue: true}
          ],
        }
      };

      test.equal('object', typeof info);
      test.equal(expectedInfo, info);

      // reset zone for other tests and continue
      Zone.Reporters.add(Zone.longStackTrace);
      Zone.Reporters.remove('test-reporter');
      next();
    });

    TestCollection.remove({_id: 'foo'}, function () {
      TestCollection.insert({_id: 'foo', bar: 'baz'}, function () {
        TestCollection.remove({_id: 'foo'}, function () {
          throw new Error('test-error');
        });
      });
    });
  }
);
<|endoftext|>


<commit_before>jQuery.fn.extend({
	text: function( text ) {
		if ( typeof text !== "object" && text != null )
			return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );

		var ret = "";

		jQuery.each( text || this, function(){
			jQuery.each( this.childNodes, function(){
				if ( this.nodeType != 8 )
					ret += this.nodeType != 1 ?
						this.nodeValue :
						jQuery.fn.text( [ this ] );
			});
		});

		return ret;
	},

	wrapAll: function( html ) {
		if(jQuery.isFunction(html)) {
			return this.each(function() { jQuery(this).wrapAll(html.call(this)); });
		}

		if ( this[0] ) {
			// The elements to wrap the target around
			var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone();

			if ( this[0].parentNode )
				wrap.insertBefore( this[0] );

			wrap.map(function(){
				var elem = this;

				while ( elem.firstChild && elem.firstChild.nodeType === 1 )
					elem = elem.firstChild;

				return elem;
			}).append(this);
		}

		return this;
	},

	wrapInner: function( html ) {
		return this.each(function(){
			jQuery( this ).contents().wrapAll( html );
		});
	},

	wrap: function( html ) {
		return this.each(function(){
			jQuery( this ).wrapAll( html );
		});
	},

	append: function() {
		return this.domManip(arguments, true, function(elem){
			if (this.nodeType == 1)
				this.appendChild( elem );
		});
	},

	prepend: function() {
		return this.domManip(arguments, true, function(elem){
			if (this.nodeType == 1)
				this.insertBefore( elem, this.firstChild );
		});
	},

	before: function() {
		return this.domManip(arguments, false, function(elem){
			this.parentNode.insertBefore( elem, this );
		});
	},

	after: function() {
		return this.domManip(arguments, false, function(elem){
			this.parentNode.insertBefore( elem, this.nextSibling );
		});
	},

	clone: function( events ) {
		// Do the clone
		var ret = this.map(function(){
			if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {
				// IE copies events bound via attachEvent when
				// using cloneNode. Calling detachEvent on the
				// clone will also remove the events from the orignal
				// In order to get around this, we use innerHTML.
				// Unfortunately, this means some modifications to
				// attributes in IE that are actually only stored
				// as properties will not be copied (such as the
				// the name attribute on an input).
				var html = this.outerHTML, ownerDocument = this.ownerDocument;
				if ( !html ) {
					var div = ownerDocument.createElement("div");
					div.appendChild( this.cloneNode(true) );
					html = div.innerHTML;
				}

				return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")], ownerDocument)[0];
			} else
				return this.cloneNode(true);
		});

		// Copy the events from the original to the clone
		if ( events === true ) {
			var orig = this.find("*").andSelf(), i = 0;

			ret.find("*").andSelf().each(function(){
				if ( this.nodeName !== orig[i].nodeName )
					return;

				var events = jQuery.data( orig[i], "events" );

				for ( var type in events ) {
					for ( var handler in events[ type ] ) {
						jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data );
					}
				}

				i++;
			});
		}

		// Return the cloned set
		return ret;
	},

	html: function( value ) {
		return value === undefined ?
			(this[0] ?
				this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g, "") :
				null) :
			this.empty().append( value );
	},

	replaceWith: function( value ) {
		return this.after( value ).remove();
	},

	domManip: function( args, table, callback ) {
		var fragment, scripts, cacheable, cached, cacheresults, first;
		var value = args[0];

		if ( jQuery.isFunction(value) ) {
			return this.each(function() {
				args[0] = value.call(this);
				return jQuery(this).domManip( args, table, callback );
			});
		};

		if ( this[0] ) {
			if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && args[0].indexOf("<option") < 0 ) {
				cacheable = true;
				cacheresults = jQuery.fragments[ args[0] ];
				if ( cacheresults ) {
					if ( cacheresults !== 1 ) {
						fragment = cacheresults;
					}
					cached = true;
				}
			}

			if ( !fragment ) {
				fragment = (this[0].ownerDocument || this[0]).createDocumentFragment();
				scripts = jQuery.clean( args, (this[0].ownerDocument || this[0]), fragment );
			}

			first = fragment.firstChild;

			if ( first ) {
				table = table && jQuery.nodeName( first, "tr" );

				for ( var i = 0, l = this.length; i < l; i++ ) {
					callback.call(
						table ?
							root(this[i], first) :
							this[i],
						cacheable || this.length > 1 || i > 0 ?
							fragment.cloneNode(true) :
							fragment
					);
				}
			}

			if ( scripts ) {
				jQuery.each( scripts, evalScript );
			}

			if ( cacheable ) {
				jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;
			}
		}

		return this;

		function root( elem, cur ) {
			return jQuery.nodeName(elem, "table") ?
				(elem.getElementsByTagName("tbody")[0] ||
				elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
				elem;
		}
	}
});

jQuery.fragments = {};

jQuery.each({
	appendTo: "append",
	prependTo: "prepend",
	insertBefore: "before",
	insertAfter: "after",
	replaceAll: "replaceWith"
}, function(name, original){
	jQuery.fn[ name ] = function( selector ) {
		var ret = [], insert = jQuery( selector );

		for ( var i = 0, l = insert.length; i < l; i++ ) {
			var elems = (i > 0 ? this.clone(true) : this).get();
			jQuery.fn[ original ].apply( jQuery(insert[i]), elems );
			ret = ret.concat( elems );
		}

		return this.pushStack( ret, name, selector );
	};
});

jQuery.each({
	remove: function( selector ) {
		if ( !selector || jQuery.multiFilter( selector, [ this ] ).length ) {
			if ( this.nodeType === 1 ) {
				cleanData( jQuery("*", this).add(this) );
			}

			if ( this.parentNode ) {
				this.parentNode.removeChild( this );
			}
		}
	},

	empty: function() {
		// Remove element nodes and prevent memory leaks
		if ( this.nodeType === 1 ) {
			cleanData( jQuery("*", this) );
		}

		// Remove any remaining nodes
		while ( this.firstChild ) {
			this.removeChild( this.firstChild );
		}
	}
}, function(name, fn){
	jQuery.fn[ name ] = function(){
		return this.each( fn, arguments );
	};
});

jQuery.extend({
	clean: function( elems, context, fragment ) {
		context = context || document;

		// !context.createElement fails in IE with an error but returns typeof 'object'
		if ( typeof context.createElement === "undefined" )
			context = context.ownerDocument || context[0] && context[0].ownerDocument || document;

		// If a single string is passed in and it's a single tag
		// just do a createElement and skip the rest
		if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) {
			var match = /^<(\w+)\s*\/?>$/.exec(elems[0]);
			if ( match )
				return [ context.createElement( match[1] ) ];
		}

		var ret = [], scripts = [], div = context.createElement("div");

		jQuery.each(elems, function(i, elem){
			if ( typeof elem === "number" )
				elem += '';

			if ( !elem )
				return;

			// Convert html string into DOM nodes
			if ( typeof elem === "string" ) {
				// Fix "XHTML"-style tags in all browsers
				elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){
					return /^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i.test(tag) ?
						all :
						front + "></" + tag + ">";
				});

				// Trim whitespace, otherwise indexOf won't work as expected
				var tags = elem.replace(/^\s+/, "").substring(0, 10).toLowerCase();

				var wrap =
					// option or optgroup
					!tags.indexOf("<opt") &&
					[ 1, "<select multiple='multiple'>", "</select>" ] ||

					!tags.indexOf("<leg") &&
					[ 1, "<fieldset>", "</fieldset>" ] ||

					/^<(thead|tbody|tfoot|colg|cap)/.test(tags) &&
					[ 1, "
", "
" ] ||

					!tags.indexOf("<tr") &&
					[ 2, "

", "

" ] ||

				 	//
 matched above
					(!tags.indexOf("<td") || !tags.indexOf("<th")) &&
					[ 3, "

", "

" ] ||

					!tags.indexOf("<col") &&
					[ 2, "

<colgroup>", "</colgroup>
" ] ||

					// IE can't serialize <link> and