<commit_before>/*
 * Increase version number
 *
 * grunt bump
 * grunt bump:git
 * grunt bump:patch
 * grunt bump:minor
 * grunt bump:major
 *
 * @author Vojta Jina <vojta.jina@gmail.com>
 * @author Mathias Paumgarten <mail@mathias-paumgarten.com>
 * @author Adam Biggs <email@adambig.gs>
 */
var semver = require('semver');
var exec = require('child_process').exec;

module.exports = function(grunt) {

  var DESC = 'Increment the version, commit, tag and push.';
  grunt.registerTask('bump', DESC, function(versionType, incOrCommitOnly) {
    var opts = this.options({
      bumpVersion: true,
      files: ['package.json'],
      updateConfigs: [], // array of config properties to update (with files)
      commit: true,
      commitMessage: 'Release v%VERSION%',
      commitFiles: ['package.json'], // '-a' for all files
      createTag: true,
      tagName: 'v%VERSION%',
      tagMessage: 'Version %VERSION%',
      push: true,
      pushTo: 'upstream',
      gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d'
    });

    if (incOrCommitOnly === 'bump-only') {
      grunt.verbose.writeln('Only incrementing the version.');

      opts.commit = false;
      opts.createTag = false;
      opts.push = false;
    }

    if (incOrCommitOnly === 'commit-only') {
      grunt.verbose.writeln('Only commiting/taggin/pushing.');

      opts.bumpVersion = false;
    }

    var exactVersionToSet = grunt.option('setversion');
    if (!semver.valid(exactVersionToSet)) {
        exactVersionToSet = false;
    }

    var done = this.async();
    var queue = [];
    var next = function() {
      if (!queue.length) {
        return done();
      }
      queue.shift()();
    };
    var runIf = function(condition, behavior) {
      if (condition) {
        queue.push(behavior);
      }
    };

    var globalVersion; // when bumping multiple files
    var gitVersion;    // when bumping using `git describe`
    var VERSION_REGEXP = /([\'|\"]version[\'|\"][ ]*:[ ]*[\'|\"])([\d||A-a|.|-]*)([\'|\"])/i;

    // GET VERSION FROM GIT
    runIf(opts.bumpVersion && versionType === 'git', function(){
      exec('git describe ' + opts.gitDescribeOptions, function(err, stdout, stderr){
        if (err) {
          grunt.fatal('Can not get a version number using `git describe`');
        }
        gitVersion = stdout.trim();
        next();
      });
    });

    // BUMP ALL FILES
    runIf(opts.bumpVersion, function(){
      opts.files.forEach(function(file, idx) {
        var version = null;
        var content = grunt.file.read(file).replace(VERSION_REGEXP, function(match, prefix, parsedVersion, suffix) {
          gitVersion = gitVersion && parsedVersion + '-' + gitVersion;
          version = exactVersionToSet || gitVersion || semver.inc(parsedVersion, versionType || 'patch');
          return prefix + version + suffix;
        });

        if (!version) {
          grunt.fatal('Can not find a version to bump in ' + file);
        }

        grunt.file.write(file, content);
        grunt.log.ok('Version bumped to ' + version + (opts.files.length > 1 ? ' (in ' + file + ')' : ''));

        if (!globalVersion) {
          globalVersion = version;
        } else if (globalVersion !== version) {
          grunt.warn('Bumping multiple files with different versions!');
        }

        var configProperty = opts.updateConfigs[idx];
        if (!configProperty) {
          return;
        }

        var cfg = grunt.config(configProperty);
        if (!cfg) {
          return grunt.warn('Can not update "' + configProperty + '" config, it does not exist!');
        }

        cfg.version = version;
        grunt.config(configProperty, cfg);
        grunt.log.ok(configProperty + '\'s version updated');
      });
      next();
    });

    // when only commiting, read the version from package.json / pkg config
    runIf(!opts.bumpVersion, function() {
      if (opts.updateConfigs.length) {
        globalVersion = grunt.config(opts.updateConfigs[0]).version;
      } else {
        globalVersion = grunt.file.readJSON(opts.files[0]).version;
      }

      next();
    });

    // COMMIT
    runIf(opts.commit, function() {
      var commitMessage = opts.commitMessage.replace('%VERSION%', globalVersion);

      exec('git commit ' + opts.commitFiles.join(' ') + ' -m "' + commitMessage + '"', function(err, stdout, stderr) {
        if (err) {
          grunt.fatal('Can not create the commit:\n  ' + stderr);
        }
        grunt.log.ok('Committed as "' + commitMessage + '"');
        next();
      });
    });

    // CREATE TAG
    runIf(opts.createTag, function() {
      var tagName = opts.tagName.replace('%VERSION%', globalVersion);
      var tagMessage = opts.tagMessage.replace('%VERSION%', globalVersion);

      exec('git tag -a ' + tagName + ' -m "' + tagMessage + '"' , function(err, stdout, stderr) {
        if (err) {
          grunt.fatal('Can not create the tag:\n  ' + stderr);
        }
        grunt.log.ok('Tagged as "' + tagName + '"');
        next();
      });
    });

    // PUSH CHANGES
    runIf(opts.push, function() {
      exec('git push ' + opts.pushTo + ' && git push ' + opts.pushTo + ' --tags', function(err, stdout, stderr) {
        if (err) {
          grunt.fatal('Can not push to ' + opts.pushTo + ':\n  ' + stderr);
        }
        grunt.log.ok('Pushed to ' + opts.pushTo);
        next();
      });
    });

    next();
  });

  // ALIASES
  DESC = 'Increment the version only.';
  grunt.registerTask('bump-only', DESC, function(versionType) {
    grunt.task.run('bump:' + (versionType || '') + ':bump-only');
  });

  DESC = 'Commit, tag, push without incrementing the version.';
  grunt.registerTask('bump-commit', DESC, 'bump::commit-only');
};

<commit_msg>feat: support non-json file version bump<commit_after>/*
 * Increase version number
 *
 * grunt bump
 * grunt bump:git
 * grunt bump:patch
 * grunt bump:minor
 * grunt bump:major
 *
 * @author Vojta Jina <vojta.jina@gmail.com>
 * @author Mathias Paumgarten <mail@mathias-paumgarten.com>
 * @author Adam Biggs <email@adambig.gs>
 */
var semver = require('semver');
var exec = require('child_process').exec;

module.exports = function(grunt) {

  var DESC = 'Increment the version, commit, tag and push.';
  grunt.registerTask('bump', DESC, function(versionType, incOrCommitOnly) {
    var opts = this.options({
      bumpVersion: true,
      files: ['package.json'],
      updateConfigs: [], // array of config properties to update (with files)
      commit: true,
      commitMessage: 'Release v%VERSION%',
      commitFiles: ['package.json'], // '-a' for all files
      createTag: true,
      tagName: 'v%VERSION%',
      tagMessage: 'Version %VERSION%',
      push: true,
      pushTo: 'upstream',
      gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d'
    });

    if (incOrCommitOnly === 'bump-only') {
      grunt.verbose.writeln('Only incrementing the version.');

      opts.commit = false;
      opts.createTag = false;
      opts.push = false;
    }

    if (incOrCommitOnly === 'commit-only') {
      grunt.verbose.writeln('Only commiting/taggin/pushing.');

      opts.bumpVersion = false;
    }

    var exactVersionToSet = grunt.option('setversion');
    if (!semver.valid(exactVersionToSet)) {
        exactVersionToSet = false;
    }

    var done = this.async();
    var queue = [];
    var next = function() {
      if (!queue.length) {
        return done();
      }
      queue.shift()();
    };
    var runIf = function(condition, behavior) {
      if (condition) {
        queue.push(behavior);
      }
    };

    var globalVersion; // when bumping multiple files
    var gitVersion;    // when bumping using `git describe`
    var VERSION_REGEXP = /([\'|\"]?version[\'|\"]?[ ]*:[ ]*[\'|\"]?)([\d||A-a|.|-]*)([\'|\"]?)/i;

    // GET VERSION FROM GIT
    runIf(opts.bumpVersion && versionType === 'git', function(){
      exec('git describe ' + opts.gitDescribeOptions, function(err, stdout, stderr){
        if (err) {
          grunt.fatal('Can not get a version number using `git describe`');
        }
        gitVersion = stdout.trim();
        next();
      });
    });

    // BUMP ALL FILES
    runIf(opts.bumpVersion, function(){
      opts.files.forEach(function(file, idx) {
        var version = null;
        var content = grunt.file.read(file).replace(VERSION_REGEXP, function(match, prefix, parsedVersion, suffix) {
          gitVersion = gitVersion && parsedVersion + '-' + gitVersion;
          version = exactVersionToSet || gitVersion || semver.inc(parsedVersion, versionType || 'patch');
          return prefix + version + suffix;
        });

        if (!version) {
          grunt.fatal('Can not find a version to bump in ' + file);
        }

        grunt.file.write(file, content);
        grunt.log.ok('Version bumped to ' + version + (opts.files.length > 1 ? ' (in ' + file + ')' : ''));

        if (!globalVersion) {
          globalVersion = version;
        } else if (globalVersion !== version) {
          grunt.warn('Bumping multiple files with different versions!');
        }

        var configProperty = opts.updateConfigs[idx];
        if (!configProperty) {
          return;
        }

        var cfg = grunt.config(configProperty);
        if (!cfg) {
          return grunt.warn('Can not update "' + configProperty + '" config, it does not exist!');
        }

        cfg.version = version;
        grunt.config(configProperty, cfg);
        grunt.log.ok(configProperty + '\'s version updated');
      });
      next();
    });

    // when only commiting, read the version from package.json / pkg config
    runIf(!opts.bumpVersion, function() {
      if (opts.updateConfigs.length) {
        globalVersion = grunt.config(opts.updateConfigs[0]).version;
      } else {
        globalVersion = grunt.file.readJSON(opts.files[0]).version;
      }

      next();
    });

    // COMMIT
    runIf(opts.commit, function() {
      var commitMessage = opts.commitMessage.replace('%VERSION%', globalVersion);

      exec('git commit ' + opts.commitFiles.join(' ') + ' -m "' + commitMessage + '"', function(err, stdout, stderr) {
        if (err) {
          grunt.fatal('Can not create the commit:\n  ' + stderr);
        }
        grunt.log.ok('Committed as "' + commitMessage + '"');
        next();
      });
    });

    // CREATE TAG
    runIf(opts.createTag, function() {
      var tagName = opts.tagName.replace('%VERSION%', globalVersion);
      var tagMessage = opts.tagMessage.replace('%VERSION%', globalVersion);

      exec('git tag -a ' + tagName + ' -m "' + tagMessage + '"' , function(err, stdout, stderr) {
        if (err) {
          grunt.fatal('Can not create the tag:\n  ' + stderr);
        }
        grunt.log.ok('Tagged as "' + tagName + '"');
        next();
      });
    });

    // PUSH CHANGES
    runIf(opts.push, function() {
      exec('git push ' + opts.pushTo + ' && git push ' + opts.pushTo + ' --tags', function(err, stdout, stderr) {
        if (err) {
          grunt.fatal('Can not push to ' + opts.pushTo + ':\n  ' + stderr);
        }
        grunt.log.ok('Pushed to ' + opts.pushTo);
        next();
      });
    });

    next();
  });

  // ALIASES
  DESC = 'Increment the version only.';
  grunt.registerTask('bump-only', DESC, function(versionType) {
    grunt.task.run('bump:' + (versionType || '') + ':bump-only');
  });

  DESC = 'Commit, tag, push without incrementing the version.';
  grunt.registerTask('bump-commit', DESC, 'bump::commit-only');
};

<|endoftext|>


<commit_before>/*
 * grunt-curl
 * https://github.com/twolfson/grunt-curl
 *
 * Copyright (c) 2013 Todd Wolfson
 * Licensed under the MIT license.
 */

var request = require('request');
module.exports = function (grunt) {

  // Please see the grunt documentation for more information regarding task and
  // helper creation: https://github.com/gruntjs/grunt/blob/master/docs/toc.md

  // ==========================================================================
  // TASKS
  // ==========================================================================

  grunt.registerMultiTask('curl', 'Your task description goes here.', function () {
    // Collect the filepaths we need
    var file = this.file,
        data = this.data,
        src = file.src,
        srcFiles = src,
        dest = file.dest,
        callback = this.async();

    // Upcast the src to an array
    if (!Array.isArray(srcFiles)) {
      srcFiles = [src];
    }

    // Asynchronously fetch the files in parallel
    grunt.async.map(srcFiles, grunt.helper.bind(grunt, 'curl'));

    // Concatenate the srcFiles, process the blob through our helper,
    var separator = data.separator || '\n',
        content = curlFiles.join(separator);

    // Write out the content
    grunt.file.write(dest, content);

    // Fail task if errors were logged.
    if (this.errorCount) { return false; }

    // Otherwise, print a success message.
    grunt.log.writeln('File "' + this.file.dest + '" created.');
  });

  // ==========================================================================
  // HELPERS
  // ==========================================================================

  grunt.registerHelper('curl', request.get);

};
<commit_msg>grunt-curl completed!<commit_after>/*
 * grunt-curl
 * https://github.com/twolfson/grunt-curl
 *
 * Copyright (c) 2013 Todd Wolfson
 * Licensed under the MIT license.
 */

var request = require('request');
module.exports = function (grunt) {

  // Please see the grunt documentation for more information regarding task and
  // helper creation: https://github.com/gruntjs/grunt/blob/master/docs/toc.md

  // ==========================================================================
  // TASKS
  // ==========================================================================

  grunt.registerMultiTask('curl', 'Your task description goes here.', function () {
    // Collect the filepaths we need
    var file = this.file,
        data = this.data,
        src = file.src,
        dest = file.dest,
        done = this.async(),
        that = this;

    // Upcast the srcFiles to an array
    var srcFiles = src;
    if (!Array.isArray(srcFiles)) {
      srcFiles = [src];
    }

    // Asynchronously fetch the files in parallel
    var async = grunt.utils.async;
    async.map(srcFiles, grunt.helper.bind(grunt, 'curl'), curlResultFn);

    function curlResultFn(err, files) {
      // If there is an error, fail
      if (err) {
        return grunt.fail.fatal(err);
      }

      // Concatenate the srcFiles, process the blob through our helper,
      var separator = data.separator || '\n',
          content = files.join(separator);

      // Write out the content
      grunt.file.write(dest, content);

      // Fail task if errors were logged.
      if (that.errorCount) { return false; }

      // Otherwise, print a success message.
      grunt.log.writeln('File "' + dest + '" created.');

      // Callback
      done();
    }
  });

  // ==========================================================================
  // HELPERS
  // ==========================================================================

  grunt.registerHelper('curl', function (url, cb) {
    // Request the url
    request.get(url, function (err, res, body) {
      // Callback with the error and body
      cb(err, body);
    });
  });

};
<|endoftext|>


<commit_before>/*
 * grunt-contrib-haml
 *
 * Copyright (c) 2012 Concordus Applications
 * Licensed under the MIT license.
 */

module.exports = function(grunt) {
  'use strict';

  // TODO: ditch this when grunt v0.4 is released
  grunt.util = grunt.util || grunt.utils;

  grunt.registerMultiTask('haml', 'Compile Haml files into JavaScript', function() {
    var path = require('path');

    var helpers = require('grunt-contrib-lib').init(grunt);

    var options = helpers.options(this, {
      basePath: false
    });

    grunt.verbose.writeflags(options, 'Options');

    // TODO: ditch this when grunt v0.4 is released
    this.files = this.files || helpers.normalizeMultiTaskFiles(this.data, this.target);

    var basePath;
    var newFileDest;

    var srcFiles;
    var srcCompiled;
    var taskOutput;

    this.files.forEach(function(file) {
      file.dest = path.normalize(file.dest);
      srcFiles = grunt.file.expandFiles(file.src);

      if (srcFiles.length === 0) {
        grunt.log.writeln('Unable to compile; no valid source files were found.');
        return;
      }

      taskOutput = [];

      srcFiles.forEach(function(srcFile) {
        srcCompiled = compileHaml(srcFile, options);

        if (helpers.isIndividualDest(file.dest)) {
          basePath = helpers.findBasePath(srcFiles, options.basePath);
          newFileDest = helpers.buildIndividualDest(file.dest, srcFile, basePath, options.flatten);

          grunt.file.write(newFileDest, srcCompiled || '');
          grunt.log.writeln('File ' + newFileDest.cyan + ' created.');
        } else {
          taskOutput.push(srcCompiled);
        }
      });

      if (taskOutput.length > 0) {
        grunt.file.write(file.dest, taskOutput.join('\n') || '');
        grunt.log.writeln('File ' + file.dest.cyan + ' created.');
      }
    });
  });

  var compileHaml = function(srcFile, options) {
    options = grunt.util._.extend({filename: srcFile}, options);
    delete options.basePath;
    delete options.flatten;

    var srcCode = grunt.file.read(srcFile);

    try {
      var hamlc = require('haml-coffee');
      return hamlc.template(srcCode, 'haml', 'this._template', options);
    } catch (e) {
      grunt.log.error(e);
      grunt.fail.warn('Haml failed to compile.');
    }
  };
};
<commit_msg>Updated functionality quite a bit.<commit_after>/*
 * grunt-contrib-haml
 *
 * Copyright (c) 2012 Concordus Applications
 * Licensed under the MIT license.
 */

module.exports = function(grunt) {
  'use strict';

  var path = require('path');
  var _    = grunt.util._;

  grunt.registerMultiTask('haml', 'Compile Haml files', function() {
    var helpers = require('grunt-lib-contrib').init(grunt);
    var options = helpers.options(this);

    // Write options iff verbose.
    grunt.verbose.writeflags(options, 'Options');

    // Ensure we have files to compile.
    if (this.file.src.length === 0) {
      grunt.log.writeln('Unable to compile; no valid files were found.');
      return;
    }

    // Compile each file; concatenating them into the source if desired.
    var output = [];
    this.file.src.forEach(function(file) {
      output.push(transpile(file, options));
    });

    // If we managed to get anything; let the world know.
    if (output.length > 0) {
      grunt.file.write(this.file.dest, output.join('\n') || '');
      grunt.log.writeln('File ' + this.file.dest.cyan + ' created.');
    }
  });

  var transpile = function(name, options) {
    // Construct appropriate options to pass to the compiler
    options = _({filename: name}).extend(options);
    options = _(options).defaults({
      // Default target is javascript.
      target: 'js',

      // Default language choice to coffee-script and haml-coffee.
      language: 'coffee',

      // Default placement; either `amd` or `global`.
      placement: 'amd',

      // Default global placement namespace to `window`.
      namespace: 'window.HAML',

      // Default hash of dependencies for AMD.
      dependencies: {}
    });

    // Read in the file
    var input = grunt.file.read(name);

    try {
      // Store the desired language.
      var language = options.language;
      var target = options.target;
      var context = options.context;

      var template = options.name;
      if (template === undefined) {
        // Default template name is the basename w/o the extension.
        template = path.basename(name, path.extname(name));
      }

      // Remove options not understood by any compiler.
      delete options.language;
      delete options.target;
      delete options.name;
      delete options.context;

      switch (language) {
      case 'js':
        var haml = require('haml');

        // First pass; generate the javascript method.
        var output = haml(input);

        if (target === 'html') {
          // Evaluate method with the context and return it.
          return output(context);
        } else if (target !== 'js') {
          grunt.fail.warn(
            'Target ' + target + ' is not a valid ' +
            'destination target for `haml-coffee`; choices ' +
            'are: html and js\n');
        }

        // Reduce to a true annoymous, unnamed method.
        // TODO: Push this upstream.
        output = output.toString().substring(27);
        output = 'function(locals)' + output;

        switch (options.placement) {
        case 'global':
          // Set in the desired namespace.
          output = options.namespace + "['" + template + "'] = " + output;
          output = '\n' + output + '\n';
          break;

        case 'amd':
          // Build define statement.
          var defineStatement = 'define([';
          var modules = _(options.dependencies).values();
          modules = modules.length ? "'" + modules.join("','") + "'" : "";
          defineStatement += modules;
          defineStatement += '], function(';
          defineStatement += _(options.dependencies).keys().join(',');
          defineStatement += ') { \n';

          // Wrap ouptut in it.
          output = defineStatement + 'return ' + output + ';\n});\n';
          break;

        default:
          grunt.fail.warn(
            'Placement ' + options.placement + ' is not a valid ' +
            'destination placement for `haml-js`; choices ' +
            'are: amd and global\n');
        }

        // Return the final template.
        return output;

      case 'coffee':
        var hamlc = require('haml-coffee');
        var namespace = options.namespace;

        // Remove options not understood by the compiler.
        delete options.namespace;

        switch (target) {
        case 'js':
          // Pass it off to haml-coffee to render a template in javascript.
          return hamlc.template(input, template, namespace, options);

        case 'html':
          // Pass it off to haml-coffee to render a template in javascript.
          var output = hamlc.compile(input, options);

          // Now we render it as HTML with the given context.
          return eval(output)(context);

        default:
          grunt.fail.warn(
            'Target ' + target + ' is not a valid ' +
            'destination target for `haml-coffee`; choices ' +
            'are: html and js\n');
        }

      default:
        grunt.fail.warn(
          'Language ' + language + ' is not a valid ' +
          'source language for HAML; choices are: coffee and js\n');
      }

      // return 'YODEL';
      // return require('coffee-script').compile(output, options);
    } catch (e) {
      grunt.log.error(e);
      grunt.fail.warn('Haml failed to compile.');
    }
  };
};
<|endoftext|>


<commit_before>/*
 * grunt-contrib-haml
 *
 * Copyright (c) 2012 Concordus Applications
 * Licensed under the MIT license.
 */

module.exports = function(grunt) {
  'use strict';

  var path = require('path');
  var _    = grunt.util._;

  grunt.registerMultiTask('haml', 'Compile Haml files', function() {
    var helpers = require('grunt-lib-contrib').init(grunt);
    var defaultOptions = helpers.options(this);
    // Set up some defaults for the options.
    _.defaults(defaultOptions, {
      // Default target is javascript.
      target: 'html',

      // Default language choice to coffee-script and haml-coffee.
      language: 'js',

      // Default placement; either `amd` or `global`.
      placement: 'global',

      // Default global placement namespace to `window`.
      namespace: 'window.HAML',

      // Default hash of dependencies for AMD.
      dependencies: {}
    });

    // Set the target options.
    var options = this.options(defaultOptions);

    // Write options iff verbose.
    grunt.verbose.writeflags(options, 'Options');

    // Transpile each src/dest group of files.
    this.files.forEach(function(file) {

      // Get only files that are actually there.
      var validFiles = file.src.filter(function(filepath) {
        if (grunt.file.exists(filepath)) {
          return true;
        } else {
          grunt.log.warn('Source file "' + filepath + '" not found.');
          return false;
        }
      });

      // Ensure we have files to transpile.
      if (validFiles.length > 0) {
        // Transpile each file.
        var output = validFiles.map(function (filename) {
          // Pass in a copy so we don't mutate the original target options.
          return transpile(filename, _.cloneDeep(options));
        });
        // Write the new file.
        grunt.file.write(file.dest, output.join('\n'));
        grunt.log.writeln('File ' + file.dest.cyan + ' created.');
      } else {
        grunt.log.writeln('Unable to compile; no valid files were found.');
      }
    });
  });

  var transpile = function(name, options) {
    // Read in the file
    options.input = grunt.file.read(name);

    // Ensure we have a template name.
    if (options.name === undefined) {
      // Default template name is the basename w/o the extension.
      options.name = path.basename(name, path.extname(name));
    }

    try {
      switch (options.language) {
      case 'js': return transpileJs(options);
      case 'coffee': return transpileCoffee(options);
      default:
        grunt.fail.warn(
          'Language ' + options.language + ' is not a valid ' +
          'source language for HAML; choices are: coffee and js\n');
      }
    } catch (e) {
      grunt.log.error(e);
      grunt.fail.warn('Haml failed to compile.');
    }
  };

  var transpileJs = function(options) {

    var haml = require('haml');

    // First pass; generate the javascript method.
    var output = haml(options.input);

    if (options.target === 'html') {
      // Evaluate method with the context and return it.
      return output(options.context);
    } else if (options.target !== 'js') {
      grunt.fail.warn(
        'Target ' + options.target + ' is not a valid ' +
        'destination target for `haml-coffee`; choices ' +
        'are: html and js\n');
    }

    // Reduce to a true annoymous, unnamed method.
    // TODO: Push this upstream.
    output = output.toString().substring(27);
    output = 'function(locals)' + output;

    switch (options.placement) {
    case 'global':
      // Set in the desired namespace.
      output = options.namespace + "['" + options.name + "'] = " + output;
      output = '\n' + output + '\n';
      break;

    case 'amd':
      // Search for additional dependencies
      var lookup = /require.*?\(.*?["'](.*)["'].*?\)/g;
      var extra = lookup.exec(options.input);
      while (extra !== null) {
        var base = path.basename(extra[1]);
        options.dependencies[base] = extra[1];
        extra = lookup.exec(options.input);
      }

      // Build define statement.
      var defineStatement = 'define([';
      var modules = _.values(options.dependencies);
      modules = modules.length ? "'" + modules.join("','") + "'" : "";
      defineStatement += modules;
      defineStatement += '], function(';
      defineStatement += _.keys(options.dependencies).join(',');
      defineStatement += ') { \n';

      // Wrap output in it.
      output = defineStatement + 'return ' + output + ';\n});\n';
      break;

    default:
      grunt.fail.warn(
        'Placement ' + options.placement + ' is not a valid ' +
        'destination placement for `haml-js`; choices ' +
        'are: amd and global\n');
    }
    // Return the final template.
    return output;
  };

  var transpileCoffee = function(options) {
    var hamlc = require('haml-coffee');

    switch (options.target) {
    case 'js':
      // Pass it off to haml-coffee to render a template in javascript.
      return hamlc.template(options.input, options.name, options.namespace,
        options);

    case 'html':
      // Pass it off to haml-coffee to render a template in javascript.
      var output = hamlc.compile(options.input, options);
      // Now we render it as HTML with the given context.
      return output(options.context);

    default:
      grunt.fail.warn(
        'Target ' + options.target + ' is not a valid ' +
        'destination target for `haml-coffee`; choices ' +
        'are: html and js\n');
    }
  };
};
<commit_msg>Filename is needed in the options.<commit_after>/*
 * grunt-contrib-haml
 *
 * Copyright (c) 2012 Concordus Applications
 * Licensed under the MIT license.
 */

module.exports = function(grunt) {
  'use strict';

  var path = require('path');
  var _    = grunt.util._;

  grunt.registerMultiTask('haml', 'Compile Haml files', function() {
    // Set the target options with some defaults.
    var options = this.options({
      // Default target is javascript.
      target: 'html',

      // Default language choice to coffee-script and haml-coffee.
      language: 'js',

      // Default placement; either `amd` or `global`.
      placement: 'global',

      // Default global placement namespace to `window`.
      namespace: 'window.HAML',

      // Default hash of dependencies for AMD.
      dependencies: {}
    });

    // Write options iff verbose.
    grunt.verbose.writeflags(options, 'Options');

    // Transpile each src/dest group of files.
    this.files.forEach(function(file) {

      // Get only files that are actually there.
      var validFiles = file.src.filter(function(filepath) {
        if (grunt.file.exists(filepath)) {
          return true;
        } else {
          grunt.log.warn('Source file "' + filepath + '" not found.');
          return false;
        }
      });

      // Ensure we have files to transpile.
      if (validFiles.length > 0) {
        // Transpile each file.
        var output = validFiles.map(function (filename) {
          return transpile(filename, options);
        });
        // Write the new file.
        grunt.file.write(file.dest, output.join('\n'));
        grunt.log.writeln('File ' + file.dest.cyan + ' created.');
      } else {
        grunt.log.writeln('Unable to compile; no valid files were found.');
      }
    });
  });

  var transpile = function(name, opts) {
    // Construct appropriate options to pass to the compiler
    // Create a new object so we do not mutate the target options.
    var options = _.extend({filename: name}, opts);
    // Read in the file
    options.input = grunt.file.read(name);

    // Ensure we have a template name.
    if (options.name === undefined) {
      // Default template name is the basename w/o the extension.
      options.name = path.basename(name, path.extname(name));
    }

    try {
      switch (options.language) {
      case 'js': return transpileJs(options);
      case 'coffee': return transpileCoffee(options);
      default:
        grunt.fail.warn(
          'Language ' + options.language + ' is not a valid ' +
          'source language for HAML; choices are: coffee and js\n');
      }
    } catch (e) {
      grunt.log.error(e);
      grunt.fail.warn('Haml failed to compile.');
    }
  };

  var transpileJs = function(options) {

    var haml = require('haml');

    // First pass; generate the javascript method.
    var output = haml(options.input);

    if (options.target === 'html') {
      // Evaluate method with the context and return it.
      return output(options.context);
    } else if (options.target !== 'js') {
      grunt.fail.warn(
        'Target ' + options.target + ' is not a valid ' +
        'destination target for `haml-coffee`; choices ' +
        'are: html and js\n');
    }

    // Reduce to a true annoymous, unnamed method.
    // TODO: Push this upstream.
    output = output.toString().substring(27);
    output = 'function(locals)' + output;

    switch (options.placement) {
    case 'global':
      // Set in the desired namespace.
      output = options.namespace + "['" + options.name + "'] = " + output;
      output = '\n' + output + '\n';
      break;

    case 'amd':
      // Search for additional dependencies
      var lookup = /require.*?\(.*?["'](.*)["'].*?\)/g;
      var extra = lookup.exec(options.input);
      while (extra !== null) {
        var base = path.basename(extra[1]);
        options.dependencies[base] = extra[1];
        extra = lookup.exec(options.input);
      }

      // Build define statement.
      var defineStatement = 'define([';
      var modules = _.values(options.dependencies);
      modules = modules.length ? "'" + modules.join("','") + "'" : "";
      defineStatement += modules;
      defineStatement += '], function(';
      defineStatement += _.keys(options.dependencies).join(',');
      defineStatement += ') { \n';

      // Wrap output in it.
      output = defineStatement + 'return ' + output + ';\n});\n';
      break;

    default:
      grunt.fail.warn(
        'Placement ' + options.placement + ' is not a valid ' +
        'destination placement for `haml-js`; choices ' +
        'are: amd and global\n');
    }
    // Return the final template.
    return output;
  };

  var transpileCoffee = function(options) {
    var hamlc = require('haml-coffee');

    switch (options.target) {
    case 'js':
      // Pass it off to haml-coffee to render a template in javascript.
      return hamlc.template(options.input, options.name, options.namespace,
        options);

    case 'html':
      // Pass it off to haml-coffee to render a template in javascript.
      var output = hamlc.compile(options.input, options);
      // Now we render it as HTML with the given context.
      return output(options.context);

    default:
      grunt.fail.warn(
        'Target ' + options.target + ' is not a valid ' +
        'destination target for `haml-coffee`; choices ' +
        'are: html and js\n');
    }
  };
};
<|endoftext|>


<commit_before>/*
 * grunt-http
 * https://github.com/johngeorgewright/grunt-contrib-http
 *
 * Copyright (c) 2014 John Wright
 * Licensed under the MIT license.
 */

'use strict';

var request = require('request'),
    async = require('async'),
    FormData = require('form-data');

module.exports = function (grunt) {

  function responseHandler(dest, ignoreErrors, callback, done) {
    return function (error, response, body) {

      response = response || { statusCode: 0 };

      grunt.verbose.subhead('Response');

      if (error && !ignoreErrors) {
        return done(error);
      } else if (!ignoreErrors && (response.statusCode < 200 || response.statusCode > 399)) {
        return done(response.statusCode + " " + body);
      }

      grunt.log.ok(response.statusCode);
      grunt.verbose.writeln(body);

      if (dest) {
        grunt.file.write(dest, body);
      }

      if (callback) {
        callback(error, response, body);
      }

      done();
    };
  }

  function readFile(filepath) {
    return grunt.file.read(filepath);
  }

  grunt.registerMultiTask('http', 'Sends a HTTP request and deals with the response.', function () {

    var options = this.options({
          ignoreErrors: false,
          sourceField: 'body'
        }),
        done = this.async(),
        sourceField = options.sourceField,
        sourcePath = sourceField.split('.'),
        sourceKey = sourcePath.pop(),
        sourceObj = options,
        formCallback = typeof options.form === 'function' ? options.form : null,
        callback = options.callback,
        files = [];

    sourcePath.forEach(function (key) {
      sourceObj = sourceObj[key];
    });

    if (formCallback) {
      delete options.form;
    }

    if (callback && typeof callback !== 'function') {
      throw new Error('`callback` option must be a function');
    }

    function configureSource(file) {
      if (file.src) {
        sourceObj[sourceKey] = file.src;
      } else if (sourceObj[sourceKey]) {
        delete sourceObj[sourceKey];
      }
    }

    function call(file, next) {
      var r, callback, form;
      file = file || {};
      configureSource(file);
      if (typeof(options.body) === 'function') {
        options.body = options.body();
      }
      if (typeof(options.json) === 'function') {
        options.json = options.json();
      }
      callback = responseHandler(file.dest, options.ignoreErrors, options.callback, next);
      r = request(options, callback);
      if (formCallback) {
        form = r.form();
        formCallback(form);
      }
    }

    function resolve(err) {
      if (err) {
        grunt.fail.fatal(err);
      }
      done(err);
    }

    function addToFilesArray(file) {
      var contents;

      if (file.src) {
        contents = file.src.map(readFile).join('\n');
      }

      grunt.verbose.subhead('Request');
      grunt.verbose.writeln(JSON.stringify(options, null, 2));

      files.push({
        src: contents,
        dest: file.dest
      });
    }

    if (this.files.length) {
      this.files.forEach(addToFilesArray);
      async.each(files, call, resolve);
    } else {
      call(null, resolve);
    }

  });

};

<commit_msg>Fixed #20<commit_after>/*
 * grunt-http
 * https://github.com/johngeorgewright/grunt-contrib-http
 *
 * Copyright (c) 2014 John Wright
 * Licensed under the MIT license.
 */

'use strict';

var request = require('request'),
    async = require('async'),
    FormData = require('form-data');

module.exports = function (grunt) {

  function responseHandler(dest, ignoreErrors, callback, done) {
    return function (error, response, body) {

      response = response || { statusCode: 0 };

      grunt.verbose.subhead('Response');

      if (error && !ignoreErrors) {
        return done(error);
      } else if (!ignoreErrors && (response.statusCode < 200 || response.statusCode > 399)) {
        return done(response.statusCode + " " + body);
      }

      grunt.log.ok(response.statusCode);
      grunt.verbose.writeln(body);

      if (dest) {
        grunt.file.write(dest, body);
      }

      if (callback) {
        callback(error, response, body);
      }

      done();
    };
  }

  function readFile(filepath) {
    return grunt.file.read(filepath);
  }

  grunt.registerMultiTask('http', 'Sends a HTTP request and deals with the response.', function () {

    var options = this.options({
          ignoreErrors: false,
          sourceField: 'body'
        }),
        done = this.async(),
        sourceField = options.sourceField,
        sourcePath = sourceField.split('.'),
        sourceKey = sourcePath.pop(),
        sourceObj = options,
        formCallback = typeof options.form === 'function' ? options.form : null,
        callback = options.callback,
        files = [];

    sourcePath.forEach(function (key) {
      sourceObj = sourceObj[key];
    });

    if (formCallback) {
      delete options.form;
    }

    if (callback && typeof callback !== 'function') {
      throw new Error('`callback` option must be a function');
    }

    function configureSource(file) {
      if (file.src) {
        sourceObj[sourceKey] = file.src;
      }
    }

    function call(file, next) {
      var r, callback, form;
      file = file || {};
      configureSource(file);
      if (typeof(options.body) === 'function') {
        options.body = options.body();
      }
      if (typeof(options.json) === 'function') {
        options.json = options.json();
      }
      callback = responseHandler(file.dest, options.ignoreErrors, options.callback, next);
      r = request(options, callback);
      if (formCallback) {
        form = r.form();
        formCallback(form);
      }
    }

    function resolve(err) {
      if (err) {
        grunt.fail.fatal(err);
      }
      done(err);
    }

    function addToFilesArray(file) {
      var contents;

      if (file.src) {
        contents = file.src.map(readFile).join('\n');
      }

      grunt.verbose.subhead('Request');
      grunt.verbose.writeln(JSON.stringify(options, null, 2));

      files.push({
        src: contents,
        dest: file.dest
      });
    }

    if (this.files.length) {
      this.files.forEach(addToFilesArray);
      async.each(files, call, resolve);
    } else {
      call(null, resolve);
    }

  });

};

<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import icBEM from './utils/icBEM';
import prefixClass from './utils/prefixClass';

import './styles/_animations.scss';
import './styles/Icon.scss';

const COMPONENT_NAME = prefixClass('icon');
const ROOT_BEM = icBEM(COMPONENT_NAME);

const GRAY = 'gray';
const BLUE = 'blue';
const RED = 'red';
export const ICON_COLOR = { GRAY, BLUE, RED };

function Icon({
    type,
    color,
    large,
    spinning,
    className,
    ...otherProps
}) {
    let bemClass = ROOT_BEM
        .modifier('large', large)
        .modifier('spin', spinning);

    if (color) {
        bemClass = bemClass.modifier(color);
    }

    const rootClassName = classNames(
        className,
        bemClass.toString(),
        `gyp-icon-${type}`
    );

    return (
        <span
            className={rootClassName}
            role="presentation"
            {...otherProps} />
    );
}

Icon.propTypes = {
    type: PropTypes.string.isRequired,
    color: PropTypes.oneOf(Object.values(ICON_COLOR)),
    large: PropTypes.bool,
    spinning: PropTypes.bool,
};

Icon.defaultProps = {
    color: undefined,
    large: false,
    spinning: false,
};

export default Icon;
<commit_msg>Fix Icon color prop table in storybook<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import icBEM from './utils/icBEM';
import prefixClass from './utils/prefixClass';

import './styles/_animations.scss';
import './styles/Icon.scss';

const COMPONENT_NAME = prefixClass('icon');
const ROOT_BEM = icBEM(COMPONENT_NAME);

const GRAY = 'gray';
const BLUE = 'blue';
const RED = 'red';

function Icon({
    type,
    color,
    large,
    spinning,
    className,
    ...otherProps
}) {
    let bemClass = ROOT_BEM
        .modifier('large', large)
        .modifier('spin', spinning);

    if (color) {
        bemClass = bemClass.modifier(color);
    }

    const rootClassName = classNames(
        className,
        bemClass.toString(),
        `gyp-icon-${type}`
    );

    return (
        <span
            className={rootClassName}
            role="presentation"
            {...otherProps} />
    );
}

Icon.propTypes = {
    type: PropTypes.string.isRequired,
    color: PropTypes.oneOf([GRAY, BLUE, RED]),
    large: PropTypes.bool,
    spinning: PropTypes.bool,
};

Icon.defaultProps = {
    color: undefined,
    large: false,
    spinning: false,
};

export default Icon;
<|endoftext|>


<commit_before>var db = require('../helpers/db');
var _ = require('underscore');

var express = require('express');
var router = express.Router();

router.get('/', function(req, res) {
  var query = "SELECT * FROM continent";

  db.query(query)
  .then(function(result) {
    res.status(200).send(result.rows);
  })
  .catch(function(error) {
    res.status(500).send(error);
  });
});

router.post('/', function(req, res) {
  var name = req.body.name;

  if(!(_.isString(name))) {
    res.status(400).send("Bad Request: no name parameter");
    return;
  }

  var query = 'INSERT INTO continent ("name") VALUES ($1) RETURNING continent_id';
  var values = [name];

  db.query(query, values)
  .then(function(result) {
    res.status(201).send(result.rows[0]);
  })
  .catch(function(error) {
    res.status(500).send(error);
  });
});

router.use('/:id', function(req, res, next) {
  var id = Number(req.params.id);

  if(_.isNumber(id)) {
    next();
  } else {
    res.status(400).send("Value should be a number");
  }
});

router.get('/:id', function(req, res) {
  var query = "SELECT * FROM continent WHERE continent_id = $1";
  var values = [req.params.id];

  db.query(query, values)
  .then(function(result) {
    res.status(200).send(result.rows[0]);
  })
  .catch(function(error) {
    res.status(500).send(error);
  });
});

module.exports = router;
<commit_msg>Create put method<commit_after>var db = require('../helpers/db');
var _ = require('underscore');

var express = require('express');
var router = express.Router();

router.get('/', function(req, res) {
  var query = "SELECT * FROM continent";

  db.query(query)
  .then(function(result) {
    res.status(200).send(result.rows);
  })
  .catch(function(error) {
    res.status(500).send(error);
  });
});

router.post('/', function(req, res) {
  var name = req.body.name;

  if(!(_.isString(name))) {
    res.status(400).send("Bad Request: no name parameter");
    return;
  }

  var query = 'INSERT INTO continents ("name") VALUES ($1) RETURNING continent_id';
  var values = [name];

  db.query(query, values)
  .then(function(result) {
    res.status(201).send(result.rows[0]);
  })
  .catch(function(error) {
    res.status(500).send(error);
  });
});

router.use('/:id', function(req, res, next) {
  var id = Number(req.params.id);

  if(_.isNumber(id)) {
    next();
  } else {
    res.status(400).send("Value should be a number");
  }
});

router.get('/:id', function(req, res) {
  var query = "SELECT * FROM continents WHERE continent_id = $1";
  var values = [req.params.id];

  db.query(query, values)
  .then(function(result) {
    res.status(200).send(result.rows[0]);
  })
  .catch(function(error) {
    res.status(500).send(error);
  });
});

router.put('/:id', function(req, res) {
  var name = req.body.name;

  if(!(_.isString(name))) {
    res.status(400).send("Bad Request: no name parameter");
    return;
  }

  var query = "UPDATE continents SET name = $1 WHERE continent_id = $2";
  var values = [name, req.params.id];

  db.query(query, values)
  .then(function(result) {
    res.status(200).end();
  })
  .catch(function(error) {
    res.status(500).send(error);
  })
});

module.exports = router;
<|endoftext|>


<commit_before>/*global define*/
/**
 * To load this extension, add the following to your custom.js:
 *
 * require(['base/js/events'], function (events) {
 *     events.on('app_initialized.NotebookApp', function() {
 *         IPython.load_extensions('nbgrader');
 *     });
 * });
 *
**/

define([
    'require',
    'jquery',
    'base/js/namespace',
    'base/js/dialog',
    'notebook/js/celltoolbar',
    'base/js/events'

], function (require, $, IPython, dialog, celltoolbar, events) {
    "use strict";

    var nbgrader_preset_name = "Create Assignment";
    var nbgrader_highlight_cls = "nbgrader-highlight";
    var nbgrader_cls = "nbgrader-cell";
    var warning;

    var CellToolbar = celltoolbar.CellToolbar;

    // trigger an event when the toolbar is being rebuilt
    CellToolbar.prototype._rebuild = CellToolbar.prototype.rebuild;
    CellToolbar.prototype.rebuild = function () {
        events.trigger('toolbar_rebuild.CellToolbar', this.cell);
        this._rebuild();
    };

    // trigger an event when the toolbar is being (globally) hidden
    CellToolbar._global_hide = CellToolbar.global_hide;
    CellToolbar.global_hide = function () {
        $("#nbgrader-total-points-group").hide();

        CellToolbar._global_hide();
        for (var i=0; i < CellToolbar._instances.length; i++) {
            events.trigger('global_hide.CellToolbar', CellToolbar._instances[i].cell);
        }
    };

    // show the total points when the preset is activated
    events.on('preset_activated.CellToolbar', function(evt, preset) {
        var elem = $("#nbgrader-total-points-group");
        if (preset.name === nbgrader_preset_name) {
            if (elem.length == 0) {
                elem = $("<div />").attr("id", "nbgrader-total-points-group");
                elem.addClass("btn-group");
                elem.append($("<span />").text("Total points:"));
                elem.append($("<input />")
                            .attr("disabled", "disabled")
                            .attr("type", "number")
                            .attr("id", "nbgrader-total-points"));
                $("#maintoolbar-container").append(elem);
            }
            elem.show();
            update_total();
        } else {
            elem.hide();
        }
    });

    // remove nbgrader class when the cell is either hidden or rebuilt
    events.on("global_hide.CellToolbar toolbar_rebuild.CellToolbar", function (evt, cell) {
        if (cell.element && cell.element.hasClass(nbgrader_cls)) {
            cell.element.removeClass(nbgrader_cls);
        }
        if (cell.element && cell.element.hasClass(nbgrader_highlight_cls)) {
            cell.element.removeClass(nbgrader_highlight_cls);
        }
    });

    // update total points when a cell is deleted
    events.on("delete.Cell", function (evt, info) {
        update_total();
    });

    // validate cell ids on save
    events.on("before_save.Notebook", function (evt) {
        validate_ids();
    });

    var to_float = function(val) {
        if (val === undefined || val === "") {
            return 0;
        }
        return parseFloat(val);
    };

    var update_total = function() {
        var total_points = 0;
        var cells = IPython.notebook.get_cells();
        for (var i=0; i < cells.length; i++) {
            if (is_grade(cells[i])) {
                total_points += to_float(cells[i].metadata.nbgrader.points);
            }
        }
        $("#nbgrader-total-points").attr("value", total_points);
    };

    var validate_ids = function() {
        var elems, set, i, label;

        if (warning !== undefined) {
            return;
        }

        var valid = /^[a-zA-Z0-9_\-]+$/;
        var modal_opts = {
            notebook: IPython.notebook,
            keyboard_manager: IPython.keyboard_manager,
            buttons: {
                OK: {
                    class: "btn-primary",
                    click: function () {
                        warning = undefined;
                    }
                }
            }
        };

        elems = $(".nbgrader-id-input");
        set = new Object();
        for (i = 0; i < elems.length; i++) {
            label = $(elems[i]).val();
            if (!valid.test(label)) {
                modal_opts.title = "Invalid nbgrader cell ID";
                modal_opts.body = "At least one cell has an invalid nbgrader ID. Cell IDs must contain at least one character, and may only container letters, numbers, hyphens, and/or underscores.";
                warning = dialog.modal(modal_opts);
                break;
            } else if (label in set) {
                modal_opts.title = "Duplicate nbgrader cell ID";
                modal_opts.body = "The nbgrader ID \"" + label + "\" has been used for more than one cell. Please make sure all grade cells have unique ids.";
                warning = dialog.modal(modal_opts);
                break;
            } else {
                set[label] = true;
            }
        }
    };

    /**
     * Is the cell a solution cell?
     */
    var is_solution = function (cell) {
        if (cell.metadata.nbgrader === undefined) {
            return false;
        } else if (cell.metadata.nbgrader.solution === undefined) {
            return false;
        } else {
            return cell.metadata.nbgrader.solution;
        }
    };

    /**
     * Set whether this cell is or is not a solution cell.
     */
    var set_solution = function (cell, val) {
        if (cell.metadata.nbgrader === undefined) {
            cell.metadata.nbgrader = {};
        }
        cell.metadata.nbgrader.solution = val;
    };

    /**
     * Is the cell a grade cell?
     */
    var is_grade = function (cell) {
        if (cell.metadata.nbgrader === undefined) {
            return false;
        } else if (cell.metadata.nbgrader.grade === undefined) {
            return false;
        } else {
            return cell.metadata.nbgrader.grade;
        }
    };

    /**
     * Set whether this cell is or is not a grade cell.
     */
    var set_grade = function (cell, val) {
        if (cell.metadata.nbgrader === undefined) {
            cell.metadata.nbgrader = {};
        }
        cell.metadata.nbgrader.grade = val;
    };

    var get_points = function (cell) {
        if (cell.metadata.nbgrader === undefined) {
            return 0;
        } else {
            return to_float(cell.metadata.nbgrader.points);
        }
    };

    var set_points = function (cell, val) {
        if (cell.metadata.nbgrader === undefined) {
            cell.metadata.nbgrader = {};
        }
        cell.metadata.nbgrader.points = to_float(val);
    };

    var get_grade_id = function (cell) {
        if (cell.metadata.nbgrader === undefined) {
            return '';
        } else if (cell.metadata.nbgrader.grade_id === undefined) {
            return '';
        } else {
            return cell.metadata.nbgrader.grade_id;
        }
    };

    var set_grade_id = function (cell, val) {
        if (cell.metadata.nbgrader === undefined) {
            cell.metadata.nbgrader = {};
        }
        if (val === undefined) {
            cell.metadata.nbgrader.grade_id = '';
        } else {
            cell.metadata.nbgrader.grade_id = val;
        }
    };

    var is_locked = function (cell) {
        if (is_solution(cell)) {
            return false;
        } else if (is_grade(cell)) {
            return true;
        } else if (cell.metadata.nbgrader === undefined) {
            return false;
        } else if (cell.metadata.nbgrader.locked === undefined) {
            return false;
        } else {
            return cell.metadata.nbgrader.locked;
        }
    };

    var set_locked = function (cell, val) {
        if (cell.metadata.nbgrader === undefined) {
            cell.metadata.nbgrader = {};
        }
        if (is_solution(cell)) {
            cell.metadata.nbgrader.locked = false;
        } else if (is_grade(cell)) {
            cell.metadata.nbgrader.locked = true;
        } else {
            cell.metadata.nbgrader.locked = val;
        }
    };

    /**
     * Add a display class to the cell element, depending on the
     * nbgrader cell type.
     */
    var display_cell = function (cell) {
        if (is_grade(cell) || is_solution(cell)) {
            if (cell.element && !cell.element.hasClass(nbgrader_highlight_cls)) {
                cell.element.addClass(nbgrader_highlight_cls);
            }
        }
        if (is_grade(cell) || is_solution(cell) || is_locked(cell)) {
            if (cell.element && !cell.element.hasClass(nbgrader_cls)) {
                cell.element.addClass(nbgrader_cls);
            }
        }
    };

    var create_celltype_select = function (div, cell, celltoolbar) {
        // hack -- the DOM element for the celltoolbar is created before the
        // cell type is actually set, so we need to wait until the cell type
        // has been set before we can actually create the select menu
        if (cell.cell_type === null) {
            setTimeout(function () {
                create_celltype_select(div, cell, celltoolbar);
            }, 100);

        } else {

            var options_list = [];
            options_list.push(["-", ""]);
            options_list.push(["Manually graded answer", "manual"]);
            if (cell.cell_type == "code") {
                options_list.push(["Autograded answer", "solution"]);
                options_list.push(["Autograder tests", "tests"]);
            }
            options_list.push(["Read-only", "readonly"]);

            var setter = function (cell, val) {
                if (val === "") {
                    set_solution(cell, false);
                    set_grade(cell, false);
                    set_locked(cell, false);
                } else if (val === "manual") {
                    set_solution(cell, true);
                    set_grade(cell, true);
                    set_locked(cell, false);
                } else if (val === "solution") {
                    set_solution(cell, true);
                    set_grade(cell, false);
                    set_locked(cell, false);
                } else if (val === "tests") {
                    set_solution(cell, false);
                    set_grade(cell, true);
                    set_locked(cell, true);
                } else if (val === "readonly") {
                    set_solution(cell, false);
                    set_grade(cell, false);
                    set_locked(cell, true);
                } else {
                    throw new Error("invalid nbgrader cell type: " + val);
                }
            };

            var getter = function (cell) {
                if (is_solution(cell) && is_grade(cell)) {
                    return "manual";
                } else if (is_solution(cell) && cell.cell_type === "code") {
                    return "solution";
                } else if (is_grade(cell) && cell.cell_type === "code") {
                    return "tests";
                } else if (is_locked(cell)) {
                    return "readonly";
                } else {
                    return "";
                }
            };

            var select = $('<select/>');
            for(var i=0; i < options_list.length; i++){
                var opt = $('<option/>')
                    .attr('value', options_list[i][1])
                    .text(options_list[i][0]);
                select.append(opt);
            }
            select.val(getter(cell));
            select.change(function () {
                setter(cell, select.val());
                celltoolbar.rebuild();
                update_total();
                display_cell(cell);
                validate_ids();
                IPython.notebook.save_checkpoint();
            });
            display_cell(cell);
            $(div).append($('<span/>').append(select));
        }
    };

    /**
     * Create the input text box for the problem or test id.
     */
    var create_id_input = function (div, cell, celltoolbar) {
        if (!is_grade(cell) && !is_solution(cell) && !is_locked(cell)) {
            return;
        }

        var local_div = $('<div/>');
        var text = $('<input/>').attr('type', 'text');
        var lbl = $('<label/>').append($('<span/>').text('ID: '));
        lbl.append(text);

        text.addClass('nbgrader-id-input');
        text.attr("value", get_grade_id(cell));
        text.change(function () {
            set_grade_id(cell, text.val());
            validate_ids();
            IPython.notebook.save_checkpoint();
        });

        local_div.addClass('nbgrader-id');
        $(div).append(local_div.append($('<span/>').append(lbl)));

        IPython.keyboard_manager.register_events(text);
    };

    /**
     * Create the input text box for the number of points the problem
     * is worth.
     */
    var create_points_input = function (div, cell, celltoolbar) {
        if (!is_grade(cell)) {
            return;
        }

        var local_div = $('<div/>');
        var text = $('<input/>').attr('type', 'number');
        var lbl = $('<label/>').append($('<span/>').text('Points: '));
        lbl.append(text);

        text.addClass('nbgrader-points-input');
        text.attr("value", get_points(cell));
        update_total();

        text.change(function () {
            set_points(cell, text.val());
            text.val(get_points(cell));
            update_total();
            IPython.notebook.save_checkpoint();
        });

        local_div.addClass('nbgrader-points');
        $(div).append(local_div.append($('<span/>').append(lbl)));

        IPython.keyboard_manager.register_events(text);
    };

    var create_lock_cell_button = function (div, cell, celltoolbar) {
        var lock = $("<a />").addClass("lock-button");
        if (is_locked(cell)) {
            lock.append($("<li />").addClass("fa fa-lock"));
            lock.tooltip({
                placement: "right",
                title: "Student changes will be overwritten"
            });
        }

        $(div).addClass("lock-cell-container").append(lock);
    };

    /**
     * Load custom css for the nbgrader toolbar.
     */
    var load_css = function () {
        var link = document.createElement('link');
        link.type = 'text/css';
        link.rel = 'stylesheet';
        link.href = require.toUrl('./nbgrader.css');
        document.getElementsByTagName('head')[0].appendChild(link);
    };

    /**
     * Load the nbgrader toolbar extension.
     */
    var load_extension = function () {
        load_css();
        CellToolbar.register_callback('create_assignment.grading_options', create_celltype_select);
        CellToolbar.register_callback('create_assignment.id_input', create_id_input);
        CellToolbar.register_callback('create_assignment.points_input', create_points_input);
        CellToolbar.register_callback('create_assignment.lock_cell', create_lock_cell_button);

        var preset = [
            'create_assignment.lock_cell',
            'create_assignment.points_input',
            'create_assignment.id_input',
            'create_assignment.grading_options',
        ];
        CellToolbar.register_preset(nbgrader_preset_name, preset, IPython.notebook);
        console.log('nbgrader extension for metadata editing loaded.');
    };

    return {
        'load_ipython_extension': load_extension
    };
});
<commit_msg>Don't save checkpoints<commit_after>/*global define*/
/**
 * To load this extension, add the following to your custom.js:
 *
 * require(['base/js/events'], function (events) {
 *     events.on('app_initialized.NotebookApp', function() {
 *         IPython.load_extensions('nbgrader');
 *     });
 * });
 *
**/

define([
    'require',
    'jquery',
    'base/js/namespace',
    'base/js/dialog',
    'notebook/js/celltoolbar',
    'base/js/events'

], function (require, $, IPython, dialog, celltoolbar, events) {
    "use strict";

    var nbgrader_preset_name = "Create Assignment";
    var nbgrader_highlight_cls = "nbgrader-highlight";
    var nbgrader_cls = "nbgrader-cell";
    var warning;

    var CellToolbar = celltoolbar.CellToolbar;

    // trigger an event when the toolbar is being rebuilt
    CellToolbar.prototype._rebuild = CellToolbar.prototype.rebuild;
    CellToolbar.prototype.rebuild = function () {
        events.trigger('toolbar_rebuild.CellToolbar', this.cell);
        this._rebuild();
    };

    // trigger an event when the toolbar is being (globally) hidden
    CellToolbar._global_hide = CellToolbar.global_hide;
    CellToolbar.global_hide = function () {
        $("#nbgrader-total-points-group").hide();

        CellToolbar._global_hide();
        for (var i=0; i < CellToolbar._instances.length; i++) {
            events.trigger('global_hide.CellToolbar', CellToolbar._instances[i].cell);
        }
    };

    // show the total points when the preset is activated
    events.on('preset_activated.CellToolbar', function(evt, preset) {
        var elem = $("#nbgrader-total-points-group");
        if (preset.name === nbgrader_preset_name) {
            if (elem.length == 0) {
                elem = $("<div />").attr("id", "nbgrader-total-points-group");
                elem.addClass("btn-group");
                elem.append($("<span />").text("Total points:"));
                elem.append($("<input />")
                            .attr("disabled", "disabled")
                            .attr("type", "number")
                            .attr("id", "nbgrader-total-points"));
                $("#maintoolbar-container").append(elem);
            }
            elem.show();
            update_total();
        } else {
            elem.hide();
        }
    });

    // remove nbgrader class when the cell is either hidden or rebuilt
    events.on("global_hide.CellToolbar toolbar_rebuild.CellToolbar", function (evt, cell) {
        if (cell.element && cell.element.hasClass(nbgrader_cls)) {
            cell.element.removeClass(nbgrader_cls);
        }
        if (cell.element && cell.element.hasClass(nbgrader_highlight_cls)) {
            cell.element.removeClass(nbgrader_highlight_cls);
        }
    });

    // update total points when a cell is deleted
    events.on("delete.Cell", function (evt, info) {
        update_total();
    });

    // validate cell ids on save
    events.on("before_save.Notebook", function (evt) {
        validate_ids();
    });

    var to_float = function(val) {
        if (val === undefined || val === "") {
            return 0;
        }
        return parseFloat(val);
    };

    var update_total = function() {
        var total_points = 0;
        var cells = IPython.notebook.get_cells();
        for (var i=0; i < cells.length; i++) {
            if (is_grade(cells[i])) {
                total_points += to_float(cells[i].metadata.nbgrader.points);
            }
        }
        $("#nbgrader-total-points").attr("value", total_points);
    };

    var validate_ids = function() {
        var elems, set, i, label;

        if (warning !== undefined) {
            return;
        }

        var valid = /^[a-zA-Z0-9_\-]+$/;
        var modal_opts = {
            notebook: IPython.notebook,
            keyboard_manager: IPython.keyboard_manager,
            buttons: {
                OK: {
                    class: "btn-primary",
                    click: function () {
                        warning = undefined;
                    }
                }
            }
        };

        elems = $(".nbgrader-id-input");
        set = new Object();
        for (i = 0; i < elems.length; i++) {
            label = $(elems[i]).val();
            if (!valid.test(label)) {
                modal_opts.title = "Invalid nbgrader cell ID";
                modal_opts.body = "At least one cell has an invalid nbgrader ID. Cell IDs must contain at least one character, and may only container letters, numbers, hyphens, and/or underscores.";
                warning = dialog.modal(modal_opts);
                break;
            } else if (label in set) {
                modal_opts.title = "Duplicate nbgrader cell ID";
                modal_opts.body = "The nbgrader ID \"" + label + "\" has been used for more than one cell. Please make sure all grade cells have unique ids.";
                warning = dialog.modal(modal_opts);
                break;
            } else {
                set[label] = true;
            }
        }
    };

    /**
     * Is the cell a solution cell?
     */
    var is_solution = function (cell) {
        if (cell.metadata.nbgrader === undefined) {
            return false;
        } else if (cell.metadata.nbgrader.solution === undefined) {
            return false;
        } else {
            return cell.metadata.nbgrader.solution;
        }
    };

    /**
     * Set whether this cell is or is not a solution cell.
     */
    var set_solution = function (cell, val) {
        if (cell.metadata.nbgrader === undefined) {
            cell.metadata.nbgrader = {};
        }
        cell.metadata.nbgrader.solution = val;
    };

    /**
     * Is the cell a grade cell?
     */
    var is_grade = function (cell) {
        if (cell.metadata.nbgrader === undefined) {
            return false;
        } else if (cell.metadata.nbgrader.grade === undefined) {
            return false;
        } else {
            return cell.metadata.nbgrader.grade;
        }
    };

    /**
     * Set whether this cell is or is not a grade cell.
     */
    var set_grade = function (cell, val) {
        if (cell.metadata.nbgrader === undefined) {
            cell.metadata.nbgrader = {};
        }
        cell.metadata.nbgrader.grade = val;
    };

    var get_points = function (cell) {
        if (cell.metadata.nbgrader === undefined) {
            return 0;
        } else {
            return to_float(cell.metadata.nbgrader.points);
        }
    };

    var set_points = function (cell, val) {
        if (cell.metadata.nbgrader === undefined) {
            cell.metadata.nbgrader = {};
        }
        cell.metadata.nbgrader.points = to_float(val);
    };

    var get_grade_id = function (cell) {
        if (cell.metadata.nbgrader === undefined) {
            return '';
        } else if (cell.metadata.nbgrader.grade_id === undefined) {
            return '';
        } else {
            return cell.metadata.nbgrader.grade_id;
        }
    };

    var set_grade_id = function (cell, val) {
        if (cell.metadata.nbgrader === undefined) {
            cell.metadata.nbgrader = {};
        }
        if (val === undefined) {
            cell.metadata.nbgrader.grade_id = '';
        } else {
            cell.metadata.nbgrader.grade_id = val;
        }
    };

    var is_locked = function (cell) {
        if (is_solution(cell)) {
            return false;
        } else if (is_grade(cell)) {
            return true;
        } else if (cell.metadata.nbgrader === undefined) {
            return false;
        } else if (cell.metadata.nbgrader.locked === undefined) {
            return false;
        } else {
            return cell.metadata.nbgrader.locked;
        }
    };

    var set_locked = function (cell, val) {
        if (cell.metadata.nbgrader === undefined) {
            cell.metadata.nbgrader = {};
        }
        if (is_solution(cell)) {
            cell.metadata.nbgrader.locked = false;
        } else if (is_grade(cell)) {
            cell.metadata.nbgrader.locked = true;
        } else {
            cell.metadata.nbgrader.locked = val;
        }
    };

    /**
     * Add a display class to the cell element, depending on the
     * nbgrader cell type.
     */
    var display_cell = function (cell) {
        if (is_grade(cell) || is_solution(cell)) {
            if (cell.element && !cell.element.hasClass(nbgrader_highlight_cls)) {
                cell.element.addClass(nbgrader_highlight_cls);
            }
        }
        if (is_grade(cell) || is_solution(cell) || is_locked(cell)) {
            if (cell.element && !cell.element.hasClass(nbgrader_cls)) {
                cell.element.addClass(nbgrader_cls);
            }
        }
    };

    var create_celltype_select = function (div, cell, celltoolbar) {
        // hack -- the DOM element for the celltoolbar is created before the
        // cell type is actually set, so we need to wait until the cell type
        // has been set before we can actually create the select menu
        if (cell.cell_type === null) {
            setTimeout(function () {
                create_celltype_select(div, cell, celltoolbar);
            }, 100);

        } else {

            var options_list = [];
            options_list.push(["-", ""]);
            options_list.push(["Manually graded answer", "manual"]);
            if (cell.cell_type == "code") {
                options_list.push(["Autograded answer", "solution"]);
                options_list.push(["Autograder tests", "tests"]);
            }
            options_list.push(["Read-only", "readonly"]);

            var setter = function (cell, val) {
                if (val === "") {
                    set_solution(cell, false);
                    set_grade(cell, false);
                    set_locked(cell, false);
                } else if (val === "manual") {
                    set_solution(cell, true);
                    set_grade(cell, true);
                    set_locked(cell, false);
                } else if (val === "solution") {
                    set_solution(cell, true);
                    set_grade(cell, false);
                    set_locked(cell, false);
                } else if (val === "tests") {
                    set_solution(cell, false);
                    set_grade(cell, true);
                    set_locked(cell, true);
                } else if (val === "readonly") {
                    set_solution(cell, false);
                    set_grade(cell, false);
                    set_locked(cell, true);
                } else {
                    throw new Error("invalid nbgrader cell type: " + val);
                }
            };

            var getter = function (cell) {
                if (is_solution(cell) && is_grade(cell)) {
                    return "manual";
                } else if (is_solution(cell) && cell.cell_type === "code") {
                    return "solution";
                } else if (is_grade(cell) && cell.cell_type === "code") {
                    return "tests";
                } else if (is_locked(cell)) {
                    return "readonly";
                } else {
                    return "";
                }
            };

            var select = $('<select/>');
            for(var i=0; i < options_list.length; i++){
                var opt = $('<option/>')
                    .attr('value', options_list[i][1])
                    .text(options_list[i][0]);
                select.append(opt);
            }
            select.val(getter(cell));
            select.change(function () {
                setter(cell, select.val());
                celltoolbar.rebuild();
                update_total();
                display_cell(cell);
                validate_ids();
            });
            display_cell(cell);
            $(div).append($('<span/>').append(select));
        }
    };

    /**
     * Create the input text box for the problem or test id.
     */
    var create_id_input = function (div, cell, celltoolbar) {
        if (!is_grade(cell) && !is_solution(cell) && !is_locked(cell)) {
            return;
        }

        var local_div = $('<div/>');
        var text = $('<input/>').attr('type', 'text');
        var lbl = $('<label/>').append($('<span/>').text('ID: '));
        lbl.append(text);

        text.addClass('nbgrader-id-input');
        text.attr("value", get_grade_id(cell));
        text.change(function () {
            set_grade_id(cell, text.val());
            validate_ids();
        });

        local_div.addClass('nbgrader-id');
        $(div).append(local_div.append($('<span/>').append(lbl)));

        IPython.keyboard_manager.register_events(text);
    };

    /**
     * Create the input text box for the number of points the problem
     * is worth.
     */
    var create_points_input = function (div, cell, celltoolbar) {
        if (!is_grade(cell)) {
            return;
        }

        var local_div = $('<div/>');
        var text = $('<input/>').attr('type', 'number');
        var lbl = $('<label/>').append($('<span/>').text('Points: '));
        lbl.append(text);

        text.addClass('nbgrader-points-input');
        text.attr("value", get_points(cell));
        update_total();

        text.change(function () {
            set_points(cell, text.val());
            text.val(get_points(cell));
            update_total();
        });

        local_div.addClass('nbgrader-points');
        $(div).append(local_div.append($('<span/>').append(lbl)));

        IPython.keyboard_manager.register_events(text);
    };

    var create_lock_cell_button = function (div, cell, celltoolbar) {
        var lock = $("<a />").addClass("lock-button");
        if (is_locked(cell)) {
            lock.append($("<li />").addClass("fa fa-lock"));
            lock.tooltip({
                placement: "right",
                title: "Student changes will be overwritten"
            });
        }

        $(div).addClass("lock-cell-container").append(lock);
    };

    /**
     * Load custom css for the nbgrader toolbar.
     */
    var load_css = function () {
        var link = document.createElement('link');
        link.type = 'text/css';
        link.rel = 'stylesheet';
        link.href = require.toUrl('./nbgrader.css');
        document.getElementsByTagName('head')[0].appendChild(link);
    };

    /**
     * Load the nbgrader toolbar extension.
     */
    var load_extension = function () {
        load_css();
        CellToolbar.register_callback('create_assignment.grading_options', create_celltype_select);
        CellToolbar.register_callback('create_assignment.id_input', create_id_input);
        CellToolbar.register_callback('create_assignment.points_input', create_points_input);
        CellToolbar.register_callback('create_assignment.lock_cell', create_lock_cell_button);

        var preset = [
            'create_assignment.lock_cell',
            'create_assignment.points_input',
            'create_assignment.id_input',
            'create_assignment.grading_options',
        ];
        CellToolbar.register_preset(nbgrader_preset_name, preset, IPython.notebook);
        console.log('nbgrader extension for metadata editing loaded.');
    };

    return {
        'load_ipython_extension': load_extension
    };
});
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Apigee Corporation
 *
 * 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 _ = require('lodash');
var debug = require('debug')('swagger-tools:middleware:ui');
var fs = require('fs');
var helpers = require('../lib/helpers');
var parseurl = require('parseurl');
var path = require('path');
var serveStatic = require('serve-static');

var defaultOptions = {
  apiDocs: '/api-docs',
  swaggerUi: '/docs'
};
var staticOptions = {};

/**
 * Middleware for serving the Swagger documents and Swagger UI.
 *
 * @param {object} rlOrSO - The Resource Listing (Swagger 1.2) or Swagger Object (Swagger 2.0)
 * @param {object[]} apiDeclarations - The array of API Declarations (Swagger 1.2)
 * @param {object} [options] - The configuration options
 * @param {string=/api-docs} [options.apiDocs] - The relative path to serve your Swagger documents from
 * @param {string=/docs} [options.swaggerUi] - The relative path to serve Swagger UI from
 * @param {string} [options.swaggerUiDir] - The filesystem path to your custom swagger-ui deployment to serve
 *
 * @returns the middleware function
 */
exports = module.exports = function swaggerUIMiddleware (rlOrSO, apiDeclarations, options) {
  debug('Initializing swagger-ui middleware');

  var swaggerVersion = helpers.getSwaggerVersion(rlOrSO);
  var apiDocsCache = {}; // Swagger document endpoints cache
  var apiDocsPaths = [];
  var staticMiddleware;
  var swaggerUiPath;

  if (swaggerVersion !== '1.2') {
    options = apiDeclarations;
    apiDeclarations = [];
  }

  // Set the defaults
  options = _.defaults(options || {}, defaultOptions);

  if (_.isUndefined(rlOrSO)) {
    throw new Error('rlOrSO is required');
  } else if (!_.isPlainObject(rlOrSO)) {
    throw new TypeError('rlOrSO must be an object');
  }

  if (swaggerVersion === '1.2') {
    if (_.isUndefined(apiDeclarations)) {
      throw new Error('apiDeclarations is required');
    } else if (!_.isPlainObject(apiDeclarations)) {
      throw new TypeError('apiDeclarations must be an object');
    }
  }

  swaggerUiPath = options.swaggerUiDir ?
    path.resolve(options.swaggerUiDir) :
    path.join(__dirname, 'swagger-ui');

  if (options.swaggerUiDir) {
    if (!fs.existsSync(swaggerUiPath)) {
      throw new Error('options.swaggerUiDir path does not exist: ' + swaggerUiPath);
    } else if (!fs.statSync(swaggerUiPath).isDirectory()) {
      throw new Error('options.swaggerUiDir path is not a directory: ' + swaggerUiPath);
    }
  }

  staticMiddleware = serveStatic(swaggerUiPath, staticOptions);

  // Sanitize values
  if (options.apiDocs.charAt(options.apiDocs.length -1) === '/') {
    options.apiDocs = options.apiDocs.substring(0, options.apiDocs.length - 1);
  }

  if (options.swaggerUi.charAt(options.swaggerUi.length -1) === '/') {
    options.swaggerUi = options.swaggerUi.substring(0, options.swaggerUi.length - 1);
  }

  debug('  Using swagger-ui from: %s', options.swaggerUiDir ? swaggerUiPath : 'internal');
  debug('  API Docs path: %s', options.apiDocs);

  // Add the Resource Listing or SwaggerObject to the response cache
  apiDocsCache[options.apiDocs] = JSON.stringify(rlOrSO, null, 2);

  // Add API Declarations to the response cache
  _.each(apiDeclarations, function (resource, resourcePath) {
    var adPath = options.apiDocs + resourcePath;

    // Respond with pretty JSON (Configurable?)
    apiDocsCache[adPath] = JSON.stringify(resource, null, 2);

    debug('    API Declaration path: %s', adPath);
  });

  apiDocsPaths = Object.keys(apiDocsCache);

  debug('  swagger-ui path: %s', options.swaggerUi);

  return function swaggerUI (req, res, next) {
    var path = parseurl(req).pathname;
    var isApiDocsPath = apiDocsPaths.indexOf(path) > -1;
    var isSwaggerUiPath = path === options.swaggerUi || path.indexOf(options.swaggerUi + '/') === 0;

    debug('%s %s', req.method, req.url);
    debug('  Will process: %s', isApiDocsPath || isSwaggerUiPath ? 'no' : 'yes');

    if (isApiDocsPath) {
      debug('  Serving API Docs');

      res.setHeader('Content-Type', 'application/json');

      return res.end(apiDocsCache[path]);
    } else if (isSwaggerUiPath) {
      debug('  Serving swagger-ui');

      res.setHeader('Swagger-API-Docs-URL', options.apiDocs);

      if (path === options.swaggerUi || path === options.swaggerUi + '/') {
        req.url = '/';
      } else {
        req.url = req.url.substring(options.swaggerUi.length);
      }

      return staticMiddleware(req, res, next);
    }

    return next();
  };
};
<commit_msg>Fixed issue with invalid debugging in swagger-ui<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Apigee Corporation
 *
 * 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 _ = require('lodash');
var debug = require('debug')('swagger-tools:middleware:ui');
var fs = require('fs');
var helpers = require('../lib/helpers');
var parseurl = require('parseurl');
var path = require('path');
var serveStatic = require('serve-static');

var defaultOptions = {
  apiDocs: '/api-docs',
  swaggerUi: '/docs'
};
var staticOptions = {};

/**
 * Middleware for serving the Swagger documents and Swagger UI.
 *
 * @param {object} rlOrSO - The Resource Listing (Swagger 1.2) or Swagger Object (Swagger 2.0)
 * @param {object[]} apiDeclarations - The array of API Declarations (Swagger 1.2)
 * @param {object} [options] - The configuration options
 * @param {string=/api-docs} [options.apiDocs] - The relative path to serve your Swagger documents from
 * @param {string=/docs} [options.swaggerUi] - The relative path to serve Swagger UI from
 * @param {string} [options.swaggerUiDir] - The filesystem path to your custom swagger-ui deployment to serve
 *
 * @returns the middleware function
 */
exports = module.exports = function swaggerUIMiddleware (rlOrSO, apiDeclarations, options) {
  debug('Initializing swagger-ui middleware');

  var swaggerVersion = helpers.getSwaggerVersion(rlOrSO);
  var apiDocsCache = {}; // Swagger document endpoints cache
  var apiDocsPaths = [];
  var staticMiddleware;
  var swaggerUiPath;

  if (swaggerVersion !== '1.2') {
    options = apiDeclarations;
    apiDeclarations = [];
  }

  // Set the defaults
  options = _.defaults(options || {}, defaultOptions);

  if (_.isUndefined(rlOrSO)) {
    throw new Error('rlOrSO is required');
  } else if (!_.isPlainObject(rlOrSO)) {
    throw new TypeError('rlOrSO must be an object');
  }

  if (swaggerVersion === '1.2') {
    if (_.isUndefined(apiDeclarations)) {
      throw new Error('apiDeclarations is required');
    } else if (!_.isPlainObject(apiDeclarations)) {
      throw new TypeError('apiDeclarations must be an object');
    }
  }

  swaggerUiPath = options.swaggerUiDir ?
    path.resolve(options.swaggerUiDir) :
    path.join(__dirname, 'swagger-ui');

  if (options.swaggerUiDir) {
    if (!fs.existsSync(swaggerUiPath)) {
      throw new Error('options.swaggerUiDir path does not exist: ' + swaggerUiPath);
    } else if (!fs.statSync(swaggerUiPath).isDirectory()) {
      throw new Error('options.swaggerUiDir path is not a directory: ' + swaggerUiPath);
    }
  }

  staticMiddleware = serveStatic(swaggerUiPath, staticOptions);

  // Sanitize values
  if (options.apiDocs.charAt(options.apiDocs.length -1) === '/') {
    options.apiDocs = options.apiDocs.substring(0, options.apiDocs.length - 1);
  }

  if (options.swaggerUi.charAt(options.swaggerUi.length -1) === '/') {
    options.swaggerUi = options.swaggerUi.substring(0, options.swaggerUi.length - 1);
  }

  debug('  Using swagger-ui from: %s', options.swaggerUiDir ? swaggerUiPath : 'internal');
  debug('  API Docs path: %s', options.apiDocs);

  // Add the Resource Listing or SwaggerObject to the response cache
  apiDocsCache[options.apiDocs] = JSON.stringify(rlOrSO, null, 2);

  // Add API Declarations to the response cache
  _.each(apiDeclarations, function (resource, resourcePath) {
    var adPath = options.apiDocs + resourcePath;

    // Respond with pretty JSON (Configurable?)
    apiDocsCache[adPath] = JSON.stringify(resource, null, 2);

    debug('    API Declaration path: %s', adPath);
  });

  apiDocsPaths = Object.keys(apiDocsCache);

  debug('  swagger-ui path: %s', options.swaggerUi);

  return function swaggerUI (req, res, next) {
    var path = parseurl(req).pathname;
    var isApiDocsPath = apiDocsPaths.indexOf(path) > -1;
    var isSwaggerUiPath = path === options.swaggerUi || path.indexOf(options.swaggerUi + '/') === 0;

    debug('%s %s', req.method, req.url);
    debug('  Will process: %s', isApiDocsPath || isSwaggerUiPath ? 'yes' : 'no');

    if (isApiDocsPath) {
      debug('  Serving API Docs');

      res.setHeader('Content-Type', 'application/json');

      return res.end(apiDocsCache[path]);
    } else if (isSwaggerUiPath) {
      debug('  Serving swagger-ui');

      res.setHeader('Swagger-API-Docs-URL', options.apiDocs);

      if (path === options.swaggerUi || path === options.swaggerUi + '/') {
        req.url = '/';
      } else {
        req.url = req.url.substring(options.swaggerUi.length);
      }

      return staticMiddleware(req, res, next);
    }

    return next();
  };
};
<|endoftext|>