<commit_before>import gulp from "gulp";
import cp from "child_process";
import gutil from "gulp-util";
import postcss from "gulp-postcss";
import cssImport from "postcss-import";
import cssnext from "postcss-cssnext";
import BrowserSync from "browser-sync";
import webpack from "webpack";
import webpackConfig from "./webpack.conf";
import beautify from "gulp-html-beautify";

const browserSync = BrowserSync.create();
const hugoBin = "hugo";
const defaultArgs = ["-d", "../dist", "-s", "site", "-v"];

gulp.task("hugo", (cb) => buildSite(cb));
gulp.task("hugo-preview", (cb) => buildSite(cb, ["--buildDrafts", "--buildFuture"]));

gulp.task("build", ["css", "js", "hugo"]);
gulp.task("build-preview", ["css", "js", "hugo-preview"]);

gulp.task("beautify", () => (
  gulp.src("./dist/**/*.html")
    .pipe(beautify())
    .pipe(gulp.dest("./dist/"))
));

gulp.task("css", () => (
  gulp.src("./src/css/*.css")
    .pipe(postcss([cssImport({from: "./src/css/main.css"}), cssnext()]))
    .pipe(gulp.dest("./dist/css"))
    .pipe(browserSync.stream())
));

gulp.task("js", (cb) => {
  const myConfig = Object.assign({}, webpackConfig);

  webpack(myConfig, (err, stats) => {
    if (err) throw new gutil.PluginError("webpack", err);
    gutil.log("[webpack]", stats.toString({
      colors: true,
      progress: true
    }));
    browserSync.reload();
    cb();
  });
});

gulp.task("server", ["hugo", "css", "js", "beautify"], () => {
  browserSync.init({
    server: {
      baseDir: "./dist"
    }
  });
  gulp.watch("./src/js/**/*.js", ["js"]);
  gulp.watch("./src/css/**/*.css", ["css"]);
  gulp.watch("./site/**/*", ["hugo", "beautify"]);
});

function buildSite(cb, options) {
  const args = options ? defaultArgs.concat(options) : defaultArgs;

  return cp.spawn(hugoBin, args, {stdio: "inherit"}).on("close", (code) => {
    if (code === 0) {
      browserSync.reload();
      cb();
    } else {
      browserSync.notify("Hugo build failed :(");
      cb("Hugo build failed");
    }
  });
}
<commit_msg>beautify production build only<commit_after>import gulp from "gulp";
import cp from "child_process";
import gutil from "gulp-util";
import postcss from "gulp-postcss";
import cssImport from "postcss-import";
import cssnext from "postcss-cssnext";
import BrowserSync from "browser-sync";
import webpack from "webpack";
import webpackConfig from "./webpack.conf";
import beautify from "gulp-html-beautify";

const browserSync = BrowserSync.create();
const hugoBin = "hugo";
const defaultArgs = ["-d", "../dist", "-s", "site", "-v"];

gulp.task("hugo", (cb) => buildSite(cb));
gulp.task("hugo-preview", (cb) => buildSite(cb, ["--buildDrafts", "--buildFuture"]));

gulp.task("build", ["css", "js", "hugo", "beautify"]);
gulp.task("build-preview", ["css", "js", "hugo-preview"]);

gulp.task("beautify", () => (
  gulp.src("./dist/**/*.html")
    .pipe(beautify())
    .pipe(gulp.dest("./dist/"))
));

gulp.task("css", () => (
  gulp.src("./src/css/*.css")
    .pipe(postcss([cssImport({from: "./src/css/main.css"}), cssnext()]))
    .pipe(gulp.dest("./dist/css"))
    .pipe(browserSync.stream())
));

gulp.task("js", (cb) => {
  const myConfig = Object.assign({}, webpackConfig);

  webpack(myConfig, (err, stats) => {
    if (err) throw new gutil.PluginError("webpack", err);
    gutil.log("[webpack]", stats.toString({
      colors: true,
      progress: true
    }));
    browserSync.reload();
    cb();
  });
});

gulp.task("server", ["hugo", "css", "js"], () => {
  browserSync.init({
    server: {
      baseDir: "./dist"
    }
  });
  gulp.watch("./src/js/**/*.js", ["js"]);
  gulp.watch("./src/css/**/*.css", ["css"]);
  gulp.watch("./site/**/*", ["hugo"]);
});

function buildSite(cb, options) {
  const args = options ? defaultArgs.concat(options) : defaultArgs;

  return cp.spawn(hugoBin, args, {stdio: "inherit"}).on("close", (code) => {
    if (code === 0) {
      browserSync.reload();
      cb();
    } else {
      browserSync.notify("Hugo build failed :(");
      cb("Hugo build failed");
    }
  });
}
<|endoftext|>


<commit_before>module.exports = {
  mode: "jit",
  purge: [
    "./src/**/*.{js,ts,vue}",

    // Symfony's global templates (including global layout)
    "../apps/koohii/templates/*.php",

    // Symfony's per module/action templates
    "../apps/koohii/modules/**/templates/*.md",
    "../apps/koohii/modules/**/templates/*.php",
  ],

  theme: {
    colors: {
      body: {
        // default body text (not all black)
        DEFAULT: "#42413d",
        // less contrasted body text (mainly headings atm)
        light: "#7f7d75",
      },

      danger: {
        DEFAULT: "#9f0e0b",
      },

      shaded: {
        DEFAULT: "#e7e1d3",
      },
    },

    // redeclare to remove the baked-in line-height, and add `md` alias
    fontSize: {
      xs: "0.75rem",
      sm: "0.875rem",
      base: "1rem",
      md: "1rem", // alias for "base"
      lg: "1.125rem",
    },

    extend: {
      flex: {
        // can be used with flex-1 to distribute space between smaller/larger items in a row
        2: "2 2 0%",
      },

      lineHeight: {
        1: 1, // alias for `leading-none`
      },
    },
  },

  variants: {},
  plugins: [],
};
<commit_msg>Update tailwind.config.js for Tailwind v3.x<commit_after>module.exports = {
  content: [
    "./src/**/*.{js,ts,vue}",

    // Symfony's global templates (including global layout)
    "../apps/koohii/templates/*.php",

    // Symfony's per module/action templates
    "../apps/koohii/modules/**/templates/*.{md,php}",
  ],

  theme: {
    colors: {
      body: {
        // default body text (not all black)
        DEFAULT: "#42413d",
        // less contrasted body text (mainly headings atm)
        light: "#7f7d75",
      },

      danger: {
        DEFAULT: "#9f0e0b",
      },

      shaded: {
        DEFAULT: "#e7e1d3",
      },
    },

    // redeclare to remove the baked-in line-height, and add `md` alias
    fontSize: {
      xs: "0.75rem",
      sm: "0.875rem",
      base: "1rem",
      md: "1rem", // alias for "base"
      lg: "1.125rem",
    },

    extend: {
      flex: {
        // can be used with flex-1 to distribute space between smaller/larger items in a row
        2: "2 2 0%",
      },

      lineHeight: {
        1: 1, // alias for `leading-none`
      },
    },
  },

  variants: {},
  plugins: [],
};
<|endoftext|>


<commit_before>require("../list/list-test");
require("../map/map-test");
require("../define-test");
var DefineMap = require("can-define/map/map");
var DefineList = require("can-define/list/list");
var isArray = require("can-util/js/is-array/is-array");
var isPlainObject = require("can-util/js/is-plain-object/is-plain-object");
var types = require("can-types");

var QUnit = require("steal-qunit");

QUnit.module("can-define: map and list combined");

QUnit.test("basics", function(){
    var items = new DefineMap({ people: [{name: "Justin"},{name: "Brian"}], count: 1000 });
    QUnit.ok(items.people instanceof types.DefineList, "people is list");
    QUnit.ok(items.people.item(0) instanceof types.DefineMap, "1st object is Map");
    QUnit.ok(items.people.item(1) instanceof types.DefineMap, "2nd object is Map");
    QUnit.equal(items.people.item(1).name, "Brian", "2nd object's name is right");
    QUnit.equal(items.count, 1000, "count is number");
});

QUnit.test("serialize works", function(){
    var Person = DefineMap.extend({
        first: "string",
        last: "string"
    });
    var People = DefineList.extend({
        "*": Person
    });

    var people = new People([{first: "j", last: "m"}]);
    QUnit.deepEqual(people.serialize(), [{first: "j", last: "m"}]);

});

QUnit.test("Extended Map with empty def converts to default Observables", function(){
    var School = DefineMap.extend({
        students: {},
        teacher: {}
    });

    var school = new School();

    school.students = [{name: "J"}];
    school.teacher = {name: "M"};

    ok(school.students instanceof types.DefineList, "converted to DefineList");
    ok(school.teacher instanceof types.DefineMap, "converted to DefineMap");

});

QUnit.test("default 'observable' type prevents Type from working (#29)", function(){
    var M = DefineMap.extend("M",{
        id: "number"
    });
    var L = DefineList.extend("L",{
        "*": M
    });

    var MyMap = DefineMap.extend({
        l: L
    });

    var m = new MyMap({
        l: [{id: 5}]
    });

    QUnit.ok( m.l[0] instanceof M, "is instance" );
    QUnit.ok(m.l[0].id, "5", "correct props");
});

QUnit.test("inline DefineList Type", function(){
    var M = DefineMap.extend("M",{
        id: "number"
    });

    var MyMap = DefineMap.extend({
        l: {Type: [M]}
    });

    var m = new MyMap({
        l: [{id: 5}]
    });

    QUnit.ok( m.l[0] instanceof M, "is instance" );
    QUnit.ok(m.l[0].id, "5", "correct props");
});

QUnit.test("recursively `get`s (#31)", function(){
    var M = DefineMap.extend("M",{
        id: "number"
    });

    var MyMap = DefineMap.extend({
        l: {Type: [M]}
    });

    var m = new MyMap({
        l: [{id: 5}]
    });

    var res = m.get();
    QUnit.ok( isArray(res.l), "is a plain array");
    QUnit.ok( isPlainObject(res.l[0]), "plain object");
});

QUnit.test("DefineList trigger deprecation warning when set with Map.set (#93)", 0, function(){
	var map = new DefineMap({
		things: [{ foo: 'bar' }]
	});
	map.things.attr = function(){
		ok(false, "attr should not be called");
	};

	map.set({ things: [{ baz: 'luhrmann' }] });
});
<commit_msg>Replaced QUnit.ok with QUnit.equal<commit_after>require("../list/list-test");
require("../map/map-test");
require("../define-test");
var DefineMap = require("can-define/map/map");
var DefineList = require("can-define/list/list");
var isArray = require("can-util/js/is-array/is-array");
var isPlainObject = require("can-util/js/is-plain-object/is-plain-object");
var types = require("can-types");

var QUnit = require("steal-qunit");

QUnit.module("can-define: map and list combined");

QUnit.test("basics", function(){
    var items = new DefineMap({ people: [{name: "Justin"},{name: "Brian"}], count: 1000 });

    QUnit.ok(items.people instanceof types.DefineList, "people is list");
    QUnit.ok(items.people.item(0) instanceof types.DefineMap, "1st object is Map");
    QUnit.ok(items.people.item(1) instanceof types.DefineMap, "2nd object is Map");
    QUnit.equal(items.people.item(1).name, "Brian", "2nd object's name is right");
    QUnit.equal(items.count, 1000, "count is number");
});

QUnit.test("serialize works", function(){
    var Person = DefineMap.extend({
        first: "string",
        last: "string"
    });
    var People = DefineList.extend({
        "*": Person
    });

    var people = new People([{first: "j", last: "m"}]);
    QUnit.deepEqual(people.serialize(), [{first: "j", last: "m"}]);

});

QUnit.test("Extended Map with empty def converts to default Observables", function(){
    var School = DefineMap.extend({
        students: {},
        teacher: {}
    });

    var school = new School();

    school.students = [{name: "J"}];
    school.teacher = {name: "M"};

    ok(school.students instanceof types.DefineList, "converted to DefineList");
    ok(school.teacher instanceof types.DefineMap, "converted to DefineMap");

});

QUnit.test("default 'observable' type prevents Type from working (#29)", function(){
    var M = DefineMap.extend("M",{
        id: "number"
    });
    var L = DefineList.extend("L",{
        "*": M
    });

    var MyMap = DefineMap.extend({
        l: L
    });

    var m = new MyMap({
        l: [{id: 5}]
    });

    QUnit.ok( m.l[0] instanceof M, "is instance" );
    QUnit.equal(m.l[0].id, 5, "correct props");
});

QUnit.test("inline DefineList Type", function(){
    var M = DefineMap.extend("M",{
        id: "number"
    });

    var MyMap = DefineMap.extend({
        l: {Type: [M]}
    });

    var m = new MyMap({
        l: [{id: 5}]
    });

    QUnit.ok( m.l[0] instanceof M, "is instance" );
    QUnit.equal(m.l[0].id, 5, "correct props");
});

QUnit.test("recursively `get`s (#31)", function(){
    var M = DefineMap.extend("M",{
        id: "number"
    });

    var MyMap = DefineMap.extend({
        l: {Type: [M]}
    });

    var m = new MyMap({
        l: [{id: 5}]
    });

    var res = m.get();
    QUnit.ok( isArray(res.l), "is a plain array");
    QUnit.ok( isPlainObject(res.l[0]), "plain object");
});

QUnit.test("DefineList trigger deprecation warning when set with Map.set (#93)", 0, function(){
	var map = new DefineMap({
		things: [{ foo: 'bar' }]
	});
	map.things.attr = function(){
		ok(false, "attr should not be called");
	};

	map.set({ things: [{ baz: 'luhrmann' }] });
});
<|endoftext|>


<commit_before>'use strict';

var byline        = require('byline'),
    chalk         = require('chalk'),
    eventStream   = require('event-stream'),
    fs            = require('fs'),
    isBinaryFile  = require('isbinaryfile'),
    minimatch     = require('minimatch'),
    readdirp      = require('readdirp'),
    EventEmitter = require('events').EventEmitter,
    eventEmitter = new EventEmitter(),
    Github        = require('./github'),
    replace       = require('replace-in-file'),
    messageChecks = require('./messageChecks');

var ignoredDirectories  = ['node_modules/**', '.git/**', '.hg/**'],
    filesToScan         = ['**/*.js', 'Makefile', '**/*.sh'],
    scanPath            = process.cwd(),
    fileEncoding        = 'utf8',
    github              = null, // Will be initialized later
    lineLengthLimit     = 1000,
    skipChecks          = [];

/**
 * Determines whether or not to let the file through. by ensuring that the
 * file name does not match one of the excluded directories, and ensuring it
 * matches one of the file filters.
 *
 * It will also ensure that even if a binary file matches the filter patterns,
 * it will not let it through as searching binary file contents for string
 * matches will never make sense.
 *
 * @param   {String} fileInformation
 *
 * @return  {Boolean}
 */
// TODO: This could be simpler using minimatch negation patterns in one set, instead disparate ones for files and directories. [Issue #undefined]
function fileFilterer (fileInformation) {
  var shouldIgnoreDirectory = false,
      shouldIgnoreFile      = true,
      letTheFileThrough;

  ignoredDirectories.forEach(function (directoryPattern) {
    if (shouldIgnoreDirectory) return;
    shouldIgnoreDirectory = minimatch(fileInformation.path, directoryPattern, { dot: true });
  });

  if (!shouldIgnoreDirectory) {
    filesToScan.forEach(function (filePattern) {
      if (!shouldIgnoreFile) return;

      shouldIgnoreFile = !(minimatch(fileInformation.name, filePattern));
    });
  }

  letTheFileThrough = !(shouldIgnoreDirectory || (!shouldIgnoreDirectory && shouldIgnoreFile));

  // Never let binary files through, searching them for comments will make no sense...
  if (letTheFileThrough && isBinaryFile.sync(fileInformation.fullPath)) {
    letTheFileThrough = false;
  }

  return letTheFileThrough;
}

/**
 * Takes a line of a file and the line number, and returns an array of all of
 * the messages found in that line. Can return multiple messages per line, for
 * example, if a message was annotated with more than one type. EG: FIXME TODO
 *
 * Each message in the array will have a label, a line_number, a colorer, and a
 * message. Will also include an author property if one is found on the
 * message.
 *
 * @param   {String} lineString The
 * @param   {Number} lineNumber
 *
 * @return  {Array}
 */
function retrieveMessagesFromLine (lineString, lineNumber) {
  var messageFormat = {
    author:       null,
    message:      null,
    label:        null,
    colorer:      null,
    line_number:  lineNumber
  },
  messages = [];

  Object.keys(messageChecks).forEach(function (checkName) {

    var matchResults  = lineString.match(messageChecks[checkName].regex),
        checker       = messageChecks[checkName],
        thisMessage;

    if (matchResults && matchResults.length) {
      thisMessage = JSON.parse(JSON.stringify(messageFormat)); // Clone the above structure.

      thisMessage.label   = checker.label;
      thisMessage.colorer = checker.colorer;

      if (matchResults[1] && matchResults[1].length) {
        thisMessage.author = matchResults[1].trim();
      }

      if (matchResults[2] && matchResults[2].length) {
        thisMessage.message = matchResults[2].trim();
      }
    }

    if (thisMessage) messages.push(thisMessage);
  });

  return messages;
}

/**
 * Takes a line number and returns a padded string matching the total number of
 * characters in totalLinesNumber. EG: A lineNumber of 12 and a
 * totalLinesNumber of 1323 will return the string '  12'.
 *
 * @param   {Number} lineNumber
 * @param   {Number} totalLinesNumber
 *
 * @return  {String}
 */
function getPaddedLineNumber (lineNumber, totalLinesNumber) {
  var paddedLineNumberString = '' + lineNumber;

  while (paddedLineNumberString.length < ('' + totalLinesNumber).length) {
    paddedLineNumberString = ' ' + paddedLineNumberString;
  }

  return paddedLineNumberString;
}

/**
 * Takes an individual message object, as output from retrieveMessagesFromLine
 * and formats it for output.
 *
 * @param     {Object}    individualMessage
 * @property  {String}    individualMessage.author
 * @property  {String}    individualMessage.message
 * @property  {String}    individualMessage.label
 * @property  {Function}  individualMessage.colorer
 * @property  {Number}    individualMessage.line_number
 * @param     {Number}    totalNumberOfLines
 *
 * @return    {String}    The formatted message string.
 */
function formatMessageOutput (individualMessage, totalNumberOfLines) {
  var paddedLineNumber = getPaddedLineNumber(individualMessage.line_number, totalNumberOfLines),
      finalLabelString,
      finalNoteString;

  finalNoteString = chalk.gray('  [Line ' + paddedLineNumber + '] ');

  finalLabelString = individualMessage.label;

  if (individualMessage.author) {
    finalLabelString += (' from ' + individualMessage.author + ': ');
  } else {
    finalLabelString += ': ';
  }

  finalLabelString = chalk.bold(individualMessage.colorer(finalLabelString));

  finalNoteString += finalLabelString;

  if (individualMessage.message && individualMessage.message.length) {
    finalNoteString += individualMessage.colorer(individualMessage.message);
  } else {
    finalNoteString += chalk.grey('[[no message to display]]');
  }

  return finalNoteString;
}

/**
 * Formatter function for the file name. Takes a file path, and the total
 * number of messages in the file, and formats this information for display as
 * the heading for the file messages.
 *
 * @param   {String} filePath
 * @param   {Number} numberOfMessages
 *
 * @return  {String}
 */
function formatFilePathOutput (filePath, numberOfMessages) {
  var filePathOutput = chalk.bold.white('\n* ' + filePath + ' '),
      messagesString = 'messages';

  if (numberOfMessages === 1) {
    messagesString = 'message';
  }

  filePathOutput += chalk.grey('[' + numberOfMessages + ' ' + messagesString + ']:');

  return filePathOutput;
}

/**
 * Takes an object representing the messages and other meta-info for the file
 * and calls off to the formatters for the messages, as well as logs the
 * formatted result.
 *
 * @param     {Object}  messagesInfo
 * @property  {String}  messagesInfo.path The file path
 * @property  {Array}   messagesInfo.messages All of the message objects for the file.
 * @property  {String}  messagesInfo.total_lines Total number of lines in the file.
 */
function logMessages (messagesInfo) {
  if (messagesInfo.messages.length) {
    console.log(formatFilePathOutput(messagesInfo.path, messagesInfo.messages.length));

    messagesInfo.messages.forEach(function (message) {
      var formattedMessage = formatMessageOutput(message, messagesInfo.total_lines);
      console.log(formattedMessage);
    });
  }
}

/**
 * Reads through the configured path scans the matching files for messages.
 */
function scanAndProcessMessages () {

  var stream = readdirp({
    root:       scanPath,
    fileFilter: fileFilterer
  });

  // Remove skipped checks for our mapping
  skipChecks.forEach(function (checkName) {
    delete messageChecks[checkName];
  });

  // TODO: Actually do something meaningful/useful with these handlers. [Issue #99]
  stream
    .on('warn', console.warn)
    .on('error', console.error);

  stream
    .pipe(eventStream.map(function (fileInformation, callback) {
      var input                 = fs.createReadStream(fileInformation.fullPath, { encoding: fileEncoding }),
          // lineStream            = byline.createStream(input, { encoding: fileEncoding }),
          fileMessages          = { path: null, total_lines: 0, messages: [] },
          currentFileLineNumber = 1;

      fileMessages.path = fileInformation.path;

      input.pipe( eventStream.split() )
        .pipe( eventStream.map( function( fileLineString, cb ){
          var messages,
              lengthError;

          if (fileLineString.length < lineLengthLimit) {
            messages = retrieveMessagesFromLine(fileLineString, currentFileLineNumber);

            messages.forEach(function (message) {

              if (github) {
                if (github.isRepository()) {
                  if (message.message.indexOf(' [Issue #') < 0) {
                    var remoteFilePath = github.getLink() +'/blob/' + github.getBranch() + '/' + fileMessages.path + '#L' + message.line_number;
                    message.description = `I have found a ${message.label.toLowerCase()} in the file [${fileMessages.path}](${remoteFilePath}) at line ${message.line_number}: ${message.message}`;
                    // Create Issue
                    github.createIssue(message).then(function(issue){
                      try {
                        let changedFiles = replace.sync({
                          files: fileMessages.path,
                          from: message.message,
                          to: message.message + ' [Issue #' + issue.number +']'
                        });
                      } catch (error) {
                        console.log('[Index] Error occurred when trying to replace message:' +  error);
                      }
                    });
                  }
                }
              }

              // Add messages
              fileMessages.messages.push(message);
            });
          } else if (skipChecks.indexOf('line') === -1){
            lengthError = 'Fixme is skipping this line because its length is ' +
                          'greater than the maximum line-length of ' +
                          lineLengthLimit + '.';

            fileMessages.messages.push({
              message:      lengthError,
              line_number:  currentFileLineNumber,
              label:        ' ⚠ SKIPPING CHECK',
              colorer:      chalk.underline.red
            });
          }

          currentFileLineNumber += 1;
        })
      );

      input.on('end', function () {
        fileMessages.total_lines = currentFileLineNumber;
        logMessages(fileMessages);
      });

      callback();
    }));
}

/**
 * Takes an options object and over-writes the defaults, then calls off to the
 * scanner to scan the files for messages.
 *
 * @param     {Object}  options
 * @property  {String}  options.path                The base directory to recursively scan for messages. Defaults to process.cwd()
 * @property  {Array}   options.ignored_directories An array of minimatch glob patterns for directories to ignore scanning entirely.
 * @property  {Array}   options.file_patterns       An array of minimatch glob patterns for files to scan for messages.
 * @property  {String}  options.file_encoding       The encoding the files scanned will be opened with, defaults to 'utf8'.
 * @property  {Number}  options.line_length_limit   The number of characters a line can be before it is ignored. Defaults to 1000.
 * @property  {Array}   options.skip                An array of names of checks to skip.
 */
function parseUserOptionsAndScan (options) {
  if (options) {
    if (options.path) {
      scanPath = options.path;
    }

    if (options.ignored_directories &&
        Array.isArray(options.ignored_directories) &&
        options.ignored_directories.length) {
      ignoredDirectories = options.ignored_directories;
    }

    if (options.file_patterns &&
        Array.isArray(options.file_patterns) &&
        options.file_patterns.length) {
      filesToScan = options.file_patterns;
    }

    if (options.file_encoding) {
      fileEncoding = options.file_encoding;
    }

    if (options.line_length_limit) {
      lineLengthLimit = options.line_length_limit;
    }

    if (options.skip &&
        Array.isArray(options.skip) &&
        options.skip.length) {
      skipChecks = options.skip;
    }

    if(messageChecks){
      options.annotations = messageChecks;
    }

    // Init Github
    if (options.github) {
      github = new Github(options);

      github.getEventEmitter().on('githubReady', function(){
        console.log(chalk.green('[Index] Github class has been initialized !'));
        scanAndProcessMessages();
      });

      // Emit Event
      github.getEventEmitter().on('githubError', function(){
        //console.log(chalk.red('Github error occured !'));
        github = undefined;
        scanAndProcessMessages();
      });
    }else{
      console.log(chalk.red('No github options were passed to index !'))
      scanAndProcessMessages();
    }
  }
}

// TODO: how to deal with assigning issues? TODO @me => issue assigned to me; [Issue #98]
// TODO @aymen => get list of contributors and match aymen with one of the contributors [Issue #89]
// TODO: add option: if issue is closed => remove annotated line [Issue #93]
// TODO: Support Grunt tasks [Issue #102]

module.exports = parseUserOptionsAndScan;
<commit_msg>Update ignored directories<commit_after>'use strict';

var byline        = require('byline'),
    chalk         = require('chalk'),
    eventStream   = require('event-stream'),
    fs            = require('fs'),
    isBinaryFile  = require('isbinaryfile'),
    minimatch     = require('minimatch'),
    readdirp      = require('readdirp'),
    EventEmitter = require('events').EventEmitter,
    eventEmitter = new EventEmitter(),
    Github        = require('./github'),
    replace       = require('replace-in-file'),
    messageChecks = require('./messageChecks');

var ignoredDirectories  = ['node_modules/**', '.git/**', '.hg/**', 'bower_components/**'],
    filesToScan         = ['**/*.js', 'Makefile', '**/*.sh'],
    scanPath            = process.cwd(),
    fileEncoding        = 'utf8',
    github              = null, // Will be initialized later
    lineLengthLimit     = 1000,
    skipChecks          = [];

/**
 * Determines whether or not to let the file through. by ensuring that the
 * file name does not match one of the excluded directories, and ensuring it
 * matches one of the file filters.
 *
 * It will also ensure that even if a binary file matches the filter patterns,
 * it will not let it through as searching binary file contents for string
 * matches will never make sense.
 *
 * @param   {String} fileInformation
 *
 * @return  {Boolean}
 */
// TODO: This could be simpler using minimatch negation patterns in one set, instead disparate ones for files and directories. [Issue #undefined]
function fileFilterer (fileInformation) {
  var shouldIgnoreDirectory = false,
      shouldIgnoreFile      = true,
      letTheFileThrough;

  ignoredDirectories.forEach(function (directoryPattern) {
    if (shouldIgnoreDirectory) return;
    shouldIgnoreDirectory = minimatch(fileInformation.path, directoryPattern, { dot: true });
  });

  if (!shouldIgnoreDirectory) {
    filesToScan.forEach(function (filePattern) {
      if (!shouldIgnoreFile) return;

      shouldIgnoreFile = !(minimatch(fileInformation.name, filePattern));
    });
  }

  letTheFileThrough = !(shouldIgnoreDirectory || (!shouldIgnoreDirectory && shouldIgnoreFile));

  // Never let binary files through, searching them for comments will make no sense...
  if (letTheFileThrough && isBinaryFile.sync(fileInformation.fullPath)) {
    letTheFileThrough = false;
  }

  return letTheFileThrough;
}

/**
 * Takes a line of a file and the line number, and returns an array of all of
 * the messages found in that line. Can return multiple messages per line, for
 * example, if a message was annotated with more than one type. EG: FIXME TODO
 *
 * Each message in the array will have a label, a line_number, a colorer, and a
 * message. Will also include an author property if one is found on the
 * message.
 *
 * @param   {String} lineString The
 * @param   {Number} lineNumber
 *
 * @return  {Array}
 */
function retrieveMessagesFromLine (lineString, lineNumber) {
  var messageFormat = {
    author:       null,
    message:      null,
    label:        null,
    colorer:      null,
    line_number:  lineNumber
  },
  messages = [];

  Object.keys(messageChecks).forEach(function (checkName) {

    var matchResults  = lineString.match(messageChecks[checkName].regex),
        checker       = messageChecks[checkName],
        thisMessage;

    if (matchResults && matchResults.length) {
      thisMessage = JSON.parse(JSON.stringify(messageFormat)); // Clone the above structure.

      thisMessage.label   = checker.label;
      thisMessage.colorer = checker.colorer;

      if (matchResults[1] && matchResults[1].length) {
        thisMessage.author = matchResults[1].trim();
      }

      if (matchResults[2] && matchResults[2].length) {
        thisMessage.message = matchResults[2].trim();
      }
    }

    if (thisMessage) messages.push(thisMessage);
  });

  return messages;
}

/**
 * Takes a line number and returns a padded string matching the total number of
 * characters in totalLinesNumber. EG: A lineNumber of 12 and a
 * totalLinesNumber of 1323 will return the string '  12'.
 *
 * @param   {Number} lineNumber
 * @param   {Number} totalLinesNumber
 *
 * @return  {String}
 */
function getPaddedLineNumber (lineNumber, totalLinesNumber) {
  var paddedLineNumberString = '' + lineNumber;

  while (paddedLineNumberString.length < ('' + totalLinesNumber).length) {
    paddedLineNumberString = ' ' + paddedLineNumberString;
  }

  return paddedLineNumberString;
}

/**
 * Takes an individual message object, as output from retrieveMessagesFromLine
 * and formats it for output.
 *
 * @param     {Object}    individualMessage
 * @property  {String}    individualMessage.author
 * @property  {String}    individualMessage.message
 * @property  {String}    individualMessage.label
 * @property  {Function}  individualMessage.colorer
 * @property  {Number}    individualMessage.line_number
 * @param     {Number}    totalNumberOfLines
 *
 * @return    {String}    The formatted message string.
 */
function formatMessageOutput (individualMessage, totalNumberOfLines) {
  var paddedLineNumber = getPaddedLineNumber(individualMessage.line_number, totalNumberOfLines),
      finalLabelString,
      finalNoteString;

  finalNoteString = chalk.gray('  [Line ' + paddedLineNumber + '] ');

  finalLabelString = individualMessage.label;

  if (individualMessage.author) {
    finalLabelString += (' from ' + individualMessage.author + ': ');
  } else {
    finalLabelString += ': ';
  }

  finalLabelString = chalk.bold(individualMessage.colorer(finalLabelString));

  finalNoteString += finalLabelString;

  if (individualMessage.message && individualMessage.message.length) {
    finalNoteString += individualMessage.colorer(individualMessage.message);
  } else {
    finalNoteString += chalk.grey('[[no message to display]]');
  }

  return finalNoteString;
}

/**
 * Formatter function for the file name. Takes a file path, and the total
 * number of messages in the file, and formats this information for display as
 * the heading for the file messages.
 *
 * @param   {String} filePath
 * @param   {Number} numberOfMessages
 *
 * @return  {String}
 */
function formatFilePathOutput (filePath, numberOfMessages) {
  var filePathOutput = chalk.bold.white('\n* ' + filePath + ' '),
      messagesString = 'messages';

  if (numberOfMessages === 1) {
    messagesString = 'message';
  }

  filePathOutput += chalk.grey('[' + numberOfMessages + ' ' + messagesString + ']:');

  return filePathOutput;
}

/**
 * Takes an object representing the messages and other meta-info for the file
 * and calls off to the formatters for the messages, as well as logs the
 * formatted result.
 *
 * @param     {Object}  messagesInfo
 * @property  {String}  messagesInfo.path The file path
 * @property  {Array}   messagesInfo.messages All of the message objects for the file.
 * @property  {String}  messagesInfo.total_lines Total number of lines in the file.
 */
function logMessages (messagesInfo) {
  if (messagesInfo.messages.length) {
    console.log(formatFilePathOutput(messagesInfo.path, messagesInfo.messages.length));

    messagesInfo.messages.forEach(function (message) {
      var formattedMessage = formatMessageOutput(message, messagesInfo.total_lines);
      console.log(formattedMessage);
    });
  }
}

/**
 * Reads through the configured path scans the matching files for messages.
 */
function scanAndProcessMessages () {

  var stream = readdirp({
    root:       scanPath,
    fileFilter: fileFilterer
  });

  // Remove skipped checks for our mapping
  skipChecks.forEach(function (checkName) {
    delete messageChecks[checkName];
  });

  // TODO: Actually do something meaningful/useful with these handlers. [Issue #99]
  stream
    .on('warn', console.warn)
    .on('error', console.error);

  stream
    .pipe(eventStream.map(function (fileInformation, callback) {
      var input                 = fs.createReadStream(fileInformation.fullPath, { encoding: fileEncoding }),
          // lineStream            = byline.createStream(input, { encoding: fileEncoding }),
          fileMessages          = { path: null, total_lines: 0, messages: [] },
          currentFileLineNumber = 1;

      fileMessages.path = fileInformation.path;

      input.pipe( eventStream.split() )
        .pipe( eventStream.map( function( fileLineString, cb ){
          var messages,
              lengthError;

          if (fileLineString.length < lineLengthLimit) {
            messages = retrieveMessagesFromLine(fileLineString, currentFileLineNumber);

            messages.forEach(function (message) {

              if (github) {
                if (github.isRepository()) {
                  if (message.message.indexOf(' [Issue #') < 0) {
                    var remoteFilePath = github.getLink() +'/blob/' + github.getBranch() + '/' + fileMessages.path + '#L' + message.line_number;
                    message.description = `I have found a ${message.label.toLowerCase()} in the file [${fileMessages.path}](${remoteFilePath}) at line ${message.line_number}: ${message.message}`;
                    // Create Issue
                    github.createIssue(message).then(function(issue){
                      try {
                        let changedFiles = replace.sync({
                          files: fileMessages.path,
                          from: message.message,
                          to: message.message + ' [Issue #' + issue.number +']'
                        });
                      } catch (error) {
                        console.log('[Index] Error occurred when trying to replace message:' +  error);
                      }
                    });
                  }
                }
              }

              // Add messages
              fileMessages.messages.push(message);
            });
          } else if (skipChecks.indexOf('line') === -1){
            lengthError = 'Fixme is skipping this line because its length is ' +
                          'greater than the maximum line-length of ' +
                          lineLengthLimit + '.';

            fileMessages.messages.push({
              message:      lengthError,
              line_number:  currentFileLineNumber,
              label:        ' ⚠ SKIPPING CHECK',
              colorer:      chalk.underline.red
            });
          }

          currentFileLineNumber += 1;
        })
      );

      input.on('end', function () {
        fileMessages.total_lines = currentFileLineNumber;
        logMessages(fileMessages);
      });

      callback();
    }));
}

/**
 * Takes an options object and over-writes the defaults, then calls off to the
 * scanner to scan the files for messages.
 *
 * @param     {Object}  options
 * @property  {String}  options.path                The base directory to recursively scan for messages. Defaults to process.cwd()
 * @property  {Array}   options.ignored_directories An array of minimatch glob patterns for directories to ignore scanning entirely.
 * @property  {Array}   options.file_patterns       An array of minimatch glob patterns for files to scan for messages.
 * @property  {String}  options.file_encoding       The encoding the files scanned will be opened with, defaults to 'utf8'.
 * @property  {Number}  options.line_length_limit   The number of characters a line can be before it is ignored. Defaults to 1000.
 * @property  {Array}   options.skip                An array of names of checks to skip.
 */
function parseUserOptionsAndScan (options) {
  if (options) {
    if (options.path) {
      scanPath = options.path;
    }

    if (options.ignored_directories &&
        Array.isArray(options.ignored_directories) &&
        options.ignored_directories.length) {
      ignoredDirectories = options.ignored_directories;
    }

    if (options.file_patterns &&
        Array.isArray(options.file_patterns) &&
        options.file_patterns.length) {
      filesToScan = options.file_patterns;
    }

    if (options.file_encoding) {
      fileEncoding = options.file_encoding;
    }

    if (options.line_length_limit) {
      lineLengthLimit = options.line_length_limit;
    }

    if (options.skip &&
        Array.isArray(options.skip) &&
        options.skip.length) {
      skipChecks = options.skip;
    }

    if(messageChecks){
      options.annotations = messageChecks;
    }

    // Init Github
    if (options.github) {
      github = new Github(options);

      github.getEventEmitter().on('githubReady', function(){
        console.log(chalk.green('[Index] Github class has been initialized !'));
        scanAndProcessMessages();
      });

      // Emit Event
      github.getEventEmitter().on('githubError', function(){
        //console.log(chalk.red('Github error occured !'));
        github = undefined;
        scanAndProcessMessages();
      });
    }else{
      console.log(chalk.red('No github options were passed to index !'))
      scanAndProcessMessages();
    }
  }
}

// TODO: how to deal with assigning issues? TODO @me => issue assigned to me; [Issue #98]
// TODO @aymen => get list of contributors and match aymen with one of the contributors [Issue #89]
// TODO: add option: if issue is closed => remove annotated line [Issue #93]
// TODO: Support Grunt tasks [Issue #102]

module.exports = parseUserOptionsAndScan;
<|endoftext|>


<commit_before>/**
 * Léo Le Bras
 * http://leolebras.com/
 *
 * Work with Gulp
 * http://gulpjs.com/
 *
 * Copyright 2014 - 2015
 * Released under the MIT license
 * http://opensource.org/licenses/MIT
 *
 * Date of creative : 2014-01-04
 * Last updated: 2015-11-27
 */

import base64 from 'gulp-base64';
import babel from 'gulp-babel';
import browserSync, { reload }  from 'browser-sync';
import clean  from 'gulp-rimraf';
import cssbeautify  from 'gulp-cssbeautify';
import cssnano  from 'gulp-cssnano';
import del from 'del';
import gulp  from 'gulp';
import imagemin  from 'gulp-imagemin';
import inline  from 'gulp-inline-source';
import pngquant  from 'imagemin-pngquant';
import postcss  from 'gulp-postcss';
import sass  from 'gulp-sass';
import sourcemaps  from 'gulp-sourcemaps';
import uglify  from 'gulp-uglify';
import ttf2woff  from 'gulp-ttf2woff';
import ttf2woff2  from 'gulp-ttf2woff2';
import watch  from 'gulp-watch';
import webpack  from 'gulp-webpack';
import config from './config.js';
const { srcDir, buildDir, distDir, cssDir, imgDir, sassDir, fontsDir, jsDir } = config.dir;

// Browser sync
gulp.task('browser_sync', () => (
    browserSync({
        server: { baseDir: buildDir },
        port: config.server.port
    })
));

// Sass
gulp.task('sass', () => {

    let customFonts = {},
        weights = [],
        fonts = config.fonts.custom;

    weights[300] = 'Light';
    weights[400] = 'Regular';
    weights[600] = 'SemiBold';
    weights[700] = 'Bold';
    weights[800] = 'ExtraBold';

    for(let font in fonts) {
        customFonts[font] = {variants: {}};
        fonts[font].map(weight => {
            let url = {};
            config.fonts.formats.split(' ').map(format => {
                url[format] = `./../fonts/${font.replace(/\s+/g, '')}/${font.replace(/\s+/g, '')}-${weights[weight]}.${format}`;
            });
            customFonts[font]['variants'][weight] = {
                normal: { url: url }
            };
        });
    }

    return gulp.src([srcDir + 'sass/*.scss'])
        .pipe(sourcemaps.init())
        .pipe(sass.sync().on('error', sass.logError))
        .pipe(postcss([
            require('autoprefixer')({
                browsers: config.css.autoprefixer
            }),
            require('postcss-pxtorem')({
                media_query: true,
                prop_white_list: []
            }),
            require('postcss-font-magician')({
                custom: customFonts,
                formats: config.fonts.formats
            })
        ]))
        .pipe(cssbeautify())
        .pipe(sourcemaps.write('.'))
        .pipe(gulp.dest(buildDir + cssDir))
        .pipe(reload({
            stream: true
        }));
});

// Babel
gulp.task('js', () => (
    gulp.src(`${srcDir + jsDir}*.js`)
        .pipe(webpack(require('./webpack.config.js')))
        .pipe(gulp.dest(buildDir + jsDir))
        .pipe(reload({
            stream: true
        }))
));

// Images
gulp.task('img', () => (
    gulp.src([srcDir + imgDir + '**'])
        .pipe(imagemin({
            progressive: true,
            svgoPlugins: [],
            use: [pngquant()]
        }))
        .pipe(gulp.dest(buildDir + imgDir))
        .pipe(reload({
            stream: true
        }))
));

// HTML
gulp.task('html', () => (
    gulp.src(srcDir + '*.html')
        .pipe(gulp.dest(buildDir))
        .pipe(reload({
            stream: true
        }))
));

// Cleaner
gulp.task('clean', () => (
    gulp.src(buildDir, {
        read: false
    }).pipe(clean())
));

// Fonts
gulp.task('fonts', () => {

    // ttf
    gulp.src(srcDir + 'fonts/**/*.ttf')
        .pipe(gulp.dest(buildDir + fontsDir));

    // ttf to woff
    gulp.src(srcDir + 'fonts/**/*.ttf')
        .pipe(ttf2woff())
        .pipe(gulp.dest(buildDir + fontsDir));

    // ttf to woff2
    gulp.src(srcDir + 'fonts/**/*.ttf')
        .pipe(ttf2woff2())
        .pipe(gulp.dest(buildDir + fontsDir));

});

// Dev
gulp.task('dev', ['clean'], () => {
    gulp.start('browser_sync', 'fonts', 'sass', 'img', 'js', 'html');
    watch(srcDir + imgDir + '**', () => gulp.start('img'));
    watch(srcDir + sassDir + '**/*.scss', () => gulp.start('sass'));
    watch(srcDir + fontsDir + '**/*', () => gulp.start('fonts'));
    watch(srcDir + '*.html', () => gulp.start('html'));
});

// Clean dist dir
gulp.task('clean-dist', () => del([distDir + '**/*']) );

// Prod
gulp.task('build', ['clean-dist'], () => {

    // Move img files
    gulp.src(buildDir + imgDir + '**')
        .pipe(gulp.dest(distDir + imgDir));

    // Move html files + inline scripts
    gulp.src(buildDir + '*.html')
        .pipe(inline())
        .pipe(gulp.dest(distDir));

    // Move fonts files
    gulp.src(buildDir + fontsDir + '**/*')
        .pipe(gulp.dest(distDir + fontsDir));

    // Base64 img in css files files and minify (except css font files)
    gulp.src(buildDir + cssDir + '*')
        .pipe(base64({
            extensions: ['svg', 'png', 'jpg']
        }))
        .pipe(cssnano())
        .pipe(gulp.dest(distDir + cssDir));

    // Uglify js files
    gulp.src(buildDir + jsDir + '**/*.js')
        .pipe(babel(config.javascript.babel))
        .pipe(uglify())
        .pipe(gulp.dest(distDir + jsDir));

});

/*

      _____       _
     / ____|     | |
    | |  __ _   _| |_ __
    | | |_ |  | | | |  _ \
    | |__| | |_| | | |_) |
     \_____|\__,_|_|  __/  .
                   | |
                   |_|

*/
<commit_msg>Fix Browsersync<commit_after>/**
 * Léo Le Bras
 * http://leolebras.com/
 *
 * Work with Gulp
 * http://gulpjs.com/
 *
 * Copyright 2014 - 2015
 * Released under the MIT license
 * http://opensource.org/licenses/MIT
 *
 * Date of creative : 2014-01-04
 * Last updated: 2015-11-27
 */

import base64 from 'gulp-base64';
import babel from 'gulp-babel';
import browserSync, { reload }  from 'browser-sync';
import clean  from 'gulp-rimraf';
import cssbeautify  from 'gulp-cssbeautify';
import cssnano  from 'gulp-cssnano';
import del from 'del';
import gulp  from 'gulp';
import imagemin  from 'gulp-imagemin';
import inline  from 'gulp-inline-source';
import pngquant  from 'imagemin-pngquant';
import postcss  from 'gulp-postcss';
import sass  from 'gulp-sass';
import sourcemaps  from 'gulp-sourcemaps';
import uglify  from 'gulp-uglify';
import ttf2woff  from 'gulp-ttf2woff';
import ttf2woff2  from 'gulp-ttf2woff2';
import watch  from 'gulp-watch';
import webpack  from 'gulp-webpack';
import config from './config.js';
const { srcDir, buildDir, distDir, cssDir, imgDir, sassDir, fontsDir, jsDir } = config.dir;

// Browser sync
gulp.task('browser_sync', () => (
    browserSync({
        server: {
            baseDir: buildDir
        },
        port: config.server.port,
        online: true
    })
));

// Sass
gulp.task('sass', () => {

    let customFonts = {},
        weights = [],
        fonts = config.fonts.custom;

    weights[300] = 'Light';
    weights[400] = 'Regular';
    weights[600] = 'SemiBold';
    weights[700] = 'Bold';
    weights[800] = 'ExtraBold';

    for(let font in fonts) {
        customFonts[font] = {variants: {}};
        fonts[font].map(weight => {
            let url = {};
            config.fonts.formats.split(' ').map(format => {
                url[format] = `./../fonts/${font.replace(/\s+/g, '')}/${font.replace(/\s+/g, '')}-${weights[weight]}.${format}`;
            });
            customFonts[font]['variants'][weight] = {
                normal: { url: url }
            };
        });
    }

    return gulp.src([srcDir + 'sass/*.scss'])
        .pipe(sourcemaps.init())
        .pipe(sass.sync().on('error', sass.logError))
        .pipe(postcss([
            require('autoprefixer')({
                browsers: config.css.autoprefixer
            }),
            require('postcss-pxtorem')({
                media_query: true,
                prop_white_list: []
            }),
            require('postcss-font-magician')({
                custom: customFonts,
                formats: config.fonts.formats
            })
        ]))
        .pipe(cssbeautify())
        .pipe(sourcemaps.write('.'))
        .pipe(gulp.dest(buildDir + cssDir))
        .pipe(reload({
            stream: true
        }));
});

// Babel
gulp.task('js', () => (
    gulp.src(`${srcDir + jsDir}*.js`)
        .pipe(webpack(require('./webpack.config.js')))
        .pipe(gulp.dest(buildDir + jsDir))
        .pipe(reload({
            stream: true
        }))
));

// Images
gulp.task('img', () => (
    gulp.src([srcDir + imgDir + '**'])
        .pipe(imagemin({
            progressive: true,
            svgoPlugins: [],
            use: [pngquant()]
        }))
        .pipe(gulp.dest(buildDir + imgDir))
        .pipe(reload({
            stream: true
        }))
));

// HTML
gulp.task('html', () => (
    gulp.src(srcDir + '*.html')
        .pipe(gulp.dest(buildDir))
        .pipe(reload({
            stream: true
        }))
));

// Cleaner
gulp.task('clean', () => (
    gulp.src(buildDir, {
        read: false
    }).pipe(clean())
));

// Fonts
gulp.task('fonts', () => {

    // ttf
    gulp.src(srcDir + 'fonts/**/*.ttf')
        .pipe(gulp.dest(buildDir + fontsDir));

    // ttf to woff
    gulp.src(srcDir + 'fonts/**/*.ttf')
        .pipe(ttf2woff())
        .pipe(gulp.dest(buildDir + fontsDir));

    // ttf to woff2
    gulp.src(srcDir + 'fonts/**/*.ttf')
        .pipe(ttf2woff2())
        .pipe(gulp.dest(buildDir + fontsDir));

});

// Dev
gulp.task('dev', ['clean'], () => {
    gulp.start('browser_sync', 'fonts', 'sass', 'img', 'js', 'html');
    watch(srcDir + imgDir + '**', () => gulp.start('img'));
    watch(srcDir + sassDir + '**/*.scss', () => gulp.start('sass'));
    watch(srcDir + fontsDir + '**/*', () => gulp.start('fonts'));
    watch(srcDir + '*.html', () => gulp.start('html'));
});

// Clean dist dir
gulp.task('clean-dist', () => del([distDir + '**/*']) );

// Prod
gulp.task('build', ['clean-dist'], () => {

    // Move img files
    gulp.src(buildDir + imgDir + '**')
        .pipe(gulp.dest(distDir + imgDir));

    // Move html files + inline scripts
    gulp.src(buildDir + '*.html')
        .pipe(inline())
        .pipe(gulp.dest(distDir));

    // Move fonts files
    gulp.src(buildDir + fontsDir + '**/*')
        .pipe(gulp.dest(distDir + fontsDir));

    // Base64 img in css files files and minify (except css font files)
    gulp.src(buildDir + cssDir + '*')
        .pipe(base64({
            extensions: ['svg', 'png', 'jpg']
        }))
        .pipe(cssnano())
        .pipe(gulp.dest(distDir + cssDir));

    // Uglify js files
    gulp.src(buildDir + jsDir + '**/*.js')
        .pipe(babel(config.javascript.babel))
        .pipe(uglify())
        .pipe(gulp.dest(distDir + jsDir));

});

/*

      _____       _
     / ____|     | |
    | |  __ _   _| |_ __
    | | |_ |  | | | |  _ \
    | |__| | |_| | | |_) |
     \_____|\__,_|_|  __/  .
                   | |
                   |_|

*/
<|endoftext|>


<commit_before>var should = require('should');
var assert = require('assert');
var request = require('supertest');

var app = require("./server.js");

var server = app.listen(0);
var port = server.address().port;

describe('Test cubieboard-monitor', function() {
    var server;
    var port;
    var url;;

    // within before() you can run all the operations that are needed to setup your tests. In this case
    before(function(done) {
        server = app.listen(0, done);
        port = server.address.port();
        url = 'http://localhost:'+port;
        done();
    });
    after(function(done){
        server.stop();
        done();
    });
    // use describe to give a title to your test suite, in this case the tile is "Monitor"
    // and then specify a function in which we are going to declare all the tests
    // we want to run. Each test starts with the function it() and as a first argument
    // we have to provide a meaningful title for it, whereas as the second argument we
    // specify a function that takes a single parameter, "done", that we will use
    // to specify when our test is completed, and that's what makes easy
    // to perform async test!
    describe('Monitor', function() {
        it('debería de devolver el hostname', function(done) {

            // once we have specified the info we want to send to the server via POST verb,
            // we need to actually perform the action on the resource, in this case we want to
            // POST on /api/profiles and we want to send some info
            // We do this using the request object, requiring supertest!
            request(url)
                .post('/SYS_hostname')
                // end handles the response
                .end(function(err, res) {
                    if (err) {
                        throw err;
                    }
                    // this is should.js syntax, very clear
                    //res.should.have.status(400);
                    res.body.should.not.equal(null);
                    done();
                });
        });
    });
    describe('Visión General', function() {
        describe('CPU', function(done) {

            it('debería de devolver la temperatura de la CPU', function(done) {
                // once we have specified the info we want to send to the server via POST verb,
                // we need to actually perform the action on the resource, in this case we want to
                // POST on /api/profiles and we want to send some info
                // We do this using the request object, requiring supertest!
                request(url)
                    .post('/CPU_Temp')
                    // end handles the response
                    .end(function(err, res) {
                        if (err) {
                            throw err;
                        }
                        // this is should.js syntax, very clear
                        //res.should.have.status(400);
                        res.body.should.not.equal(null);
                        done();
                    });

            });
            it('debería de devolver el uso de la CPU', function(done) {
                // once we have specified the info we want to send to the server via POST verb,
                // we need to actually perform the action on the resource, in this case we want to
                // POST on /api/profiles and we want to send some info
                // We do this using the request object, requiring supertest!
                request(url)
                    .post('/CPU_Uso')
                    // end handles the response
                    .end(function(err, res) {
                        if (err) {
                            throw err;
                        }
                        // this is should.js syntax, very clear
                        //res.should.have.status(400);
                        res.body.should.not.equal(null);
                        done();
                    });

            });
        });

        describe('HDD', function(done) {

            it('debería de devolver la temperatura del disco', function(done) {
                // once we have specified the info we want to send to the server via POST verb,
                // we need to actually perform the action on the resource, in this case we want to
                // POST on /api/profiles and we want to send some info
                // We do this using the request object, requiring supertest!
                request(url)
                    .post('/HDD_Temp')
                    // end handles the response
                    .end(function(err, res) {
                        if (err) {
                            throw err;
                        }
                        // this is should.js syntax, very clear
                        //res.should.have.status(400);
                        res.body.should.not.equal(null);
                        done();
                    });

            });
            it('debería de devolver el uso del disco', function(done) {
                // once we have specified the info we want to send to the server via POST verb,
                // we need to actually perform the action on the resource, in this case we want to
                // POST on /api/profiles and we want to send some info
                // We do this using the request object, requiring supertest!
                request(url)
                    .post('/HDD_Uso')
                    // end handles the response
                    .end(function(err, res) {
                        if (err) {
                            throw err;
                        }
                        // this is should.js syntax, very clear
                        //res.should.have.status(400);
                        res.body.should.not.equal(null);
                        done();
                    });

            });
        });

    });
});
<commit_msg>Update test.js<commit_after>var should = require('should');
var assert = require('assert');
var request = require('supertest');

var app = require("../server.js");

var server = app.listen(0);
var port = server.address().port;

describe('Test cubieboard-monitor', function() {
    var server;
    var port;
    var url;;

    // within before() you can run all the operations that are needed to setup your tests. In this case
    before(function(done) {
        server = app.listen(0, done);
        port = server.address.port();
        url = 'http://localhost:'+port;
        done();
    });
    after(function(done){
        server.stop();
        done();
    });
    // use describe to give a title to your test suite, in this case the tile is "Monitor"
    // and then specify a function in which we are going to declare all the tests
    // we want to run. Each test starts with the function it() and as a first argument
    // we have to provide a meaningful title for it, whereas as the second argument we
    // specify a function that takes a single parameter, "done", that we will use
    // to specify when our test is completed, and that's what makes easy
    // to perform async test!
    describe('Monitor', function() {
        it('debería de devolver el hostname', function(done) {

            // once we have specified the info we want to send to the server via POST verb,
            // we need to actually perform the action on the resource, in this case we want to
            // POST on /api/profiles and we want to send some info
            // We do this using the request object, requiring supertest!
            request(url)
                .post('/SYS_hostname')
                // end handles the response
                .end(function(err, res) {
                    if (err) {
                        throw err;
                    }
                    // this is should.js syntax, very clear
                    //res.should.have.status(400);
                    res.body.should.not.equal(null);
                    done();
                });
        });
    });
    describe('Visión General', function() {
        describe('CPU', function(done) {

            it('debería de devolver la temperatura de la CPU', function(done) {
                // once we have specified the info we want to send to the server via POST verb,
                // we need to actually perform the action on the resource, in this case we want to
                // POST on /api/profiles and we want to send some info
                // We do this using the request object, requiring supertest!
                request(url)
                    .post('/CPU_Temp')
                    // end handles the response
                    .end(function(err, res) {
                        if (err) {
                            throw err;
                        }
                        // this is should.js syntax, very clear
                        //res.should.have.status(400);
                        res.body.should.not.equal(null);
                        done();
                    });

            });
            it('debería de devolver el uso de la CPU', function(done) {
                // once we have specified the info we want to send to the server via POST verb,
                // we need to actually perform the action on the resource, in this case we want to
                // POST on /api/profiles and we want to send some info
                // We do this using the request object, requiring supertest!
                request(url)
                    .post('/CPU_Uso')
                    // end handles the response
                    .end(function(err, res) {
                        if (err) {
                            throw err;
                        }
                        // this is should.js syntax, very clear
                        //res.should.have.status(400);
                        res.body.should.not.equal(null);
                        done();
                    });

            });
        });

        describe('HDD', function(done) {

            it('debería de devolver la temperatura del disco', function(done) {
                // once we have specified the info we want to send to the server via POST verb,
                // we need to actually perform the action on the resource, in this case we want to
                // POST on /api/profiles and we want to send some info
                // We do this using the request object, requiring supertest!
                request(url)
                    .post('/HDD_Temp')
                    // end handles the response
                    .end(function(err, res) {
                        if (err) {
                            throw err;
                        }
                        // this is should.js syntax, very clear
                        //res.should.have.status(400);
                        res.body.should.not.equal(null);
                        done();
                    });

            });
            it('debería de devolver el uso del disco', function(done) {
                // once we have specified the info we want to send to the server via POST verb,
                // we need to actually perform the action on the resource, in this case we want to
                // POST on /api/profiles and we want to send some info
                // We do this using the request object, requiring supertest!
                request(url)
                    .post('/HDD_Uso')
                    // end handles the response
                    .end(function(err, res) {
                        if (err) {
                            throw err;
                        }
                        // this is should.js syntax, very clear
                        //res.should.have.status(400);
                        res.body.should.not.equal(null);
                        done();
                    });

            });
        });

    });
});
<|endoftext|>


<commit_before>var hasOwnProperty = Object.prototype.hasOwnProperty;

var Status = {
  OK: 200,
  BAD_REQUEST: 400,
  UNAUTHORIZED: 401,
  NOT_FOUND: 404,
  UNSUPPORTED_ACTION: 405,
  VALIDATION_FAILED: 422,
  SERVER_ERROR: 500
};

function statusMessage(status) {
  switch (status) {
    case Status.BAD_REQUEST:
      return 'Bad Request';
    case Status.UNAUTHORIZED:
      return 'Unauthorized';
    case Status.NOT_FOUND:
      return 'Not Found';
    case Status.UNSUPPORTED_ACTION:
      return 'Unsupported Action';
    case Status.VALIDATION_FAILED:
      return 'Validation Failed';
    case Status.SERVER_ERROR:
      return 'Internal Server Error';
  }
}

function jsonResponse(res, body, options) {
  options || (options = {});
  options.status || (options.status = Status.OK);
  res.json(options.status, body || null);
}

var api = {
  ok: function (req, res, data) {
    jsonResponse(res, data, { status: Status.OK });
  },

  badRequest: function (req, res, errors) {
    Array.isArray(errors) || (errors = [errors]);

    var body = {
      message: statusMessage(Status.BAD_REQUEST),
      errors: errors
    };

    jsonResponse(res, body, { status: Status.BAD_REQUEST });
  },

  unauthorized: function (req, res) {
    var body = { message: statusMessage(Status.UNAUTHORIZED) };

    jsonResponse(res, body, { status: Status.UNAUTHORIZED });
  },

  notFound: function (req, res) {
    var body = { message: statusMessage(Status.NOT_FOUND) };

    jsonResponse(res, body, { status: Status.NOT_FOUND });
  },

  unsupportedAction: function (req, res) {
    var body = { message: statusMessage(Status.UNSUPPORTED_ACTION) };

    jsonResponse(res, body, { status: Status.UNSUPPORTED_ACTION });
  },

  invalid: function (req, res, errors) {
    Array.isArray(errors) || (errors = [errors]);

    var body = {
      message: statusMessage(Status.VALIDATION_FAILED),
      errors: errors
    };

    jsonResponse(res, body, { status: Status.VALIDATION_FAILED });
  },

  serverError: function (req, res, error) {
    if (error instanceof Error) {
      error = {
        message: error.message,
        stacktrace: error.stack
      };
    }
    var body = {
      message: statusMessage(Status.SERVER_ERROR),
      error: error
    };

    jsonResponse(res, body, { status: Status.SERVER_ERROR });
  },

  requireParams: function (req, res, params, next) {
    var missing = []
      , hasOwn = Object.prototype.hasOwnProperty;

    Array.isArray(params) || (params = [params]);

    params.forEach(function (param) {
      if (!(req.body && hasOwnProperty.call(req.body, param)) &&
          !(req.params && hasOwnProperty.call(req.params, param)) &&
          !hasOwnProperty.call(req.query, param)) {
        missing.push("Missing required parameter: " + param);
      }
    });

    if (missing.length) {
      api.badRequest(req, res, missing);
    }
    else {
      next();
    }
  }
};

module.exports = api;
<commit_msg>Fix deprecation warnings on Express 4 and add support for checking headers.<commit_after>'use strict';

var _hasOwnProperty = Object.prototype.hasOwnProperty;

var Status = {
    OK: 200,
    BAD_REQUEST: 400,
    UNAUTHORIZED: 401,
    NOT_FOUND: 404,
    UNSUPPORTED_ACTION: 405,
    VALIDATION_FAILED: 422,
    SERVER_ERROR: 500
};

function statusMessage(status) {
    switch (status) {
        case Status.BAD_REQUEST:
            return 'Bad Request';
        case Status.UNAUTHORIZED:
            return 'Unauthorized';
        case Status.NOT_FOUND:
            return 'Not Found';
        case Status.UNSUPPORTED_ACTION:
            return 'Unsupported Action';
        case Status.VALIDATION_FAILED:
            return 'Validation Failed';
        case Status.SERVER_ERROR:
            return 'Internal Server Error';
    }
}

function jsonResponse(res, body, options) {
    options = options || {};
    options.status = options.status || Status.OK;
    res.status(options.status).json(body || null);
}

var api = {
    ok: function(req, res, data) {
        jsonResponse(res, data, {
            status: Status.OK
        });
    },

    badRequest: function(req, res, errors) {
        errors = Array.isArray(errors) ? errors : [errors];

        var body = {
            message: statusMessage(Status.BAD_REQUEST),
            errors: errors
        };

        jsonResponse(res, body, {
            status: Status.BAD_REQUEST
        });
    },

    unauthorized: function(req, res) {
        var body = {
            message: statusMessage(Status.UNAUTHORIZED)
        };

        jsonResponse(res, body, {
            status: Status.UNAUTHORIZED
        });
    },

    notFound: function(req, res) {
        var body = {
            message: statusMessage(Status.NOT_FOUND)
        };

        jsonResponse(res, body, {
            status: Status.NOT_FOUND
        });
    },

    unsupportedAction: function(req, res) {
        var body = {
            message: statusMessage(Status.UNSUPPORTED_ACTION)
        };

        jsonResponse(res, body, {
            status: Status.UNSUPPORTED_ACTION
        });
    },

    invalid: function(req, res, errors) {
        errors = Array.isArray(errors) ? errors : [errors];

        var body = {
            message: statusMessage(Status.VALIDATION_FAILED),
            errors: errors
        };

        jsonResponse(res, body, {
            status: Status.VALIDATION_FAILED
        });
    },

    serverError: function(req, res, error) {
        if (error instanceof Error) {
            error = {
                message: error.message,
                stacktrace: error.stack
            };
        }
        var body = {
            message: statusMessage(Status.SERVER_ERROR),
            error: error
        };

        jsonResponse(res, body, {
            status: Status.SERVER_ERROR
        });
    },

    requireParams: function(req, res, params, next) {
        var missing = [];

        params = Array.isArray(params) ? params : [params];

        params.forEach(function(param) {
            if (!(req.body && _hasOwnProperty.call(req.body, param)) && !(req.params && _hasOwnProperty.call(req.params, param)) && !_hasOwnProperty.call(req.query, param)) {
                missing.push('Missing required parameter: ' + param);
            }
        });

        if (missing.length) {
            api.badRequest(req, res, missing);
        } else {
            next();
        }
    },

    requireHeaders: function(req, res, headers, next) {
        var missing = [];

        headers = Array.isArray(headers) ? headers : [headers];

        headers.forEach(function(header) {
            if (!(req.headers && _hasOwnProperty.call(req.headers, header))) {
                missing.push('Missing required header parameter: ' + header);
            }
        });

        if (missing.length) {
            api.badRequest(req, res, missing);
        } else {
            next();
        }
    }
};

module.exports = api;
<|endoftext|>